1.信號(hào)量簡(jiǎn)介
信號(hào)量常用于控制對(duì)共享資源的訪問(wèn)與任務(wù)同步。資源共享例如火車票售賣,所有用戶都可以進(jìn)行買票和退票操作,對(duì)于所用用戶來(lái)說(shuō)火車票就是共享資源,當(dāng)賣出一張票信號(hào)量減一、有人退一張票信號(hào)量加一,這種案例就屬于計(jì)數(shù)型信號(hào)量。常用的信號(hào)量還有二值信號(hào)量。例如使用公共電話,同一時(shí)間只能一個(gè)人使用,此時(shí)電話就只有兩種狀態(tài):使用或者未使用,若將電話這兩個(gè)狀態(tài)作為信號(hào)量的話則就是二值信號(hào)量。
信號(hào)量的另一應(yīng)用場(chǎng)合就是任務(wù)同步。用于任務(wù)與任務(wù)間或任務(wù)與中斷間同步。在執(zhí)行中斷服務(wù)函數(shù)時(shí)可以向任務(wù)發(fā)送信號(hào)量通知任務(wù)該事件發(fā)生了,在退出中斷服務(wù)函數(shù)以后任務(wù)調(diào)度器的調(diào)度下同步的任務(wù)就會(huì)執(zhí)行。因?yàn)橹袛喾?wù)函數(shù)需要快進(jìn)快出,代碼簡(jiǎn)潔,一般在中斷服務(wù)函數(shù)中設(shè)置標(biāo)志位,然后在其它地方根據(jù)標(biāo)志位來(lái)實(shí)現(xiàn)具體功能,在FreeRTOS中就可使用信號(hào)量來(lái)完成此功能。
2.二值信號(hào)量
二值信號(hào)量通常用于互斥訪問(wèn)或同步,二值信號(hào)量和互斥信號(hào)量非常相似,但還是有細(xì)微差別,互斥信號(hào)量擁有優(yōu)先級(jí)繼承機(jī)制,二值信號(hào)沒(méi)有。因此二值信量適合于同步(任務(wù)與任務(wù)、任務(wù)與中斷同步),而互斥信號(hào)量適合于簡(jiǎn)單的互斥訪問(wèn)。
二值信號(hào)量其實(shí)就是一個(gè)只有一個(gè)隊(duì)列項(xiàng)的隊(duì)列,這個(gè)特殊的隊(duì)列要么是滿的,要么是空的。使用二值信號(hào)量必須包含semphr.h頭文件。
函數(shù)名 | 功能 |
vSemaphoreCreateBinary() | 動(dòng)態(tài)創(chuàng)建二值信號(hào)量,老版FreeRTOS創(chuàng)建二值信號(hào)量函數(shù) |
xSemaphoreCreateBinary() | 動(dòng)態(tài)創(chuàng)建二值信號(hào)量,新版FreeRTOS創(chuàng)建二值信號(hào)量函數(shù) |
xSemaphoreCreateBinaryStatic() | 靜態(tài)創(chuàng)建二值信號(hào)量 |
3.二值信號(hào)量應(yīng)用示例
此示例通過(guò)創(chuàng)建3個(gè)任務(wù),start_task、LED0_task、Semaphore_task。通過(guò)任務(wù)start_task創(chuàng)建另外兩個(gè)任務(wù)。
#include "freeRTOS.h"
#include "task.h"http://創(chuàng)建相關(guān)頭文件
#include "queue.h"http://消息隊(duì)列相關(guān)頭文件
#include "semphr.h"http://信號(hào)量相關(guān)頭文件
#define START_TASK_PRIO 1 //任務(wù)優(yōu)先級(jí)
#define START_STK_SIZE 128 //任務(wù)堆棧大小
TaskHandle_t StartTask_Handler; //任務(wù)句柄
void start_task(void *pvParameters);//任務(wù)函數(shù)
#define LED0_TASK_PRIO 2 //任務(wù)優(yōu)先級(jí),數(shù)字越大優(yōu)先級(jí)越高
#define LED0_STK_SIZE 128 //任務(wù)堆棧大小
TaskHandle_t LED0Task_Handler; //任務(wù)句柄
void LED0_task(void); //任務(wù)函數(shù)
#define Semaphore_TASK_PRIO 2 //任務(wù)優(yōu)先級(jí)
#define Semaphore_STK_SIZE 128 //任務(wù)堆棧大小
TaskHandle_t SemaphoreTask_Handler; //任務(wù)句柄
void Semaphore_task(void); //任務(wù)函數(shù)
主函數(shù)
int main()
{
Beep_Init();//蜂鳴器初始化
LED_Init();//LED初始化
KEY_Init();
Usart1_Init(115200);//串口1初始化
TIMx_Init(TIM2,72,20000);//20ms
TIMx_Init(TIM3,7200,5000);//500ms
TIM3->CR1|=1<<0;
/*創(chuàng)建任務(wù)*/
xTaskCreate((TaskFunction_t)start_task,//任務(wù)函數(shù)
(const char *)"start_task",//任務(wù)名稱
(uint16_t)START_STK_SIZE,//堆棧大小
NULL, //傳遞給任務(wù)函數(shù)的參數(shù)
(UBaseType_t)START_TASK_PRIO,//任務(wù)優(yōu)先級(jí)
(TaskHandle_t *)&StartTask_Handler//任務(wù)句柄
);
vTaskStartScheduler(); //開啟任務(wù)調(diào)度
}
開始任務(wù)
SemaphoreHandle_t BinarySemaphore; //二值信號(hào)量句柄
/*開始任務(wù)函數(shù)*/
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); //進(jìn)入臨界區(qū)
/*創(chuàng)建二值信號(hào)量*/
BinarySemaphore=xSemaphoreCreateBinary();//創(chuàng)建二值信號(hào)量
//創(chuàng)建LED0任務(wù)
xTaskCreate( (TaskFunction_t )LED0_task,//任務(wù)函數(shù)
(const char *)"LED0_task",//任務(wù)名稱
(uint16_t)LED0_STK_SIZE,//堆棧大小
NULL, //傳遞給任務(wù)函數(shù)的參數(shù)
(UBaseType_t )LED0_TASK_PRIO,//任務(wù)優(yōu)先級(jí)
(TaskHandle_t *)&LED0Task_Handler);//任務(wù)句柄
xTaskCreate( (TaskFunction_t )Semaphore_task,//任務(wù)函數(shù)
(const char *)"Semaphore_task",//任務(wù)名稱
(uint16_t )Semaphore_STK_SIZE,//堆棧大小
NULL, //傳遞給任務(wù)函數(shù)的參數(shù)
(UBaseType_t )Semaphore_TASK_PRIO,//任務(wù)優(yōu)先級(jí)
(TaskHandle_t *)&SemaphoreTask_Handler);//任務(wù)句柄
vTaskDelete(StartTask_Handler); //刪除開始任務(wù)
taskEXIT_CRITICAL(); //退出臨界區(qū)
}
LED0任務(wù),此任務(wù)1000ms進(jìn)行LED翻轉(zhuǎn)
void LED0_task(void)
{
while(1)
{
LED1=!LED1;
Delay_Ms(1000);
}
}
Semaphore函數(shù),此任務(wù)函數(shù)獲取信號(hào)量,處理串口1中斷接收數(shù)據(jù)。
void Semaphore_task(void)//任務(wù)函數(shù)
{
BaseType_t err=pdFALSE;
while(1)
{
if(BinarySemaphore!=NULL)
{
err=xSemaphoreTake(BinarySemaphore,portMAX_DELAY); //獲取信號(hào)量
if(err==pdTRUE)
{
usart1_rx_buff[usart1_cnt]='\0';
printf("rx=%s\r\n",usart1_rx_buff);
usart1_cnt=0;
}
}
}
}
串口中斷服務(wù)函數(shù)
#include "FreeRTOS.h" //FreeRTOS使用
#include "task.h"
#include "queue.h" //消息隊(duì)列
#include "semphr.h"http://信號(hào)量
u8 usart1_rx_buff[1024];//串口1接收數(shù)據(jù)緩沖區(qū)
u16 usart1_cnt=0;//保存數(shù)組下班
u8 usart1_flag;//接收完成標(biāo)志符
extern SemaphoreHandle_t BinarySemaphore; //二值信號(hào)量句柄
void USART1_IRQHandler(void)
{
u8 c;
BaseType_t pxHigherPriorityTaskWoken;//保存任務(wù)是否需要切換的值
if(USART1->SR&1<<5)
{
c=USART1->DR;
if(usart1_flag==0)//判斷上一次數(shù)據(jù)是否處理完成
{
if(usart1_cnt<1024)
{
usart1_rx_buff[usart1_cnt++]=c;
TIM2->CNT=0;//清空計(jì)數(shù)器值
TIM2->CR1|=1<<0;//開啟定時(shí)
}
else usart1_flag=1;
}
}
if( usart1_flag && (BinarySemaphore!=NULL))
{
//釋放信號(hào)量
xSemaphoreGiveFromISR(BinarySemaphore,&pxHigherPriorityTaskWoken);
//如果需要的話,進(jìn)行一次上下文切換
portYIELD_FROM_ISR(pxHigherPriorityTaskWoken);
usart1_flag=0;
}
}
定時(shí)器中斷服務(wù)函數(shù)
#include "FreeRTOS.h" //FreeRTOS使用
#include "semphr.h"
extern SemaphoreHandle_t BinarySemaphore; //二值信號(hào)量句柄//消息隊(duì)列句柄
void TIM2_IRQHandler(void)
{
BaseType_t pxHigherPriorityTaskWoken;//保存任務(wù)是否需要切換的值
if(TIM2->SR&1<<0)//判斷是否為更新中斷
{
TIM2->CR1&=~(1<<0);//關(guān)閉定時(shí)器2
usart1_flag=1;
if( usart1_flag && (BinarySemaphore!=NULL))
{
//釋放信號(hào)量
xSemaphoreGiveFromISR(BinarySemaphore,&pxHigherPriorityTaskWoken);
//如果需要的話,進(jìn)行一次上下文切換
portYIELD_FROM_ISR(pxHigherPriorityTaskWoken);
usart1_flag=0;
}
}
TIM2->SR=0;//清除標(biāo)志位
}
實(shí)現(xiàn)效果
-
操作系統(tǒng)
+關(guān)注
關(guān)注
37文章
6892瀏覽量
123742 -
STM32
+關(guān)注
關(guān)注
2272文章
10923瀏覽量
357565 -
RTOS
+關(guān)注
關(guān)注
22文章
819瀏覽量
119887 -
FreeRTOS
+關(guān)注
關(guān)注
12文章
484瀏覽量
62395 -
信號(hào)量
+關(guān)注
關(guān)注
0文章
53瀏覽量
8373
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論