既有适合小白学习的零基础资料,也有适合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行业感兴趣的新人**
**都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**