Bootstrap

UCOS-III笔记2-信号量

一、基础概念

一般使用二值信号量,这边先不对计数信号量做讨论

二值信号量的运行机制

 最开始创建一个信号量的时候,系统会将其置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的优先级改高就解决了

;