FreeRTOS记录(九、一个裸机工程转FreeRTOS的实例)_freertos项目

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新

需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)

如果你需要这些资料,可以戳这里获取

目录

对于裸机向FreeRTOS的转变,简单可以用下图表示:

在这里插入图片描述

我们前面的文章介绍过的FreeRTOS的任务原理,调度机制,这篇文章只做移植记录。

一、裸机程序到FreeRTOS概述

裸机到FreeRTOS的转变:

  • 该写的驱动还是要写,如果平台一样是可以直接用裸机中的。
    比如工程中的按键驱动mod_button.c
    按键驱动程序源码请参考我的另一篇博文:几个实用的按键驱动
  • 以前 驱动 或 函数 中的 ”干等“”的延时函数,不是中断中调用的情况下是可以直接改成·osDelay(ms 延时函数),us 的延时函数(I2C协议中使用的),可以沿用以前的。(STM32CubeMX 下并没有现成的 us 延时函数,可以自己写一个简单的);
    .
    在这里插入图片描述.
    上图为温湿度读取的函数,可以看到修改了多种不同的延时函数,因为用在了不同的平台上面;
    .
    在这里插入图片描述
    上图为 32Mhz 主频下面的 不准确 us 延时函数。
  • 以前 驱动 或 函数 中有些也是 轮询方式设计的,如果使用了 FreeRTOS 的一些信号量,任务通知,消息队列等可以实现 唤醒触发任务方式的机制,需要稍作修改。
    .
    在这里插入图片描述
    上图中判断是否接收到报文的语句if(Read_pt != Enocean_Data)是裸机中用来判断串口是否开始接收到了数据,接收到了,立即 干等 一段时间HAL_Delay(7);但是在FreeRTOS 中不需要这样的干等。
  • 以前的全局变量,为了修改少,移植简单,可以沿用以前的全局变量,包括一些标志位。
    .
    在这里插入图片描述
  • 以前的 中断 ,不直接涉及到任务的,该怎样还是怎样:
    .
    在这里插入图片描述
    如果直接和任务有关的,需要做一定的修改, 比如 定时器定时任务 与 事件组有关:
    .
    在这里插入图片描述
    再比如串口接收中断 使用 消息队列接收数据:
    .在这里插入图片描述
  • 考虑到 STM32L051 的 ram 空间只有 8KB,还需要时刻关注着内存使用情况!!!

二、移植过程

2.1 基本框架搭建

1、首先在STM32CubeMX中根据原理图把基础的东西设置好,本测试的芯片是STM32L051C8T6,可以参考博文:

STM32L051测试 (一、使用CubeMX生成工程文件)

在window下使用VScode搭建ARM开发环境——手把手教学详细版
在这里插入图片描述

2、然后在FreeRTOS配置中,新建3个任务 和 一个消息队列,可参考博文:

FreeRTOS记录(一、熟悉开发环境以及CubeMX下FreeRTOS配置)

FreeRTOS记录(六、FreeRTOS消息队列—Enocean模块串口通讯、RAM空间不足问题分析)
.
在这里插入图片描述

3、添加基本的代码,添加以前写好的驱动文件,每个驱动拿过来记得在Makefile中添加一下,然后每一步编译保证没有错误(此部分是最初的源码,后面还需要补充,还会对每个细节进行说明):

在这里插入图片描述

4、添加FreeRTOS相关基本代码,直接上源码(此部分是最初的源码,后面还需要补充,还会对每个细节进行说明):

/\* Includes ------------------------------------------------------------------\*/
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis\_os.h"

/\* Private includes ----------------------------------------------------------\*/
/\* USER CODE BEGIN Includes \*/     
#include "stdio.h"
#include "Enocean.h"
#include "mod\_button.h"
#include <string.h>
/\* USER CODE END Includes \*/

/\* Private typedef -----------------------------------------------------------\*/
/\* USER CODE BEGIN PTD \*/

/\* USER CODE END PTD \*/

/\* Private define ------------------------------------------------------------\*/
/\* USER CODE BEGIN PD \*/

/\* USER CODE END PD \*/

/\* Private macro -------------------------------------------------------------\*/
/\* USER CODE BEGIN PM \*/
BTN_STRUCT	LEARN_BUTTON_2S ={ Lrn_Key_GPIO_Port,	
            Lrn_Key_Pin, // Pin
						BTN_ACTIVE,			                  // Active state
						2000,		                          // Time the button has to be in 'Active state' to be recognized as pressed
						100 };

BTN_STRUCT	LEARN_BUTTON_150mS ={ Lrn_Key_GPIO_Port,	
            Lrn_Key_Pin, // Pin
						BTN_ACTIVE,			                  // Active state
						150,		                          // Time the button has to be in 'Active state' to be recognized as pressed
						100 };		

BTN_STRUCT	CLEAR_BUTTON_2S = { Clr_Key_GPIO_Port,	
            Clr_Key_Pin, // Pin
						BTN_ACTIVE,			                  // Active state
						2000,		                          //Time the button has to be in 'Active state' to be recognized as pressed
						100	 };	
BTN_STRUCT	CLEAR_BUTTON_150mS = { Clr_Key_GPIO_Port,	
            Clr_Key_Pin, // Pin
						BTN_ACTIVE,			                  // Active state
						150,		                          //Time the button has to be in 'Active state' to be recognized as pressed
						100	 };	

BTN_STRUCT	CLEAR_BUTTON_5S = { Clr_Key_GPIO_Port,	
            Clr_Key_Pin, // Pin
						BTN_ACTIVE,			                  // Active state
						4500,		                          // Time the button has to be in 'Active state' to be recognized as pressed
						100	 };	

