一、基础概念
一般使用二值信号量,这边先不对计数信号量做讨论
二值信号量的运行机制
最开始创建一个信号量的时候,系统会将其置0,即无效信号量,任务接收到这个无效信号量的时候会进入阻塞态;
之后在中断或者任务中释放有效信号量,任务接收到该有效信号量的时候会进入就绪态,从而达到唤醒任务的目的
二、创建、释放、接收信号量
1、创建信号量函数:
OSSemCreate (OS_SEM *p_sem, //信号量控制块指针
CPU_CHAR *p_name, //信号量名称
OS_SEM_CTR cnt, //资源数目或事件是否发生标志
OS_ERR *p_err) //返回错误类型
创建信号量之前需要先定义错误类型和信号量控制块,下面是具体创建过程
OS_ERR err; //错误类型
OS_SEM my_sem; //信号量控制块
OSSemCreate((OS_SEM*)&my_sem,
(CPU_CHAR*)"my_sem",
(OS_SEM_CTR)0,
(OS_ERR*)&err);
2、释放信号量函数:
OSSemPost (OS_SEM *p_sem, //信号量控制块指针
OS_OPT opt, //选项
OS_ERR *p_err) //返回错误类型
选项可选择释放给单个任务或者所有任务:
#define OS_OPT_POST_1 (OS_OPT)(0x0000u) /* Post message to highest priority task waiting */
#define OS_OPT_POST_ALL (OS_OPT)(0x0200u) /* Broadcast message to ALL tasks waiting
下面是具体释放过程:
OSSemPost(&my_sem,OS_OPT_POST_1,&err);
3、获取信号量函数:
OSSemPend (OS_SEM *p_sem, //信号量指针
OS_TICK timeout, //等待超时时间
OS_OPT opt, //选项
CPU_TS *p_ts, //等到信号量时的时间戳
OS_ERR *p_err) //返回错误类型
选项有两个,分别是等待不到对象进行阻塞和不进行阻塞
#define OS_OPT_PEND_BLOCKING (OS_OPT)(0x0000u)//阻塞
#define OS_OPT_PEND_NON_BLOCKING (OS_OPT)(0x8000u)//不阻塞
下面是具体获取过程
OSSemPend(&my_sem,4,OS_OPT_PEND_BLOCKING,NULL,&err);
三、进行实验
1、实验目的:key控制led的亮灭
2、实验过程:
必要的初始化:
void BSP_Init (void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置优先级分组
delay_init(168);//配置时钟
GPIO_Config(GPIOF,GPIO_Pin_9,GPIO_Mode_OUT,GPIO_OType_PP,GPIO_PuPd_NOPULL);
KEY0_Init();
}
main.c:
int main(void)
{
OS_ERR err;
CPU_SR_ALLOC();
BSP_Init();
OSInit(&err); //初始化UCOSIII
OS_CRITICAL_ENTER(); //进入临界区
create_star_task(10);
OS_CRITICAL_EXIT(); //退出临界区
OSStart(&err);
while(1);
}
起始任务:
static void star_task(void *p_arg)
{
OS_ERR err;
p_arg = p_arg;//防止编译器报警
CPU_SR_ALLOC();
CPU_Init();//cpu初始化
OS_CRITICAL_ENTER(); //进入临界区
/* 创建任务区 */
creat_led_task(5);
creat_key_task(4);
OS_CRITICAL_EXIT(); //退出临界区
OS_TaskSuspend((OS_TCB*)&StarTaskTCB,&err); //挂起开始任务
}
key_task:
static OS_ERR err; //错误类型
OS_SEM key_sem; //信号量控制块
void key_task(void *p_arg)
{
OSSemCreate((OS_SEM*)&key_sem,(CPU_CHAR*)"key_sem",(OS_SEM_CTR)0,(OS_ERR*)&err);//创建信号量
for(;;)
{
if(Key_Scan()==RESET)
{
OSSemPost(&key_sem,OS_OPT_POST_1,&err);//释放信号量
}
delay_ms(4);
}
}
led_task:
static void led_task(void *p_arg)
{
for(;;)
{
OSSemPend(&key_sem,4,OS_OPT_PEND_BLOCKING,NULL,&err);
if(err==OS_ERR_NONE)
{
GPIO_ToggleBits(GPIOF,GPIO_Pin_9);
}
}
}
3、遇到问题:
出现一堆报错:
解决方法:将创建信号量函数放在任务函数里解决
出现另一个报错:
解决方法:将err定义static解决
key_task进不去:
将led_task的优先级和key_task的优先级设置成一样的了,一直在led_task中出不去,将key_task的优先级改高就解决了