Freertos 二元信号量

来源:互联网 发布:解除端口占用的命令 编辑:程序博客网 时间:2024/06/07 08:08
Freertos 二元信号量

     信号量是任务与任务之间,任务与中断之间同步的重要方式,二元信号量与互斥锁十分相像,两者之间的差别在于优先级的继承机制,当另外一个具有更高优先级的任务试图获取同一个互斥锁时,已经获得互斥锁的任务将继承试图获取同一互斥锁的任务的优先级。而信号量没有这种机制,所以二元信号量更适合实现同步,互斥锁更适合实现简单的互斥。需要注意的是互斥锁在使用完资源后必须返还,否则高优先级的任务永远也无法获取互斥锁,低优先级的任务将不会放弃优先级的继承。二元信号量并不需要在得到后立即释放,因此同步操作一般可以通过一个任务或中断持续释放信号量,另一个任务持续获取信号量来实现。

一、简单例程
同样实现间隔一秒按顺序打印A/B/C的测试,这里用信号量来实现。
/* includes. */#include <stdio.h>#include "FreeRTOS.h"#include "task.h"#include "queue.h"#include "stm32f10x.h"#include "semphr.h"#include "portmacro.h"static void prvSetupHardware( void );static void vLEDTask( void *pvParameters );void vPrintTask(void *pvParameters);void vTask1(void *pvparameters);void vTask2(void *pvparameters);void vTask3(void *pvparameters);void vLedInit(void);void UartInit(void);#define LED1_ON() GPIO_SetBits(GPIOB,GPIO_Pin_0)#define LED1_OFF() GPIO_ResetBits(GPIOB,GPIO_Pin_0)SemaphoreHandle_t xSemaphore_1;SemaphoreHandle_t xSemaphore_2;SemaphoreHandle_t xSemaphore_3;int main( void ){    prvSetupHardware();    xSemaphore_1 = xSemaphoreCreateBinary();    xSemaphore_2 = xSemaphoreCreateBinary();    xSemaphore_3 = xSemaphoreCreateBinary();    xTaskCreate( vTask1, "vTask1", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+7, NULL );    xTaskCreate( vTask2, "vTask2", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+6, NULL );    xTaskCreate( vTask3, "vTask3", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+5, NULL );    xTaskCreate( vLEDTask, "LED", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+3, NULL );    vTaskStartScheduler();    return 0;}void vTask1(void *pvparameters){    TickType_t xLastWakeTime;    while(1)    {        if(xSemaphoreTake( xSemaphore_1, portMAX_DELAY ) == pdTRUE)        {            xLastWakeTime = xTaskGetTickCount();            vTaskDelayUntil( &xLastWakeTime, 1000/portTICK_RATE_MS );//            vTaskDelay(1000/portTICK_RATE_MS );            printf("Task1:A\r\n");            xSemaphoreGive( xSemaphore_2);        }    }}void vTask2(void *pvparameters){    TickType_t xLastWakeTime;    while(1)    {        if( xSemaphoreTake( xSemaphore_2, portMAX_DELAY ) == pdTRUE )        {            xLastWakeTime = xTaskGetTickCount();            vTaskDelayUntil( &xLastWakeTime, 1000/portTICK_RATE_MS  );//            vTaskDelay(1000/portTICK_RATE_MS );            printf("Task2:B\r\n");            xSemaphoreGive( xSemaphore_3);        }    }}void vTask3(void *pvparameters){    xSemaphoreGive( xSemaphore_1);    while(1)    {        TickType_t xLastWakeTime;        if( xSemaphoreTake( xSemaphore_3, portMAX_DELAY ) == pdTRUE )        {            xLastWakeTime = xTaskGetTickCount();            vTaskDelayUntil( &xLastWakeTime, 1000/portTICK_RATE_MS  );//            vTaskDelay(1000/portTICK_RATE_MS );            printf("Task3:C\r\n");            xSemaphoreGive( xSemaphore_1);        }    }}void vLEDTask( void *pvParameters ){    TickType_t xLastWakeTime;    for( ;; )    {        LED1_ON();        xLastWakeTime = xTaskGetTickCount();        vTaskDelayUntil( &xLastWakeTime, 1000/portTICK_RATE_MS  );        LED1_OFF();        xLastWakeTime = xTaskGetTickCount();        vTaskDelayUntil( &xLastWakeTime, 1000/portTICK_RATE_MS  );    }}static void prvSetupHardware( void ){    vLedInit();    UartInit();}void vLedInit( void ){    GPIO_InitTypeDef GPIO_InitStructure;    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;    GPIO_Init(GPIOB, &GPIO_InitStructure);}void UartInit(void){     USART_InitTypeDef USART_InitStructure;     GPIO_InitTypeDef GPIO_InitStructure;     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1 ,ENABLE);     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;     GPIO_Init(GPIOA, &GPIO_InitStructure);     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;     GPIO_Init(GPIOA, &GPIO_InitStructure);     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_None;     USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;     USART_Init(USART1, &USART_InitStructure);     USART_Cmd(USART1, ENABLE);}

结果:


二、分析
SemaphoreHandle_t xSemaphore_1;
创建信号量句柄。
xSemaphore_1 = xSemaphoreCreateBinary();
xSemaphore_2 = xSemaphoreCreateBinary();
xSemaphore_3 = xSemaphoreCreateBinary();
创建三个信号量,用于三个任务间的同步。
xSemaphoreGive( xSemaphore_1);
在任务3中先发送信号量给任务1,启动打印过程。
xSemaphoreTake( xSemaphore_1, portMAX_DELAY )
接收信号量,第一个参数为信号量句柄,大二个参数为最大等待时间,接收到则返回pdTRUE,失败则返回pdFALSE。

创建三个信号量,任务3先发送信号量给任务1,任务1接收到信号量过1秒后打印'A',并发送信号量给任务2,以此类推来实现间隔一秒依次打印A/B/C的操作。

三、其他
在V8.0之后的版本,创建信号量时初值为空,在函数中实现了判断,如果为满则清空操作。
在中断中发送信号量时使用xSemaphoreGiveFromISR( xSemaphore, &xHigherPriorityTaskWoken );函数,以FromISR结尾的函数具有保护功能,任务中接收信号量使用xSemaphoreTake( xSemaphore_1, portMAX_DELAY )。

0 0
原创粉丝点击