持续创作,加快生长!这是我参加「日新计划 10 月更文挑战」的第9天,点击检查活动详情

记载一下一个实际项目由裸机程序改成FreeRTOS,曾经产品的渠道仍是C8051单片机上面的程序,
硬件渠道改成了STM32L051,一起运用STM32CubeMX生成的工程,运用FreeRTOS系统
..EEPROM数据存储读取函数修正更新						

关于裸机向FreeRTOS的改变,简略能够用下图表明:

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

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

一、裸机程序到FreeRTOS概述

裸机到FreeRTOS的改变:

  • 该写的驱动仍是要写,假如渠道相同是能够直接用裸机中的。 比方工程中的按键驱动mod_button.c 按键驱动程序源码请参阅我的另一篇博文:几个有用的按键驱动
  • 曾经 驱动 或 函数 中的 ”干等“”的延时函数,不是中止中调用的状况下是能够直接改成osDelay(ms 延时函数),us 的延时函数(I2C协议中运用的),能够沿袭曾经的。(STM32CubeMX 下并没有现成的 us 延时函数,能够自己写一个简略的);

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

上图为温湿度读取的函数,能够看到修正了多种不同的延时函数,由于用在了不同的渠道上面;

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

上图为 32Mhz 主频下面的 不准确 us 延时函数。

  • 曾经 驱动 或 函数 中有些也是 轮询方法规划的,假如运用了 FreeRTOS 的一些信号量,使命告诉,音讯行列等能够完成 唤醒触发使命方法的机制,需求稍作修正。

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

上图中判断是否接纳到报文的语句if(Read_pt != Enocean_Data)是裸机中用来判断串口是否开始接纳到了数据,接纳到了,立即 干等 一段时间HAL_Delay(7);可是在FreeRTOS 中不需求这样的干等。

  • 曾经的全局变量,为了修正少,移植简略,能够沿袭曾经的全局变量,包含一些标志位。

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

  • 曾经的 中止 ,不直接涉及到使命的,该怎样仍是怎样:

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

假如直接和使命有关的,需求做一定的修正, 比方 守时器守时使命 与 事情组有关:

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

再比方串口接纳中止 运用 音讯行列接纳数据:

.

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

  • 考虑到 STM32L051 的 ram 空间只要 8KB,还需求时间重视着内存运用状况!!!

二、移植进程

2.1 根本结构搭建

1、首先在STM32CubeMX中依据原理图把根底的东西设置好,本测验的芯片是STM32L051C8T6,能够参阅博文:

STM32L051测验 (一、运用CubeMX生成工程文件)

在window下运用VScode搭建ARM开发环境——手把手教育详细版

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

2、然后在FreeRTOS装备中,新建3个使命 和 一个音讯行列,可参阅博文:

FreeRTOS记载(一、熟悉开发环境以及CubeMX下FreeRTOS装备)

FreeRTOS记载(六、FreeRTOS音讯行列—Enocean模块串口通讯、RAM空间缺乏问题剖析)

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

3、增加根本的代码,增加曾经写好的驱动文件,每个驱动拿过来记得在Makefile中增加一下,然后每一步编译确保没有错误(此部分是开始的源码,后边还需求弥补,还会对每个细节进行阐明):

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

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

时间重视着 内存运用状况:

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

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;
    case 7:
      FLASH_WriteWord(CH8_CHANNEL2_ADDR,sensorid);
      HAL_FLASHEx_DATAEEPROM_Unlock(); 
      for(i=0; i<4; i++){
        while(HAL_FLASHEx_DATAEEPROM_Program(FLASH_TYPEPROGRAMDATA_BYTE, CH8_CHANNEL2_ADDR + 4 + i, sensorvalue[i]) != HAL_OK);
      }
      break; 
    default:
      break;
    }
  }
  HAL_FLASHEx_DATAEEPROM_Lock();
}