BTN_STRUCT	LEARN_BUTTON_5S = { Lrn_Key_GPIO_Port,	
            Lrn_Key_Pin, // Pin
						BTN_ACTIVE,			                  // Active state
						5000,		                          // Time the button has to be in 'Active state' to be recognized as pressed
						100	 };	
/\* USER CODE END PM \*/

/\* Private variables ---------------------------------------------------------\*/
/\* USER CODE BEGIN Variables \*/

/\* USER CODE END Variables \*/
osThreadId KeyTaskHandle;
osThreadId LEDTaskHandle;
osThreadId enoecanreceivedHandle;
osMessageQId EnoceanQueueHandle;

/\* Private function prototypes -----------------------------------------------\*/
/\* USER CODE BEGIN FunctionPrototypes \*/
void Relay\_On(uint8\_t ch)
{
  if(ch == 1){
    HAL\_GPIO\_WritePin(Relay1_Control_GPIO_Port,Relay1_Control_Pin,GPIO_PIN_SET);
    osDelay(20);
    HAL\_GPIO\_WritePin(Relay1_Control_GPIO_Port,Relay1_Control_Pin,GPIO_PIN_RESET);
  }
  else if(ch == 2){
    HAL\_GPIO\_WritePin(Relay2_Control_GPIO_Port,Relay2_Control_Pin,GPIO_PIN_SET);
    osDelay(20);
    HAL\_GPIO\_WritePin(Relay2_Control_GPIO_Port,Relay2_Control_Pin,GPIO_PIN_RESET);
  }
}

void Relay\_Off(uint8\_t ch)
{
  if(ch == 1){
    HAL\_GPIO\_WritePin(Relay1_Close_GPIO_Port,Relay1_Close_Pin,GPIO_PIN_SET);
    osDelay(20);
    HAL\_GPIO\_WritePin(Relay1_Close_GPIO_Port,Relay1_Close_Pin,GPIO_PIN_RESET);
  }
  else if(ch == 2){
    HAL\_GPIO\_WritePin(Relay2_Close_GPIO_Port,Relay2_Close_Pin,GPIO_PIN_SET);
    osDelay(20);
    HAL\_GPIO\_WritePin(Relay2_Close_GPIO_Port,Relay2_Close_Pin,GPIO_PIN_RESET);
  }
} 

/\* USER CODE END FunctionPrototypes \*/

void StartKeyTask(void const \* argument);
void StartLEDTask(void const \* argument);
void StartenoecanTask(void const \* argument);

void MX\_FREERTOS\_Init(void); /\* (MISRA C 2004 rule 8.1) \*/

/\* GetIdleTaskMemory prototype (linked to static allocation support) \*/
void vApplicationGetIdleTaskMemory( StaticTask_t \*\*ppxIdleTaskTCBBuffer, StackType_t \*\*ppxIdleTaskStackBuffer, uint32\_t \*pulIdleTaskStackSize );

/\* USER CODE BEGIN GET\_IDLE\_TASK\_MEMORY \*/
static StaticTask_t xIdleTaskTCBBuffer;
static StackType_t xIdleStack[configMINIMAL_STACK_SIZE];
  
void vApplicationGetIdleTaskMemory( StaticTask_t \*\*ppxIdleTaskTCBBuffer, StackType_t \*\*ppxIdleTaskStackBuffer, uint32\_t \*pulIdleTaskStackSize )
{
  \*ppxIdleTaskTCBBuffer = &xIdleTaskTCBBuffer;
  \*ppxIdleTaskStackBuffer = &xIdleStack[0];
  \*pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
  /\* place for user code \*/
}                   
/\* USER CODE END GET\_IDLE\_TASK\_MEMORY \*/

/\*\*
 \* @brief FreeRTOS initialization
 \* @param None
 \* @retval None
 \*/
void MX\_FREERTOS\_Init(void) {
  /\* USER CODE BEGIN Init \*/
  printf("Free RTOS init! \r\n");  //for printf test
  /\* USER CODE END Init \*/

  /\* USER CODE BEGIN RTOS\_MUTEX \*/
  /\* add mutexes, ... \*/
  /\* USER CODE END RTOS\_MUTEX \*/

  /\* USER CODE BEGIN RTOS\_SEMAPHORES \*/
  /\* add semaphores, ... \*/
  /\* USER CODE END RTOS\_SEMAPHORES \*/

  /\* USER CODE BEGIN RTOS\_TIMERS \*/
  /\* start timers, add new ones, ... \*/
  
  /\* USER CODE END RTOS\_TIMERS \*/

  /\* Create the queue(s) \*/
  /\* definition and creation of EnoceanQueue \*/
  osMessageQDef(EnoceanQueue, 50, uint8\_t);
  EnoceanQueueHandle = osMessageCreate(osMessageQ(EnoceanQueue), NULL);

  /\* USER CODE BEGIN RTOS\_QUEUES \*/
  /\* add queues, ... \*/
  /\* USER CODE END RTOS\_QUEUES \*/

  /\* Create the thread(s) \*/
  /\* definition and creation of KeyTask \*/
  osThreadDef(KeyTask, StartKeyTask, osPriorityAboveNormal, 0, 300);
  KeyTaskHandle = osThreadCreate(osThread(KeyTask), NULL);

  /\* definition and creation of LEDTask \*/
  osThreadDef(LEDTask, StartLEDTask, osPriorityLow, 0, 64);
  LEDTaskHandle = osThreadCreate(osThread(LEDTask), NULL);

  /\* definition and creation of enoecanreceived \*/
  osThreadDef(enoecanreceived, StartenoecanTask, osPriorityHigh, 0, 192);
  enoecanreceivedHandle = osThreadCreate(osThread(enoecanreceived), NULL);

  /\* USER CODE BEGIN RTOS\_THREADS \*/
  /\* add threads, ... \*/
  \_\_HAL\_UART\_ENABLE\_IT(&hlpuart1,UART_IT_RXNE); //

  COMMAND\_GetmoduleID(); 
  /\* USER CODE END RTOS\_THREADS \*/

}

