1、“信号量”为操作系统用于处理临界区问题和实现进程间同步提供了一种有效的机制。
在很多操作系统原理书中都提到了信号量的概念,常用P操作与V操作来表明信号量的行为。
PV操作的伪代码如下:
设s为一整数型变量: P操作:while( s==0); s--;
V操作:s++
2、例程代码

1 /*****************************************************************************************************************************
2 *
3 * 文件名称:main.c
4 * 文件功能:主函数
5 * 文件说明:无
6 *
7 *****************************************************************************************************************************/
8 /**********************************************************
9 *
10 * 头文件声明
11 *
12 **********************************************************/
13
14 #include "pbdata.h"
15
16
17
18
19
20
21 /**********************************************************
22 *
23 * 调用函数声明
24 *
25 **********************************************************/
26 void RCC_Configuration(void);//时钟配置函数
27
28 void start_task(void *pdata);//开始任务函数
29
30
31
32
33
34 /**********************************************************
35 *
36 * 主函数
37 *
38 **********************************************************/
39 int main(void)
40 {
41 Delay_Init();//延时函数初始化
42
43 RCC_Configuration();//时钟配置
44
45 LED_GPIO();//LED的GPIO引脚配置
46
47 KEY_GPIO();//KEY的GPIO引脚配置
48
49
50 /*操作系统的处理*/
51 OSInit();//初始化UCOS操作系统
52 led1_SEM=OSSemCreate(0);//建立LED1的信号量
53 OSTaskCreate(
54 start_task, //指向任务代码的指针
55 (void *)0, //任务开始执行时,传递给任务参数的指针
56 (OS_STK *) & START_TASK_STK[START_STK_SIZE-1],//分配给任务堆栈的栈顶指针
57 START_TASK_PRIO//分配给任务的优先级
58 );
59 OSStart();//启动OS操作系统
60
61
62
63
64 }
65
66
67
68 /**********************************************************
69 *
70 * 函数名称:RCC_Configuration(void)
71 * 函数功能:时钟配置
72 * 输入参数:无
73 * 输出参数:无
74 * 函数说明:无
75 *
76 **********************************************************/
77 void RCC_Configuration(void)
78 {
79 SystemInit();//系统初始化
80
81 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//LED1对应GPIO时钟使能
82
83 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);//按键对应GPIO时钟使能
84 }
85
86
87
88
89
90
91 /**********************************************************
92 *
93 * 函数名称:start_task(void *pdata)
94 * 函数功能:开始任务
95 * 输入参数:*pdata
96 * 输出参数:无
97 * 函数说明:无
98 *
99 **********************************************************/
100 void start_task(void *pdata)
101 {
102 OS_CPU_SR cpu_sr=0;
103
104 pdata=pdata;//防止编译器报错
105
106 OSStatInit();//初始化统计任务
107
108 OS_ENTER_CRITICAL();//进入临界区,中断无法打断
109
110 /*创建任务*/
111 /*LED1任务*/
112 OSTaskCreate(
113 led1_task, //指向任务代码的指针
114 (void *)0, //任务开始执行时,传递给任务参数的指针
115 (OS_STK *) & LED1_TASK_STK[LED1_STK_SIZE-1],//分配给任务堆栈的栈顶指针
116 LED1_TASK_PRIO//分配给任务的优先级
117 );
118
119 /*key任务*/
120 OSTaskCreate(
121 key_task, //指向任务代码的指针
122 (void *)0, //任务开始执行时,传递给任务参数的指针
123 (OS_STK *) & KEY_TASK_STK[KEY_STK_SIZE-1],//分配给任务堆栈的栈顶指针
124 KEY_TASK_PRIO//分配给任务的优先级
125 );
126
127 OSTaskSuspend(START_TASK_PRIO);//挂起开始任务
128
129 OS_EXIT_CRITICAL();//退出临界区,可以被中断打断
130
131 }

1 /*****************************************************************************************************************************
2 *
3 * 文件名称:pbdata.c
4 * 文件功能:自定义函数
5 * 文件说明:无
6 *
7 *****************************************************************************************************************************/
8
9
10
11 #include "pbdata.h"
12
13 u8 dt=0;
14 static u8 fac_us=0;//us延时倍乘数
15 static u16 fac_ms=0;//ms延时倍乘数
16
17 OS_EVENT* led1_SEM;
18
19 /**********************************************************
20 *
21 * 函数名称:Delay_Init(void)
22 * 函数功能:初始化延时函数
23 * 输入参数:无
24 * 输出参数:无
25 * 函数说明:当使用ucos的时候,此函数会初始化ucos的时钟节拍
26 * SYSTICK的时钟固定为HCLK时钟的1/8
27 * SYSCLK:系统时钟
28 *
29 **********************************************************/
30 void Delay_Init(void)
31 {
32 u32 reload;
33 SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //选择外部时钟,HCLK/8
34 fac_us=SystemCoreClock/8000000; //为系统时钟的1/8
35
36 reload=SystemCoreClock/8000000; //每秒钟的计数次数,单位为K
37 reload*=1000000/OS_TICKS_PER_SEC;//根据OS_TICKS_PER_SEC设定溢出事件,reload为24位寄存器,最大值:16777216,在72M下,约合1.86s左右
38
39 fac_ms=1000/OS_TICKS_PER_SEC;// 代表ucos可以延时的最少单位
40 SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk; //开启SYSTICK中断
41 SysTick->LOAD=reload; //每1/OS_TICKS_PER_SEC秒中断一次
42 SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启SYSTICK
43 }
44
45
46
47
48
49 /**********************************************************
50 *
51 * 函数名称:delay_us(u32 nus)
52 * 函数功能:延时微秒子程序
53 * 输入参数:nus, 延时微秒数
54 * 输出参数:无
55 * 函数说明:无
56 *
57 **********************************************************/
58 void delay_us(u32 nus)
59 {
60 u32 ticks;
61 u32 told,tnow,tcnt=0;
62 u32 reload=SysTick->LOAD; //LOAD的值
63 ticks=nus*fac_us; //需要的节拍数
64 tcnt=0;
65 told=SysTick->VAL; //刚进入时的计数器值
66 while(1)
67 {
68 tnow=SysTick->VAL;
69 if(tnow!=told)
70 {
71 if(tnow<told)tcnt+=told-tnow;//这里注意一下SYSTICK是一个递减的计数器就可以了
72 else tcnt+=reload-tnow+told;
73 told=tnow;
74 if(tcnt>=ticks)break;//时间超过/等于要延时的事件,则退出
75 }
76 };
77 }
78
79
80
81
82
83
84 /**********************************************************
85 *
86 * 函数名称:delay_ms(u16 nms)
87 * 函数功能:延时毫秒子程序
88 * 输入参数:nms, 延时微秒数
89 * 输出参数:无
90 * 函数说明:无
91 *
92 **********************************************************/
93 void delay_ms(u16 nms)
94 {
95 if(OSRunning==TRUE)//如果os已经在跑了
96 {
97 if(nms>=fac_ms)//延时的事件大于ucos的最少时间周期
98 {
99 OSTimeDly(nms/fac_ms);//ucos延时
100 }
101 nms%=fac_ms; //ucos已经无法提供这么小的延时了,采用普通方式延时
102 }
103 delay_us((u32)(nms*1000)); //普通方式延时,此时ucos无法启动调度
104 }
105
106
107
108
109 /**********************************************************
110 *
111 * 函数名称:delay(u32 nCount)
112 * 函数功能:普通不精确延时
113 * 输入参数:nCount, 延时时间长短
114 * 输出参数:无
115 * 函数说明:无
116 *
117 **********************************************************/
118 void delay(u32 nCount)
119 {
120 for(;nCount!=0;nCount--);
121 }

1 /***************************************************************************************************************************** 2 * 3 * 文件名称:pbdata.h 4 * 文件功能:自定义函数的头文件声明 5 * 文件说明:无 6 * 7 *****************************************************************************************************************************/ 8 9 10 #ifndef _pbdata_H 11 #define _pbdata_H 12 13 14 15 16 17 18 /********************************************************** 19 * 20 * 需要引入的头文件 21 * 22 **********************************************************/ 23 #include "stm32f10x.h" 24 #include "includes.h" 25 #include "misc.h" 26 27 #include "led.h"//LED相关头文件 28 #include "key.h"//key相关头文件 29 30 31 /********************************************************** 32 * 33 * 任务相关设置 34 * 35 **********************************************************/ 36 /*开始任务*/ 37 #define START_TASK_PRIO 9 //设置任务优先级 38 #define START_STK_SIZE 64 //空间大小=64*4(字节) 39 static OS_STK START_TASK_STK[START_STK_SIZE];//创建任务堆栈空间 40 41 42 /*LED1任务*/ 43 #define LED1_TASK_PRIO 6 //设置任务优先级 44 #define LED1_STK_SIZE 64 //空间大小=64*4(字节) 45 static OS_STK LED1_TASK_STK[LED1_STK_SIZE];//创建任务堆栈空间 46 47 48 /*key任务*/ 49 #define KEY_TASK_PRIO 5 //设置任务优先级 50 #define KEY_STK_SIZE 64 //空间大小=64*4(字节) 51 static OS_STK KEY_TASK_STK[KEY_STK_SIZE];//创建任务堆栈空间 52 53 54 55 56 57 /********************************************************** 58 * 59 * 外部变量声明 60 * 61 **********************************************************/ 62 extern OS_EVENT* led1_SEM; 63 64 65 66 /********************************************************** 67 * 68 * 子函数程序声明 69 * 70 **********************************************************/ 71 void delay(u32 nCount);//普通不精确延时 72 void Delay_Init(void);//延时函数初始化 73 void delay_us(u32 nus);//微秒延时 74 void delay_ms(u16 nms);//毫秒延时 75 76 77 78 79 #endif

1 /*****************************************************************************************************************************
2 *
3 * 文件名称:led.c
4 * 文件功能:led相关函数
5 * 文件说明:无
6 *
7 *****************************************************************************************************************************/
8
9
10
11
12 #include "pbdata.h"
13
14
15
16 /**********************************************************
17 *
18 * 函数名称:LED_GPIO(void)
19 * 函数功能:LED的GPIO配置
20 * 输入参数:无
21 * 输出参数:无
22 * 函数说明:无
23 *
24 **********************************************************/
25
26 void LED_GPIO(void)//GPIO初始化函数
27 {
28 GPIO_InitTypeDef GPIO_InitStructure;//定义一个GPIO设置的结构体变量
29
30 /*LED1配置*/
31 /*结构体变量赋值*/
32 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;////引脚配置
33 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;//配置频率
34 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//推挽输出
35 /*对应的GPIO初始化*/
36 GPIO_Init(GPIOB,&GPIO_InitStructure);
37 }
38
39
40
41
42
43
44
45 /**********************************************************
46 *
47 * 函数名称:led1_task(void *pdata)
48 * 函数功能:led1任务处理函数
49 * 输入参数:*pdata
50 * 输出参数:无
51 * 函数说明:无
52 *
53 **********************************************************/
54
55 void led1_task(void *pdata)
56 {
57 INT8U err;
58
59 pdata=pdata;//防止编译器报错
60
61 while(1)
62 {
63
64 OSSemPend(led1_SEM,0,&err);//等待LED1的信号量
65
66 GPIO_SetBits(GPIOB,GPIO_Pin_5);//指定端口设置为高电平
67
68 delay_ms(1000);//1s,delay,公共函数库中自己定义
69
70 GPIO_ResetBits(GPIOB,GPIO_Pin_5);//指定端口设置低电平
71
72 delay_ms(1000);//1s,delay,公共函数库中自己定义
73
74 }
75 }

1 /***************************************************************************************************************************** 2 * 3 * 文件名称:led.h 4 * 文件功能:led相关函数的头文件 5 * 文件说明:无 6 * 7 *****************************************************************************************************************************/ 8 9 10 #ifndef _LED_H 11 #define _LED_H 12 13 #include "pbdata.h" 14 15 16 void LED_GPIO(void);//LED的GIPO引脚配置 17 18 void led1_task(void *pdata);//LED1任务 19 20 21 22 23 #endif

1 /*****************************************************************************************************************************
2 *
3 * 文件名称:key.c
4 * 文件功能:按键处理函数头文件
5 * 文件说明:无
6 *
7 *****************************************************************************************************************************/
8
9 #include "pbdata.h"
10
11
12
13
14
15 /**********************************************************
16 *
17 * 函数名称:KEY_GPIO(void)
18 * 函数功能:KEY的GPIO配置
19 * 输入参数:无
20 * 输出参数:无
21 * 函数说明:无
22 *
23 **********************************************************/
24 void KEY_GPIO(void)//GPIO初始化函数
25 {
26 GPIO_InitTypeDef GPIO_InitStructure;//定义一个GPIO设置的结构体变量
27
28 /*key配置*/
29 /*结构体变量赋值*/
30 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;////引脚配置
31 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;//配置频率
32 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;//上拉输入
33 /*对应的GPIO初始化*/
34 GPIO_Init(GPIOC,&GPIO_InitStructure);
35
36 }
37
38
39
40 /**********************************************************
41 *
42 * 函数名称:key_task(void *pdata)
43 * 函数功能:key任务处理函数
44 * 输入参数:*pdata
45 * 输出参数:无
46 * 函数说明: 不断查询4个按键,当查询到某个按键时,
47 *
48 **********************************************************/
49 void key_task(void *pdata)
50 {
51 pdata=pdata;//防止编译器报错
52
53 while(1)
54 {
55 /*k1按下*/
56 if(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_5)==Bit_RESET)//如果按键K1按下
57 {
58 delay_ms(20);//延时消抖
59 if(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_5)==Bit_RESET)//如果按键K1确实按下
60 {
61 OSSemPost(led1_SEM);//发送led1信号量
62 }
63 }
64 delay_ms(100);
65 }
66 }

1 /***************************************************************************************************************************** 2 * 3 * 文件名称:key.h 4 * 文件功能:按键处理函数头文件 5 * 文件说明:无 6 * 7 *****************************************************************************************************************************/ 8 9 10 #ifndef _KEY_H 11 #define _KEY_H 12 13 #include "pbdata.h" 14 15 16 17 void KEY_GPIO(void);//key的GPIO初始化 18 19 void key_task(void *pdata);//key的任务处理函数 20 21 22 #endif
3、例程工程下载:
http://download.csdn.net/detail/a1181803348/8832369
来源:https://www.cnblogs.com/STM32bo/p/4596287.html
