Free RTOS的计数型信号量

上篇讲解了二值信号量,二值信号量只能判断有无,而不能确定事件发生的次数,因此我们为了确定事件的次数引入了计数型信号量!
使用计数型信号量时,需要在freertosconfig.h中加入一行配置代码
//为1时使用计数信号量#define configuse_counting_semaphores 1  
仔细阅读源码的同学就会发现有很多类似的代码(如下图),这些代码让freerto可以实现不同需要的裁剪,以减少系统开销
创建计数型信号量
 xsemaphorecreatecounting( ubasetype_t uxmaxcount, ubasetype_t uxinitialcount ) 参数:
uxmaxcount:计数信号量最大计数值,但信号量值等于此值的时候,释放信号量就会失败
uxinitialcount :计数信号量初始值
返回值:
null:计数信号量创建失败
其他值:计数信号量创建成功,返回计数信号量句柄
释放信号量
非中断释放
xsemaphoregive( semaphorehandle_t xsemaphore ) 参数:
xsemaphore : 要释放的信号量句柄
返回值:
pdpass:           释放信号量成功
errqueu_full:释放信号量失败
中断释放
     basetype_t xsemaphoregivefromisr( semaphorehandle_t xsemaphore, basetype_t* pxhigherprioritytaskwoken) 参数:
xsemaphore:要释放的信号量句柄
    pxhigherprioritytaskwoken:标记退出此函数后是否需要进行任务切换,pxhigherprioritytaskwoken是可选参数,可以设置为null。当该值为pdtrue的时候在退出中断服务函数之前一定要进行一次任务切换。
返回值:
释放成功返回pdpass,失败返回errqueue_full
获取信号量
非中断获取
basetype_t xsemaphoretake( semaphorehandle_t xsemaphore, ticktype_t xblocktime) 参数:
        xsemaphore:要释放的信号量句柄
        xblocktime:阻塞时间
返回值:
        获取成功返回pdtrue,失败返回pdfalse
中断获取
   basetype_t xsemaphoretakefromisr( semaphorehandle_t xsemaphore,basetype_t* pxhigherprioritytaskwoken) 参数:
    xsemaphore:要释放的信号量句柄
    pxhigherprioritytaskwoken:标记退出此函数后是否需要进行任务切换
返回值:
    获取成功返回pdtrue,失败返回pdfalse