/\* USER CODE BEGIN Header\_StartKeyTask \*/
/\*\*
 \* @brief Function implementing the KeyTask thread.
 \* @param argument: Not used 
 \* @retval None
 \*/
/\* USER CODE END Header\_StartKeyTask \*/
void StartKeyTask(void const \* argument)
{
  /\* USER CODE BEGIN StartKeyTask \*/
  /\* Infinite loop \*/
  for(;;)
  {
    if(btn\_getState(&LEARN_BUTTON_150mS) == BTN_EDGE2){
        taskENTER\_CRITICAL();
        printf("K1 kicked !!,BIT\_KEY set!\r\n");
        taskEXIT\_CRITICAL();

    }

    if((btn\_getState(&LEARN_BUTTON_2S) == BTN_PRESSED)){  
        taskENTER\_CRITICAL();
        printf("K1 pushed 2S!!,send enocean!\r\n");
        taskEXIT\_CRITICAL();
        // osThreadSuspendAll();
        // SendLrnTelegram();
        // osThreadResumeAll();
        while(btn\_getState(&LEARN_BUTTON_150mS));
    }

    if(btn\_getState(&CLEAR_BUTTON_150mS) == BTN_EDGE2){
        taskENTER\_CRITICAL();
        printf("K2 pushed!!\r\n");        
        printf("==================================\r\n");
        printf("任务名 任务状态 优先级 剩余栈 任务序号\r\n");
        taskEXIT\_CRITICAL();
        uint8\_t mytaskstatebuffer[500];
        osThreadList((uint8\_t \*)&mytaskstatebuffer);
        taskENTER\_CRITICAL();
        printf("%s\r\n",mytaskstatebuffer);
        taskEXIT\_CRITICAL();
    }

    if((btn\_getState(&CLEAR_BUTTON_5S) == BTN_PRESSED)){  
        taskENTER\_CRITICAL();
        printf("Clear pushed 5S!!\r\n");
        taskEXIT\_CRITICAL();
        // osThreadSuspendAll();
        // SendLrnTelegram();
        // osThreadResumeAll();
        while(btn\_getState(&CLEAR_BUTTON_2S));
        while(btn\_getState(&CLEAR_BUTTON_150mS));
    }
    osDelay(1);
  }
  /\* USER CODE END StartKeyTask \*/
}

/\* USER CODE BEGIN Header\_StartLEDTask \*/
/\*\*
\* @brief Function implementing the LEDTask thread.
\* @param argument: Not used
\* @retval None
\*/
/\* USER CODE END Header\_StartLEDTask \*/
void StartLEDTask(void const \* argument)
{
  /\* USER CODE BEGIN StartLEDTask \*/
  /\* Infinite loop \*/
  for(;;)
  {
    HAL\_GPIO\_TogglePin(Clr_Led_GPIO_Port,Clr_Led_Pin);
    osDelay(500);
    HAL\_GPIO\_TogglePin(Lrn_Led_GPIO_Port,Lrn_Led_Pin);
    osDelay(500);
  }
  /\* USER CODE END StartLEDTask \*/
}

/\* USER CODE BEGIN Header\_StartenoecanTask \*/
/\*\*
\* @brief Function implementing the enoecanreceived thread.
\* @param argument: Not used
\* @retval None
\*/
/\* USER CODE END Header\_StartenoecanTask \*/
void StartenoecanTask(void const \* argument)
{
  /\* USER CODE BEGIN StartenoecanTask \*/
  TEL_RADIO_TYPE	rTel;
  TEL_PARAM_TYPE  pTel;
  /\* Infinite loop \*/
  for(;;)
  {
    if(xQueueReceive(EnoceanQueueHandle,&USART_Enocean_BUF[Enocean_Data++],portMAX_DELAY) == pdPASS){
      while(xQueueReceive(EnoceanQueueHandle,&USART_Enocean_BUF[Enocean_Data++],10));
      Enocean_Data -= 1;
      if(Enocean_Data >= 38){
        Getmodule\_ID(&u32MyId);
        taskENTER\_CRITICAL();
        printf("my ID is :0x %x\r\n",(unsigned int)(long)u32MyId);
        taskEXIT\_CRITICAL();
      }
      // HAL\_UART\_Transmit(&huart1,USART\_Enocean\_BUF, Enocean\_Data,0xFFFF); //将串口3接收到的数据通过串口1传出 
      else if(radio\_getTelegram(&rTel,&pTel) == OK){
          if((rTel.trps.u8Choice == RADIO_CHOICE_RPS)||(rTel.trps.u8Choice == RADIO_CHOICE_1BS)){
            taskENTER\_CRITICAL();
            printf("rps/1bs received!!BIT\_Radio set!\r\n");
            taskEXIT\_CRITICAL();
          }
          else if(rTel.trps.u8Choice == RADIO_CHOICE_4BS){
            taskENTER\_CRITICAL();
            printf("4bs received\r\n"); 
            taskEXIT\_CRITICAL();
          }      
      }
      memset(USART_Enocean_BUF,0,sizeof(USART_Enocean_BUF));
      Enocean_Data=0;
    }
    osDelay(1);
  }
  /\* USER CODE END StartenoecanTask \*/
}

/\* Private application code --------------------------------------------------\*/
/\* USER CODE BEGIN Application \*/
     
/\* USER CODE END Application \*/

/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* (C) COPYRIGHT STMicroelectronics \*\*\*\*\*END OF FILE\*\*\*\*/


2.2 代码修改

在完成上述基本移植的基础上,需要针对实际需要的功能 对 相应的代码进行修改.