需求界说3个全局变量,保存 参数装备 和 ID数据,尽管数据存放在 EEPROM 中,可是并不需求 每次比较都从 EEPROM 中读取(假如是Flash读取相对来说,次数少,时间长,影响功率), 所以只需求上电读取出来一次数据,放到全局变量中,然后比较的时分直接和全局变量比较,假如进行了参数规划,修正了 EERPOM 的数据,随时更新一下 全局变量的数值,这几个全局变量 无法防止的需求占用 RAM 空间:

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

修正到现在,仍是慨叹一下,本来是为了削减代码修正量,直接复制曾经的代码,尽或许的不修正结构,可是曾经是根据 51 单片机,关于数据存储和 STM32 大不相同,所以关于数据存储,包含后边的学习来说和曾经代码的兼容性,太费心了,还不如直接按照自己的思路从头规划一下。

时间重视着 内存运用状况:

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

关于上面的写ID函数 void FLASH_WriteSensorID(LEARNED_SENSORS * mysensors,uint8 num, CHANNEL_ID ChannelNum) 由于程序中界说的其实是一个结构体数组,所以上面的函数在写的时分永远写的是第一个数组第一个结构体的值:

FreeRTOS记录(九、一个裸机工程转FreeRTOS的实例)
函数没有问题,是在调用的时分,调用出错,正确方法应该是如下方法:

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

2.2.3 报文接纳使命(运用音讯行列接纳)

报文接纳运用音讯行列,具体的结构在另一篇博文有说到: FreeRTOS记载(六、FreeRTOS音讯行列—Enocean模块串口通讯、RAM空间缺乏问题剖析)

void StartenoecanTask(void const * argument)
{
  /* USER CODE BEGIN StartenoecanTask */
  uint8 ACK_Val;
  uint32 u32GatewayID = 0;
  /* Infinite loop */
  for(;;)
  {
    if(xQueueReceive(EnoceanQueueHandle,&USART_Enocean_BUF[Enocean_Data++],portMAX_DELAY) == pdPASS){
      while(xQueueReceive(EnoceanQueueHandle,&USART_Enocean_BUF[Enocean_Data++],7));
      if(Enocean_Data > 1)Enocean_Data -= 1;
        // printf("%d\r\n",Enocean_Data);
      if((Enocean_Data >= 38)&&(u32MyId == 0)){
        Getmodule_ID(&u32MyId);
        taskENTER_CRITICAL();
        printf("my ID is :0x %x\r\n",(unsigned int)(long)u32MyId);
        taskEXIT_CRITICAL();
        if(MyData.RepeaterParameter == 0x00);
        else{
          Rcnt = MyData.RepeaterParameter; 
          switch(Rcnt){
          case 1:
            REPEATER_OFF();
            break;
          case 2: 
            REPEATER_ONE_ON();
            break;
          case 3:
            REPEATER_TWO_ON();
            break;
          }
        }
      }  
      else if ((bLearnModeOn == FALSE)&&(bCLEARModeOn == FALSE)&&(bSettingmodeOn == FALSE)){
        if(radio_getTelegram(&rTel,&pTel) == OK){
          if(pTel.p_rx.u32DestinationId != u32MyId){
            taskENTER_CRITICAL();
            printf("receive radio need analysis!!!\r\n");
            taskEXIT_CRITICAL();
            if(MyData.IDNUM[0]){
              ACK_Val = RadioTelegram_PROCESS(smSensors_ch1,MAX_SMACK_SENSORS);
              if(ACK_Val)
              {
                ChannelAct_Process(ACK_Val,CurrentOpeartion_Mode,CHANNEL1);
                CH1_Find = 1;
              }
            }
            if(MyData.IDNUM[1]){
              ACK_Val = RadioTelegram_PROCESS(smSensors_ch2,MAX_SMACK_SENSORS);
              if(ACK_Val)
              {
                ChannelAct_Process(ACK_Val,CurrentOpeartion_Mode,CHANNEL2);
                CH2_Find = 1;
              }
            }
            if((CH1_Find == 1)&&(CH2_Find == 0))
            {
              LED_Flash_Times('L',CHANNEL1+1,bLearnModeOn);
              CH1_Find = 0;
            }
            else if((CH1_Find == 0)&&(CH2_Find == 1))
            {
              LED_Flash_Times('L',CHANNEL2+1,bLearnModeOn);
              CH2_Find = 0;
            }
            else if((CH1_Find == 1)&&(CH2_Find == 1))
            {
              LRN_LED_ON;CLR_LED_ON;
              osDelay(150);
              LRN_LED_OFF;CLR_LED_OFF;
              CH1_Find = 0;
              CH2_Find = 0;
            }
            else
            {
              CH1_Find = 0;
              CH2_Find = 0;
            }      
          }
          else{ //u32GatewayID = rTel.trps.u32Id; 指定地址发送的报文
            taskENTER_CRITICAL();
            printf("this is a radio send to me!! don't care!\r\n");
            taskEXIT_CRITICAL();
            if((rTel.trps.u8Choice == RADIO_CHOICE_RPS)||(rTel.t1bs.u8Choice == RADIO_CHOICE_1BS)){
              u32GatewayID = rTel.trps.u32Id;
              if((u32GatewayID >= 0xFF800000)&&(u32GatewayID <= 0xFFFFFF80)){
                ChannelAct_Process(rTel.trps.u8Data,CurrentOpeartion_Mode,CHANNEL1);
                LED_Flash_Times('L',1,bLearnModeOn);
              }
              //4bs的不考虑
            }
          }
        }
      }
      else if(bLearnModeOn == TRUE){ //into learn mode
          taskENTER_CRITICAL();
          printf("ready to learn!!!\r\n");
          taskEXIT_CRITICAL();
        if(radio_getTelegram(&rTel,&pTel) == OK){
          if(pTel.p_rx.u32DestinationId != u32MyId){
            if((rTel.t1bs.u8Choice == RADIO_CHOICE_1BS)||(rTel.trps.u8Choice == RADIO_CHOICE_RPS))
						  u32GatewayID = rTel.trps.u32Id;
					  else if(rTel.t4bs.u8Choice == RADIO_CHOICE_4BS)
						  u32GatewayID = rTel.t4bs.u32Id; 
            else {
              taskENTER_CRITICAL();
              printf("cann't learn!!!\r\n");
              taskEXIT_CRITICAL();
              break;
            }
            if((u32GatewayID < 0xFF800000)&&(bLearnModeOn == TRUE)){
              if(Learn_Channel1_Flag == 1){
                taskENTER_CRITICAL();
                printf("ch111 learn!!!\r\n");
                taskEXIT_CRITICAL();
                // osSignalSet(LearnTaskHandle,channel1_learn);
                executeLearn(smSensors_ch1,MAX_SMACK_SENSORS,CHANNEL1);
              }
              else if(Learn_Channel2_Flag == 1){
                taskENTER_CRITICAL();
                printf("ch222 learn!!!\r\n");
                taskEXIT_CRITICAL();
                // osSignalSet(LearnTaskHandle,channel2_learn);
                executeLearn(smSensors_ch2,MAX_SMACK_SENSORS,CHANNEL2); 
              }
            } 
          }   
        }
      }
      memset(USART_Enocean_BUF,0,sizeof(USART_Enocean_BUF));
      Enocean_Data=0;
      // taskENTER_CRITICAL();
      // printf("end!\r\n");
      // taskEXIT_CRITICAL();
    }
    osDelay(5);
  }
  /* USER CODE END StartenoecanTask */
}

运用音讯行列接纳 串口信息的使命,开始的时分界说的是 100 的缓存,音讯行列也是100的巨细,在压力测验下面,或许会使得 使命卡死。 现象便是使命永远处理阻塞状况,可是收不到音讯了,按键使命正常,所以能够检查此使命的状况。 当然这与程序测验的时分加了printf有关,终究是改成了 200 的缓存,去掉printf,测验仍是正常的。

