STM32系列课程总结5---uCOS-III任务调度及通信

一 时间管理---作用:延时。系统提供两个函数实现延时,但是精度只有毫秒基本,建议采用自身设计的滴答定时器。
   小提示:以 OS_ 开头的函数不是我们调用的,我们调用的是以 OS 开头的函数 
    1、void  OSTimeDly (OS_TICK   dly,OS_OPT    opt,OS_ERR   *p_err)    
        参数
            dly        ---》时钟节拍的个数,当前我们的时钟节拍是 1ms

    2、 
        void  OSTimeDlyHMSM (CPU_INT16U   hours,        //小时
                             CPU_INT16U   minutes,        //分钟
                             CPU_INT16U   seconds,        //秒
                             CPU_INT32U   milli,        //毫秒
                             OS_OPT       opt,
                             OS_ERR      *p_err)                

二 临界操作--解决一个任务执行本另一个优先级较高的任务打断。

    时钟节拍 :时钟节拍是利用滴答定时计数来执行的 我们的时钟节拍是 1ms ,意思就是每隔 1ms 滴答定时器中断一次
    sleep(1)

    1、 CPU_SR_ALLOC()            //申请中断
    
    2、 CPU_CRITICAL_ENTER()    //关闭中断
    
    3、CPU_CRITICAL_EXIT()        //打开中断

结合例子说明:临界操作是如何利用滴答定时器运行原理来操作开关中断,来实现睡眠的任务醒来不能突然中断正在执行的任务。

原先程序缺陷:(记住:起始任务运行函数   优先级高)
static  void  AppTaskStart (void *p_arg)
{
    OS_ERR err;
    
    printf("AppTaskStart is Created!\r\n");
    while(1)
    {
      
        printf("AppTaskStart is Running!\r\n");

        OSTimeDlyHMSM ( 0u,		//小时    //睡眠时 系统就开始统计中断次数,当数到2时这个任务就醒过来
						0u,		//分钟
						0u,		//秒
						2u,		//毫秒
						OS_OPT_TIME_HMSM_NON_STRICT,
					    (OS_ERR      *)&err);
 
    }
}

//任务1运行函数  优先级低
static  void  AppTask1 (void *p_arg)
{
    OS_ERR err;
    printf("AppTask1 is Created!\r\n");
    while(1)
    {
        
       
         printf("AppTask1 is Running!\r\n");


        OSTimeDlyHMSM ( 0u,		//小时
						0u,		//分钟
						0u,		//秒
						2u,		//毫秒
						OS_OPT_TIME_HMSM_NON_STRICT,
					    (OS_ERR      *)&err);
    }
}

-------------------------------------------------------------------------------
缺陷:任务 AppTask1t不能正常打印,经常被AppTaskStart任务打断,
原因是任务AppTaskStart优先级高,当进入睡眠时,正在执行AppTask1t,
但是AppTaskStart睡眠结束,常理下是等AppTask1t执行完再运行的,
但是因为ucos-III遵循永远执行优先级较高的任务。因此可以采用临界
操作和信号量机制。因为滴答定时器能够计时延时依靠中断和计数的方式,
计数到一定便中断标记1us,如果把中断关闭,计数暂停。
程序修改如下:
//起始任务运行函数   优先级高 
static  void  AppTaskStart (void *p_arg)
{
    OS_ERR err;
    
     CPU_SR_ALLOC();
    
    printf("AppTaskStart is Created!\r\n");
    while(1)
    {
        CPU_CRITICAL_ENTER();  //关中断
        printf("AppTaskStart is Running!\r\n");
        
        CPU_CRITICAL_EXIT();   //开中断
        
        OSTimeDlyHMSM ( 0u,		//小时    //睡眠时 系统就开始统计中断次数,当数到2时这个任务就醒过来
						0u,		//分钟
						0u,		//秒
						2u,		//毫秒
						OS_OPT_TIME_HMSM_NON_STRICT,
					    (OS_ERR      *)&err);
 
    }
}

