(学习日记)2024.04.04:UCOSIII第三十二节:计数信号量实验

本文详细描述了在UCOSIII中进行计数信号量实验的过程,涉及任务设计、实验原理和现象,以及如何通过STM32开发板的按键操作模拟停车场操作,结果通过串口调试助手显示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

写在前面:
由于时间的不足与学习的碎片化,写博客变得有些奢侈。
但是对于记录学习(忘了以后能快速复习)的渴望一天天变得强烈。
既然如此
不如以天为单位,以时间为顺序,仅仅将博客当做一个知识学习的目录,记录笔者认为最通俗、最有帮助的资料,并尽量总结几句话指明本质,以便于日后搜索起来更加容易。


标题的结构如下:“类型”:“知识点”——“简短的解释”
部分内容由于保密协议无法上传。


点击此处进入学习日记的总目录

2024.04.04:UCOSIII第三十二节:计数信号量实验

四十六、UCOSIII:计数信号量实验

1、实验设计

计数型信号量实验是模拟停车场工作运行。在创建信号量的时候初始化5个可用的信号量,并且创建了两个任务:一个是获取信号量任务, 一个是释放信号量任务,两个任务独立运行,获取信号量任务是通过按下KEY1按键进行信号量的获取,模拟停车场停车操作, 其等待时间是0,在串口调试助手输出相应信息。

释放信号量任务则是信号量的释放,释放信号量任务也是通过按下KEY2按键进行信号量的释放,模拟停车场取车操作, 在串口调试助手输出相应信息,实验源码具体如下:

#include <includes.h>


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

OS_SEM SemOfKey;          //标志KEY1是否被按下的信号量


/*
***************************************************************
*                                                 TCB
****************************************************************
*/

static  OS_TCB   AppTaskStartTCB;                      //任务控制块
static  OS_TCB   AppTaskKey1TCB;
static  OS_TCB   AppTaskKey2TCB;


/*
*****************************************************************
*                         STACKS
******************************************************************
*/

static  CPU_STK  AppTaskStartStk[APP_TASK_START_STK_SIZE];       //任务栈
static  CPU_STK  AppTaskKey1Stk [ APP_TASK_KEY1_STK_SIZE ];
static  CPU_STK  AppTaskKey2Stk [ APP_TASK_KEY2_STK_SIZE ];


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

static  void  AppTaskStart  (void *p_arg);               //任务函数声明
static  void  AppTaskKey1  ( void * p_arg );
static  void  AppTaskKey2  ( void * p_arg );




