[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 }

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/

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

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

时间: 2024-10-14 13:03:33

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

[stm32][ucos][ucgui] 2、LED闪烁、串口、滑块、文本编辑框简单例程

上一篇:[stm32][ucos] 1.基于ucos操作系统的LED闪烁.串口通信简单例程 * 内容简述: 本例程操作系统采用ucos2.86a版本, 建立了7个任务            任务名                                             优先级            APP_TASK_START_PRIO                               2            主任务            APP_TASK_USER_

[ZigBee] 16、Zigbee协议栈应用(二)——基于OSAL的无线控制LED闪烁分析(下)

说在前面:上一篇介绍了无线LED闪烁实现的OSAL部分,本篇介绍如何实现无线数据收发及数据处理: 上一篇是用SI跟着流程查看源码,我个人认为以架构的思维去了解代码能让人更清晰 ::ZMain.c程序入口文件 这里chipcon_cstartup.s51是汇编的启动文件,ZMain.c相当于main文件,里面有main函数: 1 int main( void ) 2 { 3 osal_int_disable( INTS_ALL );// Turn off interrupts 关中断 4 HAL_

uC/OS-III学习2::uC/OS-III LED闪烁实验

1 前言: 看完了uC/OS-III的基本介绍之后,大致对这个操作系统有了点了解,但真正的理解还是要通过不断的去使用,在使用中体验uC/OS-III的乐趣和更深的理解其工作原理是非常重要的.因此,我在STM32上面移植好uC/OS-III后,就開始了自己的简单实验学习,至于怎么移植,书上还有网上有非常多參考资料,当然你也能够下载别人移植好的干净的项目project直接用也能够.本文主要介绍一下怎么利用uC/OS-III来控制STM32开发板上面的LED闪烁任务. 2 硬件部分: 这里并不为某个开

由一个LED闪烁问题发现的MTK的LED driver中存在的问题

今天根据最新的需求要对LED灯的提示闪烁频率进行修改,将之前默认的2000ms改为10000ms,但是修改之后没有产生预料中的效果,而是变成了常量,百思不得其解,最后还是read the fucking code,从上层到底层,一路追下来,最终发现了问题所在,下面直接上MTK的LED driver代码: #define PMIC_PERIOD_NUM 9 // 100 * period, ex: 0.01 Hz -> 0.01 * 100 = 1 int pmic_period_array[]

WLGK-51单片机接口技术基础实验 ——LED闪烁灯

WLGK-51单片机接口技术基础实验-LED闪烁灯 当我们开始接触单片机,首先接触的第一个实验就是LED灯的使用,类似于我们学习软件开始接触的第一个程序"HelloWorld",这个实验是带领我们走入"软硬件综合使用"的一个很好入门示例,51单片机是他的一个载体.下面小伙伴们,让我们一起来揭开LED的神秘面纱吧! 万立高科官网:www.wanligaoke.com 万立高科官方商城:http://www.wlgkbj.com 万立高科淘宝直销店铺:https://r

构筑基于物联网操作系统的物联网生态环境【转】

构筑基于物联网操作系统的物联网生态环境 本文源自:http://blog.csdn.net/hellochina15/article/details/23206691 分类: 操作系统开发 物联网操作系统2014-04-08 21:00 16093人阅读 评论(2) 收藏 举报 物联网操作系统 最近跟物联网行业和移动互联网行业的一些资深从业人员做了深入交流,就物联网操作系统的概念和必要性.定位等进行了充分深入的沟通.首先说明的是,物联网操作系统的概念被广泛认同.同时,对物联网操作系统在整个物联网

构筑基于物联网操作系统的物联网生态环境 (转)

最近跟物联网行业和移动互联网行业的一些资深从业人员做了深入交流,就物联网操作系统的概念和必要性.定位等进行了充分深入的沟通.首先说明的是,物联网操作系统的概念被广泛认同.同时,对物联网操作系统在整个物联网领域的功能和地位,又有了更进一步的认识.下面简单总结,供业界的朋友们参考评论. 物联网操作系统的最基本功能,与Android操作系统在移动互联网领域的地位和作用类似.先看一下Android,其最大的贡献在于,实现了智能终端硬件和软件的分离.任何应用程序开发者,基本不用考虑智能终端的物理硬件配置(

分布式Java应用之基于消息方式实现系统间的通信(2)

基于Java自身技术实现消息方式的系统间通信 基于Java自身包实现消息方式的系统间通信的方式有:TCP/IP+BIO.TCP/IP+NIO.UDP/IP+BIO以及UDP/IP+NIO 4种,下面分别介绍如何实现这4种方式的系统间通信. TCP/IP+BIO 在Java中可基于Socket.ServerSocket来实现TCP/IP+BIO的系统间通信. Socket主要用于实现建立连接及网络IO的操作,ServerSocket主要用于实现服务器端端口的监听及Socket对象的获取. 1.基于

STM32串口通信配置(USART1+USART2+USART3+UART4)

一.串口一的配置(初始化+中断配置+中断接收函数) 1 /*=============================================================================== 2 Copyright: 3 Version: 4 Author: 5 Date: 2017/11/3 6 Description: 7 配置独立看门狗初始化函数,在主函数中运行IWDG_ReloadCounter进行喂狗主函数必须在4s内进行一次喂狗不然系统会复位: 8 函数功