注意:不管是二值信号量、计数型信号量还是互斥信号量,它们都使用上面的释放信号量和获取信号量api函数
源码例程
#include stm32f10x.h#include #include freertos.h#include task.h#include semphr.hvoid led_init(void){ gpio_inittypedef gpio_initstructure; //定义结构体变量 rcc_apb2periphclockcmd(rcc_apb2periph_gpioc,enable); //开启时钟 gpio_initstructure.gpio_pin=gpio_pin_0; //选择你要设置的io口 gpio_initstructure.gpio_mode=gpio_mode_out_pp; //设置推挽输出模式 gpio_initstructure.gpio_speed=gpio_speed_50mhz; //设置传输速率 gpio_init(gpioc,&gpio_initstructure); //初始化gpio gpio_setbits(gpioc,gpio_pin_0); //将led端口拉高,熄灭led}void key_init(void){ gpio_inittypedef gpio_initstructure; //定义结构体变量 rcc_apb2periphclockcmd(rcc_apb2periph_gpioa|rcc_apb2periph_gpioe,enable); gpio_initstructure.gpio_pin=gpio_pin_0; //选择你要设置的io口 gpio_initstructure.gpio_mode=gpio_mode_ipd;//下拉输入 gpio_initstructure.gpio_speed=gpio_speed_50mhz; //设置传输速率 gpio_init(gpioa,&gpio_initstructure); /* 初始化gpio */ gpio_initstructure.gpio_pin=gpio_pin_3|gpio_pin_2|gpio_pin_4; gpio_initstructure.gpio_mode=gpio_mode_ipu; //上拉输入 gpio_initstructure.gpio_speed=gpio_speed_50mhz; gpio_init(gpioe,&gpio_initstructure);}void usart_init(uint32_t bound){ gpio_inittypedef gpio_initstruct; //定义gpio结构体变量 usart_inittypedef usart_initstruct; //定义串口结构体变量 rcc_apb2periphclockcmd(rcc_apb2periph_gpioa|rcc_apb2periph_usart1,enable); //使能gpioc的时钟 gpio_initstruct.gpio_pin=gpio_pin_9; //配置tx引脚 gpio_initstruct.gpio_mode=gpio_mode_af_pp; //配置pa9为复用推挽输出 gpio_initstruct.gpio_speed=gpio_speed_50mhz; //配置pa9速率 gpio_init(gpioa,&gpio_initstruct); //gpio初始化函数 gpio_initstruct.gpio_pin=gpio_pin_10; //配置rx引脚 gpio_initstruct.gpio_mode=gpio_mode_in_floating; //配置pa10为浮空输入 gpio_initstruct.gpio_speed=gpio_speed_50mhz; //配置pa10速率 gpio_init(gpioa,&gpio_initstruct); //gpio初始化函数 usart_initstruct.usart_mode=usart_mode_tx|usart_mode_rx; //发送接收模式 usart_initstruct.usart_parity=usart_parity_no; //无奇偶校验 usart_initstruct.usart_baudrate=bound; //波特率 usart_initstruct.usart_stopbits=usart_stopbits_1; //停止位1位 usart_initstruct.usart_wordlength=usart_wordlength_8b; //字长8位 usart_initstruct.usart_hardwareflowcontrol=usart_hardwareflowcontrol_none; //无硬件数据流控制 usart_init(usart1,&usart_initstruct); //串口初始化函数 usart_cmd(usart1,enable); //使能usart1}int fputc(int ch,file *f) //printf重定向函数{ usart_senddata(usart1,(uint8_t)ch); //发送一字节数据 while(usart_getflagstatus(usart1,usart_flag_txe) == reset); //等待发送完成 return ch;}#define start_task_prio 1 //任务优先级#define start_stk_size 128 //任务堆栈大小taskhandle_t starttask_handler; //任务句柄void start_task(void *pvparameters);//任务函数#define send_task_prio 2 //任务优先级#define send_stk_size 50 //任务堆栈大小taskhandle_t sendtask_handler; //任务句柄void send_task(void *p_arg); //任务函数#define receive_task_prio 2 //任务优先级#define receive_stk_size 50 //任务堆栈大小taskhandle_t receivetask_handler; //任务句柄void receive_task(void *p_arg); //任务函数semaphorehandle_t countsem_handle =null; //计数型信号量句柄int main( void ) { nvic_prioritygroupconfig(nvic_prioritygroup_4);//设置系统中断优先级分组 4 led_init(); //初始化 led key_init(); usart_init(9600); //创建开始任务 xtaskcreate( (taskfunction_t )start_task, //任务函数 (const char* )start_task, //任务名称 (uint16_t )start_stk_size, //任务堆栈大小 (void* )null, //传递给任务函数的参数 (ubasetype_t )start_task_prio, //任务优先级 (taskhandle_t* )&starttask_handler //任务句柄 ); vtaskstartscheduler(); //开启调度}//开始任务函数void start_task(void *pvparameters){ taskenter_critical(); //进入临界区 /* 创建test_queue */ countsem_handle = xsemaphorecreatecounting(5,0); //创建 发送 任务 xtaskcreate( (taskfunction_t )send_task, (const char* )send_task, (uint16_t )send_stk_size, (void* )null, (ubasetype_t )send_task_prio, (taskhandle_t* )&sendtask_handler ); //创建 接收 任务 xtaskcreate( (taskfunction_t )receive_task, (const char* )receive_task, (uint16_t )receive_stk_size, (void* )null, (ubasetype_t )receive_task_prio, (taskhandle_t* )&receivetask_handler ); vtaskdelete(starttask_handler); //删除开始任务 taskexit_critical(); //退出临界区}//发送 任务函数void send_task(void *pvparameters){ basetype_t xreturn = null; while(1) { if (countsem_handle != null) { xreturn = xsemaphoregive(countsem_handle); if (xreturn == pdtrue){ printf(信号量释放成功n); } else{ printf(信号量释放失败n); } } vtaskdelay(1000); }}//接收 任务函数void receive_task(void *pvparameters){ basetype_t xreturn = null; uint16_t count = 0; while(1) { // 等待获取信号量 xreturn = xsemaphoretake(countsem_handle, portmax_delay); if (xreturn == pdtrue) { count = uxsemaphoregetcount(countsem_handle); printf(%dn,count); } else { printf(获取信号量失败n); } vtaskdelay(2000); }}  
实验现象
--end--

联想手机Z6青春版性能评测 不仅仅是一部千元游戏手机更是一部高精度定位导航设备
5G时代,LTE技术会被淘汰吗?
防水防尘、不入耳的黑科技蓝牙耳机 | 南卡 Runner Pro 骨传导耳机评测
二合一网络防雷器的原理、作用和应用方案
英特尔公司预测数据将成为未来无人驾驶的新动力
Free RTOS的计数型信号量
UPZ音频切换器的功能特点及应用优势
详解光纤的结构及波段范围
多点快速采集系统中信号可靠转贮研究
中国科大、合工大签联合培养协议,培养高水平芯片人才
不同场景的FPGA外围电路的上电时序分析与设计
嵌入式新闻周刊:第一款连接瓶香水
关于GCN的入门学习知识详解
硅调谐器设计的制约因素
三星W2017来袭:骁龙820处理器+4GB RAM+6GB ROM存储,卖两万!
上汽大众2016年销量公布,结果惊人
支持高功率应用的RDL技术解析
中国开启5G SA建设浪潮:移动积极引领,电信探索最佳实践
FM175XX使用总结及国产替代降低成本方案
深度剖析超宽禁带技术,看它如何成就卓越设计