//任务1运行函数  优先级低
static  void  AppTask1 (void *p_arg)
{
    OS_ERR err;
   CPU_SR_ALLOC(); 
    printf("AppTask1 is Created!\r\n");
    while(1)
    {
        
          CPU_CRITICAL_ENTER();  //关中断          //对方一进入睡眠状态他就开始执行任务,第一句就是关闭这个中断
         printf("AppTask1 is Running!\r\n");
        
        CPU_CRITICAL_EXIT();  //开中断

        OSTimeDlyHMSM ( 0u,		//小时
						0u,		//分钟
						0u,		//秒
						2u,		//毫秒
						OS_OPT_TIME_HMSM_NON_STRICT,
					    (OS_ERR      *)&err);
    }
}

三 信号量操作

程序下载(目录如下):链接:https://pan.baidu.com/s/1eOL0gS0botOUIEqSZL1pFQ       提取码:ebxl 

STM32系列课程总结5---uCOS-III任务调度及通信_第1张图片

STM32系列课程总结5---uCOS-III任务调度及通信_第2张图片

OS_SEM	SYNC_SEM;				//定义一个信号量,用于任务同步
--------------------------------------
	
		//创建一个信号量,且信号量初值为1,若为0,一开始调用等待信号量就会永远等待下去,不会执行程序。
		OSSemCreate ((OS_SEM*	)&SYNC_SEM,     //信号量
					 (CPU_CHAR*	)"SYNC_SEM",    //信号量的名字
					 (OS_SEM_CTR)1,		        //信号量的初值
					 (OS_ERR*	)&err);

---------------------------------------
		OSSemPend(&SYNC_SEM,0,OS_OPT_PEND_BLOCKING,0,&err); 		//请求信号量  减一

		printf("task1 is running ...\r\n");
		
        OSSemPost(&SYNC_SEM,OS_OPT_POST_1,&err);					//发送信号量  加一

四 事件标志组

原理:一个事件执行可能需要多个事件的发生或者任何其中一个事件发生即可执行。

OS_FLAG_GRP	g_os_flag;	//定义一个全局事件标志组
===========================================
//创建一个事件标志组
OSFlagCreate(	(OS_FLAG_GRP*	)&g_os_flag,    //提前先定义好一个事件标志组变量
				(CPU_CHAR*)"os_flag",
				(OS_FLAGS)0,                    //初始值 0000 0000
				(OS_ERR*		)&err);
============================================
//部门主管签字
static  void  AppTask1 (void *p_arg)
{
    OS_FLAGS os_flag;
    if(KEY0 == 0)
	{  //发送事件标志,标志值为0x1,设置g_os_flag的bit0为1
		os_flag= OSFlagPost(    (OS_FLAG_GRP*	)&g_os_flag,
							(OS_FLAGS)0x1,		            //0000 0001				
							(OS_OPT)OS_OPT_POST_FLAG_SET,
							&err);

	  printf("task1,os_flag=%02X\r\n",os_flag);

	}
}
==========================================
//老总签字
static  void  AppTask2(void *p_arg)
{
    OS_FLAGS os_flag;
    if(KEY1 == 0)
   {
	//发送事件标志,标志值为0x2,设置g_os_flag的bit1为1
	os_flag= OSFlagPost((OS_FLAG_GRP*	)&g_os_flag,
						(OS_FLAGS)0x2,              // 0000 0010
						(OS_OPT)OS_OPT_POST_FLAG_SET,
						&err);

	printf("task2,os_flag=%02X\r\n",os_flag);

   }
}
=======================================
//升职加薪
static  void  AppTask3 (void *p_arg)
{
    OS_FLAGS os_flag;
    while(1)
    {
	//OS_OPT_PEND_FLAG_SET_ANY 和OS_OPT_PEND_FLAG_SET_ALL是有区别的
	//前者是等待任意一个事件,后者要确保所有事件成立
	os_flag= OSFlagPend((OS_FLAG_GRP*	)&g_os_flag,
						(OS_FLAGS)0x3,						//等待bit1和bit0置位  0000 0011
						(OS_TICK)0,							//0代表是默认一直阻塞等待
						(OS_OPT)OS_OPT_PEND_FLAG_SET_ALL+OS_OPT_PEND_FLAG_CONSUME,	//等待事件标志组所有位置位
						//(OS_OPT)OS_OPT_PEND_FLAG_SET_ANY+OS_OPT_PEND_FLAG_CONSUME,	//等待事件标志组任何一位置位 或操作
						(CPU_TS *)0,						//默认不记录时间戳
						&err);

	printf("task3,os_flag=%02X\r\n",os_flag);
    
    }
}

 

你可能感兴趣的:(STM32学习系列)