2.2.1 按键任务(使用状态机)

首先修改的是按键部分,按键虽然有不同的情况,但我这里都放在同一个任务中,对以前的按键操作,基本上是实现了相同的效果,其中还有一个按键是查看所有任务的运气情况和任务栈使用情况,前面的FreeRTOS记录博文中也有如何实现:

void StartKeyTask(void const \* argument)
{
  /\* USER CODE BEGIN StartKeyTask \*/
  uint8 um;
  /\* Infinite loop \*/
  for(;;)
  {      
    if(btn\_getState(&LEARN_BUTTON_150mS) == BTN_EDGE2)
    {
      /\*in normol work mode,when lrn key kicked,change the work mode (1~3 mode loop )\*/
      if((bSettingmodeOn == FALSE)&&(bLearnModeOn == FALSE)&&(bCLEARModeOn == FALSE))
      {
        CurrentOpeartion_Mode++;
        if(CurrentOpeartion_Mode == 4)
          CurrentOpeartion_Mode = 1;
        LED\_Flash\_Times('L',CurrentOpeartion_Mode,0);
        taskENTER\_CRITICAL();
        printf("lrn kicked !!,change the work mode!\r\n");
        taskEXIT\_CRITICAL();
        // MyData.MODENUM = CurrentOpeartion\_Mode;
        // mem\_writeFlash((uint8 xdata \*)&MyData,APP\_FLASH\_USER\_TABLE,sizeof(MyData));
        // rTel\_State.t4bs.u8Data0 |= 0x08; 
        // rTel\_State.t4bs.u8Data0 &= 0x8F;
        // rTel\_State.t4bs.u8Data0 |= (CurrentOpeartion\_Mode<<4); 
        // radio\_sendTelegram(&rTel\_State, &pTel\_State); 
      }
      /\*in learn mode,when lrn key kicked,change the learn channal\*/
      else if(Learn_Channel1_Flag == 1){       
        for(um=0;um<2;um++)
        {
          LRN_LED_OFF;
          osDelay(100);
          LRN_LED_ON;
          osDelay(100);
        }
        taskENTER\_CRITICAL();
        printf("next chanle learn!\r\n");
        taskEXIT\_CRITICAL();
        Learn_Channel1_Flag = 0;
        Learn_Channel2_Flag = 1; 
      }
      /\*in set mode,when lrn key kicked,change the parameter(1~3 parameter loop)\*/
      else if(bSettingmodeOn == TRUE){
        parameter++;
        if(parameter == 4){parameter = 1;}
        LED\_Flash\_Times('L',parameter,bSettingmodeOn);
        taskENTER\_CRITICAL();
        printf("parameter %d set!\r\n",parameter);
        taskEXIT\_CRITICAL();
      }
    }

    if((btn\_getState(&LEARN_BUTTON_2S) == BTN_PRESSED)){
      /\*in normol work mode,when lrn key pressed 2s,get into the learn mode\*/ 
      if((clrvalue == GPIO_PIN_RESET)&&(bSettingmodeOn == FALSE)&&(bLearnModeOn == FALSE)&&(bCLEARModeOn == FALSE)){
        bSettingmodeOn = TRUE;
        for(um=0;um<6;um++)
        {
          LRN_LED_ON;CLR_LED_ON;
          osDelay(50);
          LRN_LED_OFF;CLR_LED_OFF;
          osDelay(50);
        }
        LRN_LED_ON;CLR_LED_ON;
        taskENTER\_CRITICAL();
        printf("Clr and lrn pushed 5S!!,into set mode!\r\n");
        taskEXIT\_CRITICAL();
      }
      /\*in normol work mode,when lrn and clr key pressed 2s together,get into the set mode\*/ 
      else if((clrvalue == GPIO_PIN_SET)&&(bSettingmodeOn == FALSE)){
        bLearnModeOn = !bLearnModeOn;
        if(bCLEARModeOn == TRUE)
        {
          bCLEARModeOn = FALSE;
          // Clear\_Channel1\_Flag = 0; 
          // Clear\_Channel2\_Flag = 0; 
          CLR_LED_OFF;
        }
        if (bLearnModeOn){
          ModePriority_Flag = 0;
          // radio\_sendTelegram(&rTel\_State, &pTel\_State);
          for(um=0;um<8;um++)
          {
            LRN_LED_ON;
            osDelay(50);
            LRN_LED_OFF;
            osDelay(50);
          }
          LRN_LED_ON;
          Learn_Channel1_Flag = 1;
        }
        else
        {
          LRN_LED_OFF;
          Learn_Channel2_Flag = 0;                          
          ModePriority_Flag = 1;
        }
        taskENTER\_CRITICAL();
        printf("lrn pushed 2S!!,into or out learn mode!\r\n");
        taskEXIT\_CRITICAL();
      }
      while(btn\_getState(&LEARN_BUTTON_150mS));
      while(btn\_getState(&CLEAR_BUTTON_150mS));
    }

    if(btn\_getState(&CLEAR_BUTTON_150mS) == BTN_EDGE2){
      /\*in normol work mode,when clr key kicked,send one learn Telegram\*/
      if(bSettingmodeOn == FALSE){
        taskENTER\_CRITICAL();
        printf("K2 pushed!!,send lrn radio...\r\n");        
        printf("==================================\r\n");
        printf("任务名 任务状态 优先级 剩余栈 任务序号\r\n");
        taskEXIT\_CRITICAL();
        uint8\_t mytaskstatebuffer[500];
        osThreadList((uint8\_t \*)&mytaskstatebuffer);
        taskENTER\_CRITICAL();
        printf("%s\r\n",mytaskstatebuffer);
        taskEXIT\_CRITICAL();
        SendLrnTelegram();
      }
      /\*in set mode,when clr key kicked,change the parameter value\*/
      else if(bSettingmodeOn == TRUE){
        if(parameter == 1){
          Tcnt++;
            if(Tcnt == 7)
          Tcnt = 1;
          LED\_Flash\_Times('C',Tcnt,bSettingmodeOn);
          // MyData.DelayTimeParameter = Tcnt; //LightParameter;
          // mem\_writeFlash((uint8 xdata \*)&MyData,APP\_FLASH\_USER\_TABLE,sizeof(MyData));
			
          switch(Tcnt){
          case 1: 
            ONTime_Delay = 60000;	   //delay 1min
            break;
          case 2: 
            ONTime_Delay = 300000;	   //delay 5min
            break;
          case 3: 
            ONTime_Delay = 600000;	   //delay 10min
            break;
          case 4: 
            ONTime_Delay = 900000;	   //delay 15min
            break;
          case 5: 
            ONTime_Delay = 1200000;    //delay 20min
            break;
          case 6: 
            ONTime_Delay = 1800000;    //delay 30min
            break;
          }
        }
        else if(parameter == 2){
          Lcnt++;
            if(Lcnt == 7)
          Lcnt = 1;
          LED\_Flash\_Times('C',Lcnt,bSettingmodeOn);
          // MyData.LightParameter = Lcnt; 
          // mem\_writeFlash((uint8 xdata \*)&MyData,APP\_FLASH\_USER\_TABLE,sizeof(MyData));
	
			    switch(Lcnt){
          case 1: 
            Lux_Threshold = 50; 	 //Lighter \_ 50lux 
            break;
          case 2: 
            Lux_Threshold = 100;	 //
            break;
          case 3: 
            Lux_Threshold = 150;	 //
            break;
          case 4: 
            Lux_Threshold = 200;	 //
            break;
          case 5: 
            Lux_Threshold = 300;	//
            break;
          case 6: 
            Lux_Threshold = 500;	//
            break;
          }
			  }	
			  else if(parameter == 3){
          Rcnt++;
            if(Rcnt == 4)
          Rcnt = 1;
          LED\_Flash\_Times('C',Rcnt,bSettingmodeOn);
          // MyData.RepeaterParameter = Rcnt; 
          // mem\_writeFlash((uint8 xdata \*)&MyData,APP\_FLASH\_USER\_TABLE,sizeof(MyData));

          switch(Rcnt){
          case 1:
            REPEATER\_OFF();
            break;
          case 2: 
            REPEATER\_ONE\_ON();
            break;
          case 3:
            REPEATER\_TWO\_ON();
            break;   
          }
        }
      }
    }

    if((btn\_getState(&CLEAR_BUTTON_5S) == BTN_PRESSED)){
        if(bSettingmodeOn == FALSE){
			    if(bLearnModeOn == TRUE)
			    {
            bLearnModeOn = FALSE;
            LRN_LED_OFF;
			    }
				// ClearALLLearnedID(smSensors1,APP\_FLASH\_CHANNEL1\_TABLE,MAX\_SMACK\_SENSORS,CHANNEL1);
				// ClearALLLearnedID(smSensors2,APP\_FLASH\_CHANNEL2\_TABLE,MAX\_SMACK\_SENSORS,CHANNEL2);
          LED\_Flash\_Times('C',5,0);
          bCLEARModeOn = FALSE;
				}
        else if(bSettingmodeOn == TRUE){  //在参数设置模式下,按CLEAR是退出设置模式
			  	for(um=0;um<6;um++)
          {
            LRN_LED_ON;CLR_LED_ON;
            osDelay(50);
            LRN_LED_OFF;CLR_LED_OFF;
            osDelay(50);
          }
          // CLEAR\_UART\_Buffer(RX,RX\_Buffer);
          //Globle\_Int\_EN(1);
          bSettingmodeOn = FALSE;
        }
        taskENTER\_CRITICAL();
        printf("Clear pushed 5S!!,clear all ID or exit setting mode! ...\r\n");
        taskEXIT\_CRITICAL();
        while(btn\_getState(&CLEAR_BUTTON_2S));
        while(btn\_getState(&CLEAR_BUTTON_150mS));
    }
    osDelay(1);
  }
  /\* USER CODE END StartKeyTask \*/
}

