您的位置:首页 > 其它

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

2017-03-30 19:54 671 查看
来自:http://blog.csdn.net/xukai871105/article/details/43456985

0.前言

嵌入式操作系统中互斥型信号量是任务间资源保护的重要手段。下面结合一个具体例子说明FreeRTOS中的互斥型信号量如何使用。

【相关博文】

FreeRTOS STM32移植笔记

FreeRTOS学习笔记——任务间使用队列同步数据
FreeRTOS学习笔记——二值型信号量
如何在FreeRTOS下实现低功耗——MSP430F5438平台

代码链接】——示例代码存于百度网盘

1.基本说明

互斥型信号量的使用方法如图1所示。在多数情况下,互斥型信号量和二值型信号非常相似,但是从功能上二值型信号量用于同步,而互斥型信号量用于资源保护。互斥型信号量和二值型信号量还有一个最大的区别,互斥型信号量可以有效解决优先级反转现象。



图1 互斥型信号量使用方法

2.参考代码
本例具有两个任务,两个任务都试图通过串口打印内容,此时串口就好比一个“资源”,某个任务使用串口资源时必须保护该资源,使用完串口之后在释放资源。保护和释放动作便对应互斥型信号量的两个基本操作,xSemaphoreTake和xSemaphoreGive。

【代码】

[cpp] view
plain copy







/* 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);

void TaskA( void *pvParameters );

void TaskB( void *pvParameters );

void LedInit(void);

void UART1Init(void);

/* 互斥信号量句柄 */

SemaphoreHandle_t xSemaphore = NULL;

int main(void)

{

/* 初始化硬件平台 */

Setup();

/* 创建互斥信号量 */

xSemaphore = xSemaphoreCreateMutex();

/* 建立任务 */

xTaskCreate( TaskA, "TaskA", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+3, NULL );

xTaskCreate( TaskB, "TaskB", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+4, NULL );

/* 启动OS */

vTaskStartScheduler();

return 0;

}

void TaskA( void *pvParameters )

{

for( ;; )

{

xSemaphoreTake( xSemaphore, portMAX_DELAY );

{

printf("Task A\r\n");

}

xSemaphoreGive( xSemaphore );

vTaskDelay( 2000/portTICK_RATE_MS );

}

}

void TaskB( void *pvParameters )

{

for( ;; )

{

xSemaphoreTake( xSemaphore, portMAX_DELAY );

{

printf("Task B\r\n");

}

xSemaphoreGive( xSemaphore );

vTaskDelay( 1000/portTICK_RATE_MS );

}

}

static void Setup( void )

{

LedInit();

UART1Init();

}

void LedInit( void )

{

GPIO_InitTypeDef GPIO_InitStructure;

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_InitStructure;

USART_InitTypeDef USART_InitStructure;

/* 第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参数

波特率 = 9600

数据长度 = 8

停止位 = 1

校验位 = No

禁止硬件流控(即禁止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_None;

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_InitStructure;

// NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

/* 设定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)

{}

return ch;

}

3.简单说明

SemaphoreHandle_t xSemaphore = NULL;

申明互斥型信号量,在FreeRTOS中二值型信号量和互斥型信号量类型完全相同。

xSemaphore = xSemaphoreCreateMutex();

创建互斥型信号量。

xSemaphoreTake( xSemaphore, portMAX_DELAY ); //Take:拿资源

获得资源的使用权,此处的等待时间为portMAX_DELAY(挂起最大时间),如果任务无法获得资源的使用权,任务会处于挂起状态。

xSemaphoreGive( xSemaphore ); //Give:给出资源

释放资源的使用权。

4.总结

互斥型信号量和二值型信号量使用方法相似,但二值型信号量用于同步而互斥型信号量用于资源保护。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  FreeRTOS