STM32F4X UCOSIII 信号量

STM32F4X UCOSIII 信号量

  • 信号量概念
  • 信号量工作机制
    • 停车场问题
    • UCOSIII信号量工作机制
  • 信号量常用API
    • 信号量创建
    • 信号量删除
    • 释放信号量
    • 获取信号量
  • UCOSIII 信号量例程

在以往的裸机编程中,如果我们需要判断某个事件是否已经发生,通常会使用一个标志位来进行判断,当事件已经发生时,就将该标志位置1,否则就将该标志位置0。但是有了RTOS之后,我们可以用信号量来代替裸机中的标志位。

信号量概念

信号量是RTOS中一种用于任务间同步的机制,可以实现任务间同步或互斥。简单来说,信号量就相当于是裸机中的标志位,只是在RTOS中信号量会比裸机中的标志位使用更加安全。信号量是一个非负的整数,当有任务获取信号量时,信号量的个数会减1,当有任务释放信号量时,信号量的个数会加1。当信号量个数为0时,就代表当前系统中的信号量已经使用完毕,没有多余的信号量。UCOSIII中的信号量不会传递数据

信号量工作机制

停车场问题

我们首先以一个日常生活中常见的问题进行类比。
假设有一个停车场,里面有3个停车位,刚开始停车位是空的。这时候A车进入停车场,此时停车场的停车位还有2个,过一会B车也进入了停车场,此时停车位还有1个,过一会C车进入停车场,此时停车位已经被占满了,没有空闲的停车位。这时候D车也想进入停车场,但是因为已经没有停车位了,所以D车只能在外面等,过一会A车离开了停车场,此时停车位有1个,这时D车因为有了空闲的停车位,就可以进入停车场。
在上面的场景中,共享资源是停车场里面的3个停车位,相当于是3个信号量,ABCD四辆车相当于是4个任务,车进入停车位相当于是获取信号量,信号量减1,车离开停车位相当于是释放信号量,信号量加1。D车等待停车位相当于是阻塞。

UCOSIII信号量工作机制

STM32F4X UCOSIII 信号量_第1张图片
上面的那个停车场问题用上图来进行表达,上图中定义了信号量个数为3,则代表系统中有3个可用的信号量,任务1、任务2、任务3依次获取了3个信号量,此时如果任务4想获取信号量,就只能阻塞等待或者超过等待时间自动退出,除非此时任务1/2/3中的其中一个任务释放信号量,否则任务4永远都不会得到信号量。

信号量常用API

信号量创建

在信号量创建时,用户需要指定信号量的个数。

/*
*p_sem:信号量对象
*p_name:信号量名字
*cnt:信号量个数
*p_err:错误代码
*/
void  OSSemCreate (OS_SEM      *p_sem,
                   CPU_CHAR    *p_name,
                   OS_SEM_CTR   cnt,
                   OS_ERR      *p_err)

信号量删除

当信号量被删除后,系统将不能继续该信号量

/*
*p_sem:信号量对象
*opt:用户选择
*p_err:错误代码
返回值: >0 有等待信号量的任务个数
	   ==0 没有任务等待信号量
*/
OS_OBJ_QTY  OSSemDel (OS_SEM  *p_sem,
                      OS_OPT   opt,
                      OS_ERR  *p_err)

opt选项可以选择OS_OPT_DEL_NO_PEND和OS_OPT_DEL_ALWAYS

  • OS_OPT_DEL_NO_PEND:删除信号量如果该信号量上有挂起的任务,则等待挂起的任务恢复才删除
  • OS_OPT_DEL_ALWAYS:不管该信号量上是否有挂起的任务,直接删除信号量

释放信号量

/*
*p_sem:信号量对象
*opt:用户选择
*p_err:错误代码
返回值: 当前剩余的信号量
*/
OS_SEM_CTR  OSSemPost (OS_SEM  *p_sem,
                       OS_OPT   opt,
                       OS_ERR  *p_err)

opt选项可以选择OS_OPT_POST_1、OS_OPT_POST_ALL和OS_OPT_POST_NO_SCHED

  • OS_OPT_POST_1:将消息发送到最高优先级的等待任务
  • OS_OPT_POST_ALL:将信号量广播到所有任务
  • OS_OPT_POST_NO_SCHED:释放信号量不调度

获取信号量

/*
*p_sem:信号量对象
*timeout:超时等待时间
*opt:用户选择
*p_ts:时间戳
*p_err:错误代码
返回值: 当前剩余的信号量
*/
OS_SEM_CTR  OSSemPend (OS_SEM   *p_sem,
                       OS_TICK   timeout,
                       OS_OPT    opt,
                       CPU_TS   *p_ts,
                       OS_ERR   *p_err)