int  main (void)
{
    OS_ERR  err;
    OSInit(&err);     //初始化μC/OS-III

    /* 创建起始任务 */
    OSTaskCreate((OS_TCB     *)&AppTaskStartTCB,
                //任务控制块地址
                (CPU_CHAR   *)"App Task Start",
                //任务名称
                (OS_TASK_PTR ) AppTaskStart,
                //任务函数
                (void       *) 0,
                //传递给任务函数(形参p_arg)的实参
                (OS_PRIO     ) APP_TASK_START_PRIO,
                //任务的优先级
                (CPU_STK    *)&AppTaskStartStk[0],
                //任务栈的基地址
                (CPU_STK_SIZE) APP_TASK_START_STK_SIZE / 10,
                //任务栈空间剩下1/10时限制其增长
                (CPU_STK_SIZE) APP_TASK_START_STK_SIZE,
                //任务栈空间(单位:sizeof(CPU_STK))
                (OS_MSG_QTY  ) 5u,
                //任务可接收的最大消息数
                (OS_TICK     ) 0u,
                //任务的时间片节拍数(0表默认值OSCfg_TickRate_Hz/10)
                (void       *) 0,
                //任务扩展(0表不扩展)
                (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
                //任务选项
                (OS_ERR     *)&err);
                //返回错误类型

    OSStart(&err);
    //启动多任务管理(交由μC/OS-III控制)

}




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


    (void)p_arg;

    BSP_Init();
    //板级初始化
    CPU_Init();//初始化 CPU组件(时间戳、关中断时间测量和主机名)

    cpu_clk_freq = BSP_CPU_ClkFreq();
    //获取 CPU内核时钟频率(SysTick 工作时钟)
    cnts = cpu_clk_freq / (CPU_INT32U)OSCfg_TickRate_Hz;
    //根据用户设定的时钟节拍频率计算 SysTick定时器的计数值
    OS_CPU_SysTickInit(cnts);
    //调用 SysTick初始化函数,设置定时器计数值和启动定时器

    Mem_Init();
    //初始化内存管理组件(堆内存池和内存池表)

#if OS_CFG_STAT_TASK_EN > 0u
//如果启用(默认启用)了统计任务
    OSStatTaskCPUUsageInit(&err);
    //计算没有应用任务(只有空闲任务)运行时 CPU 的(最大)
#endif
    //容量(决定OS_Stat_IdleCtrMax 的值,为后面计算 CPU使用率使用)。
    CPU_IntDisMeasMaxCurReset();
    //复位(清零)当前最大关中断时间


    /* 创建信号量 SemOfKey */
    OSSemCreate((OS_SEM      *)&SemOfKey,    //指向信号量变量的指针
                (CPU_CHAR    *)"SemOfKey",    //信号量的名字
                (OS_SEM_CTR   )5,             //表示现有资源数目
                (OS_ERR      *)&err);         //错误类型


    /* 创建 AppTaskKey1 任务 */
    OSTaskCreate((OS_TCB     *)&AppTaskKey1TCB,
                //任务控制块地址
                (CPU_CHAR   *)"App Task Key1",
                //任务名称
                (OS_TASK_PTR ) AppTaskKey1,
                //任务函数
                (void       *) 0,
                //传递给任务函数(形参p_arg)的实参
                (OS_PRIO     ) APP_TASK_KEY1_PRIO,
                //任务的优先级
                (CPU_STK    *)&AppTaskKey1Stk[0],
                //任务栈的基地址
                (CPU_STK_SIZE) APP_TASK_KEY1_STK_SIZE / 10,
                //任务栈空间剩下1/10时限制其增长
                (CPU_STK_SIZE) APP_TASK_KEY1_STK_SIZE,
                //任务栈空间(单位:sizeof(CPU_STK))
                (OS_MSG_QTY  ) 5u,
                //任务可接收的最大消息数
                (OS_TICK     ) 0u,
                //任务的时间片节拍数(0表默认值OSCfg_TickRate_Hz/10)
                (void       *) 0,
                //任务扩展(0表不扩展)
                (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
                //任务选项
                (OS_ERR     *)&err);
                //返回错误类型

    /* 创建 AppTaskKey2 任务 */
    OSTaskCreate((OS_TCB     *)&AppTaskKey2TCB,
                //任务控制块地址
                (CPU_CHAR   *)"App Task Key2",
                //任务名称
                (OS_TASK_PTR ) AppTaskKey2,
                //任务函数
                (void       *) 0,
                //传递给任务函数(形参p_arg)的实参
                (OS_PRIO     ) APP_TASK_KEY2_PRIO,
                //任务的优先级
                (CPU_STK    *)&AppTaskKey2Stk[0],
                //任务栈的基地址
                (CPU_STK_SIZE) APP_TASK_KEY2_STK_SIZE / 10,
                //任务栈空间剩下1/10时限制其增长
                (CPU_STK_SIZE) APP_TASK_KEY2_STK_SIZE,
                //任务栈空间(单位:sizeof(CPU_STK))
                (OS_MSG_QTY  ) 5u,
                //任务可接收的最大消息数
                (OS_TICK     ) 0u,
                //任务的时间片节拍数(0表默认值OSCfg_TickRate_Hz/10)
                (void       *) 0,
                //任务扩展(0表不扩展)
                (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
                //任务选项
                (OS_ERR     *)&err);
                //返回错误类型

    OSTaskDel ( & AppTaskStartTCB, & err );
    //删除起始任务本身,该任务不再运行


}


/*
********************************************************************
*                                          KEY1 TASK
*********************************************************************
*/
static  void  AppTaskKey1 ( void * p_arg )
{
    OS_ERR      err;
    OS_SEM_CTR  ctr;
    CPU_SR_ALLOC();
    //使用到临界段(在关/开中断时)时必须用到该宏,该宏声明和定义一个局部变
    //量,用于保存关中断前的 CPU 状态寄存器SR(临界段关中断只需保存SR),开中断时将该值还原。
    uint8_t ucKey1Press = 0;


    (void)p_arg;


    while (DEF_TRUE)
    //任务体
    {
        if ( Key_Scan ( macKEY1_GPIO_PORT, macKEY1_GPIO_PIN, 1, & ucKey1Press ) )
        //如果KEY1被按下
        {
            ctr = OSSemPend ((OS_SEM   *)&SemOfKey, //等待该信号量SemOfKey

                            (OS_TICK   )0,
                            //下面选择不等待,该参无效
                            (OS_OPT    )OS_OPT_PEND_NON_BLOCKING,
                            //如果没信号量可用不等待
                            (CPU_TS   *)0,       //不获取时间戳
                            (OS_ERR   *)&err);     //返回错误类型

            OS_CRITICAL_ENTER();                  //进入临界段

            if ( err == OS_ERR_NONE )
                printf ( "\r\nKEY1被按下:成功申请到停车位,剩下%d个停车位。\r\n", ctr );
            else if ( err == OS_ERR_PEND_WOULD_BLOCK )
                printf ( "\r\nKEY1被按下:不好意思,现在停车场已满,请等待!\r\n" );

            OS_CRITICAL_EXIT();

        }

        OSTimeDlyHMSM ( 0, 0, 0, 20, OS_OPT_TIME_DLY, & err );

    }

}


/*
************************************************************************
*                                          KEY2 TASK
***********************************************************************
*/
static  void  AppTaskKey2 ( void * p_arg )
{
    OS_ERR      err;
    OS_SEM_CTR  ctr;
    CPU_SR_ALLOC();
    //使用到临界段(在关/开中断时)时必须用到该宏,该宏声明和定义一个局部变
    //量,用于保存关中断前的 CPU 状态寄存器SR(临界段关中断只需保存SR)
    //,开中断时将该值还原。
    uint8_t ucKey2Press = 0;


    (void)p_arg;


    while (DEF_TRUE)
    //任务体
    {
        if ( Key_Scan ( macKEY2_GPIO_PORT, macKEY2_GPIO_PIN, 1, & ucKey2Press ) )
        //如果KEY2被按下
        {
            ctr = OSSemPost((OS_SEM  *)&SemOfKey,
                            //发布SemOfKey
                            (OS_OPT   )OS_OPT_POST_ALL,
                            //发布给所有等待任务
                            (OS_ERR  *)&err);
                            //返回错误类型

            OS_CRITICAL_ENTER();
            //进入临界段

            printf ( "\r\nKEY2被按下:释放1个停车位,剩下%d个停车位。\r\n", ctr );

            OS_CRITICAL_EXIT();

        }

        OSTimeDlyHMSM ( 0, 0, 0, 20, OS_OPT_TIME_DLY, & err );
        //每20ms扫描一次

    }

}

别忘了每次修改函数都要在app_cfg.h文件中修改 优先级的宏 和 栈的宏

*********************************************************************************************************
*                                            TASK PRIORITIES
*********************************************************************************************************
*/

#define  APP_TASK_START_PRIO                        2            //任务优先级

#define  APP_TASK_KEY1_PRIO                         3
#define  APP_TASK_KEY2_PRIO                         3


/*
*********************************************************************************************************
*                                            TASK STACK SIZES
*                             Size of the task stacks (# of OS_STK entries)
*********************************************************************************************************
*/

#define  APP_TASK_START_STK_SIZE                    128          //任务堆栈空间(单位:sizeof(CPU_STK))

#define  APP_TASK_KEY1_STK_SIZE                     512 
#define  APP_TASK_KEY2_STK_SIZE                     512 

2、信号量实验现象

将程序编译好,用USB线连接计算机和开发板的USB接口, 用DAP仿真器把配套程序下载到野火STM32开发板, 在计算机上打开串口调试助手。
按下开发板的KEY1按键获取信号量模拟停车,按下KEY2按键释放信号量模拟取车;
在串口调试助手中可以看到运行结果,具体见图
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

YunB西风英

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值