2.2.4 学习铲除使命(运用使命告诉接纳履行)

学习和铲除运用使命告诉,尽管铲除只留下悉数铲除,简略一个函数能够完成,为了后期扩展,也运用使命告诉完成。

阐明:开始是计划用使命告诉完成 学习铲除操作,可实际上终究仍是直接在按键使命,和报文接纳使命中 直接调用函数的方法完成了 学习铲除操作:

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

假如运用使命告诉就得确定一个事情,发送使命告诉是否会产生使命调度?(由于使命后续代码或许对缓存进行修正,比方铲除之类的)

这个我从使命告诉的源码里边好像没有找到(也或许是我没有细心),可是是能够经过测验来确定是否发送使命告诉会有使命调度的,具体的方法能够参照:

FreeRTOS记载(七、FreeRTOS信号量、事情标志组、邮箱和音讯行列、使命告诉的关系)

上面博文中 2.2 邮箱测验 —— 2.21 问题测验,不增加临界区与增加临界区来调查是否发送使命告诉会和邮箱相同产生使命调度,当然测验的时分需求留意 使命 与 使命之间的优先级问题。

这儿就暂时先不做测验,这个移植已经画了太多时间了= =!

这样的话,我就去掉了准备好的这个使命,只留下了2个使命:

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

时间重视着 内存运用状况(去掉一个使命后空间多了):

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

2.2.5 数据处理函数

由于前面的所有结构,根本是按照曾经逻辑的逻辑,以少修正曾经代码为条件的,所以数据处理函数仍然能够沿袭曾经的,根本不变,这儿直接放一下代码:

uint8 RadioTelegram_PROCESS(LEARNED_SENSORS *smSensors,uint8 MAX_SENSORS_NUMS){
  uint8 u8Count;
	uint16 luxValue = 0;
	for(u8Count=0;u8Count<MAX_SENSORS_NUMS;u8Count++)
  {
		if((smSensors[u8Count].u32SensorId == rTel.trps.u32Id)||(smSensors[u8Count].u32SensorId == rTel.t4bs.u32Id)){
			if((rTel.trps.u8Choice == RADIO_CHOICE_RPS)||(rTel.t1bs.u8Choice == RADIO_CHOICE_1BS)){
				if((CurrentOpeartion_Mode == 1)||(CurrentOpeartion_Mode == 3))
				{
					if((smSensors[u8Count].u8LearnSN == 0x50)||(smSensors[u8Count].u8LearnSN == 0x70))
						Left_Right_Flag = 0;    
					else if((smSensors[u8Count].u8LearnSN == 0x10)||(smSensors[u8Count].u8LearnSN == 0x30))
						Left_Right_Flag = 1;
				}
				return rTel.trps.u8Data;
			}
			if(rTel.t4bs.u8Choice == RADIO_CHOICE_4BS){
				if((smSensors[u8Count].RORG == 0xA5)&&(smSensors[u8Count].FUNC == 0x07)&&(smSensors[u8Count].TYPE == 0x03))
				{
					luxValue = rTel.t4bs.u8Data2;
			     	luxValue = (luxValue<<2)|(rTel.t4bs.u8Data1>>6);
				 	if((luxValue <= Lux_Threshold)&&(rTel.t4bs.u8Data0 &0x80))
					  return  1; 
					else
						return  0;
				}
				if((smSensors[u8Count].RORG == 0xA5)&&(smSensors[u8Count].FUNC == 0x08)&&(smSensors[u8Count].TYPE == 0x02))//A5-08-02
				{
					//luxValue = rTel.t4bs.u8Data2;
					luxValue = ((uint16)rTel.t4bs.u8Data2)*1020/255;								
					if((luxValue <= Lux_Threshold)&&(!(rTel.t4bs.u8Data0 &0x02)))
						return  1;                 
					else                          
						return  0;
		    	}
				if((smSensors[u8Count].RORG == 0xA5)&&(smSensors[u8Count].FUNC == 0x07)&&(smSensors[u8Count].TYPE == 0x02))//A5-07-02
				{
					if(rTel.t4bs.u8Data0 &0x80)
					 	return  1;                 
					else                           
						return  0;
		    	}
				if((smSensors[u8Count].RORG == 0xA5)&&(smSensors[u8Count].FUNC == 0x08)&&(smSensors[u8Count].TYPE == 0x01))//A5-08-01
				{
					luxValue = ((uint16)rTel.t4bs.u8Data2)*510/255;
					if((luxValue <= Lux_Threshold)&&(!(rTel.t4bs.u8Data0 &0x02)))
					 	return  1;              
					else                  
						return  0;
		    	}
				if((smSensors[u8Count].RORG == 0xA5)&&(smSensors[u8Count].FUNC == 0x08)&&(smSensors[u8Count].TYPE == 0x03))//A5-08-03
				{
					luxValue = ((uint16)rTel.t4bs.u8Data2)*1530/255;
					if((luxValue <= Lux_Threshold)&&(!(rTel.t4bs.u8Data0 &0x02)))
					 	return  1;             
					else                          
						return  0;
		    	}
			}
		}
	}
	return 0;
}

