你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32开发,正点原子Nano开发板移植Free RTOS实现RTC液晶显示RTC时钟

[复制链接]
STMCU小助手 发布时间:2022-5-5 14:46
1 概述
1.1 资源概述

开发板:正点原子STM32F103 Nano开发板
MDK版本:5.27
主控芯片型号:STM32F103RBT6

%X[H_Q~BNJGY7XG4JI4XBWB.png

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这种系统的任务具有高内聚的特性。因此很容易将不同的任务移植到一起。

  1. #include "led.h"
  2. #include "delay.h"
  3. #include "sys.h"
  4. #include "FreeRTOS.h"
  5. #include "task.h"
  6. #include "LCD.h"
  7. #include "gui.h"
  8. #include "RTC_Time.h"
  9. #include "queue.h"
  10. #include "key.h"
  11. #include "semphr.h"
  12. #include "malloc.h"



  13. //任务优先级
  14. #define START_TASK_PRIO                1
  15. //任务堆栈大小        
  16. #define START_STK_SIZE                 50  
  17. //任务句柄
  18. TaskHandle_t StartTask_Handler;
  19. //任务函数
  20. void start_task(void *pvParameters);

  21. //任务优先级
  22. #define LED0Toggle_task_PRIO                4
  23. //任务堆栈大小        
  24. #define LED0Toggle_STK_SIZE                 50
  25. //任务句柄
  26. TaskHandle_t LED0ToggleTask_Handler;
  27. //任务函数
  28. void LED0Toggle_task(void *pvParameters);

  29. //任务优先级
  30. #define LED1_TASK_PRIO                3
  31. //任务堆栈大小        
  32. #define LED1_STK_SIZE                 128  
  33. //任务句柄
  34. TaskHandle_t LED1Task_Handler;
  35. //任务函数
  36. void LED1_task(void *pvParameters);

  37. //任务优先级
  38. #define RTC_TASK_PRIO                5
  39. //任务堆栈大小        
  40. #define RTC_STK_SIZE                 128  
  41. //任务句柄
  42. TaskHandle_t RTCTask_Handler;
  43. //任务函数
  44. void RTC_task(void *pvParameters);

  45. //任务优先级
  46. #define BEEP_TASK_PRIO                2
  47. //任务堆栈大小        
  48. #define BEEP_STK_SIZE                 128  
  49. //任务句柄
  50. TaskHandle_t BEEPTask_Handler;
  51. //任务函数
  52. void BEEP_task(void *pvParameters);

  53. QueueHandle_t Key_Queue;                   //按键值消息队列句柄
  54. #define KEYMSG_Q_NUM    1                  //按键消息队列的数量  

  55. //二值信号量句柄
  56. SemaphoreHandle_t BinarySemaphore;        //二值信号量句柄

  57. //用于命令解析用的命令值
  58. #define BEEPON        1
  59. #define BEEPOFF        2
  60. #define COMMANDERR        0XFF

  61. //将字符串中的小写字母转换为大写
  62. //str:要转换的字符串
  63. //len:字符串长度
  64. void LowerToCap(u8 *str,u8 len)
  65. {
  66.         u8 i;
  67.         for(i=0;i<len;i++)
  68.         {
  69.                 if((96<str<i>)&&(str<i><123))        //小写字母
  70.                 str<i>=str<i>-32;                                //转换为大写
  71.         }
  72. }

  73. //命令处理函数,将字符串命令转换成命令值
  74. //str:命令
  75. //返回值: 0XFF,命令错误;其他值,命令值
  76. u8 CommandProcess(u8 *str)
  77. {
  78.         u8 CommandValue=COMMANDERR;
  79.         if(strcmp((char*)str,"BEEPON")==0) CommandValue=BEEPON;
  80.         else if(strcmp((char*)str,"BEEPOFF")==0) CommandValue=BEEPOFF;
  81.         return CommandValue;
  82. }

  83. int main(void)
  84. {
  85.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4                  
  86.         delay_init();                                            //延时函数初始化         
  87.         uart_init(115200);                                        //初始化串口
  88.         LED_Init();                                                          //初始化LED
  89.         KEY_Init();        //按键初始化
  90.         LCD_Init();           //液晶屏初始化
  91.     RTC_Init();        //RTC初始化
  92.         printf("*******************************\r\n");
  93.         printf("* WKUP_PRES Backward LED\r\n");
  94.         printf("* KEY0_PRES Forward LED\r\n");
  95.         printf("* KEY1_PRES ALL LED ON\r\n");
  96.         printf("* KEY2_PRES ALL LED OFF\r\n");
  97.         printf("* Uart send “BEEPON”:BEEP ON \r\n");
  98.         printf("* Uart send “BEEPOFF”:BEEP OFF \r\n");        
  99.         printf("*******************************\r\n");        
  100.         //创建开始任务
  101.     xTaskCreate((TaskFunction_t )start_task,            //任务函数
  102.                 (const char*    )"start_task",          //任务名称
  103.                 (uint16_t       )START_STK_SIZE,        //任务堆栈大小
  104.                 (void*          )NULL,                  //传递给任务函数的参数
  105.                 (UBaseType_t    )START_TASK_PRIO,       //任务优先级
  106.                 (TaskHandle_t*  )&StartTask_Handler);   //任务句柄              
  107.     vTaskStartScheduler();          //开启任务调度
  108. }

  109. //开始任务任务函数
  110. void start_task(void *pvParameters)
  111. {
  112.     taskENTER_CRITICAL();           //进入临界区
  113.     Key_Queue=xQueueCreate(KEYMSG_Q_NUM,sizeof(u8));        //创建消息Key_Queue
  114.         //创建二值信号量
  115.         BinarySemaphore=xSemaphoreCreateBinary();        
  116.     //创建LED0任务
  117.     xTaskCreate((TaskFunction_t )LED0Toggle_task,            
  118.                 (const char*    )"LED0Toggle_task",           
  119.                 (uint16_t       )LED0Toggle_STK_SIZE,
  120.                 (void*          )NULL,                                
  121.                 (UBaseType_t    )LED0Toggle_task_PRIO,        
  122.                 (TaskHandle_t*  )&LED0ToggleTask_Handler);   
  123.     //创建LCD任务
  124.     xTaskCreate((TaskFunction_t )LED1_task,     
  125.                 (const char*    )"LED1_task",   
  126.                 (uint16_t       )LED1_STK_SIZE,
  127.                 (void*          )NULL,
  128.                 (UBaseType_t    )LED1_TASK_PRIO,
  129.                 (TaskHandle_t*  )&LED1Task_Handler);
  130.     xTaskCreate((TaskFunction_t )RTC_task,     
  131.                 (const char*    )"RTC_task",   
  132.                 (uint16_t       )RTC_STK_SIZE,
  133.                 (void*          )NULL,
  134.                 (UBaseType_t    )RTC_TASK_PRIO,
  135.                 (TaskHandle_t*  )&RTCTask_Handler);   
  136.     xTaskCreate((TaskFunction_t )BEEP_task,     
  137.                 (const char*    )"BEEP_task",   
  138.                 (uint16_t       )BEEP_STK_SIZE,
  139.                 (void*          )NULL,
  140.                 (UBaseType_t    )BEEP_TASK_PRIO,
  141.                 (TaskHandle_t*  )&BEEPTask_Handler);                                   
  142.     vTaskDelete(StartTask_Handler); //删除开始任务
  143.     taskEXIT_CRITICAL();            //退出临界区
  144. }

  145. //LED0闪烁任务函数,提示程序正在运行,且为按键扫描程序,像队列发送信息
  146. void LED0Toggle_task(void *pvParameters)
  147. {
  148.         u8 key,i=0;
  149.     BaseType_t err;
  150.         printf("LED0Toggle Task Running!\r\n");
  151.         while(1)
  152.         {
  153.                 key=KEY_Scan(0);                    //扫描按键
  154.         if((Key_Queue!=NULL)&&(key))           //消息队列Key_Queue创建成功,并且按键被按下
  155.         {
  156.             err=xQueueSend(Key_Queue,&key,10);
  157.             if(err==errQUEUE_FULL)           //发送按键值
  158.             {
  159.                 printf("队列Key_Queue已满,数据发送失败!\r\n");
  160.             }
  161.         }
  162.         i++;
  163.         if(i==50)
  164.         {
  165.             i=0;
  166.             LED0=!LED0;
  167.         }
  168.         vTaskDelay(10);   //延时10ms,也就是10个时钟节拍        
  169.         }
  170. }   

  171. //跑马灯任务函数,使用按键控制灯的方向,以及控制灯的亮灭
  172. void LED1_task(void *pvParameters)
  173. {
  174.          u8 key=0;
  175.         printf("LED1 Task Running!\r\n");
  176.         
  177.         while(1)
  178.         {
  179.         if(Key_Queue!=NULL)
  180.         {
  181.             if(xQueueReceive(Key_Queue,&key,portMAX_DELAY))//请求消息Key_Queue
  182.             {
  183.                 switch(key)
  184.                 {
  185.                     case WKUP_PRES:                //KEY_UP控制流水灯方向,逆向
  186.                                                 LED1=1;
  187.                                                 LED7=0;
  188.                                                 vTaskDelay(200);
  189.                                                 LED7=1;
  190.                                                 LED6=0;
  191.                                                 vTaskDelay(200);
  192.                                                 LED6=1;
  193.                                                 LED5=0;
  194.                                                 vTaskDelay(200);
  195.                                                 LED5=1;
  196.                                                 LED4=0;
  197.                                                 vTaskDelay(200);
  198.                                                 LED4=1;
  199.                                                 LED3=0;
  200.                                                 vTaskDelay(200);
  201.                                                 LED3=1;
  202.                                                 LED2=0;
  203.                                                 vTaskDelay(200);        
  204.                                                 LED2=1;
  205.                                                 LED1=0;
  206.                                                 vTaskDelay(200);
  207.                         break;
  208.                     case KEY0_PRES:                //KEY0控制LED灯方向,顺向
  209.                                                 LED7=1;
  210.                                                 LED1=0;
  211.                                                 vTaskDelay(200);
  212.                                                 LED1=1;
  213.                                                 LED2=0;
  214.                                                 vTaskDelay(200);
  215.                                                 LED2=1;
  216.                                                 LED3=0;
  217.                                                 vTaskDelay(200);
  218.                                                 LED3=1;
  219.                                                 LED4=0;
  220.                                                 vTaskDelay(200);
  221.                                                 LED4=1;
  222.                                                 LED5=0;
  223.                                                 vTaskDelay(200);
  224.                                                 LED5=1;
  225.                                                 LED6=0;
  226.                                                 vTaskDelay(200);        
  227.                                                 LED6=1;
  228.                                                 LED7=0;
  229.                                                 vTaskDelay(200);
  230.                         break;
  231.                                         case KEY2_PRES:
  232.                                                 LED1=1;LED2=1;LED3=1;LED4=1;LED5=1;LED6=1;LED7=1;//关闭所有LED灯
  233.                                                 break;
  234.                                         case KEY1_PRES:
  235.                                                 LED1=0;LED2=0;LED3=0;LED4=0;LED5=0;LED6=0;LED7=0;//打开所有LED灯               
  236.                                                 break;
  237.                 }
  238.             }
  239.         }
  240.                 vTaskDelay(10);      //延时10ms,也就是10个时钟节拍        
  241.         }
  242. }
  243. //RTC的LCD液晶显示,串口打印任务,并在LCD上进行显示
  244. void RTC_task(void *pvParameters)
  245. {
  246.     printf("RTC Task Running!\r\n");
  247.         while(1)
  248.     {
  249.                 Time_Display();
  250.                 vTaskDelay(1000);//每一秒钟刷新LED屏幕,显示时间
  251.     }
  252. }

  253. //BEEP任务,通过串口发送数据控制蜂鸣器
  254. void BEEP_task(void *pvParameters)
  255. {
  256.         u8 len=0;
  257.         u8 CommandValue=COMMANDERR;
  258.         BaseType_t err=pdFALSE;
  259.         
  260.         u8 *CommandStr;
  261.         POINT_COLOR=BLUE;
  262.     printf("BEEP Task Running!\r\n");
  263.         while(1)
  264.         {
  265.                 if(BinarySemaphore!=NULL)
  266.                 {
  267.                         err=xSemaphoreTake(BinarySemaphore,portMAX_DELAY);        //获取信号量
  268.                         if(err==pdTRUE)                                                                                //获取信号量成功
  269.                         {
  270.                                 len=USART_RX_STA&0x3fff;                                                //得到此次接收到的数据长度
  271.                                 CommandStr=mymalloc(len+1);                                                //申请内存
  272.                                 sprintf((char*)CommandStr,"%s",USART_RX_BUF);
  273.                                 CommandStr[len]='\0';                                                        //加上字符串结尾符号
  274.                                 LowerToCap(CommandStr,len);                                                //将字符串转换为大写               
  275.                                 CommandValue=CommandProcess(CommandStr);                //命令解析
  276.                                 if(CommandValue!=COMMANDERR)
  277.                                 {
  278.                                         printf("命令为:%s\r\n",CommandStr);
  279.                                         switch(CommandValue)                                                //处理命令
  280.                                         {
  281.                                                 case BEEPON:
  282.                                                         BEEP=0;
  283.                                                         break;
  284.                                                 case BEEPOFF:
  285.                                                         BEEP=1;
  286.                                                         break;
  287.                                         }
  288.                                 }
  289.                                 else
  290.                                 {
  291.                                         printf("无效的命令,请重新输入!!\r\n");
  292.                                 }
  293.                                 USART_RX_STA=0;
  294.                                 memset(USART_RX_BUF,0,USART_REC_LEN);                        //串口接收缓冲区清零
  295.                                 myfree(CommandStr);                                                                //释放内存
  296.                         }
  297.                 }
  298.                 else if(err==pdFALSE)
  299.                 {
  300.                         vTaskDelay(10);      //延时10ms,也就是10个时钟节拍        
  301.                 }
  302.         }
  303. }              </i></i></i></i>
复制代码

LCD显示函数Time_Display如下

  1. void Time_Display(void)
  2. {
  3.    struct tm time;
  4.    char LCDTemp[100];
  5.    time = Time_GetCalendarTime();
  6.    printf("Time: %d-%d-%d   %02d:%02d:%02d \r\n", time.tm_year, \
  7.                    time.tm_mon+1, time.tm_mday,\
  8.                    time.tm_hour, time.tm_min, time.tm_sec);//打印到串口
  9.         
  10.         sprintf(LCDTemp,"Time: %d-%d-%d   %02d:%02d:%02d \r\n", time.tm_year, \
  11.                    time.tm_mon+1, time.tm_mday,\
  12.                    time.tm_hour, time.tm_min, time.tm_sec);//打印到字符串
  13.         Show_Str(10,80,BLUE,YELLOW,LCDTemp,16,0);//显示字符串
  14. }
复制代码


3 实验结果
打开串口,显示时间如下,每秒将时间打印到串口

9PCM0QN38(APUSTARAIJEEB.png

LCD移植后效果图

P7}XE[PQ`5X{K}EQ@Y48Z1J.png

收藏 评论0 发布时间:2022-5-5 14:46

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版