* 内容简述:

本例程操作系统采用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、主任务建立:

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

2、其他任务建立:

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

3、硬件初始化部分

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

 void BSP_Init(void)
{
/* System Clocks Configuration --72M*/
RCC_Configuration();
GPIO_Configuration();
/* NVIC configuration */
/*嵌套向量中断控制器
说明了USART1抢占优先级级别0(最多1位) ,和子优先级级别0(最多7位) */
NVIC_Configuration();
USART_Config(USART1,); //串口1初始化
}
 void RCC_Configuration(void)
{
SystemInit();
}

void RCC_Configuration(void)

 void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure; /*对控制LED指示灯的IO口进行了初始化,将端口配置为推挽上拉输出,口线速度为50Mhz。PA9,PA10端口复用为串口1的TX,RX。
在配置某个口线时,首先应对它所在的端口的时钟进行使能。否则无法配置成功,由于用到了端口B,D,E, 因此要对这几个端口的时钟
进行使能,同时由于用到复用IO口功能用于配置串口。因此还要使能AFIO(复用功能IO)时钟。*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOB , ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //LED1
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_3; //LED2, LED3
GPIO_Init(GPIOD, &GPIO_InitStructure);
}

void GPIO_Configuration(void)

 void NVIC_Configuration(void)
{ //EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure; /* Configure one bit for preemption priority */
#if defined (VECT_TAB_RAM)
/* Set the Vector Table base location at 0x20000000 */
NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#elif defined(VECT_TAB_FLASH_IAP)
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x2000);
#else /* VECT_TAB_FLASH */
/* Set the Vector Table base location at 0x08000000 */
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
#endif /* Configure the NVIC Preemption Priority Bits */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //设置串口1中断
NVIC_InitStructure.NVIC_IRQChannelSubPriority = ;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure); }

void NVIC_Configuration(void)

 void USART_Config(USART_TypeDef* USARTx,u32 baud){
USART_InitTypeDef USART_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure; //PA9,PA10 复用IO口功能用于配置串口。因此要使能AFIO(复用功能IO)时钟。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //usart_init----------------------------------------------------
/* Configure USART1 Rx (PA.10) as input floating */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入模式
GPIO_Init(GPIOA, &GPIO_InitStructure); /* Configure USART1 Tx (PA.09) as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure); USART_InitStructure.USART_BaudRate =baud; //速率115200bps
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //数据位8位
USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位1位
USART_InitStructure.USART_Parity = USART_Parity_No; //无校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件流控
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式 /* Configure USART1 */
USART_Init(USARTx, &USART_InitStructure); //配置串口参数函数 /* Enable USART1 Receive and Transmit interrupts */
USART_ITConfig(USARTx, USART_IT_RXNE, ENABLE); //使能接收中断
//USART_ITConfig(USARTx, USART_IT_TXE, ENABLE); //使能发送缓冲空中断 /* Enable the USART1 */
USART_Cmd(USARTx, ENABLE); //USART_ClearFlag(USARTx, USART_FLAG_TXE); /* 清发送完成标志,Transmission Complete flag */
}

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闪烁、串口通信简单例程的更多相关文章

  1. STM32学习笔记:【004】USART串口通信

    版本:STM32F429 Hal库v1.10 串口通信能够实现两块电路之间不同的通信,在开发中作为打印调试也是一门利器(printf重定向). 补充一点小知识: 1. weak修饰符修饰的函数,说明这 ...

  2. 基于Arduino和python的串口通信和上位机控制

    引言 经常的时候我们要实现两个代码之间的通信,比如说两个不同不同人写的代码要对接,例如将python指令控制Arduino控件的开关,此处使用串口通信是非常方便的,下面笔者将结合自己踩过的坑来讲述下自 ...

  3. 基于FPGA的电压表与串口通信(上)

    实验原理 该实验主要为利用TLC549采集模拟信号,然后将模拟信号的数字量通过串口发送到PC上上位机进行显示,使用到的TLC549驱动模块在进阶实验已经使用到了,串口模块在基础实验也已经使用到了,本实 ...

  4. 基于FPGA的电压表与串口通信(下)

    实验操作 上电 接入5V电源,用配套的线,USB那端接电脑即可: 电源开关 按下电源开关 接串口线 接下载线 现在电脑装串口线驱动 R340qd.zip 双击进行安装 设置串口调试助手 Com1要根据 ...

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

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

  6. 【STM32项目笔记】STM32CubeMX+Keil+Proteus联合实现LED闪烁

    摘要 利用STM32CubeMx配置STM32芯片的功能,然后将配置后的内容生成代码,并导出成可以使用Keil打开编辑的文件,在Keil中添加控制代码后,下载到Proteus仿真中,使用仿真观察代码执 ...

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

    说在前面:上一篇介绍了无线LED闪烁实现的OSAL部分,本篇介绍如何实现无线数据收发及数据处理: 上一篇是用SI跟着流程查看源码,我个人认为以架构的思维去了解代码能让人更清晰 ::ZMain.c程序入 ...

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

    1 前言: 看完了uC/OS-III的基本介绍之后,大致对这个操作系统有了点了解,但真正的理解还是要通过不断的去使用,在使用中体验uC/OS-III的乐趣和更深的理解其工作原理是非常重要的.因此,我在 ...

  9. Keil MDK STM32系列(三) 基于标准外设库SPL的STM32F407开发

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

随机推荐

  1. IE中无法执行JS脚本 解决WINDOWS SERVER 2008弹出INTERNET EXPLORER增强安全配置正在阻止来自下列网站的内容

    在默认状态下,使用Windows Server 2008系统自带的IE浏览器访问网页内容时,我们时常发现“Internet Explorer增强安全配置正在阻止来自下列网站的内容”的提示导致不能打开网 ...

  2. css 透明(transparent)

    opacity :  .75;     //standard css3 style for transparency -moz-opacity : .75;        // transparenc ...

  3. struts2各个jar包的作用

    ---------------------------------------------------struts2核心jar包------------------------------------ ...

  4. scala 学习: 逆变和协变

    scala 逆变和协变的概念网上有很多解释, 总结一句话就是 参数是逆变的或者不变的,返回值是协变的或者不变的. 但是为什么是这样的? 协变: 当s 是A的子类, 那么func(s) 是func(A) ...

  5. MapGIS6.7安装图文教程(完美破解)

    mapgis安装比较简单,主要注意在安装的时候,先打开软件狗,然后再进行软件安装,一般就不会照成其他安装失败的现象,有时候安装之前没有打开软件狗也安装成功了,也有这情况,不过软件使用也需要软件狗的支持 ...

  6. Spark 机器学习

    将Mahout on Spark 中的机器学习算法和MLlib中支持的算法统计如下: 主要针对MLlib进行总结 分类与回归 分类和回归是监督式学习; 监督式学习是指使用有标签的数据(LabeledP ...

  7. Oracle常量

    Oracle是有常量的,而SqlServer是没有常量的 queryFrom constant ) := ' hello ';

  8. js判断访问终端

    //判断访问终端 var browser={ versions:function(){ var u = navigator.userAgent, app = navigator.appVersion; ...

  9. mysql 大小写 整理

    mysql字段的值默认不区分大小写,如果有主键的表,主键列就不能插入重复的值(大小写不同) 实验 默认方式创建 CREATE TABLE `t1` ( `ID` varchar(40) CHARACT ...

  10. 基本数据类型范围大小&&字节大小

    char -128 ~ +127 short -32767 ~ + 32768 unsigned short 0 ~ 65536 int -2147483648 ~ +2147483647 unsig ...