时刻关注着 内存使用情况:

在这里插入图片描述

2.2.3 数据存储(使用STM32L051内置EEPROM保存数据)

因为产品在使用过程中,有一些数据是需要掉电保存的,所以需要使用到 EEPROM,当然 内部的 Flash 也是可以用来保存的,只不过对于 STM32L051 而言,有内置的 EEPROM ,使用起来更加方便,如果平台是 STM32F103系列,只能使用内部的Flash 或者外接 EEPROM 了。

对于 STM32L051 的使用说明,可以参考我的另外一篇博文:
STM32L051测试 (四、Flash和EEPROM的读写)

需要保存一些参数数据,和无线设备ID等参数数据,还考考虑2个通道,stml0_flash.h文件中一些宏定义如下:


/\*
two relay\_control
\*/
#define CHANNEL1\_ADDR\_BASE 0x08080000
#define CH1\_CHANNEL1\_ADDR 0x08080000 + 0 
#define CH2\_CHANNEL1\_ADDR 0x08080000 + 10
#define CH3\_CHANNEL1\_ADDR 0x08080000 + 20
#define CH4\_CHANNEL1\_ADDR 0x08080000 + 30
#define CH5\_CHANNEL1\_ADDR 0x08080000 + 40
#define CH6\_CHANNEL1\_ADDR 0x08080000 + 50
#define CH7\_CHANNEL1\_ADDR 0x08080000 + 60 
#define CH8\_CHANNEL1\_ADDR 0x08080000 + 70 