2.2.6 延时履行操作(运用软件守时器)

由于有些操作需求用到守时器,所以终究还得运用一下软件守时器,软件守时器的运用参阅博文:

FreeRTOS记载(八、FreeRTOS软件守时器)

在STM32cubeMX 中设置:

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

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

然后在程序中需求的地方开启软件守时器:

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

完善一下 callback 函数(仍是为了兼容曾经代码,可是实际上或许需求维护一下):

/* myTimerCallback01 function */
void myTimerCallback01(void const * argument)
{
  /* USER CODE BEGIN myTimerCallback01 */
  uint8_t myTimerID;
  uint8_t CH;
  myTimerID = (uint8_t)pvTimerGetTimerID(argument);
  if (myTimerID == time_one){
    for(CH=0;CH<CurChannelNums;CH++){
      if(FirstStart_Flag[CH] == 1){
        if(CH == 0) {
          Relay_Off(1);
          Switch_Flag = 1;
            t4bsu8Data0 &= ~Relay1_OnState;
        }
        if(CH == 1) {
          Relay_Off(2);
          Switch_Flag = 1;
            t4bsu8Data0 &= ~Relay2_OnState;                                                                                                                                                                                                                                                                   
        }
        FirstStart_Flag[CH] = 0;
      }
    }
  }
  /* USER CODE END myTimerCallback01 */
}

时间重视着 内存运用状况:

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

2.2.7 设备状况上报使命(运用使命告诉接纳履行)

在曾经的代码中,有一个全局变量 Switch_Flag ,标志着设备的状况产生了改变,假如状况改变,需求发送一次状况报文:

if(Switch_Flag == 1){
	SendConfigInfoTelegram();
 	Switch_Flag = 0;
}

所以新建了一个使命,单独作为发送状况报文:

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

可是终究以这种方法测验下来,有bug,便是影响接受使命中间的履行操作。

简略来说便是无线操控本来是很丝滑,很立即的,加了这个全局变量的判断,就变得卡卡的!

期初是觉得 Switch_Flag 改变的地方太多了,加使命告诉不太适合,可是假如直接这样判断全局变量,明显无法运用,所以仍是改为使命告诉的方法。

void StartSendconfigTask(void const * argument)
{
  /* USER CODE BEGIN StartSendconfigTask */
  osEvent gettask;
  /* Infinite loop */
  for(;;)
  {
    gettask = osSignalWait(sendconfig,osWaitForever);
    if(gettask.value.v == sendconfig){
      SendConfigInfoTelegram();
    }
    osDelay(1);
  }
  /* USER CODE END StartSendconfigTask */
}

