总目录

FreeRTOS学习—“任务”篇
FreeRTOS学习—“消息队列”篇
FreeRTOS学习—“信号量”篇
FreeRTOS学习—“事件组”篇
FreeRTOS学习—“定时器”篇

在“消息队列”篇中,我们曾经埋下一个伏笔,就是说,FreeRTOS中任务见的消息传递及同步,都是通过消息队列,难道通过全局变量不行吗?
答案是可以,不过这样会造成响应不及时,如果用全局变量,只能去轮询,必然会损失一定的时间,才能判断结果

那用信号量行不行啊?
当然行了,只不过,FreeRTOS中信号量的实现,也是通过消息队列做到的

二进制信号量

二值信号量比较直观,类似于红绿灯,创建的时候,默认是红灯的,其他任务都得不到这个信号量的,只有give之后才能变成绿灯,其他任务才能得到信号量,得以运行。(本质上,信号量是用队列实现的)上面是类比,在代码中,创建的时候,初始值是0,give是相当于将计数值设置为1,take后相当于将计数值清0。

demo程序

下面的程序创建了一个二值信号量,例如我们去操作某些硬件,读取I2C之类的,某一时刻,应该是只允许一个任务去操作,无论是读还是写,所以需要用这个信号量去控制一下,并且操作完之后,要及时让出CPU,使得其他任务能够得到信号量。