#define CHANNEL2\_ADDR\_BASE 0x08080000 + EEPROM\_PAGE\_SIZE
#define CH1\_CHANNEL2\_ADDR 0x08080000 + EEPROM\_PAGE\_SIZE + 0 
#define CH2\_CHANNEL2\_ADDR 0x08080000 + EEPROM\_PAGE\_SIZE + 10
#define CH3\_CHANNEL2\_ADDR 0x08080000 + EEPROM\_PAGE\_SIZE + 20
#define CH4\_CHANNEL2\_ADDR 0x08080000 + EEPROM\_PAGE\_SIZE + 30
#define CH5\_CHANNEL2\_ADDR 0x08080000 + EEPROM\_PAGE\_SIZE + 40
#define CH6\_CHANNEL2\_ADDR 0x08080000 + EEPROM\_PAGE\_SIZE + 50
#define CH7\_CHANNEL2\_ADDR 0x08080000 + EEPROM\_PAGE\_SIZE + 60 
#define CH8\_CHANNEL2\_ADDR 0x08080000 + EEPROM\_PAGE\_SIZE + 70 


#define User\_Data\_ADDR DATA\_EEPROM\_END\_ADDR - 100

#define CurChannelNums 2 
#define NO\_SENSOR\_ID 0x00000000 //因为L051 EEPROM 初始化是0
#define DefaultVal 0x00
#define MAX\_SMACK\_SENSORS 8

/\* 4 + 1+ 1+ 1+ 1 = 8 考虑蓝牙 +2 10 \*/
typedef struct
{
	uint32 	u32SensorId;
	uint8 	RORG;
	uint8 	FUNC;
	uint8 	TYPE;
	uint8	u8LearnSN;	
}\_\_attribute\_\_ ((packed)) LEARNED_SENSORS;

/\* 放在EEPROM 最后的地方 留 10 个字节\*/
typedef struct                    
{
	uint8 	MODENUM;
	uint8	LightParameter;
	uint8   DelayTimeParameter;
	uint8	RepeaterParameter;
	uint8 	AutoAndManual_MODE[CurChannelNums];
	uint8	IDNUM[CurChannelNums];      		
}\_\_attribute\_\_ ((packed)) User_Data;

extern User_Data MyData;
extern LEARNED_SENSORS smSensors_ch1[8];
extern LEARNED_SENSORS smSensors_ch2[8];

typedef enum                    
{
	CHANNEL1 = 0,
	CHANNEL2,
} CHANNEL_ID;



然后在stml0_flash.c文件中,加入以下相关的函数,下面是清除和读取函数(下面的写ID函数其实有问题,每次写的都是结构体指针的第一个元素的值):

/\*
 双路执行器操作
\*/
/\*
 HAL\_FLASHEx\_DATAEEPROM\_Erase(uint32\_t Address)
 0-80
 EEPROM\_PAGE\_SIZE + 80
 全部清除
\*/
void EnoceanID\_ErasePage()
{
  u8 i = 0;
	HAL\_FLASHEx\_DATAEEPROM\_Unlock(); 
  for(i=0; i<21; i++){
    HAL\_FLASHEx\_DATAEEPROM\_Erase(CH1_CHANNEL1_ADDR + 4\*i); 
    HAL\_FLASHEx\_DATAEEPROM\_Erase(CH1_CHANNEL2_ADDR + 4\*i);
  }
	HAL\_FLASHEx\_DATAEEPROM\_Lock();
}

/\* 固定地址,少传参数 \*/
User_Data Set\_User\_DataRead()
{
	User_Data uservalue;
  uservalue.MODENUM                 = FLASH\_Readbyte((uint32\_t)User_Data_ADDR);
  uservalue.LightParameter          = FLASH\_Readbyte((uint32\_t)(User_Data_ADDR + 1));
  uservalue.DelayTimeParameter      = FLASH\_Readbyte((uint32\_t)(User_Data_ADDR + 2));
  uservalue.RepeaterParameter       = FLASH\_Readbyte((uint32\_t)(User_Data_ADDR + 3));
  uservalue.AutoAndManual_MODE[0]   = FLASH\_Readbyte((uint32\_t)(User_Data_ADDR + 4));
  uservalue.AutoAndManual_MODE[1]   = FLASH\_Readbyte((uint32\_t)(User_Data_ADDR + 5));
  uservalue.IDNUM[0]                = FLASH\_Readbyte((uint32\_t)(User_Data_ADDR + 6));
  uservalue.IDNUM[1]                = FLASH\_Readbyte((uint32\_t)(User_Data_ADDR + 7));

  return uservalue;
}

LEARNED_SENSORS channel\_DataRead(uint32\_t address)
{
  LEARNED_SENSORS channelvalue;
  channelvalue.u32SensorId = FLASH\_ReadWord(address);
  channelvalue.RORG        = FLASH\_Readbyte(address + 4);
  channelvalue.FUNC        = FLASH\_Readbyte(address + 5);
  channelvalue.TYPE        = FLASH\_Readbyte(address + 6);
  channelvalue.u8LearnSN   = FLASH\_Readbyte(address + 7);
  return channelvalue;
}

void channel\_all\_dataRead(LEARNED_SENSORS \*smSensors,CHANNEL_ID ChannelNum){
  uint8 u8Count;
  for(u8Count=0;u8Count<8;u8Count++){
    if(ChannelNum == 0){
      smSensors[u8Count] = channel\_DataRead(CHANNEL1_ADDR_BASE + u8Count\*10);
    }
    else if(ChannelNum == 1){
      smSensors[u8Count] = channel\_DataRead(CHANNEL2_ADDR_BASE + u8Count\*10);
    }
  }
}