接着修正数据处理函数,由于里边涉及到设备状况的修正:

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

终究在接纳使命中履行完了数据数据函数以后,再进行使命告诉的发送才测验正常:

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

时间重视着 内存运用状况:

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

2.2.8 延时函数!!!

延时函数为什么标赤色单独拿出来说呢:

关于运用操作系统来说,延时函数运用操作系统的延时函数,能够防止裸机中一个很大的问题,便是干等,所以,在某些状况下不需求考虑,由于延时时间导致其他程序不能够无及时运转的问题!

可是!! 习惯了裸机的逻辑,操作系统的延时函数带来优点的一起,也使得运用起来必需求充分考虑! 延时的时分是会产生使命调度的,假如在某些想不被打断的操作中,千万不要运用延时函数 和 带有延时函数的函数。

在程序中有一个LED灯闪烁的函数:

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

其间运用了osDelay,然后在学习函数中 void executeLearn(LEARNED_SENSORS *smSensors,uint8 MAX_SENSORS_NUMS,CHANNEL_ID ChannelNum)

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

终究修正了一下,把做指示效果的闪灯放在终究:

/*
freertos 进入学习有个问题,就比方一个开关的接连2个报文,在学习第一条的时分,其实第二条已经过来了,第一条没有来得及学完的话,会直接学习第二条
已经解决,由于调用了闪灯函数,里边有延时函数
*/
void executeLearn(LEARNED_SENSORS *smSensors,uint8 MAX_SENSORS_NUMS,CHANNEL_ID ChannelNum)
{
	uint8 u8Count,TypeNums;	
  uint8 FUNC,TYPE,LrnBit_Flag;
  uint16 Manufacturer_ID; 
  for(u8Count=0;u8Count<MAX_SENSORS_NUMS;u8Count++)
  {
    if((smSensors[u8Count].u32SensorId == rTel.trps.u32Id)||(smSensors[u8Count].u32SensorId == rTel.t4bs.u32Id))
    {	
      // printf("%d learned!\r\n",u8Count);
      return;
    }
  }
	//Sensor ID not found so the Application needs to learn it in, proove if it is a correct result, 
	//search for free place in the APP learn table
  for(u8Count=0;u8Count<MAX_SENSORS_NUMS;u8Count++){
    if(smSensors[u8Count].u32SensorId == NO_SENSOR_ID)
      break;	
  }
		//if no free place in APP learn table, discard the learn request, no response time is needed
  if(u8Count == MAX_SENSORS_NUMS){
    LED_Flash_Times('L',4,bLearnModeOn);
    return;
  }
	//there is a free place, learn in the sensor		
  if(rTel.trps.u8Choice == RADIO_CHOICE_RPS){
    smSensors[u8Count].u32SensorId = rTel.trps.u32Id;
    smSensors[u8Count].u8LearnSN = rTel.trps.u8Data;
    // printf("%x\r\n",smSensors[u8Count].u8LearnSN);
  }
  else if(rTel.t1bs.u8Choice == RADIO_CHOICE_1BS)//if 1BS
  {
    if((rTel.t1bs.u8Data&0x08) == 0)
      smSensors[u8Count].u32SensorId = rTel.t1bs.u32Id;
    else
        return;
  }
	else if(rTel.t4bs.u8Choice == RADIO_CHOICE_4BS)    //if 4BS
  {
    if((CurrentOpeartion_Mode == 1)||(CurrentOpeartion_Mode == 3))
      return;
    else{
      FUNC = (rTel.t4bs.u8Data3&0xFC)>>2;
      TYPE = ((rTel.t4bs.u8Data3&0x03)<<5)|((rTel.t4bs.u8Data2&0xF8)>>3);
      Manufacturer_ID = rTel.t4bs.u8Data2&0x07;
      Manufacturer_ID <<= 8;
      Manufacturer_ID |= rTel.t4bs.u8Data1;
      LrnBit_Flag = rTel.t4bs.u8Data0&0x08;
      for(TypeNums=0;TypeNums<EEP_TYPE_Num;TypeNums++){
        if((FUNC == EEP_Info[TypeNums][0])&&(TYPE == EEP_Info[TypeNums][1])&&(LrnBit_Flag == 0))
        {
          smSensors[u8Count].u32SensorId = rTel.t4bs.u32Id;
          smSensors[u8Count].RORG = RADIO_CHOICE_4BS;
          smSensors[u8Count].FUNC = FUNC;
          smSensors[u8Count].TYPE = TYPE;
          break;
        }
      }
      if(TypeNums == EEP_TYPE_Num)
        return;
    }
  }
  MyData.IDNUM[ChannelNum] += 1;
  if(ChannelNum == CHANNEL1)
     t4bsu8Data1 = MyData.IDNUM[ChannelNum];
  if(ChannelNum == CHANNEL2)
     t4bsu8Data2 = MyData.IDNUM[ChannelNum];
  //保存数据需求进入临界区
  taskENTER_CRITICAL(); 
  FLASH_WriteParameter(&MyData);
  // printf("is %d\r\n",u8Count); 
  FLASH_WriteSensorID(&smSensors[u8Count],u8Count,ChannelNum); //保存数据
  channel_dataRead(&smSensors[u8Count],u8Count,ChannelNum); //学习完了更新一下数据,函数用指针操作或许不需求更新直接已经修正了smSensors_ch1
  taskEXIT_CRITICAL();
  memset(USART_Enocean_BUF,0,sizeof(USART_Enocean_BUF)); //串口缓存铲除
  Enocean_Data=0;
  LED_Flash_Times('L',2,bLearnModeOn); //问题在于这句话,闪灯会导致使命调度,由于里边有延时函数 !!!
  // Send4BSDataTelegram(&t4bsu8Data3,&t4bsu8Data2,&t4bsu8Data1,&t4bsu8Data0); 
  // mem_writeFlash((uint8 xdata *)&MyData,APP_FLASH_USER_TABLE,sizeof(MyData));//keep
  // mem_writeFlash((uint8 xdata *)smSensors,u16DstAddress,sizeof(LEARNED_SENSORS)*MAX_SMACK_SENSORS);	
  return;
}	