opt选项可以选择OS_OPT_PEND_BLOCKING和OS_OPT_PEND_NON_BLOCKING

  • OS_OPT_PEND_BLOCKING:阻塞等待信号量,除非有信号量,否则任务不会恢复
  • OS_OPT_PEND_NON_BLOCKING:不阻塞等待信号量,如果任务等待时间超过设定的超时时间,任务会恢复并返回一个错误代码

UCOSIII 信号量例程

改例程是任务1每隔1秒释放一次信号量,任务2则阻塞等待信号量

/*
*********************************************************************************************************
*                                              EXAMPLE CODE
*
*                             (c) Copyright 2013; Micrium, Inc.; Weston, FL
*
*                   All rights reserved.  Protected by international copyright laws.
*                   Knowledge of the source code may not be used to write a similar
*                   product.  This file may only be used in accordance with a license
*                   and should not be redistributed in any way.
*********************************************************************************************************
*/

/*
*********************************************************************************************************
*
*                                            EXAMPLE CODE
*
*                                       IAR Development Kits
*                                              on the
*
*                                    STM32F429II-SK KICKSTART KIT
*
* Filename      : app.c
* Version       : V1.00
* Programmer(s) : YS
*********************************************************************************************************
*/

/*
*********************************************************************************************************
*                                             INCLUDE FILES
*********************************************************************************************************
*/

#include  

/*
*********************************************************************************************************
*                                            LOCAL DEFINES
*********************************************************************************************************
*/


/*
*********************************************************************************************************
*                                       LOCAL GLOBAL VARIABLES
*********************************************************************************************************
*/

                                                                /* ----------------- APPLICATION GLOBALS -------------- */
static  OS_TCB   AppTaskStartTCB;
static  CPU_STK  AppTaskStartStk[APP_CFG_TASK_START_STK_SIZE];

#define APPTASK1NAME    "App Task1"
#define APP_TASK1_PRIO          4   
#define APP_TASK1_STK_SIZE 1024
static OS_TCB AppTask1TCB;
static void  AppTask1  (void *p_arg);
static CPU_STK AppTask1Stk[APP_TASK1_STK_SIZE];

#define APPTASK2NAME    "App Task2"
#define APP_TASK2_PRIO          5  
#define APP_TASK2_STK_SIZE 1024
static OS_TCB AppTask2TCB;
static void  AppTask2  (void *p_arg);
static CPU_STK AppTask2Stk[APP_TASK2_STK_SIZE];




static OS_SEM sem;


/*
*********************************************************************************************************
*                                         FUNCTION PROTOTYPES
*********************************************************************************************************
*/

static  void  AppTaskStart          (void     *p_arg);


/*
*********************************************************************************************************
*                                                main()
*
* Description : This is the standard entry point for C code.  It is assumed that your code will call
*               main() once you have performed all necessary initialization.
*
* Arguments   : none
*
* Returns     : none
*********************************************************************************************************
*/

int main(void)
{

    OS_ERR  err;


    OSInit(&err);                                               /* Init uC/OS-III.                                      */
   
    OSTaskCreate((OS_TCB       *)&AppTaskStartTCB,              /* Create the start task                                */
                 (CPU_CHAR     *)"App Task Start",
                 (OS_TASK_PTR   )AppTaskStart,
                 (void         *)0u,
                 (OS_PRIO       )APP_CFG_TASK_START_PRIO,
                 (CPU_STK      *)&AppTaskStartStk[0u],
                 (CPU_STK_SIZE  )AppTaskStartStk[APP_CFG_TASK_START_STK_SIZE / 10u],
                 (CPU_STK_SIZE  )APP_CFG_TASK_START_STK_SIZE,
                 (OS_MSG_QTY    )0u,
                 (OS_TICK       )0u,
                 (void         *)0u,
                 (OS_OPT        )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
                 (OS_ERR       *)&err);

    OSStart(&err);                                              /* Start multitasking (i.e. give control to uC/OS-III). */


}


/*
*********************************************************************************************************
*                                          STARTUP TASK
*
* Description : This is an example of a startup task.  As mentioned in the book's text, you MUST
*               initialize the ticker only once multitasking has started.
*
* Arguments   : p_arg   is the argument passed to 'AppTaskStart()' by 'OSTaskCreate()'.
*
* Returns     : none
*
* Notes       : 1) The first line of code is used to prevent a compiler warning because 'p_arg' is not
*                  used.  The compiler should not generate any code for this statement.
*********************************************************************************************************
*/

