STM32F1 internal FLASH read and write routines

1. Environment

STM32F107RC core board + Atollic TrueStudio + Win8.1

2. Classification of STM32F1 series microcontrollers

Open the third chapter of the reference manual, you can know that: MCUs with different storage capacities have different FLASH distributions, which are mainly divided into the following categories. 1, low-density, 2, medium-density, 3, high-density, 4. connectivity line. We need to confirm the FLASH distribution according to the capacity of the MCU used.

In the figure below, Table 3 is the description of compatibility on the STM32F107RC specification. From here and the description above in the specification, we can know:

STM32F107RC belongs to the connectivity line.

 

 

 3. Hard Rock STM32F1 open source source code

3.1 stm32f107_flash.c

/**
  ******************************************************************************
  * 文件名程: 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<NumToWrite;i++)
  {
	HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD,WriteAddr,pBuffer[i]);
	WriteAddr+=2;                                    //地址增加2.
  }
} 

/**
  * 函数功能: 从指定地址开始写入指定长度的数据
  * 输入参数: WriteAddr:起始地址(此地址必须为2的倍数!!)
  *           pBuffer:数据指针
  *           NumToWrite:半字(16位)数(就是要写入的16位数据的个数.)
  * 返 回 值: 无
  * 说    明:无
  */
void STMFLASH_Write ( uint32_t WriteAddr, uint16_t * pBuffer, uint16_t NumToWrite )	
{
  uint32_t SECTORError = 0;
  uint16_t secoff;	   //扇区内偏移地址(16位字计算)
  uint16_t secremain; //扇区内剩余地址(16位字计算)
  uint16_t i;
  uint32_t secpos;	   //扇区地址
  uint32_t offaddr;   //去掉0X08000000后的地址
	
  if(WriteAddr<FLASH_BASE||(WriteAddr>=(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<secremain;i++)//校验数据
	{
	  if(STMFLASH_BUF[secoff+i]!=0XFFFF)break;//需要擦除
	}
	if(i<secremain)//需要擦除
	{
	  //擦除这个扇区
	  /* Fill EraseInit structure*/
      EraseInitStruct.TypeErase     = FLASH_TYPEERASE_PAGES;
      EraseInitStruct.PageAddress   = secpos*STM_SECTOR_SIZE+FLASH_BASE;
      EraseInitStruct.NbPages       = 1;
      HAL_FLASHEx_Erase(&EraseInitStruct, &SECTORError);

      for(i=0;i<secremain;i++)//复制
      {
    	STMFLASH_BUF[i+secoff]=pBuffer[i];
      }
      STMFLASH_Write_NoCheck(secpos*STM_SECTOR_SIZE+FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//写入整个扇区
	}
    else
    {
      STMFLASH_Write_NoCheck(WriteAddr,pBuffer,secremain);//写已经擦除了的,直接写入扇区剩余区间. 				   
    }
    if(NumToWrite==secremain)break;//写入结束了
    else//写入未结束
    {
      secpos++;				//扇区地址增1
      secoff=0;				//偏移位置为0
      pBuffer+=secremain;  	//指针偏移
      WriteAddr+=secremain;	//写地址偏移
      NumToWrite-=secremain;	//字节(16位)数递减
      if(NumToWrite>(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<NumToRead;i++)
  {
	pBuffer[i]=STMFLASH_ReadHalfWord(ReadAddr);//读取2个字节.
	ReadAddr+=2;//偏移2个字节.
  }
}

/*
 * 函数名:Buffercmp
 * 描述  :比较两个缓冲区中的数据是否相等
 * 输入  :-pBuffer1     src缓冲区指针
 *         -pBuffer2     dst缓冲区指针
 *         -BufferLength 缓冲区长度
 * 输出  :无
 * 返回  :-PASSED pBuffer1 等于   pBuffer2
 *         -FAILED pBuffer1 不同于 pBuffer2
 */
TestStatus Buffercmp(uint16_t* pBuffer1, uint16_t* pBuffer2, uint16_t BufferLength)
{
  while(BufferLength--)
  {
    printf("data:%d - %d \n",*pBuffer1 , *pBuffer2);
    if(*pBuffer1 != *pBuffer2)
    {
      return FAILED;
    }

    pBuffer1++;
    pBuffer2++;
  }
  return PASSED;
}


/******************* (C) COPYRIGHT 2015-2020 硬石嵌入式开发团队 *****END OF FILE****/

3.2 stm32f107_flash.h

#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****/

3.3 main.c

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * 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;i<b_DtuInBufferRxCnt;i++)
  {
	a_DtuInBuffer[i] = 0;
  }
  b_DtuInBufferRxCnt = 0;
}
void cleanDtuOutBuffer(void)
{
  uint32_t i;
  for(i=0;i<b_DtuOutBufferRxCnt;i++)
  {
	a_DtuOutBuffer[i] = 0;
  }
  b_DtuOutBufferRxCnt = 0;
}

void Task_DirectTransfer(void)
{
  uint32_t i, k;
  //把数据输出到以太网或者WIFI
  if(a_DtuInOutConfig[1]==1)
  {
	if(flag_8266DTUReady==1)
	{
	  if(b_DtuInBufferRxCnt>0)
	  {
		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; i<b_DtuOutBufferRxCnt; i++)
		{
		  Can_TxData[i] = a_DtuOutBuffer[i];
		  k += Can_TxData[i];
		}
	  }
	  if(k>0)
	  {
		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****/

4 Test results

The indicator light on the development board is on, and use the emulator to observe the contents of the receiving array:

 Reference materials:

1. STM32F107 specification, https://www.st.com/resource/en/datasheet/stm32f107rc.pdf

2. STM32F107 reference manual, https://www.st.com/resource/en/reference_manual/cd00171190.pdf

3. Hard Rock YS-F1Pro development board information, http://www.ing10bbs.com/forum.php?mod=viewthread&tid=1458&extra=page%3D1

Guess you like

Origin blog.csdn.net/qq_27158179/article/details/96423428