1 概述
1.1 资源概述
开发板:正点原子STM32F103 Nano开发板
MDK版本:5.27
主控芯片型号:STM32F103RBT6
1.2 实现功能
本实验在STM32F103开发板上移植了FreeRTOS,版本为V9.0.0。例程中创建了5个任务来测试移植是否成功。
start_task任务创建其他4个测试任务
1 RTC_task:RTC的LCD液晶显示,串口打印任务
2 LED1_task:跑马灯任务函数
3 LED0Toggle_task:LED0闪烁任务函数,键盘扫描任务
4 BEEP_task 串口控制蜂鸣器任务
2 程序源码
在程序中建立5个Task,一个启动Task,4个应用Task。按键扫描使用队列,检测到对应按键时,执行相应的操作。串口通讯使用信号量,检测到字符串后控制LED灯的亮灭。另外有一个任务1S钟一次刷新LCD显示,显示时间。
主要代码借鉴了正点原子的程序,SPI屏幕商家提供的驱动以及最小系统版商家提供的驱动,由于RTOS这种系统的任务具有高内聚的特性。因此很容易将不同的任务移植到一起。
- #include "led.h"
- #include "delay.h"
- #include "sys.h"
- #include "FreeRTOS.h"
- #include "task.h"
- #include "LCD.h"
- #include "gui.h"
- #include "RTC_Time.h"
- #include "queue.h"
- #include "key.h"
- #include "semphr.h"
- #include "malloc.h"
- //任务优先级
- #define START_TASK_PRIO 1
- //任务堆栈大小
- #define START_STK_SIZE 50
- //任务句柄
- TaskHandle_t StartTask_Handler;
- //任务函数
- void start_task(void *pvParameters);
- //任务优先级
- #define LED0Toggle_task_PRIO 4
- //任务堆栈大小
- #define LED0Toggle_STK_SIZE 50
- //任务句柄
- TaskHandle_t LED0ToggleTask_Handler;
- //任务函数
- void LED0Toggle_task(void *pvParameters);
- //任务优先级
- #define LED1_TASK_PRIO 3
- //任务堆栈大小
- #define LED1_STK_SIZE 128
- //任务句柄
- TaskHandle_t LED1Task_Handler;
- //任务函数
- void LED1_task(void *pvParameters);
- //任务优先级
- #define RTC_TASK_PRIO 5
- //任务堆栈大小
- #define RTC_STK_SIZE 128
- //任务句柄
- TaskHandle_t RTCTask_Handler;
- //任务函数
- void RTC_task(void *pvParameters);
- //任务优先级
- #define BEEP_TASK_PRIO 2
- //任务堆栈大小
- #define BEEP_STK_SIZE 128
- //任务句柄
- TaskHandle_t BEEPTask_Handler;
- //任务函数
- void BEEP_task(void *pvParameters);
- QueueHandle_t Key_Queue; //按键值消息队列句柄
- #define KEYMSG_Q_NUM 1 //按键消息队列的数量
- //二值信号量句柄
- SemaphoreHandle_t BinarySemaphore; //二值信号量句柄
- //用于命令解析用的命令值
- #define BEEPON 1
- #define BEEPOFF 2
- #define COMMANDERR 0XFF
- //将字符串中的小写字母转换为大写
- //str:要转换的字符串
- //len:字符串长度
- void LowerToCap(u8 *str,u8 len)
- {
- u8 i;
- for(i=0;i<len;i++)
- {
- if((96<str<i>)&&(str<i><123)) //小写字母
- str<i>=str<i>-32; //转换为大写
- }
- }
- //命令处理函数,将字符串命令转换成命令值
- //str:命令
- //返回值: 0XFF,命令错误;其他值,命令值
- u8 CommandProcess(u8 *str)
- {
- u8 CommandValue=COMMANDERR;
- if(strcmp((char*)str,"BEEPON")==0) CommandValue=BEEPON;
- else if(strcmp((char*)str,"BEEPOFF")==0) CommandValue=BEEPOFF;
- return CommandValue;
- }
- int main(void)
- {
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
- delay_init(); //延时函数初始化
- uart_init(115200); //初始化串口
- LED_Init(); //初始化LED
- KEY_Init(); //按键初始化
- LCD_Init(); //液晶屏初始化
- RTC_Init(); //RTC初始化
- printf("*******************************\r\n");
- printf("* WKUP_PRES Backward LED\r\n");
- printf("* KEY0_PRES Forward LED\r\n");
- printf("* KEY1_PRES ALL LED ON\r\n");
- printf("* KEY2_PRES ALL LED OFF\r\n");
- printf("* Uart send “BEEPON”:BEEP ON \r\n");
- printf("* Uart send “BEEPOFF”:BEEP OFF \r\n");
- printf("*******************************\r\n");
- //创建开始任务
- xTaskCreate((TaskFunction_t )start_task, //任务函数
- (const char* )"start_task", //任务名称
- (uint16_t )START_STK_SIZE, //任务堆栈大小
- (void* )NULL, //传递给任务函数的参数
- (UBaseType_t )START_TASK_PRIO, //任务优先级
- (TaskHandle_t* )&StartTask_Handler); //任务句柄
- vTaskStartScheduler(); //开启任务调度
- }
- //开始任务任务函数
- void start_task(void *pvParameters)
- {
- taskENTER_CRITICAL(); //进入临界区
- Key_Queue=xQueueCreate(KEYMSG_Q_NUM,sizeof(u8)); //创建消息Key_Queue
- //创建二值信号量
- BinarySemaphore=xSemaphoreCreateBinary();
- //创建LED0任务
- xTaskCreate((TaskFunction_t )LED0Toggle_task,
- (const char* )"LED0Toggle_task",
- (uint16_t )LED0Toggle_STK_SIZE,
- (void* )NULL,
- (UBaseType_t )LED0Toggle_task_PRIO,
- (TaskHandle_t* )&LED0ToggleTask_Handler);
- //创建LCD任务
- xTaskCreate((TaskFunction_t )LED1_task,
- (const char* )"LED1_task",
- (uint16_t )LED1_STK_SIZE,
- (void* )NULL,
- (UBaseType_t )LED1_TASK_PRIO,
- (TaskHandle_t* )&LED1Task_Handler);
- xTaskCreate((TaskFunction_t )RTC_task,
- (const char* )"RTC_task",
- (uint16_t )RTC_STK_SIZE,
- (void* )NULL,
- (UBaseType_t )RTC_TASK_PRIO,
- (TaskHandle_t* )&RTCTask_Handler);
- xTaskCreate((TaskFunction_t )BEEP_task,
- (const char* )"BEEP_task",
- (uint16_t )BEEP_STK_SIZE,
- (void* )NULL,
- (UBaseType_t )BEEP_TASK_PRIO,
- (TaskHandle_t* )&BEEPTask_Handler);
- vTaskDelete(StartTask_Handler); //删除开始任务
- taskEXIT_CRITICAL(); //退出临界区
- }
- //LED0闪烁任务函数,提示程序正在运行,且为按键扫描程序,像队列发送信息
- void LED0Toggle_task(void *pvParameters)
- {
- u8 key,i=0;
- BaseType_t err;
- printf("LED0Toggle Task Running!\r\n");
- while(1)
- {
- key=KEY_Scan(0); //扫描按键
- if((Key_Queue!=NULL)&&(key)) //消息队列Key_Queue创建成功,并且按键被按下
- {
- err=xQueueSend(Key_Queue,&key,10);
- if(err==errQUEUE_FULL) //发送按键值
- {
- printf("队列Key_Queue已满,数据发送失败!\r\n");
- }
- }
- i++;
- if(i==50)
- {
- i=0;
- LED0=!LED0;
- }
- vTaskDelay(10); //延时10ms,也就是10个时钟节拍
- }
- }
- //跑马灯任务函数,使用按键控制灯的方向,以及控制灯的亮灭
- void LED1_task(void *pvParameters)
- {
- u8 key=0;
- printf("LED1 Task Running!\r\n");
-
- while(1)
- {
- if(Key_Queue!=NULL)
- {
- if(xQueueReceive(Key_Queue,&key,portMAX_DELAY))//请求消息Key_Queue
- {
- switch(key)
- {
- case WKUP_PRES: //KEY_UP控制流水灯方向,逆向
- LED1=1;
- LED7=0;
- vTaskDelay(200);
- LED7=1;
- LED6=0;
- vTaskDelay(200);
- LED6=1;
- LED5=0;
- vTaskDelay(200);
- LED5=1;
- LED4=0;
- vTaskDelay(200);
- LED4=1;
- LED3=0;
- vTaskDelay(200);
- LED3=1;
- LED2=0;
- vTaskDelay(200);
- LED2=1;
- LED1=0;
- vTaskDelay(200);
- break;
- case KEY0_PRES: //KEY0控制LED灯方向,顺向
- LED7=1;
- LED1=0;
- vTaskDelay(200);
- LED1=1;
- LED2=0;
- vTaskDelay(200);
- LED2=1;
- LED3=0;
- vTaskDelay(200);
- LED3=1;
- LED4=0;
- vTaskDelay(200);
- LED4=1;
- LED5=0;
- vTaskDelay(200);
- LED5=1;
- LED6=0;
- vTaskDelay(200);
- LED6=1;
- LED7=0;
- vTaskDelay(200);
- break;
- case KEY2_PRES:
- LED1=1;LED2=1;LED3=1;LED4=1;LED5=1;LED6=1;LED7=1;//关闭所有LED灯
- break;
- case KEY1_PRES:
- LED1=0;LED2=0;LED3=0;LED4=0;LED5=0;LED6=0;LED7=0;//打开所有LED灯
- break;
- }
- }
- }
- vTaskDelay(10); //延时10ms,也就是10个时钟节拍
- }
- }
- //RTC的LCD液晶显示,串口打印任务,并在LCD上进行显示
- void RTC_task(void *pvParameters)
- {
- printf("RTC Task Running!\r\n");
- while(1)
- {
- Time_Display();
- vTaskDelay(1000);//每一秒钟刷新LED屏幕,显示时间
- }
- }
- //BEEP任务,通过串口发送数据控制蜂鸣器
- void BEEP_task(void *pvParameters)
- {
- u8 len=0;
- u8 CommandValue=COMMANDERR;
- BaseType_t err=pdFALSE;
-
- u8 *CommandStr;
- POINT_COLOR=BLUE;
- printf("BEEP Task Running!\r\n");
- while(1)
- {
- if(BinarySemaphore!=NULL)
- {
- err=xSemaphoreTake(BinarySemaphore,portMAX_DELAY); //获取信号量
- if(err==pdTRUE) //获取信号量成功
- {
- len=USART_RX_STA&0x3fff; //得到此次接收到的数据长度
- CommandStr=mymalloc(len+1); //申请内存
- sprintf((char*)CommandStr,"%s",USART_RX_BUF);
- CommandStr[len]='\0'; //加上字符串结尾符号
- LowerToCap(CommandStr,len); //将字符串转换为大写
- CommandValue=CommandProcess(CommandStr); //命令解析
- if(CommandValue!=COMMANDERR)
- {
- printf("命令为:%s\r\n",CommandStr);
- switch(CommandValue) //处理命令
- {
- case BEEPON:
- BEEP=0;
- break;
- case BEEPOFF:
- BEEP=1;
- break;
- }
- }
- else
- {
- printf("无效的命令,请重新输入!!\r\n");
- }
- USART_RX_STA=0;
- memset(USART_RX_BUF,0,USART_REC_LEN); //串口接收缓冲区清零
- myfree(CommandStr); //释放内存
- }
- }
- else if(err==pdFALSE)
- {
- vTaskDelay(10); //延时10ms,也就是10个时钟节拍
- }
- }
- } </i></i></i></i>
复制代码
LCD显示函数Time_Display如下
- void Time_Display(void)
- {
- struct tm time;
- char LCDTemp[100];
- time = Time_GetCalendarTime();
- printf("Time: %d-%d-%d %02d:%02d:%02d \r\n", time.tm_year, \
- time.tm_mon+1, time.tm_mday,\
- time.tm_hour, time.tm_min, time.tm_sec);//打印到串口
-
- sprintf(LCDTemp,"Time: %d-%d-%d %02d:%02d:%02d \r\n", time.tm_year, \
- time.tm_mon+1, time.tm_mday,\
- time.tm_hour, time.tm_min, time.tm_sec);//打印到字符串
- Show_Str(10,80,BLUE,YELLOW,LCDTemp,16,0);//显示字符串
- }
复制代码
3 实验结果
打开串口,显示时间如下,每秒将时间打印到串口
LCD移植后效果图
|