static  void  AppTaskStart (void *p_arg)
{
    CPU_INT32U  cpu_clk_freq;
    CPU_INT32U  cnts;
    OS_ERR      err;


   (void)p_arg;

    BSP_Init();                      
    CPU_Init();                                                 /* Initialize the uC/CPU services                       */

    cpu_clk_freq = BSP_CPU_ClkFreq();                           /* Determine SysTick reference freq.                    */
    cnts         = cpu_clk_freq                                 /* Determine nbr SysTick increments                     */
                 / (CPU_INT32U)OSCfg_TickRate_Hz;

    OS_CPU_SysTickInit(cnts);                                   /* Init uC/OS periodic time src (SysTick).              */

    Mem_Init();                                                 /* Initialize memory managment module                   */
    Math_Init();                                                /* Initialize mathematical module                       */


#if OS_CFG_STAT_TASK_EN > 0u
    OSStatTaskCPUUsageInit(&err);                               /* Compute CPU capacity with no task running            */
#endif

#ifdef CPU_CFG_INT_DIS_MEAS_EN
    CPU_IntDisMeasMaxCurReset();
#endif


#if (APP_CFG_SERIAL_EN == DEF_ENABLED)
    App_SerialInit();                                           /* Initialize Serial communication for application ...  */
#endif
	

	OSTaskCreate((OS_TCB     *)&AppTask1TCB,  // 线程TCB              
			 (CPU_CHAR   *)APPTASK1NAME, // 线程名字
			 (OS_TASK_PTR ) AppTask1, // 线程入口函数
			 (void       *) "TASK1", // 线程参数
			 (OS_PRIO     ) APP_TASK1_PRIO, // 线程优先级
			 (CPU_STK    *)&AppTask1Stk[0], // 线程栈起始地址
			 (CPU_STK_SIZE) APP_TASK1_STK_SIZE / 10, // 栈深度的限制位置
			 (CPU_STK_SIZE) APP_TASK1_STK_SIZE, // 栈大小
			 (OS_MSG_QTY  ) 20u, // 最大的消息个数
			 (OS_TICK     ) 0u, // 时间片
			 (void       *) 0, // 向用户提供的内存位置的指针
			 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), // 线程特定选项
			 (OS_ERR     *)&err); // 错误标志
	if(OS_ERR_NONE == err)
		printf("%s Create Success\r\n",APPTASK1NAME);
	else
		printf("%s Create Error\r\n",APPTASK1NAME);
	
			 
	OSTaskCreate((OS_TCB     *)&AppTask2TCB,  // 线程TCB              
			 (CPU_CHAR   *)APPTASK2NAME, // 线程名字
			 (OS_TASK_PTR ) AppTask2, // 线程入口函数
			 (void       *) "TASK2", // 线程参数
			 (OS_PRIO     ) APP_TASK2_PRIO, // 线程优先级
			 (CPU_STK    *)&AppTask2Stk[0], // 线程栈起始地址
			 (CPU_STK_SIZE) APP_TASK2_STK_SIZE / 10, // 栈深度的限制位置
			 (CPU_STK_SIZE) APP_TASK2_STK_SIZE, // 栈大小
			 (OS_MSG_QTY  ) 20u, // 最大的消息个数
			 (OS_TICK     ) 0u, // 时间片
			 (void       *) 0, // 向用户提供的内存位置的指针
			 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), // 线程特定选项
			 (OS_ERR     *)&err); // 错误标志
	if(OS_ERR_NONE == err)
		printf("%s Create Success\r\n",APPTASK2NAME);
	else
		printf("%s Create Error\r\n",APPTASK2NAME);
	

		

	OSSemCreate(&sem,(CPU_CHAR*)"sem",(OS_SEM_CTR)2,&err);
	if(OS_ERR_NONE == err)
		printf("Create Sem Success\r\n");
	else
		printf("Create Sem Error\r\n");
	
	OSTaskDel ( & AppTaskStartTCB, & err );		 

}

static void  AppTask1  (void *p_arg)
{
    OS_ERR      err;

	while(DEF_TRUE)
	{
		OSTimeDly ( 1000, OS_OPT_TIME_DLY, & err ); // 1000ms释放一次信号量
		OSSemPost(&sem,OS_OPT_POST_ALL,&err);
		if(OS_ERR_NONE == err)
			printf("%s send post success\r\n",__func__);
		else
			printf("%s send post error\r\n",__func__);
		

	}
	
}
static void  AppTask2  (void *p_arg)
{
    OS_ERR      err;

	while(DEF_TRUE)
	{
		OSSemPend (&sem,0,OS_OPT_PEND_BLOCKING,0,&err); // 获取信号量
		if(OS_ERR_NONE == err)
			printf("%s send pend success\r\n",__func__);
		else
			printf("%s send pend error\r\n",__func__);
		
	}
	
}

STM32F4X UCOSIII 信号量_第2张图片

你可能感兴趣的:(RTOS,stm32,单片机)