• 嵌入式:UCOSIII的使用(17.01.24补充)


    0、一些移植、系统相关 

    OS_CFG_APP.H

                                                                /* --------------------- MISCELLANEOUS ------------------ */
    #define  OS_CFG_MSG_POOL_SIZE            100u               /* 消息池 大小                                       */
    #define  OS_CFG_ISR_STK_SIZE             128u               /* Stack size of ISR stack (number of CPU_STK elements)   */
    #define  OS_CFG_TASK_STK_LIMIT_PCT_EMPTY  10u               /* Stack limit position in percentage to empty            */
    
    
                                                                /* ---------------------- IDLE TASK --------------------- */
    #define  OS_CFG_IDLE_TASK_STK_SIZE       128u               /* 空闲任务 堆栈空间大小   (一般不做修改)                 */
    
    
                                                                /* ------------------ ISR HANDLER TASK ------------------ */
    #define  OS_CFG_INT_Q_SIZE                10u               /* 中断服务队列 大小                                  */
    #define  OS_CFG_INT_Q_TASK_STK_SIZE      128u               /* 中断服务队列 堆栈空间大小(一般不做修改)                  */
    
                                                                /* ------------------- STATISTIC TASK ------------------- */
    #define  OS_CFG_STAT_TASK_PRIO    (OS_CFG_PRIO_MAX-2u)   /* 统计任务 优先级         (一般不做修改)                 */
    #define  OS_CFG_STAT_TASK_RATE_HZ         10u               /* 统计任务频率 (1 to 10 Hz)                             */
    #define  OS_CFG_STAT_TASK_STK_SIZE       128u               /* 统计任务 堆栈空间大小    (一般不做修改)                 */
    
    
                                                                /* ------------------------ TICKS ----------------------- */
    #define  OS_CFG_TICK_RATE_HZ            200u                /* 时钟节拍频率 200HZ = 5ms  (10 to 1000 Hz)                */
    #define  OS_CFG_TICK_TASK_PRIO             1u               /* 时钟节拍优先级,一般设置一个相对较高的优先级             */
    #define  OS_CFG_TICK_TASK_STK_SIZE       128u               /* 时钟节拍堆栈空间大小    (一般不做修改)                 */
    #define  OS_CFG_TICK_WHEEL_SIZE           17u               /* Number of 'spokes' in tick  wheel; SHOULD be prime     */
    
    
                                                                /* ----------------------- TIMERS ----------------------- */
    #define  OS_CFG_TMR_TASK_PRIO              2u               /* 软件定时器优先级				          */
    #define  OS_CFG_TMR_TASK_RATE_HZ         100u               /* 软件定时器频率 100HZ = 10ms,不能小于心跳时钟节拍        */
    #define  OS_CFG_TMR_TASK_STK_SIZE        128u               /* 软件定时器堆栈空间大小   (一般不做修改)                  */
    #define  OS_CFG_TMR_WHEEL_SIZE            17u               /* Number of 'spokes' in timer wheel; SHOULD be prime     */
    

    OS_CFG.H:功能性裁剪

    OS_APP_HOOKS.C:钩子函数

    OS_CPU_A.ASM:PendSV中断、任务切换

    OS_CPU_C.C: OSTaskStkInit函数,任务创建时,对堆栈初始化,寄存器地址要参照手册

    1、框架写法(个人习惯相关)

    1-1、main 函数里创建一个开始任务

    int main(void)
    {
    	OS_ERR err;
    	CPU_SR_ALLOC();
    	
    	初始化外设
    	
    	OSInit(&err);	      //初始化UCOSIII
    
    	OS_CRITICAL_ENTER();    //进入临界区
    
    	OSTaskCreate();       //创建开始任务 
    
    	OS_CRITICAL_EXIT();    //退出临界区
     
    	OSStart(&err);       //开启UCOSIII
    
            while(1);
    }   

    1-2、开始任务里,创建我们要运行的多个任务

    void start_task(void *p_arg)
    {
    	OS_ERR err;
    	CPU_SR_ALLOC();
    	p_arg = p_arg;
    
    	CPU_Init();
    	
    #if OS_CFG_STAT_TASK_EN > 0u           //统计任务
       OSStatTaskCPUUsageInit(&err);                      
    #endif
    	
    #ifdef CPU_CFG_INT_DIS_MEAS_EN	    //测量中断关闭时间
        CPU_IntDisMeasMaxCurReset();	
    #endif
    	
    #if	OS_CFG_SCHED_ROUND_ROBIN_EN   //时间片轮转
    	OSSchedRoundRobinCfg(DEF_ENABLED,1,&err);       //时间片长度为1个系统时钟节拍,既1*5=5ms
    #endif		
    	
    	OS_CRITICAL_ENTER();	    //进入临界区
    	
    	OSTaskCreate(); 	    //创建任务	1		
    	OSTaskCreate(); 	    //创建任务	2		 
    	OSTaskCreate(); 	    //创建任务	3
    	 
    	OS_CRITICAL_EXIT();	     //进入临界区
    	
    	OSTaskDel((OS_TCB*)0,&err);  //删除start_task任务自身
    }    
    

      

    2、任务创建、挂起、删除

    2-1、任务创建

    //==================任务创建宏定义,便于修改==================
    
    #define START_TASK_PRIO		3		//任务优先级
    #define START_STK_SIZE 		128		//任务堆栈大小
    
    OS_TCB StartTaskTCB;				//任务控制块
    CPU_STK START_TASK_STK[START_STK_SIZE];	     //任务堆栈	
    
    void start_task(void *p_arg);			//任务函数
    
    //==================任务创建函数==================
    
    OSTaskCreate((OS_TCB 	* )&StartTaskTCB,	//任务 控制块
    	   (CPU_CHAR	* )"start task", 	//任务 名字
    	   (OS_TASK_PTR  )start_task, 		//任务 函数
    	   (void	* )0,			//任务 任务函数的参数
    	   (OS_PRIO	  )START_TASK_PRIO,     //任务 优先级
    	   (CPU_STK   * )&START_TASK_STK[0],	//任务 堆栈基地址
    	   (CPU_STK_SIZE)START_STK_SIZE/10,	//任务 堆栈深度限位
    	   (CPU_STK_SIZE)START_STK_SIZE,	//任务 堆栈大小
    	   (OS_MSG_QTY  )0,			//任务 内部消息队列能够接收的最大消息数目,为0时禁止接收消息
    	   (OS_TICK	 )0,			//任务 使用时间片轮转,时间片长度,为0时为默认长度,
    	   (void   	*)0,			//任务 用户补充的存储区
    	   (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,   //任务 选项
    	   (OS_ERR 	*)&err);		//任务 创建成功与否

    2-2、任务挂起

    OSTaskSuspend((OS_TCB*)&Task1TaskTCB,&err);		//挂起开始任务

    2-3、任务解挂

    OSTaskResume((OS_TCB*)&Task1TaskTCB,&err);    //任务解挂

    2-4、任务删除

    OSTaskDel((OS_TCB*)0,&err);	//删除start_task任务自身

    3、时间片轮转

    3-1、两个任务优先级相等

    #define Task0_Task_Prio		4                //优先级4
    #define Task0_Stk_Size		128
    OS_TCB Task0TaskTCB;
    CPU_STK Task0_Task_Stk[Task0_Stk_Size];
    void Task0Task(void *p_arg);
    
    #define Task1_Task_Prio		4                //优先级4
    #define Task1_Stk_Size		128
    OS_TCB Task1TaskTCB;
    CPU_STK Task1_Task_Stk[Task1_Stk_Size];
    void Task1Task(void *p_arg); 
    

    3-2、使能轮转调度,调用API,设置单位时间

    #if	OS_CFG_SCHED_ROUND_ROBIN_EN      //使用时间片轮转
    
    	OSSchedRoundRobinCfg(DEF_ENABLED,1,&err);  //时间片长度为1个系统时钟节拍,既1*5=5ms
    	
    #endif	
    

    3-3、创建任务时,设置任务的时间片大小

    OSTaskCreate((OS_TCB 	* )&Task1TaskTCB,		
    			 (CPU_CHAR	* )"Task1 task", 		
    			 (OS_TASK_PTR )Task1Task, 			
    			 (void		* )0,					
    			 (OS_PRIO	  )Task1_Task_Prio,     	
    			 (CPU_STK   * )&Task1_Task_Stk[0],	
    			 (CPU_STK_SIZE)Task1_Stk_Size/10,	
    			 (CPU_STK_SIZE)Task1_Stk_Size,		
    			 (OS_MSG_QTY  )0,					
    			 (OS_TICK	  )2,						//时间片长度为2*5=10ms					
    			 (void   	* )0,				
    			 (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, 
    			 (OS_ERR 	* )&err);	
    

    4、钩子函数。函数指针,UCOS不希望我们去修改他的文件,弄了钩子函数,比如 App_OS_IdleTaskHook ,在空闲时运行这个函数,功能自己填写。

    4-1、使能钩子函数功能,并设置所有函数指针

    #if OS_CFG_APP_HOOKS_EN > 0u	  //使能钩子函数
    	App_OS_SetAllHooks();			
    #endif
    

    4-2、在 os_app_hooks.c 里的 App_OS_*Hook,里面填写你要的功能。

    void  App_OS_IdleTaskHook (void)
    {
    	static int num ;
    	num++;                //计算运行了多少次空闲任务
    }
    

    5、软件定时器

    5-1、软件定时器创建

    //==============定时器结构体、函数声明==============
    
    OS_TMR Timer0;
    void timer0CallBack(void *p_tmr, void *p_arg);
    
    //==============定时器创建==============
    
    //创建定时器0任务
    OSTmrCreate (  (OS_TMR			*)&Timer0,		//定时器 结构体
    		(CPU_CHAR		*)"time0",		//定时器 名字
    		(OS_TICK		 )10,			//定时器 初次延时节拍 10*10 = 100ms
    		(OS_TICK		 )100,			//定时器 以后延时节拍 100*10 = 1000ms = 1s
    		(OS_OPT			 )OS_OPT_TMR_PERIODIC,	//定时器 选项 : 单次 或 周期。
    		(OS_TMR_CALLBACK_PTR	 )timer0CallBack,	//定时器 回调函数,伪中断服务函数
    		(void			*)0,			//定时器 中断服务函数的参数
    		(OS_ERR			*)&err);		//定时器 创建成功与否
    

    5-2、定时器“中断服务函数”,回调函数

    void timer0CallBack(void *p_tmr, void *p_arg)
    {
    	//do something
    }
    

     

    6、信号量

    6-1、信号量创建

    OSSemCreate (   (OS_SEM      *)&mySem,		//信号量 结构体
    		(CPU_CHAR    *)"semtest",	//信号量 名字
    		(OS_SEM_CTR   )1,		//信号量 初始值,
    		(OS_ERR      *)&err);		//信号量 创建成功是否
    

    6-2、信号量等待

    OSSemPend ((OS_SEM   *)&mySem,			//信号量 结构体
    	  (OS_TICK   )0,			//信号量 等待超时时间
    	  (OS_OPT    )OS_OPT_PEND_BLOCKING,	//信号量 阻塞 或 不阻塞
    	  (CPU_TS   *)0,			//信号量 时间戳
    	  (OS_ERR   *)&err);			//信号量 等待错误
    

    6-3、信号量发送

    OSSemPost ((OS_SEM  *)&mySem,		//信号量 结构体
    	  (OS_OPT   )OS_OPT_POST_1,	//信号量 给就绪最高优先级
    	  (OS_ERR  *)&err);		//信号量 等待错误
    

    用途:   1、访问共享资源。

        2、中断发送信号,让处理在任务。

    7、任务内建信号量

    7-1、等待自身的信号量

    OSTaskSemPend ( (OS_TICK   )0,				//内建信号量 超时时间
    		(OS_OPT    )OS_OPT_PEND_BLOCKING,	//内建信号量 阻塞 或 不阻塞	
    		(CPU_TS   *)0,				//内建信号量 时间戳
    		(OS_ERR   *)&err);			//内建信号量 等待错误
    

    7-2、其他任务,给等待内建信号量的任务发送信号量

    OSTaskSemPost ( (OS_TCB  *)&Task0TaskTCB,	//内建信号量 等待的任务
    		(OS_OPT   )OS_OPT_POST_NONE,	//内建信号量 调度 或 不调度
    		(OS_ERR  *)&err);		//内建信号量 等待错误
    

     

    8、互斥信号量

    8-1、互斥信号量创建

    OSMutexCreate ( (OS_MUTEX  	*)&myMutex,	//互斥信号量 结构体
    		(CPU_CHAR	*)"Mutextest",	//互斥信号量 名字
    		(OS_ERR      *)err);		//互斥信号量 创建错误
    

    8-2、互斥信号量等待

    OSMutexPend (  (OS_MUTEX	*)&myMutex,		//互斥信号量 结构体
    		(OS_TICK    )0,				//互斥信号量 等待超时时间
    		(OS_OPT     )OS_OPT_PEND_BLOCKING,	//互斥信号量 阻塞 或 不阻塞
    		(CPU_TS   	*)0,			//互斥信号量 时间戳
    		(OS_ERR   	*)&err);		//互斥信号量 等待错误
    

    8-3、互斥信号量发送

    OSMutexPost ( (OS_MUTEX  *)&myMutex,		//互斥信号量 结构体
    	    (OS_OPT   )OS_OPT_POST_NONE,	//互斥信号量 调度 或 不调度
    	    (OS_ERR  *)&err);		//互斥信号量 发送错误
    

      

    用途:防止优先级反转,如:2个任务共享一个资源,而,两者的优先级,中间隔着多个优先级(任务)。高优先级 等待 低优先级 释放,而,低优先级 此时又被 中等优先级 打断,变成 高优先级 要等 中等优先级。

    用互斥信号的话,此时 低优先级 ,会暂时提高到共享资源的 高优先级 级别。不会被中等优先级打算。处理完,降回 低优先级 ,高优先级接着访问。再 中等优先级。

    发现:1、高优先级 等待时, 低优先级用OSSched(); 此时达到预计效果,不会被 中等优先级抢占。

         2、高优先级 等待时,低优先级用OSTimeDlyHMSM();延时指令,此时,会被中等优先级抢占。

    9、消息队列

    9-1、消息队列创建

    //================消息队列宏定义================
    
    OS_Q my_MSG_Q;
    #define my_MSG_QTY	(OS_MSG_QTY)5
    
    //================消息队列创建================
    
    OSQCreate ( (OS_Q        *)&my_MSG_Q,	     //消息队列 结构体
    	  (CPU_CHAR    *)"MSG_Q_Test",  	//消息队列 名字
    	  (OS_MSG_QTY   )my_MSG_QTY,		//消息队列 大小
    	  (OS_ERR      *)&err);		//消息队列 创建错误
    

    9-2、消息发送

    u8 *MSG = (u8 *)"testtet";
    	
    OSQPost (  (OS_Q         *)&my_MSG_Q,		//消息队列 结构体
    	  (void         *)MSG,			//消息队列 发送的消息
    	  (OS_MSG_SIZE   )8,			//消息队列 发送的消息大小
    	  (OS_OPT        )OS_OPT_POST_FIFO,	//消息队列 发送方式,普通FIFO,紧急LIFO,及发送给所有等待该消息、发送调度与否
    	  (OS_ERR       *)&err);		//消息队列 发送错误

    9-3、消息接收

    u8 *MSG;	
    u8 Q_size;	
    		
    MSG = OSQPend ( (OS_Q         *)&my_MSG_Q,		//消息队列 结构体
    		(OS_TICK       )0,			//消息队列 等待超时
    		(OS_OPT        )OS_OPT_PEND_BLOCKING,	//消息队列 阻塞 或 不阻塞
    		(OS_MSG_SIZE  *)&Q_size,		//消息队列 收到的大小
    		(CPU_TS       *)0,			//消息队列 时间戳
    		(OS_ERR       *)&err);			//消息队列 接收错误
    

     

    10、任务内建消息队列

    10-1、内建消息队列发送

    u8 *MSG = (u8 *)"testtet";
    
    OSTaskQPost (  (OS_TCB       *)&MSG_Q_TaskTCB,	  //内建消息队列 接收的任务				
    		(void         *)MSG,		  //内建消息队列 发送的消息
    		(OS_MSG_SIZE   )8,		  //内建消息队列 发送的消息大小
    		(OS_OPT        )OS_OPT_POST_FIFO,  //内建消息队列 发送方式,普通FIFO,紧急LIFO,及发送给所有等待该消息、发送调度与否
    		(OS_ERR       *)&err);		  //内建消息队列 发送错误

    10-2、内建消息队列接收

    u8 *MSG;
    u8 Q_size;
    		
    MSG = OSTaskQPend (	(OS_TICK		)0,		//内建消息队列 等待超时
    			(OS_OPT        )OS_OPT_PEND_BLOCKING,	//内建消息队列 阻塞 或 不阻塞
    			(OS_MSG_SIZE  *)&Q_size,		//内建消息队列 收到的大小
    			(CPU_TS       *)0,			//内建消息队列 时间戳
    			(OS_ERR       *)&err);			//内建消息队列 接收错误	
    

      

    11、标记位组

    11-1、标记位组创建

    OS_FLAG_GRP my_FLAG;
    
    #define FLAG_INIT	0x00
    #define FLAG_BIT0	0x01
    #define FLAG_BIT1	0x02
    
    OSFlagCreate (	(OS_FLAG_GRP  *)&my_FLAG,	//标记位组 结构体
    		(CPU_CHAR     *)"Flag test",	//标记位组 名字
    		(OS_FLAGS      )FLAG_INIT,	//标记位组 标记初始值
    		(OS_ERR       *)&err);		//标记位组 创建成功与否
    

    11-2、标记位组发送

    OSFlagPost ((OS_FLAG_GRP  *)&my_FLAG,			//标记位组 结构体
    	   (OS_FLAGS      )FLAG_BIT0,			//标记位组 bit0
    	   (OS_OPT        )OS_OPT_POST_FLAG_SET,	//标记位组 置1
    	   (OS_ERR       *)&err);			//标记位组 bit0 置 1 成功与否
    

    11-3、标记为组等待

    OS_FLAGS index;
    		
    index = OSFlagPend ((OS_FLAG_GRP  *)&my_FLAG,		  //标记位组 结构体
    		    (OS_FLAGS      )FLAG_BIT0 | FLAG_BIT1, //标记位组 等待的BIT位
    		    (OS_TICK       )0,			  //标记位组 等待超时时间
    		    (OS_OPT        )OS_OPT_PEND_FLAG_SET_ANY | OS_OPT_PEND_FLAG_CONSUME | OS_OPT_PEND_BLOCKING,	  //标记位组 任意1个Bit置1,接收后清0,阻塞
    		    (CPU_TS       *)0,			  //标记位组 时间戳
    		    (OS_ERR       *)&err);		  //标记位组 等待错误
    

      

    12、多个内核对象

    12-1、多个内核对象 创建

    //=================多个内核对象 结构体=================
    
    OS_SEM my_Sem1;
    
    OS_SEM my_Sem2;
    
    OS_Q  my_Q1;
    #define my_Q1_SIZE	5
    	
    //=================多个内核对象 创建=================
    
    OSSemCreate (	(OS_SEM      *)&my_Sem1,
    		(CPU_CHAR    *)"sem1 test",
    		(OS_SEM_CTR   )0,
    		(OS_ERR      *)&err);
    
    OSSemCreate (	(OS_SEM      *)&my_Sem2,
    		(CPU_CHAR    *)"sem2 test",
    		(OS_SEM_CTR   )0,
    		(OS_ERR      *)&err);			
    					
    OSQCreate (	(OS_Q        *)&my_Q1,
                    (CPU_CHAR    *)"my_Q1",
                    (OS_MSG_QTY   )my_Q1_SIZE,
                    (OS_ERR      *)&err);

    12-2、等待多个内核对象

    //===============多个内核对象 宏定义===============
    
    #define MY_OBJ_NUM 3					//多个内核对象 等待数量
    	
    //===============多个内核对象 等待===============
    
    OS_PEND_DATA my_OBJ_data[MY_OBJ_NUM];	//多个内核对象 数组
    	
    my_OBJ_data[0].PendObjPtr = (OS_PEND_OBJ *)&my_Sem1;	//多个内核对象 对象0
    my_OBJ_data[1].PendObjPtr = (OS_PEND_OBJ *)&my_Sem2;	//多个内核对象 对象1
    my_OBJ_data[2].PendObjPtr = (OS_PEND_OBJ *)&my_Q1;	//多个内核对象 对象2
    	
    my_return_data = OSPendMulti (	(OS_PEND_DATA  *)my_OBJ_data,	    //多个内核对象 对象数组
    				(OS_OBJ_QTY     )MY_OBJ_NUM,	    //多个内核对象 对象数量
    				(OS_TICK        )0,		    //多个内核对象 等待超时时间
    				(OS_OPT         )OS_OPT_PEND_BLOCKING,	//多个内核对象 阻塞 或 不阻塞
    				(OS_ERR        *)&err);			//多个内核对象 等待错误
    

    12-3、多个内核对象 发送

    任意对象 post ,都会结束等待

    13、内存管理

    13-1、内存创建

    //==================内存 宏定义==================
    
    OS_MEM IN_MEM;
    #define IN_MEM_Block	5			//必须大于2
    #define IN_MEM_Zone		25 * 4		//必须大于4,且为4的倍数,存放下一块的地址内容,4字节
    CPU_INT08U IN_MEM_DATA[IN_MEM_Block][IN_MEM_Zone];
    
    //==================内存 创建==================
    
    OSMemCreate (  (OS_MEM       *)&IN_MEM,			//内存 结构体
                   (CPU_CHAR     *)"IN_MEM",		//内存 名字
                   (void         *)&IN_MEM_DATA[0][0],	//内存 基地址
                   (OS_MEM_QTY    )IN_MEM_Block,		//内存 几个块,一维数组
                   (OS_MEM_SIZE   )IN_MEM_Zone,		//内存 每个块大小,二维数组
                   (OS_ERR       *)&error);			//内存 创建成功与否
    

    13-2、内存申请

    u8 *p;
    
    p = OSMemGet (	(OS_MEM  *)&IN_MEM,	//内存 结构体
    		(OS_ERR  *)&err);	//内存 申请成功与否
    

    13-3、内存释放

    OSMemPut ( (OS_MEM  *)&IN_MEM,	  //内存 结构体
    	  (void    *)p,	  //内存 要释放的地址
    	  (OS_ERR  *)&err);	  //内存 释放成功与否
    

    备注:内存有申请,必释放,如果申请后,不释放,再申请,那之前申请的地址就找不到了,因为你的指针地址变了。

        所以,如果要多次申请的话,1、还要弄个指针数组,2、或者普通数组来存放当前申请的地址,3、或者知道UCOS的内存管理机制,直接去内存数组里找到地址。

    暂时就这样,以后再检查修改,手酸。

    ================================================ 17.01.24 补充================================================

    1、中断处理

    void xxx_Handler(void)			//某中断服务函数
    {	
    
    	OSIntEnter();			//进入中断
    		
    	//中断处理
    		
    	OSIntExit();       	 	//触发任务切换软中断
    }
    

      

    2、临界段处理

    OS_CRITICAL_ENTER();    //进入临界区
    
    //不想被打断的时序任务、功能
    
    OS_CRITICAL_EXIT();	//退出临界区	 
    

    3、引起调度函数

    3-1、延时

    OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_HMSM_STRICT,&err);     //延时1s,严格按照 60分60秒1000毫秒,进位。
    

      

  • 相关阅读:
    Linux普通用户登录后,命令行提示:-bash-4.1$ ,原因分析及解决
    ps命令
    Linux命令ping
    Linux 系统管理 : last 命令详解
    Linux命令head
    Linux more与less命令
    Mac下开启Chrome非安全模式
    mac host 修改
    mac 电脑记
    a的样式顺序
  • 原文地址:https://www.cnblogs.com/leonlincq/p/6295390.html
Copyright © 2020-2023  润新知