STM32F107RC核心板 + Atollic TrueStudio + Win8.1
打开参考手册第三章,可以获知:不同储存容量的单片机有不同的FLASH分布,而主要分为以下几类。1、low-density,2、medium-density,3、high-density,4、connectivity line。我们需要根据使用的单片机容量,确认其FLASH分布。
下图中,Table 3是STM32F107RC规格书上的关于兼容性的描述。从这里以及规格书上文描述,我们可以知道:
STM32F107RC属于connectivity line。
/**
******************************************************************************
* 文件名程: stm_flash.c
* 作 者: 硬石嵌入式开发团队
* 版 本: V1.0
* 编写日期: 2015-10-04
* 功 能: 内部Falsh读写实现
******************************************************************************
* 说明:
* 本例程配套硬石stm32开发板YS-F1Pro使用。
*
* 淘宝:
* 论坛:http://www.ing10bbs.com
* 版权归硬石嵌入式开发团队所有,请勿商用。
******************************************************************************
*/
/* 包含头文件 ----------------------------------------------------------------*/
#include "stm32f107_flash.h"
/* 私有类型定义 --------------------------------------------------------------*/
/* 私有宏定义 ----------------------------------------------------------------*/
#if STM32_FLASH_SIZE < 256
#define STM_SECTOR_SIZE 1024 //字节
#else
#define STM_SECTOR_SIZE 2048
#endif
/* 私有变量 ------------------------------------------------------------------*/
#if STM32_FLASH_WREN //如果使能了写
static uint16_t STMFLASH_BUF [ STM_SECTOR_SIZE / 2 ];//最多是2K字节
static FLASH_EraseInitTypeDef EraseInitStruct;
#endif
/* 扩展变量 ------------------------------------------------------------------*/
/* 私有函数原形 --------------------------------------------------------------*/
/* 函数体 --------------------------------------------------------------------*/
/**
* 函数功能: 读取指定地址的半字(16位数据)
* 输入参数: faddr:读地址(此地址必须为2的倍数!!)
* 返 回 值: 返回值:对应数据.
* 说 明:无
*/
uint16_t STMFLASH_ReadHalfWord ( uint32_t faddr )
{
return *(__IO uint16_t*)faddr;
}
#if STM32_FLASH_WREN //如果使能了写
/**
* 函数功能: 不检查的写入
* 输入参数: WriteAddr:起始地址
* pBuffer:数据指针
* NumToWrite:半字(16位)数
* 返 回 值: 无
* 说 明:无
*/
void STMFLASH_Write_NoCheck ( uint32_t WriteAddr, uint16_t * pBuffer, uint16_t NumToWrite )
{
uint16_t i;
for(i=0;i=(FLASH_BASE+1024*STM32_FLASH_SIZE)))return;//非法地址
HAL_FLASH_Unlock(); //解锁
offaddr=WriteAddr-FLASH_BASE; //实际偏移地址.
secpos=offaddr/STM_SECTOR_SIZE; //扇区地址 0~127 for STM32F103RBT6
secoff=(offaddr%STM_SECTOR_SIZE)/2; //在扇区内的偏移(2个字节为基本单位.)
secremain=STM_SECTOR_SIZE/2-secoff; //扇区剩余空间大小
if(NumToWrite<=secremain)secremain=NumToWrite;//不大于该扇区范围
while(1)
{
STMFLASH_Read(secpos*STM_SECTOR_SIZE+FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//读出整个扇区的内容
for(i=0;i(STM_SECTOR_SIZE/2))secremain=STM_SECTOR_SIZE/2;//下一个扇区还是写不完
else secremain=NumToWrite;//下一个扇区可以写完了
}
};
HAL_FLASH_Lock();//上锁
}
#endif
/**
* 函数功能: 从指定地址开始读出指定长度的数据
* 输入参数: ReadAddr:起始地址
* pBuffer:数据指针
* NumToRead:半字(16位)数
* 返 回 值: 无
* 说 明:无
*/
void STMFLASH_Read ( uint32_t ReadAddr, uint16_t *pBuffer, uint16_t NumToRead )
{
uint16_t i;
for(i=0;i
#ifndef __STMFLASH_H__
#define __STMFLASH_H__
/* 包含头文件 ----------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/* 类型定义 ------------------------------------------------------------------*/
/* 宏定义 --------------------------------------------------------------------*/
/************************** STM32 内部 FLASH 配置 *****************************/
#define STM32_FLASH_SIZE 256 // 所选STM32的FLASH容量大小(单位为K)
#define STM32_FLASH_WREN 1 // stm32芯片内容FLASH 写入使能(0,禁用;1,使能)
typedef enum
{
FAILED = 0,
PASSED = !FAILED
}TestStatus;
#define FLASH_WriteAddress 0x0803F800 // 写在靠后位置,防止破坏程序
#define FLASH_ReadAddress FLASH_WriteAddress
#define FLASH_TESTSIZE 512 //实际是512*2=1024字节
/* 扩展变量 ------------------------------------------------------------------*/
/* 函数声明 ------------------------------------------------------------------*/
uint16_t STMFLASH_ReadHalfWord(uint32_t faddr); //读出半字
void STMFLASH_WriteLenByte(uint32_t WriteAddr, uint32_t DataToWrite, uint16_t Len ); //指定地址开始写入指定长度的数据
uint32_t STMFLASH_ReadLenByte(uint32_t ReadAddr, uint16_t Len ); //指定地址开始读取指定长度数据
void STMFLASH_Write( uint32_t WriteAddr, uint16_t * pBuffer, uint16_t NumToWrite ); //从指定地址开始写入指定长度的数据
void STMFLASH_Read( uint32_t ReadAddr, uint16_t * pBuffer, uint16_t NumToRead ); //从指定地址开始读出指定长度的数据
//static TestStatus Buffercmp(uint16_t* pBuffer1, uint16_t* pBuffer2, uint16_t BufferLength);
TestStatus Buffercmp(uint16_t* pBuffer1, uint16_t* pBuffer2, uint16_t BufferLength);
#endif /* __STMFLASH_H__ */
/******************* (C) COPYRIGHT 2015-2020 硬石嵌入式开发团队 *****END OF FILE****/
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* © Copyright (c) 2019 STMicroelectronics.
* All rights reserved.
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "can.h"
#include "dma.h"
#include "lwip.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "string.h"
#include "tcp_echoclient.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define COUNTOF(__BUFFER__) (sizeof(__BUFFER__) / sizeof(*(__BUFFER__)))
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
uint32_t counter_10ms, counter_50ms, counter_100ms, counter_200ms, counter_500ms, counter_1000ms, counter_2000ms, counter_5000ms, counter_10s;
uint8_t flag_1ms, flag_10ms, flag_50ms, flag_100ms, flag_200ms, flag_500ms, flag_1000ms, flag_2000ms, flag_5000ms, flag_10s;
uint8_t b_KeyNumber;
uint8_t a_DtuInBuffer[100];
uint16_t b_DtuInBufferRxCnt;
uint8_t a_DtuOutBuffer[100];
uint16_t b_DtuOutBufferRxCnt;
struct netif gnetif;
extern struct tcp_pcb *echoclient_pcb;
uint32_t status_TCPProc;
uint8_t a_SocketConfig[7];
uint8_t a_SocketHeartBeat[60];
uint8_t a_SocketHeartBeatInterval[2];
uint8_t a_SocketRegister[60];
uint8_t a_DtuInOutConfig[2];
uint8_t b_WifiMode;
uint8_t a_RouterSsid[20];
uint8_t a_RouterPswd[20];
uint8_t a_Rs485Config[5];
uint8_t a_CanConfig[5];
uint8_t flag_DtuConfigUpdate;
uint8_t flag_DtuEthReady = 0;
uint32_t b_HeartBeatPackageCnt = 0;
uint32_t b_232STM32ParamConfigBusyCnt = 0; //尝试通过串口和STM32交互时候,会让出相应时间,优先处理
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void Task_HeartBeatPackSent(void)
{
uint16_t b_interval;
b_interval = (a_SocketHeartBeatInterval[0]<<8) + a_SocketHeartBeatInterval[1];
b_HeartBeatPackageCnt++;
if(b_HeartBeatPackageCnt>=b_interval)
{
b_HeartBeatPackageCnt = 0;
if(a_DtuInOutConfig[1]==1)
{
if(flag_8266DTUReady==1)
{
HAL_UART_Transmit(&huart3, a_SocketHeartBeat, strlen((char*)a_SocketHeartBeat), 100);
printf("\r\n");
printf("\r\nA heart beat package is sent.\r\n ");
}
}
else if(a_DtuInOutConfig[1]==2)
{
if(status_TCPProc>=2)
{
tcp_senddata(1);
printf("\r\n");
printf("\r\nA heart beat package is sent.\r\n ");
}
}
}
}
void cleanDtuInBuffer(void)
{
uint32_t i;
for(i=0;i0)
{
printf("\r\n");
printf("\r\nData sent to Wifi: ");
HAL_UART_Transmit(&huart3, (uint8_t*)a_DtuInBuffer, b_DtuInBufferRxCnt, 100);
HAL_UART_Transmit(&huart1, (uint8_t*)a_DtuInBuffer, b_DtuInBufferRxCnt, 100); //debug
cleanDtuInBuffer();
}
}
}
else if(a_DtuInOutConfig[1]==2)
{
if(status_TCPProc>=2)
{
if(status_TCPProc == 2)
{
tcp_senddata(0); //专门发送注册包
}
if(b_DtuInBufferRxCnt>0)
{
if(status_TCPProc <= 3)
{
tcp_senddata(0);
}
else
{
status_TCPProc = 0;
}
cleanDtuInBuffer();
}
}
}
//把数据输出到RS232,RS485或者CAN
if(a_DtuInOutConfig[0]==1)
{
if(b_DtuOutBufferRxCnt>0)
{
HAL_UART_Transmit(&huart1, (uint8_t*)a_DtuOutBuffer, b_DtuOutBufferRxCnt, 100);
cleanDtuOutBuffer();
}
}
else if(a_DtuInOutConfig[0]==2)
{
if(b_DtuOutBufferRxCnt>0)
{
printf("\r\n");
printf("\r\nData sent to RS485: ");
HAL_UART_Transmit(&huart1, (uint8_t*)a_DtuOutBuffer, b_DtuOutBufferRxCnt, 100);//debug
RS485_TX_MODE();
HAL_UART_Transmit(&huart5, (uint8_t*)a_DtuOutBuffer, b_DtuOutBufferRxCnt, 100);
HAL_Delay(1);
RS485_RX_MODE();
cleanDtuOutBuffer();
}
}
else if(a_DtuInOutConfig[0]==3)
{
if(b_DtuOutBufferRxCnt>0)
{
k = 0;
if(b_DtuOutBufferRxCnt>8)
{
for(i=0; i<8; i++)
{
Can_TxData[i] = a_DtuOutBuffer[i];
k += Can_TxData[i];
}
}
else
{
for(i=0; i0)
{
if(b_DtuOutBufferRxCnt>8)
{
Can_TxMessage(0, Can_TxHeader.StdId, 8, Can_TxData);
}
else
{
Can_TxMessage(0, Can_TxHeader.StdId, b_DtuOutBufferRxCnt, Can_TxData);
}
ArrayLeftShift8bits(a_DtuOutBuffer, &b_DtuOutBufferRxCnt);
}
else
{
b_DtuOutBufferRxCnt = 0;
}
}
}
}
void Task_DtuRedoConfig(void)
{
if(flag_DtuConfigUpdate==0)
return;
HAL_Delay(10);
printf("Re-initialize ETH, WIFI module, RS485... ");
//ETH:
if(status_TCPProc >= 2)
{
tcp_echoclient_disconnect();
status_TCPProc = 0;
}
//ESP8266:
if(Status_NodeMCU>=6)
{
sprintf((char *)a_8266TxBuffer, "+++"); //esp8266 接收到这个+++会停止透传模式
HAL_UART_Transmit(&huart3, (uint8_t *)a_8266TxBuffer, strlen((char *)a_8266TxBuffer), 100);
Status_NodeMCU = 0;
HAL_Delay(100);
}
//485
//MX_RS485_Reconfigure();
printf("Completed.\r\n");
//
flag_DtuConfigUpdate = 0;
HAL_UART_Receive_IT(&huart1, &b_232RxByte, 1);
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
MX_USART3_UART_Init();
MX_CAN1_Init();
MX_UART5_Init();
MX_LWIP_Init();
/* USER CODE BEGIN 2 */
RS232Interact_Init();
printf("Hello. STM32F107_DTU project: DTU. All in one.\n");
HAL_UART_Receive_IT(&huart1, &b_232RxByte, 1);
HAL_UART_Receive_IT(&huart5, &b_485RxByte, 1);
sprintf((char *)a_8266TxBuffer, "+++"); //esp8266 接收到这个+++会停止透传模式
HAL_UART_Transmit(&huart3, (uint8_t *)a_8266TxBuffer, strlen((char *)a_8266TxBuffer), 100);
Status_NodeMCU = 0;
status_TCPProc = 0;
RS485_RX_MODE();
CAN_Config_User();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
if(a_DtuInOutConfig[1]==2)
{
MX_LWIP_Process();
}
if(flag_1ms ==1)
{
flag_1ms = 0;
Task_232PC_Interact();
if(flag_DtuConfigUpdate ==1)
{
Task_DtuRedoConfig();
}
if(b_232STM32ParamConfigBusyCnt>6)
{
Task_DirectTransfer();
}
}
if(flag_10ms==1)
{
flag_10ms=0;
}
if(flag_50ms==1) { flag_50ms=0; }
if(flag_100ms==1)
{
if(b_232STM32ParamConfigBusyCnt>6)
{
if(a_DtuInOutConfig[1]==1)
{
if((flag_ProcNodeMCUActive ==1)&&(status_232PC<12))
{
Proc_NodeMCU();
}
}
}
flag_100ms=0;
}
if(flag_200ms==1) { flag_200ms=0; }
if(flag_500ms==1) { flag_500ms=0; }
if(flag_1000ms==1)
{
flag_1000ms=0;
HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
if(b_232STM32ParamConfigBusyCnt>6)
{
if(a_DtuInOutConfig[1]==2)
{
if(status_TCPProc<=1)
{
printf("connecting to TCP Server...\r\n");
tcp_echoclient_connect();
}
}
Task_HeartBeatPackSent();
}
if(flag_ProcNodeMCUActive ==0)
{
flag_ProcNodeMCUActive = 1;
}
if(b_232STM32ParamConfigBusyCnt<80)
{
b_232STM32ParamConfigBusyCnt++;
}
}
if(flag_2000ms==1)
{
flag_2000ms=0;
}
if(flag_5000ms==1)
{
flag_5000ms=0;
}
if(flag_10s==1)
{
flag_10s=0;
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV5;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.Prediv1Source = RCC_PREDIV1_SOURCE_PLL2;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
RCC_OscInitStruct.PLL2.PLL2State = RCC_PLL2_ON;
RCC_OscInitStruct.PLL2.PLL2MUL = RCC_PLL2_MUL10;
RCC_OscInitStruct.PLL2.HSEPrediv2Value = RCC_HSE_PREDIV2_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
/** Enables the Clock Security System
*/
HAL_RCC_EnableCSS();
/** Configure the Systick interrupt time
*/
__HAL_RCC_PLLI2S_ENABLE();
}
/* USER CODE BEGIN 4 */
/**
* @brief HAL_SYSTICK_Callback()
* SW timer triggered every 1ms.
*/
void HAL_SYSTICK_Callback(void)
{
flag_1ms = 1;
/*update counters*/
if(counter_10ms<9) { counter_10ms++; }
else { counter_10ms = 0; flag_10ms = 1; }
if(counter_50ms<49) { counter_50ms++; }
else { counter_50ms = 0; flag_50ms = 1; }
if(counter_100ms<99) { counter_100ms++; }
else { counter_100ms = 0; flag_100ms = 1;
if(counter_200ms<1) { counter_200ms++; }
else { counter_200ms = 0; flag_200ms = 1; }
if(counter_500ms<4) { counter_500ms++; }
else { counter_500ms = 0; flag_500ms = 1; }
if(counter_1000ms<9) { counter_1000ms++; }
else { counter_1000ms = 0; flag_1000ms = 1; }
if(counter_2000ms<19) { counter_2000ms++; }
else { counter_2000ms = 0; flag_2000ms = 1; }
if(counter_5000ms<49) { counter_5000ms++; }
else { counter_5000ms = 0; flag_5000ms = 1; }
if(counter_10s<99) { counter_10s++; }
else { counter_10s = 0; flag_10s = 1; }
}
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin ==GPIO_PIN_13)
{
b_KeyNumber++;
if(b_KeyNumber>=2)
{
b_KeyNumber = 0;
}
sprintf((char *)a_DtuInBuffer, "a simple package\r\n");
b_DtuInBufferRxCnt = strlen((char *)a_DtuInBuffer);
}
}
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
开发板上面的指示灯亮了,同时使用仿真器观察接收数组的内容:
参考资料:
1、STM32F107规格书,https://www.st.com/resource/en/datasheet/stm32f107rc.pdf
2、STM32F107参考手册,https://www.st.com/resource/en/reference_manual/cd00171190.pdf
3、硬石YS-F1Pro开发板资料,http://www.ing10bbs.com/forum.php?mod=viewthread&tid=1458&extra=page%3D1