SemaphoreHandle_t xSemaphore = NULL;// A task that uses the semaphore.
void WriteSomethingTask( void * pvParameters )
{long lValueToSend; /* 该任务会被创建两个实例,所以写入队列的值通过任务入口参数传递 – 这种方式使得每个实例使用不同的值。队列创建时指定其数据单元为long型,所以把入口参数强制转换为数据单元要求的类型 */ lValueToSend = ( long ) pvParameters; for(;;){if( xSemaphore != NULL ){if( xSemaphoreTake(xSemaphore,( TickType_t ) 10 ) == pdTRUE ){printf("tast:%ld get signal ,keep it 2 seconds\n",lValueToSend);{//my workvTaskDelay(2000 / portTICK_PERIOD_MS); }xSemaphoreGive(xSemaphore);taskYIELD(); }else{}}}
}void app_main(void)
{ // Semaphore cannot be used before a call to xSemaphoreCreateBinary().// This is a macro so pass the variable in directly.xSemaphore = xSemaphoreCreateBinary();if( xSemaphore != NULL ){xSemaphoreGive(xSemaphore);xTaskCreate(WriteSomethingTask, "write1", 1000, ( void * ) 1, 1, NULL ); xTaskCreate(WriteSomethingTask, "write2", 1000, ( void * ) 2, 1, NULL ); xTaskCreate(WriteSomethingTask, "write3", 1000, ( void * ) 3, 1, NULL ); }
}

创建二值信号量

SemaphoreHandle_t xSemaphoreCreateBinary( void )
参数 含义
返回值 NULL 表示没有足够的堆空间分配给信号量而导致创建失败。
非 NULL 值表示信号量创建成功。此返回值应当保存下来,以作为操作此信号量的句柄。

二值信号量减一

portBASE_TYPE xSemaphoreTake( xSemaphoreHandle xSemaphore, portTickType xTicksToWait );
参数 含义
xSemaphore 获取得到的信号量,信号量由定义为 xSemaphoreHandle 类型的变量引用。信号量在使用前必须先创建。
xTicksToWait 阻塞超时时间。任务进入阻塞态以等待信号量有效的最长时间。如果 xTicksToWait 为 0,则 xSemaphoreTake()在信号量无效时会立即返回。阻塞时间是以系统心跳周期为单位的,所以绝对时间取决于系统心跳频率。常量 portTICK_RATE_MS 可以用来把心跳时间单位转换为毫秒时间单位。如果把 xTicksToWait 设置为 portMAX_DELAY ,并且在FreeRTOSConig.h 中设定 INCLUDE_vTaskSuspend 为 1,那么阻塞等待将没有超时限制。
返回值 有两个可能的返回值:
1. pdPASS 只有一种情况会返回 pdPASS,那就是成功获得信号量。如果设定了阻塞超时时间(xTicksToWait 非 0),在函数返回之前任务将被转移到阻塞态以等待信号量有效。如果在超时到来前信号量变为有效,亦可被成功获取,返回 pdPASS。
2. pdFALSE 未能获得信号量。如果设定了阻塞超时时间(xTicksToWait 非 0),在函数返回之前任务将被转移到阻塞态以等待信号量有效。但直到超时信号量也没有变为有效,所以不会获得信号量,返回 pdFALSE。

下面函数专门用于中断下的信号量获取

portBASE_TYPE xSemaphoreGiveFromISR( xSemaphoreHandle xSemaphore, portBASE_TYPE *pxHigherPriorityTaskWoken );
参数 含义
xSemaphore 给出的信号量,信号量由定义为 xSemaphoreHandle 类型的变量引用。信号量在使用前必须先创建。
pxHigherPriorityTaskWoken 对某个信号量而言,可能有不止一个任务处于阻塞态在等待其有效。调用 xSemaphoreGiveFromISR()会让信号量变为有效,所以会让其中一个等待任务切出阻塞态。如果调用 xSemaphoreGiveFromISR()使得一个任务解除阻塞,并且这个任务的优先级高于当前任务(也就是被中断的任务),那么 xSemaphoreGiveFromISR()会在函数内部将 *pxHigherPriorityTaskWoken 设 为pdTRUE。如 果 xSemaphoreGiveFromISR() 将此值设为pdTRUE,则在中断退出前应当进行一次上下文切换。这样才能保证中断直接返回到就绪态任务中优先级最高的任务中。
返回值 有两个可能的返回值:
1. pdPASS xSemaphoreGiveFromISR()调用成功。
2. pdFAIL 如果信号量已经有效,无法给出,则返回 pdFAIL。

二值信号量加一

void xSemaphoreGive( SemaphoreHandle_t xSemaphore )
参数 含义
xSemaphore 目标信号量的句柄。这个句柄即是调用 xSemaphoreCreateBinary()创建该信号量时的返回值。

多值信号量

在中断不频繁的系统中,使用二值信号量没有问题,但是中断频繁发生时,则会有中断丢失的问题。因为中断发生时延迟任务执行,延迟任务执行的过程中,如果又来了两次中断,则只会处理第一次,第二次将会丢失。为此引入多值信号量来处理这个问题。

demo

这个demo模拟的是两个任务增加信号量,一个任务处理信号,就类似于接受多个消息,处理多次,然后不丢失记录。

SemaphoreHandle_t xSemaphore = NULL;// A task that uses the semaphore.
void WriteSomethingTask1( void * pvParameters )
{int countme=0;for(;;){printf("write1 %d\n",countme++);xSemaphoreGive(xSemaphore);vTaskDelay(1000 / portTICK_PERIOD_MS); taskYIELD(); }
}
// A task that uses the semaphore.
void WriteSomethingTask2( void * pvParameters )
{int countme=0;for(;;){printf("write2 %d\n",countme++);xSemaphoreGive(xSemaphore);vTaskDelay(1000 / portTICK_PERIOD_MS); taskYIELD(); }
}// A task that uses the semaphore.
void ReadSomethingTask( void * pvParameters )
{int countme=0;for(;;){if(xSemaphoreTake(xSemaphore,( TickType_t ) 0 ) == pdTRUE ){printf("read %d\n",countme++);}else{}vTaskDelay(10 / portTICK_PERIOD_MS); taskYIELD(); }
}void app_main(void)
{ xSemaphore = xSemaphoreCreateCounting( 10, 0 );if( xSemaphore != NULL ){xTaskCreate(WriteSomethingTask1, "write1", 1000, NULL, 1, NULL ); xTaskCreate(WriteSomethingTask2, "write2", 1000, NULL, 1, NULL ); xTaskCreate(ReadSomethingTask, "read", 1000, NULL, 1, NULL ); }
}

多值信号量创建

SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t uxMaxCount, UBaseType_t uxInitialCount )
参数 含义
uxMaxCount 多值信号量最大值。
uxInitialCount 多值信号量初始值。
返回值 NULL 表示没有足够的堆空间分配给信号量而导致创建失败。
非 NULL 值表示信号量创建成功。此返回值应当保存下来,以作为操作此信号量的句柄。

其他操作与二值信号量函数一样。

互斥信号量

互斥量是一种特殊的二值信号量,用于控制在两个或多个任务间访问共享资源。单词MUTEX(互斥量)源于”MUTual EXclusion”。
在用于互斥的场合,互斥量从概念上可看作是与共享资源关联的令牌。一个任务想要合法地访问资源,其必须先成功地得到(Take)该资源对应的令牌(成为令牌持有者)。当令牌持有者完成资源使用,其必须马上归还(Give)令牌。只有归还了令牌,其它任务才可能成功持有,也才可能安全地访问该共享资源。一个任务除非持有了令牌,否则不允许访问共享资源。

如果某资源同时只准一个任务访问,可以用互斥量保护这个资源。这个资源一定是存在的,所以创建互斥量时会先释放一个互斥量,表示这个资源可以使用。任务想访问资源时,先获取互斥量,等使用完资源后,再释放它。也就是说互斥量一旦创建好后,要先获取,后释放,要在同一个任务中获取和释放。这也是互斥量和二进制信号量的一个重要区别,二进制信号量可以在随便一个任务中获取或释放,然后也可以在任意一个任务中释放或获取。互斥量不同于二进制信号量的还有:互斥量具有优先级继承机制,二进制信号量没有,互斥量不可以用于中断服务程序,二进制信号量可以。

简单说就是谁用谁释放。

demo

两个写任务,只有一个能写临界资源,所以用互斥信号量来控制。自己抢自己释放,这就是互斥。

SemaphoreHandle_t xSemaphore = NULL;void WriteSomethingTask1( void * pvParameters )
{for(;;){xSemaphoreTake(xSemaphore,portMAX_DELAY);printf("WriteSomethingTask1 work\n");xSemaphoreGive(xSemaphore);vTaskDelay(1000 / portTICK_PERIOD_MS); }}
void WriteSomethingTask2( void * pvParameters )
{for(;;){xSemaphoreTake(xSemaphore,portMAX_DELAY);printf("WriteSomethingTask2 work\n");xSemaphoreGive(xSemaphore);vTaskDelay(1000 / portTICK_PERIOD_MS); }}void app_main(void)
{ xSemaphore = xSemaphoreCreateMutex();if( xSemaphore != NULL ){xSemaphoreGive(xSemaphore);xTaskCreate(WriteSomethingTask1, "write1", 1000, NULL, 1, NULL ); xTaskCreate(WriteSomethingTask2, "write2", 1000, NULL, 1, NULL ); }
}

互斥信号量创建

SemaphoreHandle_t xSemaphoreCreateMutex( void )
参数 含义
返回值 NULL 表示没有足够的堆空间分配给信号量而导致创建失败。
非 NULL 值表示信号量创建成功。此返回值应当保存下来,以作为操作此信号量的句柄。

异常错误

在某次测试中,发现这个看门狗的报错,随机出现了程序重启,这个是因为有任务一直在运行,导致看门狗没有喂养,所以要保证每个任务,都有适当的休息时间。

结束语

闻听后面的小区有人坠楼身亡了,真是挺惋惜的,大过年的,现场也没有个家人,感觉像是意外,有人说是抑郁症,抑郁症这个名字听起来总感觉很轻微,为啥不叫病呢,起码能让人重视起来啊。哎,前几天的腾讯员工,也是如此。

轻度抑郁症长期表现为有情绪低落、不合群、离群、躯体不适、食欲不振及睡眠障碍。
自我缓解方法有:
平时多学习技术 坚持锻炼、努力多外出交际:
多观察多了解、平时整理好自己的想法写出来、多阅读书籍。

看见没,多学习技术,放在第一行了。老师我一直让你们多学习,是在帮你们远离疾病,那你们多学习,就是在自救。

FreeRTOS学习—“任务”篇
FreeRTOS学习—“消息队列”篇
FreeRTOS学习—“信号量”篇
FreeRTOS学习—“事件组”篇
FreeRTOS学习—“定时器”篇

FreeRTOS学习---“信号量”篇相关推荐

  1. freeRtos学习笔记 (7)信号量

    freeRtos学习笔记 freeRtos信号量 信号量种类 信号量分为四种:二值信号量,互斥信号量,计数信号量和递归互斥信号量,其中计数信号量用于管理系统多个共享资源,用计数值表示可用资源数目;二值 ...

  2. FreeRTOS学习笔记——互斥型信号量

    来自:http://blog.csdn.net/xukai871105/article/details/43456985 0.前言 在嵌入式操作系统中互斥型信号量是任务间资源保护的重要手段.下面结合一 ...

  3. FreeRtos学习笔记(11)查找就绪任务中优先级最高任务原理刨析

    FreeRtos学习笔记(11)查找就绪任务中优先级最高任务原理刨析 怎么查找就绪任务中优先级最高的? tasks.c中声明了一个全局变量 uxTopReadyPriority,任务从其他状态进入就绪 ...

  4. freeRtos学习笔记 (8) 任务通知

    freeRtos学习笔记 freeRtos任务通知 任务通知的优缺点 freeRtos任务控制块中包含两个32位的变量,用于任务通知,在一些情况下,任务通知可以替代信号量和事件组,并且比信号量和事件组 ...

  5. freeRtos学习笔记 (5)事件组

    freeRtos学习笔记 freeRtos事件组 为什么要用事件组? 多任务环境下, 任务.中断之间往往需要同步操作,一个事件发生会告知等待中的任 务,即形成一个任务与任务.中断与任务间的同步.事件可 ...

  6. freeRtos学习笔(4)消息队列

    freeRtos学习笔记 freeRtos消息队列 为什么要用消息队列 消息队列可以在任务与任务间,中断与任务间传递信息.为什么不用全局数组?全局数组也可以传递信息,但是和消息队列相比,消息队列有一下 ...

  7. freeRtos学习笔(2)任务管理

    freeRtos学习笔记 freeRtos任务管理 freeRtos任务状态 freeRtos中任务有四种状态:就绪态.运行态.杜塞态.挂起态. 图 16-1(1): 创建任务→就绪态(Ready): ...

  8. freeRtos学习笔(1)内核剪裁

    freeRtos学习笔记 freeRtos内核剪裁 #define configCPU_CLOCK_HZ 系统主频 #define configTICK_RATE_HZ 时钟节拍 #define co ...

  9. FreeRTOS学习笔记

    FreeRTOS学习笔记 (这是我自己学习FreeRTOS整理的笔记,仅供参考) 第一部分:实现FreeRTOS内核 变量名: 定义变量时往往会把变量的类型当作前缀加在变量上 变量类型 前缀 char ...

最新文章

  1. linux中cooy命令_Linux复制指令
  2. 最强的windows2003安全设置
  3. [待总结]高频率vim命令
  4. Oracle数据库执行exp命令--报参数'log' 不允许有多个值
  5. Ubuntu20.4安装及配置mysql详细教程
  6. mysql sql组合_详解mysql 组合查询
  7. settimeout需要清除吗_前端20个真正灵魂拷问,前端初级到中级你还需要这个!
  8. ZZULIOJ 1059:最高分
  9. Spring Boot项目CentOS域名的绑定
  10. (转)Arcgis for JS实现台风运动路径与影像范围的显示
  11. Spring : Spring Aop 创建代理
  12. 我遇见的网络故障分析报告
  13. Servlet获取全路径
  14. 开关量模块——一对多无线传输
  15. 如何找到最新的RFC文档
  16. LeetCode--441--排列硬币
  17. 金龄会为中老年群体搭建展现风采的舞台
  18. 一对一培训之视频免费分享-2018-03-19-第 04 阶段-部署-基础-环境
  19. 技术点:vue3 使用 ref 绑定 router-view,想调取某个子路由中的方法来重载数据
  20. python--关于requests库的使用(一)

热门文章

  1. 小米手机MIUI系统稳定版蓝牙无法使用AAC格式编码
  2. keycode对照表 空格 回车 F1234567890 等键代码
  3. 架构师接龙:盛大许式伟 VS 金山张宴
  4. python爬虫——全书网
  5. 移动端touch-zepto事件
  6. android touch
  7. 值得收藏一生的电影经典台词
  8. 京北商城惊艳上线,领跑互联网金融垂直电商
  9. linux系统环境变量及用户环境变量的配置
  10. Spring Boot使用JSR303校验