写在前面:
由于时间的不足与学习的碎片化,写博客变得有些奢侈。
但是对于记录学习(忘了以后能快速复习)的渴望一天天变得强烈。
既然如此
不如以天为单位,以时间为顺序,仅仅将博客当做一个知识学习的目录,记录笔者认为最通俗、最有帮助的资料,并尽量总结几句话指明本质,以便于日后搜索起来更加容易。
标题的结构如下:“类型”:“知识点”——“简短的解释”
部分内容由于保密协议无法上传。
点击此处进入学习日记的总目录
2024.04.04:UCOSIII第三十二节:计数信号量实验
- 四十六、UCOSIII:计数信号量实验
- 1、实验设计
- 2、信号量实验现象
四十六、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按键释放信号量模拟取车;
在串口调试助手中可以看到运行结果,具体见图