void  FLASH\_WriteParameter(User_Data \* mydata)
{
	u8 i = 0;
  u8 writedata[8]={0};
  writedata[0] = mydata->MODENUM;
  writedata[1] = mydata->LightParameter;
  writedata[2] = mydata->DelayTimeParameter;
  writedata[3] = mydata->RepeaterParameter;
  writedata[4] = mydata->AutoAndManual_MODE[0];
  writedata[5] = mydata->AutoAndManual_MODE[1];
  writedata[6] = mydata->IDNUM[0];
  writedata[7] = mydata->IDNUM[1];
  HAL\_FLASHEx\_DATAEEPROM\_Unlock(); 
  for(i=0; i<8; i++){
    while(HAL\_FLASHEx\_DATAEEPROM\_Program(FLASH_TYPEPROGRAMDATA_BYTE, User_Data_ADDR + i, writedata[i]) != HAL_OK);
  }
	HAL\_FLASHEx\_DATAEEPROM\_Lock();
}

/\*
void FLASH\_WriteSensorID(LEARNED\_SENSORS \* mysensors,uint8 num, CHANNEL\_ID ChannelNum)
{
 uint32 sensorid;
 uint8 sensorvalue[4];
 u8 i = 0;
 sensorid = mysensors->u32SensorId;
 sensorvalue[0] = mysensors->RORG;
 sensorvalue[1] = mysensors->FUNC;
 sensorvalue[2] = mysensors->TYPE;
 sensorvalue[3] = mysensors->u8LearnSN;
 HAL\_FLASHEx\_DATAEEPROM\_Unlock(); //!!!问题所在!!!
 if(ChannelNum == 0){
 switch (num)
 {
 case 0:
 FLASH\_WriteWord(CH1\_CHANNEL1\_ADDR,sensorid);//!!!问题所在!!!这里会锁EEPROM
 for(i=0; i<4; i++){
 while(HAL\_FLASHEx\_DATAEEPROM\_Program(FLASH\_TYPEPROGRAMDATA\_BYTE, CH1\_CHANNEL1\_ADDR + 4 + i, sensorvalue[i]) != HAL\_OK);
 \*/
      }
void  FLASH\_WriteSensorID(LEARNED_SENSORS \*mysensors,uint8 num, CHANNEL_ID  ChannelNum)
{

  uint32 sensorid;
  uint8  sensorvalue[4] = {0};
  u8 i = 0;
  sensorid        = mysensors->u32SensorId;
  sensorvalue[0]  = mysensors->RORG;
  sensorvalue[1]  = mysensors->FUNC;
  sensorvalue[2]  = mysensors->TYPE;
  sensorvalue[3]  = mysensors->u8LearnSN;

  if(ChannelNum == 0){
    switch (num)
    {
    case 0:
      FLASH\_WriteWord(CH1_CHANNEL1_ADDR,sensorid);
      HAL\_FLASHEx\_DATAEEPROM\_Unlock(); 
      for(i=0; i<4; i++){        
        while(HAL\_FLASHEx\_DATAEEPROM\_Program(FLASH_TYPEPROGRAMDATA_BYTE, CH1_CHANNEL1_ADDR + 4 + i, sensorvalue[i]) != HAL_OK);
      }
      break;
    case 1:
      FLASH\_WriteWord(CH2_CHANNEL1_ADDR,sensorid);
      HAL\_FLASHEx\_DATAEEPROM\_Unlock(); 
      for(i=0; i<4; i++){
        while(HAL\_FLASHEx\_DATAEEPROM\_Program(FLASH_TYPEPROGRAMDATA_BYTE, CH2_CHANNEL1_ADDR + 4 + i, sensorvalue[i]) != HAL_OK);
      } 
      break;
    case 2:
      FLASH\_WriteWord(CH3_CHANNEL1_ADDR,sensorid);
      HAL\_FLASHEx\_DATAEEPROM\_Unlock(); 
      for(i=0; i<4; i++){
        while(HAL\_FLASHEx\_DATAEEPROM\_Program(FLASH_TYPEPROGRAMDATA_BYTE, CH3_CHANNEL1_ADDR + 4 + i, sensorvalue[i]) != HAL_OK);
      } 
      break;
    case 3:
      FLASH\_WriteWord(CH4_CHANNEL1_ADDR,sensorid);
      HAL\_FLASHEx\_DATAEEPROM\_Unlock(); 
      for(i=0; i<4; i++){
        while(HAL\_FLASHEx\_DATAEEPROM\_Program(FLASH_TYPEPROGRAMDATA_BYTE, CH4_CHANNEL1_ADDR + 4 + i, sensorvalue[i]) != HAL_OK);
      }
      break;
    case 4:
      FLASH\_WriteWord(CH5_CHANNEL1_ADDR,sensorid);
      HAL\_FLASHEx\_DATAEEPROM\_Unlock(); 
      for(i=0; i<4; i++){
        while(HAL\_FLASHEx\_DATAEEPROM\_Program(FLASH_TYPEPROGRAMDATA_BYTE, CH5_CHANNEL1_ADDR + 4 + i, sensorvalue[i]) != HAL_OK);
      }
      break;
    case 5:
      FLASH\_WriteWord(CH6_CHANNEL1_ADDR,sensorid);
      HAL\_FLASHEx\_DATAEEPROM\_Unlock(); 
      for(i=0; i<4; i++){
        while(HAL\_FLASHEx\_DATAEEPROM\_Program(FLASH_TYPEPROGRAMDATA_BYTE, CH6_CHANNEL1_ADDR + 4 + i, sensorvalue[i]) != HAL_OK);
      }
      break;
    case 6:
      FLASH\_WriteWord(CH7_CHANNEL1_ADDR,sensorid);
      HAL\_FLASHEx\_DATAEEPROM\_Unlock(); 
      for(i=0; i<4; i++){
        while(HAL\_FLASHEx\_DATAEEPROM\_Program(FLASH_TYPEPROGRAMDATA_BYTE, CH7_CHANNEL1_ADDR + 4 + i, sensorvalue[i]) != HAL_OK);
      }
      break;
    case 7:
      FLASH\_WriteWord(CH8_CHANNEL1_ADDR,sensorid);
      HAL\_FLASHEx\_DATAEEPROM\_Unlock(); 
      for(i=0; i<4; i++){
        while(HAL\_FLASHEx\_DATAEEPROM\_Program(FLASH_TYPEPROGRAMDATA_BYTE, CH8_CHANNEL1_ADDR + 4 + i, sensorvalue[i]) != HAL_OK);
      }
      break; 
    default:
      break;
    }
  }
  else if(ChannelNum == 1){
    switch (num)
    {
    case 0:
      FLASH\_WriteWord(CH1_CHANNEL2_ADDR,sensorid);
      HAL\_FLASHEx\_DATAEEPROM\_Unlock(); 
      for(i=0; i<4; i++){
        while(HAL\_FLASHEx\_DATAEEPROM\_Program(FLASH_TYPEPROGRAMDATA_BYTE, CH1_CHANNEL2_ADDR + 4 + i, sensorvalue[i]) != HAL_OK);
      }
      break;
    case 1:
      FLASH\_WriteWord(CH2_CHANNEL2_ADDR,sensorid);
      HAL\_FLASHEx\_DATAEEPROM\_Unlock(); 
      for(i=0; i<4; i++){
        while(HAL\_FLASHEx\_DATAEEPROM\_Program(FLASH_TYPEPROGRAMDATA_BYTE, CH2_CHANNEL2_ADDR + 4 + i, sensorvalue[i]) != HAL_OK);
      }
      break;
    case 2:
      FLASH\_WriteWord(CH3_CHANNEL2_ADDR,sensorid);
      HAL\_FLASHEx\_DATAEEPROM\_Unlock(); 
      for(i=0; i<4; i++){
        while(HAL\_FLASHEx\_DATAEEPROM\_Program(FLASH_TYPEPROGRAMDATA_BYTE, CH3_CHANNEL2_ADDR + 4 + i, sensorvalue[i]) != HAL_OK);
      }
      break;
    case 3:
      FLASH\_WriteWord(CH4_CHANNEL2_ADDR,sensorid);
      HAL\_FLASHEx\_DATAEEPROM\_Unlock(); 
      for(i=0; i<4; i++){
        while(HAL\_FLASHEx\_DATAEEPROM\_Program(FLASH_TYPEPROGRAMDATA_BYTE, CH4_CHANNEL2_ADDR + 4 + i, sensorvalue[i]) != HAL_OK);
      }
      break;
    case 4:
      FLASH\_WriteWord(CH5_CHANNEL2_ADDR,sensorid);
      HAL\_FLASHEx\_DATAEEPROM\_Unlock(); 
      for(i=0; i<4; i++){
        while(HAL\_FLASHEx\_DATAEEPROM\_Program(FLASH_TYPEPROGRAMDATA_BYTE, CH5_CHANNEL2_ADDR + 4 + i, sensorvalue[i]) != HAL_OK);
      }
      break;
    case 5:
      FLASH\_WriteWord(CH6_CHANNEL2_ADDR,sensorid);
      HAL\_FLASHEx\_DATAEEPROM\_Unlock(); 
      for(i=0; i<4; i++){
        while(HAL\_FLASHEx\_DATAEEPROM\_Program(FLASH_TYPEPROGRAMDATA_BYTE, CH6_CHANNEL2_ADDR + 4 + i, sensorvalue[i]) != HAL_OK);
      }
      break;
    case 6:
      FLASH\_WriteWord(CH7_CHANNEL2_ADDR,sensorid);
      HAL\_FLASHEx\_DATAEEPROM\_Unlock(); 
      for(i=0; i<4; i++){
        while(HAL\_FLASHEx\_DATAEEPROM\_Program(FLASH_TYPEPROGRAMDATA_BYTE, CH7_CHANNEL2_ADDR + 4 + i, sensorvalue[i]) != HAL_OK);
      }
      break;


**收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。**
![img](https://img-blog.csdnimg.cn/img_convert/85318b1ec9c76c3f4aefe11a42245326.png)
![img](https://img-blog.csdnimg.cn/img_convert/fba1a80693bd057831af494b3f9ff0a2.png)

**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618679757)**

**需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人**

**都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

 + 4 + i, sensorvalue[i]) != HAL_OK);
      }
      break;
    case 5:
      FLASH\_WriteWord(CH6_CHANNEL2_ADDR,sensorid);
      HAL\_FLASHEx\_DATAEEPROM\_Unlock(); 
      for(i=0; i<4; i++){
        while(HAL\_FLASHEx\_DATAEEPROM\_Program(FLASH_TYPEPROGRAMDATA_BYTE, CH6_CHANNEL2_ADDR + 4 + i, sensorvalue[i]) != HAL_OK);
      }
      break;
    case 6:
      FLASH\_WriteWord(CH7_CHANNEL2_ADDR,sensorid);
      HAL\_FLASHEx\_DATAEEPROM\_Unlock(); 
      for(i=0; i<4; i++){
        while(HAL\_FLASHEx\_DATAEEPROM\_Program(FLASH_TYPEPROGRAMDATA_BYTE, CH7_CHANNEL2_ADDR + 4 + i, sensorvalue[i]) != HAL_OK);
      }
      break;


**收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。**
[外链图片转存中...(img-YR3X23iK-1715874443628)]
[外链图片转存中...(img-nYg7waJV-1715874443628)]

**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618679757)**

**需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人**

**都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值