[stm32][ucos] 1、基于ucos操作系统的LED闪烁、串口通信简单例程

简介:


 

* 内容简述:

      本例程操作系统采用ucos2.86a版本, 建立了5个任务
            任务名                                             优先级
            APP_TASK_START_PRIO                               2            主任务              
            Task_Com1_PRIO                                    4            COM1通信任务
            Task_Led1_PRIO                                    7            LED1 闪烁任务
            Task_Led2_PRIO                                    8            LED2 闪烁任务
            Task_Led3_PRIO                                    9            LED3 闪烁任务
         当然还包含了系统任务:
            OS_TaskIdle                  空闲任务-----------------优先级最低
            OS_TaskStat                  统计运行时间的任务-------优先级次低 


 

 1、主任务建立:

1 //建立主任务, 优先级最高  建立这个任务另外一个用途是为了以后使用统计任务
2    os_err = OSTaskCreate((void (*) (void *)) App_TaskStart,                        //指向任务代码的指针
3                           (void *) 0,                                          //任务开始执行时,传递给任务的参数的指针
4                (OS_STK *) &App_TaskStartStk[APP_TASK_START_STK_SIZE - 1],    //分配给任务的堆栈的栈顶指针   从顶向下递减
5                (INT8U) APP_TASK_START_PRIO);                                //分配给任务的优先级
  • 这个采用老版本的任务建立函数,第一个参数通俗的说法就是该任务对应的函数,如下:
复制代码
 1 static  void App_TaskStart(void* p_arg)
 2 {
 3    (void) p_arg;
 4    //初始化ucos时钟节拍
 5    OS_CPU_SysTickInit();                                       /* Initialize the SysTick.       */
 6 
 7 //使能ucos 的统计任务
 8 #if (OS_TASK_STAT_EN > 0)
 9    //----统计任务初始化函数  
10    OSStatInit();                                               /* Determine CPU capacity.                              */
11 #endif
12    //建立其他的任务
13    App_TaskCreate();
14 
15    while (1)
16    {
17       //1秒一次循环
18       OSTimeDlyHMSM(0, 0,1, 0);
19    }
20 }
复制代码
  • 当主任务建立之后,程序就转到该函数处,调用 App_TaskCreate();建立其他任务,然后进入死循环,我们会发现:这里的主任务在建立其他任务后就没啥作用的,这时可以调用相应的函数将主任务给杀死,这里没有这样做,只是让主任务进入循环。

 

2、其他任务建立:

复制代码
 1 static  void App_TaskCreate(void)
 2 {
 3    //CPU_INT08U os_err;
 4  
 5    //Com1_SEM=OSSemCreate(1);             //建立串口1中断的信号量
 6    Com1_MBOX=OSMboxCreate((void *) 0);             //建立串口1中断的消息邮箱
 7    
 8    //串口1接收及发送任务---------------------------------------------------------    
 9    OSTaskCreateExt(Task_Com1,                                      //指向任务代码的指针
10                        (void *)0,                                      //任务开始执行时,传递给任务的参数的指针
11                     (OS_STK *)&Task_Com1Stk[Task_Com1_STK_SIZE-1],//分配给任务的堆栈的栈顶指针   从顶向下递减
12                     Task_Com1_PRIO,                                  //分配给任务的优先级
13                     Task_Com1_PRIO,                                  //预备给以后版本的特殊标识符,在现行版本同任务优先级
14                     (OS_STK *)&Task_Com1Stk[0],                      //指向任务堆栈栈底的指针,用于堆栈的检验
15                     Task_Com1_STK_SIZE,                              //指定堆栈的容量,用于堆栈的检验
16                     (void *)0,                                      //指向用户附加的数据域的指针,用来扩展任务的任务控制块
17                     OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR);      //选项,指定是否允许堆栈检验,是否将堆栈清0,任务是否要进行浮点运算等等。
18    //LED1 闪烁任务------------------------------------------------------
19    OSTaskCreateExt(Task_Led1,(void *)0,(OS_STK *)&Task_Led1Stk[Task_Led1_STK_SIZE-1],Task_Led1_PRIO,Task_Led1_PRIO,(OS_STK *)&Task_Led1Stk[0],
20                     Task_Led1_STK_SIZE,
21                     (void *)0,
22                     OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR);
23    
24    //LED2 闪烁任务------------------------------------------------------
25    OSTaskCreateExt(Task_Led2,(void *)0,(OS_STK *)&Task_Led2Stk[Task_Led2_STK_SIZE-1],Task_Led2_PRIO,Task_Led2_PRIO,(OS_STK *)&Task_Led2Stk[0],
26                     Task_Led2_STK_SIZE,
27                     (void *)0,
28                     OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR); 
29    
30    //LED3 闪烁任务------------------------------------------------------
31    OSTaskCreateExt(Task_Led3,(void *)0,(OS_STK *)&Task_Led3Stk[Task_Led3_STK_SIZE-1],Task_Led3_PRIO,Task_Led3_PRIO,(OS_STK *)&Task_Led3Stk[0],
32                     Task_Led3_STK_SIZE,
33                     (void *)0,
34                     OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR);  
35 }
复制代码
  •  这里是建立四个子任务第一个是串口通信的任务,一会再说,下面三个是LED闪烁任务,这里举Task_Led1说明:
复制代码
 1 //LED1闪烁任务----------------------------------------
 2 static  void Task_Led1(void* p_arg)
 3 {
 4    (void) p_arg;        
 5    while (1)
 6    {
 7       LED_LED1_ON();
 8       OSTimeDlyHMSM(0, 0, 0, milsec1);
 9       
10       LED_LED1_OFF();
11       OSTimeDlyHMSM(0, 0, 0, milsec1);    
12    }
13 }
复制代码
  •  可见LED闪烁任务其实就是一个无限循环,让灯的电平每隔一定时间高、每隔一定时间低来呈现闪烁的效果。那么,他是怎样实现任务切换的呢?这就是操作系统的功能了,操作系统根据每个任务的优先级,在每个子任务执行到一定时期查询当前挂起任务的优先级来选择优先级最高的进行执行。下面是在app_cfg.h中对这些任务优先级的声明:
复制代码
1 #define  APP_TASK_START_PRIO                               2
2 #define  APP_TASK_USER_IF_PRIO                             13
3 #define  APP_TASK_KBD_PRIO                                 12
4 #define  Task_Com1_PRIO                                    4
5 #define  Task_Led1_PRIO                                    7
6 #define  Task_Led2_PRIO                                    8
7 #define  Task_Led3_PRIO                                    9
复制代码
  •  可见主任务的优先级最高,串口通信的优先级其次,LED闪烁的优先级趋于中等,依次为7、8、9,
复制代码
 1 static  void Task_Com1(void *p_arg){    
 2    INT8U err;    
 3    unsigned char * msg;
 4    (void)p_arg;                        
 5    while(1){
 6         
 7       //OSSemPend(Com1_SEM,0,&err);           //等待串口接收指令成功的信号量
 8       msg=(unsigned char *)OSMboxPend(Com1_MBOX,0,&err);           //等待串口接收指令成功的邮箱信息
 9       //USART_OUT(USART1,&TxBuffer1[0]);
10          if(msg[0]=='L'&&msg[1]==0x31){
11            milsec1=atoi(&msg[3]);               //LED1 的延时毫秒  (mini and V3)
12          USART_OUT(USART1,"\r\n");
13            USART_OUT(USART1,"LED1: %d ms 间隔闪烁",milsec1);         
14       }
15       else if(msg[0]=='L'&&msg[1]==0x32){
16            milsec2=atoi(&msg[3]);           //LED2 的延时毫秒  (only V3)
17          USART_OUT(USART1,"\r\n");
18            USART_OUT(USART1,"LED2: %d ms 间隔闪烁",milsec2);
19       }
20       else if(msg[0]=='L'&&msg[1]==0x33){
21             milsec3=atoi(&msg[3]);           //LED3 的延时毫秒  (only V3)
22           USART_OUT(USART1,"\r\n");
23             USART_OUT(USART1,"LED3: %d ms 间隔闪烁",milsec3);
24       } 
25    } 
26 }
复制代码
  •  这里重点讲一下串口通信的任务:这里采用消息邮箱进行消息传递,在建立其他任务App_TaskCreate(void)的开始就首先建立串口的消息邮箱:Com1_MBOX=OSMboxCreate((void *) 0);然后在串口通信的任务中进入循环后就一直等待消息邮箱的信息(第8行),如果没有消息过来就一直等待,在此期间其他任务可以进行,一旦有消息发送过来,由于串口通信的优先级较高,就能很快响应,根据收到的消息msg来重新设置led闪烁的频率。这里因为串口接收要用到中断,所以下面就说说串口通信的接收中断部分。
复制代码
 1 void USART1_IRQHandler(void)
 2 {
 3     unsigned int i;
 4     unsigned char msg[50];
 5     OS_CPU_SR  cpu_sr;
 6       
 7     OS_ENTER_CRITICAL();  //保存全局中断标志,关总中断// Tell uC/OS-II that we are starting an ISR
 8       OSIntNesting++;
 9     
10       OS_EXIT_CRITICAL();      //恢复全局中断标志
11     
12       //OSTimeTick();     // Call uC/OS-II's OSTimeTick(),在os_core.c文件里定义,主要判断延时的任务是否计时到
13  
14        if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)       //判断读寄存器是否非空
15       {    
16             // Read one byte from the receive data register 
17         
18             msg[RxCounter1++]= USART_ReceiveData(USART1);   //将读寄存器的数据缓存到接收缓冲区里
19         
20             if(msg[RxCounter1-1]=='L'){msg[0]='L'; RxCounter1=1;}     //判断起始标志
21             if(msg[RxCounter1-1]=='F')                  //判断结束标志是否是"F"
22         
23             {
24                   for(i=0; i< RxCounter1; i++){
25                     TxBuffer1[i]    =msg[i];          //将接收缓冲器的数据转到发送缓冲区,准备转发
26               
27                 }
28                           
29                 TxBuffer1[RxCounter1]=0;                                //接收缓冲区终止符
30                   RxCounter1=0;                         
31                 //OSSemPost(Com1_SEM);       
32                 OSMboxPost(Com1_MBOX,(void *)&msg);                        
33             }
34       } 
35       if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET)                     // 
36       { 
37          USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
38       }    
39     OSIntExit();  //在os_core.c文件里定义,如果有更高优先级的任务就绪了,则执行一次任务切换    
40 }
复制代码
  • 这里接收串口数据,当发现是完整的帧时,就调用OSMboxPost(Com1_MBOX,(void *)&msg);发送一个邮箱消息,进而那边的串口任务从挂起到唤醒,执行相应的过程。

 