三、总结领会

3.1 样例终究状况

终究全体测验看来没问题版别,编译结果:

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

在STM32CubeMX中的装备,给与FreeRTOS的内存空间为 3K:

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

终究剩下状况:

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

当然,这个内存占用还能够削减差不多 0.5k,由于我 打印了使命运转状况,终究在内存够的状况,没有把打印使命状况去掉。

终究修正下来,实际上我只用了3个使命,假如不是为了适配曾经的代码结构,从头构建逻辑,或许能够愈加合理的分配使命:

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

终究整个源码我上传了一份: Relay_Control.zip

3.2 一些领会

1、每个使命的栈巨细要依据实际状况调整,使命调用函数深度和变量的多少都直接影响使命栈需求的巨细,所以移植进程需求运用 vTaskList 调查使命运转占用内存状况,以便及时调整。 具体可参阅博文:

FreeRTOS记载(四、FreeRTOS使命堆栈溢出问题和临界区)

2、关于全局变量,有些数组能够运用 const 修饰,使其存放至 flash 上,节省 ram 空间。

3、其实终究修正下来,一味的追求最小程序的修正代码,反而拔苗助长,仍是自己按照现在的思路,从头规划一下会来得简略一些

4、关于 EEPROM 的读写函数规划修正,在 结构体,结构体数组 的运用于处理方面,花了一些时间!

EEPROM的读写操作需求增加临界区维护,有或许在写进程产生使命调度导致写读失败!!

5、延时函数要特别留意!!!除了运用临界区维护不想被打断的代码,延时函数和 带有延时的函数 运用考虑周全!