freertos计数信号量怎样查询信号量为空

当前访客身份:游客 [
拥有积分:3
这家伙太懒,还没有签名!
解答题中心
FreeRTOS学习笔记&&二值型信号量
( 16:20:28) &|
&评论(0)&&|
&阅读次数(4254)|
人收藏此文章,
& & 在嵌入式操作系统中二值型信号量是任务间、任务与中断间同步的重要手段。FreeRTOS的二值型信号量简单易用,下面结合一个具体例子说明FreeRTOS中的二值型信号量如何使用。
& & 【相关博文】
】——示例代码存于百度网盘
2.特别说明& &&
& & 二值型信号量的使用方法见图1所示,二值型信号量可以理解为任务与中断间或者两个任务间的标志,该标志非“满”即“空”。Send操作相当把该标志置“满”,Receive操作相关与把该标志取"空",经过send和receive操作实现任务与中断间或者两任务的操作同步。
图1 二值型信号量使用示意图
& & 【特别说明】
& & V7.X版本和V8.X的信号量操作存在少许区别
& & V7.X版本中使用
vSemaphoreCreateBinary函数,使用该函数创建的信号量初始值为“满”,receive操作立刻有返回。相关代码见文章末尾补充代码1,从补充代码1中可以发现,创建信号量之后立刻调用xSemaphoreGive函数,使得信号量由“空”变“满”。
& & V8.X版本中使用xSemaphoreCreateBinary函数,使用该函数创建的信号量初始值为“空”,receive操作不会立刻返回。
3.参考代码
& & 示例代码具有一个128字节的串口接收缓冲区,在串口中断中把接收到的字符存入缓冲区中,一旦接收到回车换行符(\r\n),便通过xSemaphoreGiveFromISR把信号量置“满”,打印任务中使用xSemaphoreTake实现于中断接收函数的同步,
xSemaphoreTake把任务挂起,一旦查询到信号量为“满”,通过串口打印结束到的内容,并清空缓冲区。
& & 【示例代码】
/* Standard includes. */
#include &stdio.h&
#include &string.h&
/* Scheduler includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
/* Library includes. */
#include "stm32f10x.h"
#define LED0_ON()
GPIO_SetBits(GPIOB,GPIO_Pin_5);
#define LED0_OFF()
GPIO_ResetBits(GPIOB,GPIO_Pin_5);
static void Setup(void);
static void PrintTask(void *pvParameters);
void LedInit(void);
void UART1Init(void);
uint8_t RxBuffer[128];
__IO uint8_t RxCounter = 0;
SemaphoreHandle_t xS
int main(void)
/* 初始化硬件平台 */
/* 创建信号量 */
xSemaphore = xSemaphoreCreateBinary();
/* 建立Print任务 */
xTaskCreate(PrintTask, "Print Task", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+4, NULL);
/* 启动OS */
vTaskStartScheduler();
void PrintTask(void *pvParameters)
if( xSemaphoreTake( xSemaphore, portMAX_DELAY ) == pdTRUE )
printf("receive:%s", RxBuffer);
memset(RxBuffer, 0x00, 128);
RxCounter = 0;
static void Setup( void )
LedInit();
UART1Init();
void LedInit( void )
GPIO_InitTypeDef GPIO_InitS
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );
/*LED0 @ GPIOB.5*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init( GPIOB, &GPIO_InitStructure );
void UART1Init(void)
GPIO_InitTypeDef GPIO_InitS
USART_InitTypeDef USART_InitS
/* 第1步:打开GPIO和USART时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);
/* 第2步:将USART1 Tx@PA9的GPIO配置为推挽复用模式 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* 第3步:将USART1 Rx@PA10的GPIO配置为浮空输入模式 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* 第4步:配置USART1参数
数据长度 = 8
禁止硬件流控(即禁止RTS和CTS)
使能接收和发送
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_N
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
/* 第5步:使能 USART1, 配置完毕 */
USART_Cmd(USART1, ENABLE);
/* 清除发送完成标志 */
USART_ClearFlag(USART1, USART_FLAG_TC);
/* 使能USART1发送中断和接收中断,并设置优先级 */
NVIC_InitTypeDef NVIC_InitS
/* 设定USART1 中断优先级 */
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = configLIBRARY_KERNEL_INTERRUPT_PRIORITY;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* 使能接收中断 */
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
int fputc(int ch, FILE *f)
/* 写一个字节到USART1 */
USART_SendData(USART1, (uint8_t) ch);
/* 等待发送结束 */
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)
void USART1_IRQHandler(void)
static BaseType_t xHigherPriorityTaskW
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
RxBuffer[RxCounter++] = USART_ReceiveData(USART1);
if (RxCounter & 2 && RxBuffer[RxCounter-2] == '\r' && RxBuffer[RxCounter-1] == '\n') {
// 在中断中发送信号量
xSemaphoreGiveFromISR( xSemaphore, &xHigherPriorityTaskWoken );
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
4.简单说明
SemaphoreHandle_t xS
& & 信号量句柄,二值型信号量、数值型信号量和互斥型信号量均使用
SemaphoreHandle_t类型声明
xSemaphore = xSemaphoreCreateBinary();
& & 创建信号量,V8.X版本中新增加函数,创建信号量时初值为“空”。
xSemaphoreGiveFromISR( xSemaphore, &xHigherPriorityTaskWoken );
& & 在中断中发送信号量,以FromISR结尾的函数具有保护功能,如果在任务中发送信号量可使用xSemaphoreGive。
xSemaphoreTake( xSemaphore, portMAX_DELAY );
& & 等待信号量,等待时间为最大等待时间,如果信号量为“空”任务会处于挂起状态。
5.在中断中使用RTOS API注意点
& & 【FromISR】
& & 应使用xSemaphoreGiveFromISR,而不是
xSemaphoreGive。
& & 【中断优先级设置】
& & 串口中断的优先级应该低于configMAX_SYSCALL_INTERRUPT_PRIORITY(191,从另一个角度可以理解为11)设置的最高优先级,本文UART的响应优先级为configLIBRARY_KERNEL_INTERRUPT_PRIORITY(该宏的具体值为15,数值越大优先级越低)。
& & 【main.c】
/* 使能USART1发送中断和接收中断,并设置优先级 */
NVIC_InitTypeDef NVIC_InitS
/* 设定USART1 中断优先级 */
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = configLIBRARY_KERNEL_INTERRUPT_PRIORITY;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
& & 【FreeRTOSConfig.h】
/* This is the raw value as per the Cortex-M3 NVIC. &Values can be 255
(lowest) to 0 (1?) (highest). */
#define configKERNEL_INTERRUPT_PRIORITY & & 255
#define configMAX_SYSCALL_INTERRUPT_PRIORITY &191 /* equivalent to 0xb0, or priority 11. */
/* This is the value being used as per the ST library which permits 16
priority values, 0 to 15. &This must correspond to the
configKERNEL_INTERRUPT_PRIORITY setting. &Here 15 corresponds to the lowest
NVIC value of 255. */
#define configLIBRARY_KERNEL_INTERRUPT_PRIORITY 15
& & 鉴于Cortex M3的NVIC的特性,请详细参考——【
& & 【1】V8.X中使用
xSemaphoreCreateBinary()
创建的信号量初始值为"空"。
& & 【2】中断中发送信号量尽量使用XXXXFromISR。
& & 【3】某中断的优先级数值应大于configMAX_SYSCALL_INTERRUPT_PRIORITY。
】——vSemaphoreCreateBinary函数实现代码
#define vSemaphoreCreateBinary( xSemaphore ) \
( xSemaphore ) = xQueueGenericCreate( ( unsigned portBASE_TYPE ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE ); \
if( ( xSemaphore ) != NULL ) \
( void ) xSemaphoreGive( ( xSemaphore ) ); \
6.参考资料
关注微信,跟着我们扩展技术视野。每天推送IT新技术文章,每周聚焦一门新技术。微信二维码如下:
微信公众账号:尚学堂(微信号:bjsxt-java)
原文链接:21ic官方微信-->
后使用快捷导航没有帐号?
查看: 1353|回复: 10
stm32f103+freeRTOS中中断里释放信号量问题
&&已结帖(10)
主题帖子积分
助理工程师, 积分 1396, 距离下一级还需 604 积分
助理工程师, 积分 1396, 距离下一级还需 604 积分
主题帖子积分
专家等级:结帖率:100%打赏:15.54受赏:68.88
主题帖子积分
助理工程师, 积分 1396, 距离下一级还需 604 积分
助理工程师, 积分 1396, 距离下一级还需 604 积分
用CUBE生成的工程文件,在外部中断里释放信号量,使等待的任务A运行。外部中断优先级是8
void MX_GPIO_Init(void)
&&GPIO_InitTypeDef GPIO_InitS
&&/* GPIO Ports Clock Enable */
&&__GPIOC_CLK_ENABLE();
&&__GPIOA_CLK_ENABLE();
&&__GPIOB_CLK_ENABLE();
&&/*Configure GPIO pins : PC0 PC1 PC2 PC3 */
&&GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3;
&&GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
&&GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
&&HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
&&/*Configure GPIO pin : PA0 */
&&GPIO_InitStruct.Pin = GPIO_PIN_0;
&&GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
&&GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
&&HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
&&/*Configure GPIO pin : PA1 */
&&GPIO_InitStruct.Pin = GPIO_PIN_1;
&&GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
&&GPIO_InitStruct.Pull = GPIO_PULLUP;
&&HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
&&/* EXTI interrupt init*/
&&HAL_NVIC_SetPriority(EXTI1_IRQn, 8, 0);
&&HAL_NVIC_EnableIRQ(EXTI1_IRQn);
FreeRTOSConfig.h里的优先级配置是这样的
#ifdef __NVIC_PRIO_BITS
/* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
#define configPRIO_BITS& && && &__NVIC_PRIO_BITS
#define configPRIO_BITS& && && &4
/* The lowest interrupt priority that can be used in a call to a &set priority&
function. */
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY& &15
/* The highest interrupt priority that can be used by any interrupt service
routine that makes calls to interrupt safe FreeRTOS API functions.&&DO NOT CALL
INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
PRIORITY THAN THIS! (higher priorities are lower numeric values. */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
/* Interrupt priorities used by the kernel port layer itself.&&These are generic
to all Cortex-M ports, and do not rely on any particular library functions. */
#define configKERNEL_INTERRUPT_PRIORITY & & & & & & & & ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY && (8 - configPRIO_BITS) )
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY & & & & ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY && (8 - configPRIO_BITS) )
外部中断函数内容是
&&* &&EXTI line detection callback
&&* @param GPIO_Pin: Specifies the pins connected EXTI line
&&* @retval None
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
&&if(GPIO_Pin == GPIO_PIN_1)
& & osSemaphoreRelease(myBinarySem01Handle);
/* StartDefaultTask function */
void StartDefaultTask(void const * argument)
&&/* USER CODE BEGIN 5 */
&&int32_t res = os_status_
&&AD1232Init();
&&/* Infinite loop */
& & //osDelay(1);
& & res = osSemaphoreWait(myBinarySem01Handle,osWaitForever);
& & if(res == osOK)
& && &AD_Value = ReadSensor();
&&/* USER CODE END 5 */
现在中断能进去释放信号量,但一直都到不了AD_Value = ReadSensor();这一步,我这样写的对不对?麻烦看看我哪里出错了!
满意回复+10
FreeRTOS的资料没有uCOS的多,我也是只接触过ucOS,不清楚最近搞的很火MBED OS到底是不是个OS。
本帖子中包含更多资源
才可以下载或查看,没有帐号?
21ic公开课,21ic网友共同的学习圈子!学单片机、嵌入式、模拟、电源……就看这里
移步更多21ic独家微课:
主题帖子积分
助理工程师, 积分 1396, 距离下一级还需 604 积分
助理工程师, 积分 1396, 距离下一级还需 604 积分
主题帖子积分
专家等级:结帖率:100%打赏:15.54受赏:68.88
主题帖子积分
助理工程师, 积分 1396, 距离下一级还需 604 积分
助理工程师, 积分 1396, 距离下一级还需 604 积分
现在网上的FreeRTOS的资料没有uCOS的多,在网上没有找到什么有用的信息。有没有用过FreeRTOS的?
21ic公开课,21ic网友共同的学习圈子!学单片机、嵌入式、模拟、电源……就看这里
移步更多21ic独家微课:
主题帖子积分
助理工程师, 积分 1396, 距离下一级还需 604 积分
助理工程师, 积分 1396, 距离下一级还需 604 积分
主题帖子积分
专家等级:结帖率:100%打赏:15.54受赏:68.88
主题帖子积分
助理工程师, 积分 1396, 距离下一级还需 604 积分
助理工程师, 积分 1396, 距离下一级还需 604 积分
我之前试过在中断里释放队列也是不行,任务A一直处在等待状态,但是如果在另一个任务B里释放队列的话,则任务A与任务B完成了同步。但是为什么在中断里就不行。
configLIBRARY_LOWEST_INTERRUPT_PRIORITY& &和configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 没有设置错啊?
21ic公开课,21ic网友共同的学习圈子!学单片机、嵌入式、模拟、电源……就看这里
移步更多21ic独家微课:
主题帖子积分
中级工程师, 积分 4891, 距离下一级还需 109 积分
中级工程师, 积分 4891, 距离下一级还需 109 积分
主题帖子积分
专家等级:结帖率:100%打赏:0.00受赏:15.00
主题帖子积分
中级工程师, 积分 4891, 距离下一级还需 109 积分
中级工程师, 积分 4891, 距离下一级还需 109 积分
FreeRTOS的资料没有uCOS的多,我也是只接触过ucOS,不清楚最近搞的很火MBED OS到底是不是个OS。
21ic公开课,21ic网友共同的学习圈子!学单片机、嵌入式、模拟、电源……就看这里
移步更多21ic独家微课:
主题帖子积分
助理工程师, 积分 1396, 距离下一级还需 604 积分
助理工程师, 积分 1396, 距离下一级还需 604 积分
主题帖子积分
专家等级:结帖率:100%打赏:15.54受赏:68.88
主题帖子积分
助理工程师, 积分 1396, 距离下一级还需 604 积分
助理工程师, 积分 1396, 距离下一级还需 604 积分
FreeRTOS的资料没有uCOS的多,我也是只接触过ucOS,不清楚最近搞的很火MBED OS到底是不是个OS。 ...
我怎么感觉它很像个线上的编译器,没有看出OS的苗头
21ic公开课,21ic网友共同的学习圈子!学单片机、嵌入式、模拟、电源……就看这里
移步更多21ic独家微课:
主题帖子积分
助理工程师, 积分 1396, 距离下一级还需 604 积分
助理工程师, 积分 1396, 距离下一级还需 604 积分
主题帖子积分
专家等级:结帖率:100%打赏:15.54受赏:68.88
主题帖子积分
助理工程师, 积分 1396, 距离下一级还需 604 积分
助理工程师, 积分 1396, 距离下一级还需 604 积分
二姨家没有人用freeRTOS?还是我发错板块了?这个问题以后有时间再研究吧,还是用回UCOSIII了。话说UCOSIII的中断处理是个什么机制?所有的中断服务函数都要进临界区,某某值加加,出临界区?
21ic公开课,21ic网友共同的学习圈子!学单片机、嵌入式、模拟、电源……就看这里
移步更多21ic独家微课:
主题帖子积分
初级工程师, 积分 2143, 距离下一级还需 857 积分
初级工程师, 积分 2143, 距离下一级还需 857 积分
主题帖子积分
专家等级:结帖率:100%
主题帖子积分
初级工程师, 积分 2143, 距离下一级还需 857 积分
初级工程师, 积分 2143, 距离下一级还需 857 积分
参考一下吧
本帖子中包含更多资源
才可以下载或查看,没有帐号?
21ic公开课,21ic网友共同的学习圈子!学单片机、嵌入式、模拟、电源……就看这里
移步更多21ic独家微课:
主题帖子积分
初级工程师, 积分 2148, 距离下一级还需 852 积分
初级工程师, 积分 2148, 距离下一级还需 852 积分
主题帖子积分
专家等级:结帖率:100%
主题帖子积分
初级工程师, 积分 2148, 距离下一级还需 852 积分
初级工程师, 积分 2148, 距离下一级还需 852 积分
相对来说UCOSIII用的人应该比较多,资料也多
21ic公开课,21ic网友共同的学习圈子!学单片机、嵌入式、模拟、电源……就看这里
移步更多21ic独家微课:
主题帖子积分
中级工程师, 积分 4891, 距离下一级还需 109 积分
中级工程师, 积分 4891, 距离下一级还需 109 积分
主题帖子积分
专家等级:结帖率:100%打赏:0.00受赏:15.00
主题帖子积分
中级工程师, 积分 4891, 距离下一级还需 109 积分
中级工程师, 积分 4891, 距离下一级还需 109 积分
我怎么感觉它很像个线上的编译器,没有看出OS的苗头
是的,OS还没有做出来呢,听说还在研发中,只给了个框架的在线编译器。
21ic公开课,21ic网友共同的学习圈子!学单片机、嵌入式、模拟、电源……就看这里
移步更多21ic独家微课:
主题帖子积分
助理工程师, 积分 1396, 距离下一级还需 604 积分
助理工程师, 积分 1396, 距离下一级还需 604 积分
主题帖子积分
专家等级:结帖率:100%打赏:15.54受赏:68.88
主题帖子积分
助理工程师, 积分 1396, 距离下一级还需 604 积分
助理工程师, 积分 1396, 距离下一级还需 604 积分
参考一下吧
这和中断服务有什么关系?
21ic公开课,21ic网友共同的学习圈子!学单片机、嵌入式、模拟、电源……就看这里
移步更多21ic独家微课:
主题帖子积分
高级工程师, 积分 7280, 距离下一级还需 720 积分
高级工程师, 积分 7280, 距离下一级还需 720 积分
主题帖子积分
专家等级:结帖率:40%打赏:15.74受赏:289.20
主题帖子积分
高级工程师, 积分 7280, 距离下一级还需 720 积分
高级工程师, 积分 7280, 距离下一级还需 720 积分
osSemaphoreRelease 能在中断里调用吗?
我最讨厌两种人:一是有种族歧视的; 二是黑人;三是不识数的!
技术新星奖章
人才类勋章
技术奇才奖章
人才类勋章
时间类勋章
沉静之湖泊
发帖类勋章
突出贡献奖章
等级类勋章STM32 FreeRTOS信号量(软件中断实现) - STM32 - 意法半导体STM32/STM8技术社区
后使用快捷导航没有帐号?
查看: 445|回复: 4
STM32 FreeRTOS信号量(软件中断实现)
在线时间18 小时
主题帖子精华
初级会员, 积分 195, 距离下一级还需 5 积分
初级会员, 积分 195, 距离下一级还需 5 积分
大家好,我最近在学习FreeRTOS,在STM32平台上。在官方给出的代码中,关于信号量切换这一章节。
这是定义的中断函数:
static void __interrupt __far vExampleInterruptHandler( void )
static portBASE_TYPE xHigherPriorityTaskW
xHigherPriorityTaskWoken = pdFALSE;
/* 'Give' the semaphore to unblock the task. */
xSemaphoreGiveFromISR( xBinarySemaphore, &xHigherPriorityTaskWoken );
if( xHigherPriorityTaskWoken == pdTRUE )
/* 给出信号量以使得等待此信号量的任务解除阻塞。如果解出阻塞的任务的优先级高于当前任务的优先
级 – 强制进行一次任务切换,以确保中断直接返回到解出阻塞的任务(优选级更高)。
说明:在实际使用中,ISR中强制上下文切换的宏依赖于具体移植。此处调用的是基于Open Watcom DOS
移植的宏。其它平台下的移植可能有不同的语法要求。对于实际使用的平台,请参如数对应移植自带的示
例程序,以决定正确的语法和符号。
portSWITCH_CONTEXT();
使用这句可以实现一个软件的中断,进入上面的中断函数。
__asm{ int 0x82 } /* 这条语句产生中断 */
int main( void )
/* 信号量在使用前都必须先创建。本例中创建了一个二值信号量 */
vSemaphoreCreateBinary( xBinarySemaphore );
/* 安装中断服务例程 */& &/这里的移植/
_dos_setvect( 0x82, vExampleInterruptHandler );
/* 检查信号量是否成功创建 */
if( xBinarySemaphore != NULL )
/* 创建延迟处理任务。此任务将与中断同步。延迟处理任务在创建时使用了一个较高的优先级,以保证
中断退出后会被立即执行。在本例中,为延迟处理任务赋予优先级3 */
xTaskCreate( vHandlerTask, &Handler&, 1000, NULL, 3, NULL );
/* 创建一个任务用于周期性产生软件中断。此任务的优先级低于延迟处理任务。每当延迟处理任务切出
阻塞态,就会抢占周期任务*/
xTaskCreate( vPeriodicTask, &Periodic&, 1000, NULL, 1, NULL );
/* Start the scheduler so the created tasks start executing. */
vTaskStartScheduler();
/* 如果一切正常,main()函数不会执行到这里,因为调度器已经开始运行任务。但如果程序运行到了这里,
很可能是由于系统内存不足而无法创建空闲任务。第五章会提供更多关于内存管理的信息 */
for( ;; );
/* 安装中断服务例程 */& &/这里的移植/
_dos_setvect( 0x82, vExampleInterruptHandler );
__asm{ int 0x82 } /* 这条语句产生中断 */
进入中断函数vExampleInterruptHandler 。
我的问题是想知道怎么实现这两者的联系。就是想知道如何移植到STM32上来实现。 在freertos的官网上说要参考编译器的手册,可我实在查不到。
我想问这种姑且被我叫做软件中断的东西如何在移植了freertos的stm32上实现。
欢迎加入STM32/STM8社区技术交流群:&7779516 & &STM32L系列开发群:
在线时间18 小时
主题帖子精华
初级会员, 积分 195, 距离下一级还需 5 积分
初级会员, 积分 195, 距离下一级还需 5 积分
一个人也没有么
ST金币1278
在线时间40 小时
主题帖子精华
金牌会员, 积分 1235, 距离下一级还需 1765 积分
金牌会员, 积分 1235, 距离下一级还需 1765 积分
pendsv?SWI中断?官方给提供了软中断的例子,你可以查看一下。
欢迎加入STM32/STM8社区技术交流群:&7779516 & &STM32L系列开发群:
在线时间18 小时
主题帖子精华
初级会员, 积分 195, 距离下一级还需 5 积分
初级会员, 积分 195, 距离下一级还需 5 积分
pendsv?SWI中断?官方给提供了软中断的例子,你可以查看一下。
您能告诉我怎么看么,学生,不知道怎么找。谢谢您
ST金币3095
在线时间459 小时
主题帖子精华
论坛元老, 积分 3766, 距离下一级还需 9996233 积分
论坛元老, 积分 3766, 距离下一级还需 9996233 积分
& && && && &&&帮忙顶
欢迎加入STM32/STM8社区技术交流群:&7779516 & &STM32L系列开发群:
站长推荐 /1
本课程将涉及前后台系统的设计,详细分析RTOS的基本功能,包括内核调度机制,任务管理,中断管理,任务间的同步与通信机制等。
Tel: 3-8064
备案号: 苏ICP备号-2
|||意法半导体STM32/STM8技术社区
Powered by博客访问: 863793
博文数量: 395
博客积分: 2147
博客等级: 大尉
技术积分: 3499
注册时间:
IT168企业级官微
微信号:IT168qiye
系统架构师大会
微信号:SACC2013
分类: 嵌入式
二进制信号灯
计数信号灯
递归互斥, 以及更多
--------------------------------------------------------------------------------
队列是内部通信的主要形式。它可以用于在任务和任务之间以及任务和中断之间发送消息。在大多数情况下使用线程安全 FIFO(先进先出)缓存,新数据放在队列的最后,虽然数据也可以放在前面。
队列可以包含固定大小的 '项目' - 每个项目的大小和队列可以保存项目的最大数量在创建队列时就已经定义了。
项目以复制而不是引用的方式放入队列,因此最好使放入队列项目的大小成为最小。以复制的方式放入队列可以使你的系统设计极大的简化,因为两个任务不会同时访问数据。队列帮助你管理所有的互斥问题。
如果你希望在队列中使用大的项目,可能最好用插入队列指针 - 但是这样做必须注意要确保你的系统明确定义任务和/或中断是数据的"所以者"。
队列 API 函数可以指定阻塞的时间。阻塞时间代表任务进入阻塞状态或者等待队列中数据时(当任务读取队列但是队列是空的时候)的最大'节拍'数,或者等待队列空间变为可以使用(当任务需要写数据到队列,但是队列已满时)。当一个以上任务在同一个队列中被阻塞时,高优先级的任务先解除阻塞。
查看用户文档中 队列管理 小节中与队列相关的 API 函数列表。搜索 FreeRTOS/Demo/Common/Minimal 文件夹下的文件可以发现多个这种用法的例子。注意中断里不能使用不是用 "FromISR" 结束的 API 函数。
写入和读取队列。在这个例子中队列保存5个项目,并且从不变满。
--------------------------------------------------------------------------------
二进制信号灯
二进制信号灯同时用于互斥和同步的目的。
二进制信号灯和互斥非常相似,但是有一些细微的不同:互斥包括优先级继承机制,而二级制信号没有。这使得二进制信号灯用于同步更方便 (在任务之间或任务与中断之间),而互斥用在简单的互相排斥更好。在怎样用互斥作为互相排斥的机制中 说明 二进制信号灯用法,这个子章节只说明使用二进制信号灯进行同步。
信号灯 API 函数可以指定阻塞的时间。阻塞时间代表任务因为等待获取信号灯而进入阻塞状态的最大'节拍'数。如果超过一个以上的任务因为同一个信号灯被阻塞,那么在信号灯可以使用时高优先级的任务先解除阻塞。
将一个二进制信号灯看作为队列,它只能保存一个项目,这个队列只能是空的或者是满的 (二进制)。使用队列的任务和中断不关心队列保存了什么 - 它们只关系队列是空的还是满的。这个机制可以用于同步任务和中断。
考虑这样一个情况,任务使用一个外设,轮询外设将浪费 CPU 资源,并阻止了其他任务的运行。因此最好是任务将大部分时间用于阻塞状态 (允许其他任务运行),只有真正需要操作时才去轮询。这就是在 '试图' 获得信号时使用二进制信号灯进行任务阻塞,而一个中断服务程序用于外设,当需要使用外设时 '给出' 信号。任务总是 '获取' 信号 (从队列读取直到队列为空),但是从不 '给出'。中断服务程序总是 '给出' 信号 (写入队列直到队列变满) 而从不获取。 xSemaphoreGiveFromISR() 源代码的文档中清楚的解释了这个方法。
可以使用任务的优先级保证及时的外设服务 - 有效的产生 '不同的中断' 方式。另外一种方法是使用队列代替信号,在中断服务程序中捕捉外设的数据并通过队列发送给任务。当队列的数据可以使用后任务解除阻塞,从队列读取数据后,进行数据处理。第二种方法允许中断程序尽可能的短,通过 post 处理而不是发生在一个任务中。
参考用户文档的 信号灯/互斥 小节中关于信号灯的 API 函数。搜索 FreeRTOS/Demo/Common/Minimal 文件夹下的文件可以获得很多这种用法的例子。注意中断里不能使用不是以 "FromISR" 结束的 API 函数。
&(29.87 KB)
使用信号灯同步任务和中断。中断只 '给出' 信号,而任务只 '获取' 信号。
--------------------------------------------------------------------------------
计数信号灯
正如二进制信号灯可以认为长度是 1 的队列,计数信号灯可以看成是长度大于 1 的队列。同样,用户的信号不是对队列数据的数值感兴趣 - 只需要看队列是不是空的。
计数信号灯典型用于两个方面:
计数事件。
在这个情况下使用一个事件处理程序将在每次事件发生时 '给出' 信号 (增加信号计数值), 同时每次处理事件时处理任务将 '获得' 信号 (减少信号计数值)。因此计数值是事件发生次数和处理次数的差,信号创建时,这个计数值是0。
资源管理。
在这个情况下,计数值代表可用的资源数。为了获得一个资源的控制,任务必须先获得信号 - 减少信号的计数值。当计数值达到 0,代表没有剩余的自由资源。当任务使用完资源后,需要 '返还' 信号 - 增加信号计数值。在这种方式下信号创建时的计数值等于最大计数值。
参考 信号灯/互斥 小节查看相关的 API 函数。搜索 FreeRTOS/Demo/Common/Minimal 文件夹下的文件可以查看关于这种用法的例子。注意中断里不能使用不以 "FromISR" 结束的 API 函数。
--------------------------------------------------------------------------------
互斥是包含优先级继承机制的 二进制信号灯。对于同步(在任务之间或者任务与中断之间)来说二进制信号灯是更好的选择,互斥对于简单的互相排斥更方便 (mutex 就是 'MUT'ual 'EX'clusion).
当用于互相排斥时,互斥就像是资源保护。当一个任务需要访问资源,它必须先获得 ('take') 令牌;当访问结束后,它必须释放令牌 - 允许其他任务能够访问这个资源。
互斥使用了和信号灯相同的 API 函数,所以也可以指定阻塞时间。阻塞时间代表了任务因为试图获取一个不可马上使用的信号而进入阻塞状态的最大 '节拍' 数。和二进制信号灯不同 - 互斥采用了优先级继承关系。这意味着如果高优先级任务因为试图获取被低优先级任务保持的互斥信号(令牌)而阻塞,那么低优先级任务的优先级将临时上升到被阻塞的任务。这个机制保证了高优先级任务被阻塞的时间最短,并减少了已经发生的 '优先级反转'。
优先级继承并不能解决优先级反转的问题!它只是在某些条件下降低了它的影响。硬实时系统要把防止优先级反转放在第一位来考虑。
&(77.37 KB)
使用互斥来保护共享的资源
--------------------------------------------------------------------------------
一个使用了递归的互斥可以反复被所有者 '获取'。互斥变为不可用直到所有者为每次 xSemaphoreTakeRecursive() 请求调用 xSemaphoreGiveRecursive()。例如,如果任务成功 '获取' 相同的互斥 5 次,然后互斥将对其他任务变为不可用,直到它正好 '返还' 互斥 5 次。
这个类型的信号灯使用了优先级继承机制,所以任务 '获取' 信号后必须总是在不再需要信号后 '返还'。
互斥类型信号不能用于中断服务程序。
浅析FreeRTOS_v4.5.0队列、信号和Mutex互斥量共用函数体Queue.c文件
typedef struct QueueDefinition
&&&&&&signed char *pcH&&&&&&&&&&&&&&&&&&&&
&&&&&&signed char *pcWriteTo;&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&signed char *pcReadF&&&&&&&&&&&&
&&&&&&xList xTasksWaitingToS&&&&&&&&&
&&&&&&xList xTasksWaitingToR&&&&&&&&&&&&&&&&&&
&&&&&&volatile unsigned portBASE_TYPE uxMessagesWaiting
&&&&&&&队列总的条目个数 */
&&&&&&unsigned portBASE_TYPE uxL&&&&&&&&&&&&&&
&&&&&&unsigned portBASE_TYPE uxItemS&&&&&、
&&&&&&signed portBASE_TYPE xRxL&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&signed portBASE_TYPE xTxL&&&&&&&&&&&&
xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize )
xQUEUE *pxNewQ
size_t xQueueSizeInB
&&&&&&if( uxQueueLength > ( unsigned portBASE_TYPE ) 0 )
&&&&&&&&&&&&&pxNewQueue = ( xQUEUE * ) pvPortMalloc( sizeof( xQUEUE ) );
&&&&&&&&&&&&&if( pxNewQueue != NULL )
&&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ) + ( size_t ) 1;
&&&&&&&&&&&&&&&&&&&&pxNewQueue->pcHead = ( signed char * ) pvPortMalloc( xQueueSizeInBytes );
&&&&&&&&&&&&&&&&&&&&if( pxNewQueue->pcHead != NULL )
&&&&&&&&&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&pxNewQueue->pcTail = pxNewQueue->pcHead + ( uxQueueLength * uxItemSize );
&&&&&&&&&&&&&&&&&&&&&&&&&&&pxNewQueue->uxMessagesWaiting = 0;
&&&&&&&&&&&&&&&&&&&&&&&&&&&pxNewQueue->pcWriteTo = pxNewQueue->pcH&&&&&//从头写入
&&&&&&&&&&&&&&&&&&&&&&&&&&&pxNewQueue->pcReadFrom = pxNewQueue->pcHead + ( ( uxQueueLength - 1 ) * uxItemSize ); //尾部读出
&&&&&&&&&&&&&&&&&&&&&&&&&&&pxNewQueue->uxLength = uxQueueL
&&&&&&&&&&&&&&&&&&&&&&&&&&&pxNewQueue->uxItemSize = uxItemS
&&&&&&&&&&&&&&&&&&&&&&&&&&&pxNewQueue->xRxLock = queueUNLOCKED;
&&&&&&&&&&&&&&&&&&&&&&&&&&&pxNewQueue->xTxLock = queueUNLOCKED;
&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) );
&&&&&&&&&&&&&&&&&&&&&&&&&&&vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) );
&&&&&&&&&&&&&&&&&&&&&&&&&&&traceQUEUE_CREATE( pxNewQueue );
&&&&&&&&&&&&&&&&&&&&&&&&&&&return&&pxNewQ
&&&&&&&&&&&&&&&&&&&&}
&&&&&&&&&&&&&&&&&&&&else
&&&&&&&&&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&&&&&&&&&&&&traceQUEUE_CREATE_FAILED();
&&&&&&&&&&&&&&&&&&&&&&&&&&&vPortFree( pxNewQueue );
&&&&&&&&&&&&&&&&&&&&}
&&&&&&&&&&&&&}
&&&&&&return NULL;
//-----------------------------------------------------------------------------------
signed portBASE_TYPE xQueueGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition )
signed portBASE_TYPE xEntryTimeSet = pdFALSE;
xTimeOutType xTimeO
taskENTER_CRITICAL();
if( pxQueue->uxMessagesWaiting uxLength )
traceQUEUE_SEND( pxQueue );
prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE )
如果唤醒的任务比当前任务优先级高,进行调度。
portYIELD_WITHIN_API();
taskEXIT_CRITICAL();
return pdPASS;
if( xTicksToWait == ( portTickType ) 0 )
没有加等待延时,直接返回。
taskEXIT_CRITICAL();
traceQUEUE_SEND_FAILED( pxQueue );
return errQUEUE_FULL;
else if( xEntryTimeSet == pdFALSE )
vTaskSetTimeOutState( &xTimeOut );&&&&&&&&
xEntryTimeSet = pdTRUE;
taskEXIT_CRITICAL();
vTaskSuspendAll();
prvLockQueue( pxQueue );
if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
if( prvIsQueueFull( pxQueue ) )&
traceBLOCKING_ON_QUEUE_SEND( pxQueue );
如上边提到的,当这里正要执行的时候,ISR突然到达,那么
//ISR可能把数据读出去了,所以空出了数据,但是这里还会进行队列调整
//因为ISR中发现Q已经被锁,所以Q不会在ISR中发生调度,仅仅是把数据读出去而已
//下面耗费多长时间也无所谓了,因为现在ISR硬件中断系统并没有关闭
vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );
上面解释:解锁queue意味着queue操作可以影响事件列表,中断(释放信号量)可以移出等待信号量任务,但是,如果此时任务调度被关闭,任务不直接放到就绪表,而是放到pending redaylist.///
prvUnlockQueue( pxQueue );
如果上面的ISR中断发生,那么本task已经被放到了Event事件双向链表上,
//下面的Unlock将使等待在Event事件队列双向链表上的最应该执行的task
//从事件队列双向链表上摘下,因为当下内核调度器被锁,所以恢复的task将被
//暂时放到PendingReady队列上
允许任务调度,移pending 到 readylist.必须进行调度。
if( !xTaskResumeAll() )&&&&&&&
portYIELD_WITHIN_API();
prvUnlockQueue( pxQueue );&&
解锁函数,会检查在解锁期间,由中断函数send,,receive 的信号量,重新移出等待列表的任务,如果调度被禁止,任务会放到pendinglist .
( void ) xTaskResumeAll();
xTastResumeALL函数代码是:
while( ( pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY(&&( ( xList * ) &xPendingReadyList ) ) ) != NULL )
vListRemove( &( pxTCB->xEventListItem ) );
vListRemove( &( pxTCB->xGenericListItem ) );
prvAddTaskToReadyQueue( pxTCB );
}&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
prvUnlockQueue( pxQueue );
( void ) xTaskResumeAll();
traceQUEUE_SEND_FAILED( pxQueue );
return errQUEUE_FULL;
//-----------------------------------------------------------------------------------
signed portBASE_TYPE xQueueGenericReceive( xQueueHandle pxQueue, const void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking )
signed portBASE_TYPE xEntryTimeSet = pdFALSE;
xTimeOutType xTimeO
signed char *pcOriginalReadP
taskENTER_CRITICAL();
if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
pcOriginalReadPosition = pxQueue->pcReadF
prvCopyDataFromQueue( pxQueue, pvBuffer );
if( xJustPeeking == pdFALSE )
traceQUEUE_RECEIVE( pxQueue );
--( pxQueue->uxMessagesWaiting );
#if ( configUSE_MUTEXES == 1 )
if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle();
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE )
portYIELD_WITHIN_API();
traceQUEUE_PEEK( pxQueue );
pxQueue->pcReadFrom = pcOriginalReadP
if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
portYIELD_WITHIN_API();
taskEXIT_CRITICAL();
return pdPASS;
if( xTicksToWait == ( portTickType ) 0 )
taskEXIT_CRITICAL();
traceQUEUE_RECEIVE_FAILED( pxQueue );
return errQUEUE_EMPTY;
else if( xEntryTimeSet == pdFALSE )
vTaskSetTimeOutState( &xTimeOut );
xEntryTimeSet = pdTRUE;
taskEXIT_CRITICAL();
vTaskSuspendAll();
prvLockQueue( pxQueue );
if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
if( prvIsQueueEmpty( pxQueue ) )
traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );
#if ( configUSE_MUTEXES == 1 )
if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
portENTER_CRITICAL();&&&&&&&
// gliethttp
//优先级继承
//如果将要悬挂在该Q上的本task对应的优先级高于Q队列上正在持有Q使用权的pxMutexHolder对应的task的优先级
//,那么提升正在使用Q资源的pxMutexHolder对应的task的优先级到达本task的优先级
// gliethttp
//低于持有mutex互斥量的task优先级的task-C不会抢占C
//高于task-C优先级的task应该抢占C
//比悬停在Q上的最高优先级task-A的优先级低的同时比持有mutex互斥量的C优先级高的task们
//才会出现优先级翻转现象
//[注:对于优先级翻转问题,可以参看《浅析μCOS/II v2.85内核OSMboxPend()和OSMboxPost()函数工作原理》
// 和《关于uC/OS-II中优先级翻转问题(转)》.文章地址:
vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );
portEXIT_CRITICAL();
vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
prvUnlockQueue( pxQueue );
if( !xTaskResumeAll() )
portYIELD_WITHIN_API();
prvUnlockQueue( pxQueue );
( void ) xTaskResumeAll();
prvUnlockQueue( pxQueue );
( void ) xTaskResumeAll();
traceQUEUE_RECEIVE_FAILED( pxQueue );
return errQUEUE_EMPTY;
//-----------------------------------------------------------------------------------
static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition )
if( pxQueue->uxItemSize == 0 )
#if ( configUSE_MUTEXES == 1 )
if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
// gliethttp
//说是恢复Q上task的优先级,倒不如说调用了mutex_unlock()
//其中xQueueReceive等效于mutex_lock();
// xQueueSend 等效于mutex_unlock();
//所以对于mutex,就没有什么Q的概念了
//任何一个对mutex发送的数据,即:xQueueSend,都会使mutex解锁,因为
//下一次肯定是等待在Q-mutex上最高优先级的task获得执行
// gliethttp
//低于持有mutex互斥量的task优先级的task-C不会抢占C
//高于task-C优先级的task应该抢占C
//比悬停在Q上的最高优先级task-A的优先级低的同时比持有mutex互斥量的C优先级高的task们
//才会出现优先级翻转现象
vTaskPriorityDisinherit( ( void * const ) pxQueue->pxMutexHolder );
else if( xPosition == queueSEND_TO_BACK )
memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize );
pxQueue->pcWriteTo += pxQueue->uxItemS
if( pxQueue->pcWriteTo >= pxQueue->pcTail )
pxQueue->pcWriteTo = pxQueue->pcH
memcpy( ( void * ) pxQueue->pcReadFrom, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize );
pxQueue->pcReadFrom -= pxQueue->uxItemS
if( pxQueue->pcReadFrom pcHead )
pxQueue->pcReadFrom = ( pxQueue->pcTail - pxQueue->uxItemSize );
++( pxQueue->uxMessagesWaiting );
阅读(3902) | 评论(0) | 转发(1) |
相关热门文章
给主人留下些什么吧!~~
请登录后评论。}

我要回帖

更多关于 freertos ucos 比较 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信