[stm32][ucos] 1、基于ucos操作系统的LED闪烁、串口通信简单例程-阿里云开发者社区

开发者社区> 开发与运维> 正文
登录阅读全文

[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,如需转载请自行联系原作者

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享: