7、uCOS-Ⅱ 信号量

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

时间: 2024-10-27 08:59:43

7、uCOS-Ⅱ 信号量的相关文章

ucos信号量集源码分析

在实际的应用之中,一个任务经常需要等待多个信号量的同时生效,或者说任务需要根据多个信号量的组合作用的结果来决定任务的运行方式,为了实现这种多信号量组合的功能,ucos实现了信号量集的特殊结构. 信号量集的基础仍然是信号量,它如同一个多个信号量组成的与非门来构成逻辑结果控制任务的执行. 信号量在ucos的实现分为两个部分,第一部分叫做标志组,其中存放了信号量集中的所有信号,第二个叫做等待任务链表,链表中的每个节点对应一个正在等待信号量集的等待任务,信号量集根据这个链表来管理等待任务 不同于消息队列

UCOS 信号量

5 OS_EVENT * Sem;//声明一个信号量 6 7 OS_STK xdata Task1Stack[CPU_MAX_STK_SIZE]; 8 OS_STK xdata Task2Stack[CPU_MAX_STK_SIZE]; 9 10 void Task1(void xdata * ppdata) reentrant 11 { 12 ppdata = ppdata; 13 while(1) 14 { 15 OSTimeDlyHMSM(0, 0, 2, 0); 16 printf("\

ucos实时操作系统学习笔记——任务间通信(信号量)

ucos实时操作系统的任务间通信有好多种,本人主要学习了sem, mutex, queue, messagebox这四种.系统内核代码中,这几种任务间通信机制的实现机制相似,接下来记录一下本人对核心代码的学习心得,供以后回来看看,不过比较遗憾的是没有仔细学习扩展代码的功能实现部分.ucos操作系统的内核代码实现相对简单,但是对理解其他操作系统内核相同功能有帮助. ucos的任务间通信机制主要是基于event实现的,其实理解这个event不用翻译成中文事件,就叫event感觉还更容易接收.下面是操

ucos事件邮箱信号量队列详解

Ucos的事件分为时钟,信号量,互斥性信号量,消息队列,以及消息邮箱 首先说信号量 信号量在ucos中的类型定义为OS_EVENT_TYPE_SEM,在任务控制块ecb中,主要是用到的是信号量计数器OSEventCnt,当有任务申请信号量的时候,如果信号量OSEventCnt的值大于0,则将OSEventCnt-1是任务继续运行,如果OSEventCnt已经为0,那么任务将会被挂到任务等代表中,当别的任务发送信号量的时候,被挂起的任务得到信号量,并设置为ready准备进行下一次调度,如果这时候任

ucos互斥信号量解决优先级反转问题

在可剥夺性的内核中,当任务以独占方式使用共享资源的时候,会出现低优先级任务高于高优先级任务运行的情况,这种情况叫做优先级反转,对于实时操作系统而言,这是一场灾难,下面我们来说说优先级反转的典型环境. 我们假设有三个任务a,b,c,a优先级高于b,b优先级高于c,a和c都需要访问一个共享资源s,保护该资源的信号量为互斥信号量, 假设当前任务c申请了信号量访问s,还没有释放,此时任务a开始运行,那么a就会剥夺c的运行而运行a,当a去访问资源s的时候,因为得不到信号量,所以必须释放以等待信号量,任务c

ucos实时操作系统学习笔记——任务间通信(互斥锁)

想讲一下ucos任务间通信中的mutex,感觉其设计挺巧妙,同sem一样使用的是event机制实现的,代码不每一行都分析,因为讲的没邵贝贝老师清楚,主要讲一下mutex的内核是如何实现的.可以理解互斥锁是设置信号量值为1时候的特殊情况,与之不同的地方是互斥锁为了避免优先级反转采用了优先级继承机制,本文主要讲一下互斥锁的创建,pend和post,对应的函数是OSMutexCreate,OSMutexPend,OSMutexPost,当然讲函数也不会所有的扩展功能都讲,只是讲一下主干部分,下面贴出来

ucos任务控制块详解

Ucos实现多任务的基础包括几个方面:任务控制块,任务堆栈,中断,任务优先级,一一说起 首先,任务控制块的结构如下 //系统在运行一个任务的时候,按照任务的优先级获取任务控制块,再在任务堆栈中获得任务代码指针 typedef struct os_tcb {//任务控制块 OS_STK          *OSTCBStkPtr;           /*指向任务堆栈栈顶的指针*/ #if OS_TASK_CREATE_EXT_EN > 0u void            *OSTCBExtPt

ucos系统初始化及启动过程

之前在ucos多任务切换中漏掉了一个变量, OSCtxSwCtr标识系统任务切换次数 主要应该还是用在调试功能中 Ucos系统初始化函数为OSInit(),主要完成以下功能 全局变量初始化 就绪任务表初始化 空任务控制块初始化 事件控制块链表初始化 信号量集初始化 存储器管理初始化 Qs队列控制初始化 系统空闲任务初始化 系统统计任务初始化 部分功能需要依靠宏定义打开另外要注意一个变量OSTaskCtr标识系统全部任务数,在初始化完成之后就可以创建任务了,创建任务完成之后启动系统使用OSStar

ucos队列的实现--源码分析

之前说到事件,讲了事件,信号量和互斥信号量,还有一个队列没说,今天说说队列. 队列是用在任务之间传送多个消息的时候,a任务发送消息,b任务发送消息,然后c任务可以依次去提取出b和a传递的消息,不会造成系统的阻塞,他的实现结构如下 在队列的实现中,也是使用事件ecb,OSEventType为OS_EVENT_TYPE_Q类型,而其OSEventPtr指向一个QS_Q结构的指针,该结构的定义如下 typedef struct os_q {                   /* QUEUE CON

uCos的多任务实现

uCos的多任务实现 作为操作系统(OS),最基本的一项服务就是提供多线程,在实时操作系统uCos里,多线程被称为多任务(Task).多任务并不是CPU能真正同时运行多个程序,实际是靠CPU在多个任务之间转换切换实现的,CPU轮番的服务于一系列的任务,这样CPU在宏观上好像在同时执行多个任务,实际在微观上CPU绝对是“单任务”的.这里要注意区别多线程和多核,如果系统里是有多个CPU,则可以实现真正的多线程了. 按照上面的思路,多任务的实现,就是要实现CPU在不同的任务之间切换.按照uCos作者的