3、硬件初始化部分

说了这么多,竟然忘了说硬件初始化的部分啦!这里包括系统时钟设置、引脚使能、中断使能...放在bsp.c文件里,在main函数开始直接调用BSP_Init();就可以。

复制代码
 1 void BSP_Init(void)
 2 {
 3   /* System Clocks Configuration --72M*/
 4   RCC_Configuration();   
 5   GPIO_Configuration();
 6   /* NVIC configuration */
 7   /*嵌套向量中断控制器 
 8       说明了USART1抢占优先级级别0(最多1位) ,和子优先级级别0(最多7位) */ 
 9   NVIC_Configuration();
10   USART_Config(USART1,115200);          //串口1初始化
11 }
复制代码
  void RCC_Configuration(void)
  void GPIO_Configuration(void)
  void NVIC_Configuration(void)
  void USART_Config(USART_TypeDef* USARTx,u32 baud)

 

PS:相关链接

LZ blog:http://www.cnblogs.com/zjutlitao/ 

工程代码:http://pan.baidu.com/s/1jG850X4



本文转自beautifulzzzz博客园博客,原文链接:http://www.cnblogs.com/zjutlitao/p/3917638.html,如需转载请自行联系原作者

相关文章
|
1月前
stm32学习 3-2 LED流水灯
stm32学习 3-2 LED流水灯
72 4
|
1月前
stm32学习3-1 LED闪烁
stm32学习3-1 LED闪烁
36 4
|
1月前
|
iOS开发 MacOS
MacOS环境-手写操作系统-26-利用时钟开发光标闪烁
MacOS环境-手写操作系统-26-利用时钟开发光标闪烁
30 0
|
1月前
|
存储 iOS开发 MacOS
MacOS环境-手写操作系统-24-消除鼠标闪烁
文章介绍了如何通过记录图层像素点对应的窗体编号来消除鼠标在窗口间移动时的闪烁现象。主要方法是在图层数据结构中添加变量map,存储每个像素点的窗体标识,并在窗口移动或尺寸改变时更新这个映射,从而避免不必要的窗口刷新,提高显示性能。
27 0
|
1月前
|
算法 iOS开发 MacOS
MacOS环境-手写操作系统-23-消除刷新的闪烁
文章介绍了如何通过修改代码来解决因频繁刷新整个窗体导致的闪烁问题,重点在于只刷新需要更新的图层,从而提高效率并减少不必要的CPU资源消耗。通过在sheet_refreshsub函数中添加图层高度参数,实现了按需刷新,成功消除了图层闪烁。然而,当鼠标位于较高图层时,仍会出现闪烁,暗示需要进一步优化刷新算法。
25 0
|
4月前
STM32CubeMX FreeRTOS点亮LED
STM32CubeMX FreeRTOS点亮LED
78 10
|
4月前
STM32CubeMX 按键控制LED
STM32CubeMX 按键控制LED
71 0
|
4月前
STM32CubeMX 点亮LED
STM32CubeMX 点亮LED
62 0
|
4月前
|
传感器 编解码 API
【STM32开发入门】温湿度监测系统实战:SPI LCD显示、HAL库应用、GPIO配置、UART中断接收、ADC采集与串口通信全解析
SPI(Serial Peripheral Interface)是一种同步串行通信接口,常用于微控制器与外围设备间的数据传输。SPI LCD是指使用SPI接口与微控制器通信的液晶显示屏。这类LCD通常具有较少的引脚(通常4个:MISO、MOSI、SCK和SS),因此在引脚资源有限的系统中非常有用。通过SPI协议,微控制器可以向LCD发送命令和数据,控制显示内容和模式。
164 0
|
5月前
使用STM32F103标准库实现定时器控制LED点亮和关闭
通过这篇博客,我们学习了如何使用STM32F103标准库,通过定时器来控制LED的点亮和关闭。我们配置了定时器中断,并在中断处理函数中实现了LED状态的切换。这是一个基础且实用的例子,适合初学者了解STM32定时器和中断的使用。 希望这篇博客对你有所帮助。如果有任何问题或建议,欢迎在评论区留言。
447 2