[stm32][ucos] 一、基於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                  統計運行時間的任務-------優先級次低 app


 

 一、主任務創建:ide

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();創建其餘任務,而後進入死循環,咱們會發現:這裏的主任務在創建其餘任務後就沒啥做用的,這時能夠調用相應的函數將主任務給殺死,這裏沒有這樣作,只是讓主任務進入循環。

 

二、其餘任務創建:函數

 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閃爍的優先級趨於中等,依次爲七、八、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);發送一個郵箱消息,進而那邊的串口任務從掛起到喚醒,執行相應的過程。

 

三、硬件初始化部分spa

說了這麼多,居然忘了說硬件初始化的部分啦!這裏包括系統時鐘設置、引腳使能、中斷使能...放在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 }
1 void RCC_Configuration(void)
2 {        
3   SystemInit(); 
4 }
void RCC_Configuration(void)
 1 void GPIO_Configuration(void)
 2 {
 3   GPIO_InitTypeDef GPIO_InitStructure;
 4 
 5   /*對控制LED指示燈的IO口進行了初始化,將端口配置爲推輓上拉輸出,口線速度爲50Mhz。PA9,PA10端口複用爲串口1的TX,RX。
 6   在配置某個口線時,首先應對它所在的端口的時鐘進行使能。不然沒法配置成功,因爲用到了端口B,D,E, 所以要對這幾個端口的時鐘
 7   進行使能,同時因爲用到複用IO口功能用於配置串口。所以還要使能AFIO(複用功能IO)時鐘。*/
 8   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOB , ENABLE); 
 9   
10   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;                                 //LED1
11   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
12   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
13   GPIO_Init(GPIOB, &GPIO_InitStructure);                     
14   
15   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_3;                     //LED2, LED3
16   GPIO_Init(GPIOD, &GPIO_InitStructure);
17 }
void GPIO_Configuration(void)
 1 void NVIC_Configuration(void)
 2 {
 3 
 4   //EXTI_InitTypeDef EXTI_InitStructure;
 5   NVIC_InitTypeDef NVIC_InitStructure;
 6   
 7   /* Configure one bit for preemption priority */
 8   #if defined (VECT_TAB_RAM)
 9   /* Set the Vector Table base location at 0x20000000 */ 
10   NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); 
11 #elif defined(VECT_TAB_FLASH_IAP)
12   NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x2000);
13 #else  /* VECT_TAB_FLASH  */
14   /* Set the Vector Table base location at 0x08000000 */ 
15   NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);   
16 #endif 
17 
18   /* Configure the NVIC Preemption Priority Bits */  
19   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
20 
21   
22   NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;                     //設置串口1中斷
23   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
24   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
25   NVIC_Init(&NVIC_InitStructure);
26  
27 }
void NVIC_Configuration(void)
 1 void USART_Config(USART_TypeDef* USARTx,u32 baud){
 2   USART_InitTypeDef USART_InitStructure;
 3   GPIO_InitTypeDef GPIO_InitStructure;
 4 
 5   //PA9,PA10 複用IO口功能用於配置串口。所以要使能AFIO(複用功能IO)時鐘。
 6   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); 
 7   RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);    
 8   RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
 9   
10   //usart_init----------------------------------------------------
11   /* Configure USART1 Rx (PA.10) as input floating */
12   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
13   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;          //浮空輸入模式       
14   GPIO_Init(GPIOA, &GPIO_InitStructure);                     
15   
16   /* Configure USART1 Tx (PA.09) as alternate function push-pull */
17   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
18   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
19   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;              //複用推輓輸出
20   GPIO_Init(GPIOA, &GPIO_InitStructure);
21   
22   
23   USART_InitStructure.USART_BaudRate =baud;                        //速率115200bps
24   USART_InitStructure.USART_WordLength = USART_WordLength_8b;        //數據位8位
25   USART_InitStructure.USART_StopBits = USART_StopBits_1;            //中止位1位
26   USART_InitStructure.USART_Parity = USART_Parity_No;                //無校驗位
27   USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;   //無硬件流控
28   USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;                    //收發模式
29 
30   /* Configure USART1 */
31   USART_Init(USARTx, &USART_InitStructure);                            //配置串口參數函數
32  
33   
34   /* Enable USART1 Receive and Transmit interrupts */
35   USART_ITConfig(USARTx, USART_IT_RXNE, ENABLE);                    //使能接收中斷
36   //USART_ITConfig(USARTx, USART_IT_TXE, ENABLE);                    //使能發送緩衝空中斷
37 
38   
39   /* Enable the USART1 */
40   USART_Cmd(USARTx, ENABLE);    
41 
42   //USART_ClearFlag(USARTx, USART_FLAG_TXE);     /* 清發送完成標誌,Transmission Complete flag */
43 }
void USART_Config(USART_TypeDef* USARTx,u32 baud)

 

PS:相關連接指針

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

工程代碼:http://pan.baidu.com/s/1jG850X4blog

相關文章
相關標籤/搜索