信号量

![[Pasted image 20250518115216.png]]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//创建二值信号量,成功则返回信号量句柄(二值信号量最大只有1个)
SemaphoreHandle_t xSemaphoreCreateBinary(void);

//创建计数信号量,成功则返回信号量句柄
SemaphoreHandle_t xSemaphoreCreateCounting(
UBseType_t uxMaxCount,//最大信号量数
UBseType_t uxInitialCount//初始信号量数
);

//获取一个信号量,如果获得信号量,则返回pdTURE
xSemaphoreTake(
SemaphoreHandle_t xSemaphore,//信号量句柄
TickType_t xTicksTowait//等待时间
);

//释放一个信号量
xSemaphoreGive(SemaphoreHandle_t xSemaphore);//信号量句柄

//删除信号量
xSemaphoreDelete(SemaphoreHandle_t xSemaphore);//信号量句柄

实例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <stdio.h>
#include "freertos/FreeRTOS.h" // FreeRTOS 主头文件
#include "freertos/task.h" // 任务管理
#include "freertos/semphr.h" // 信号量相关
#include "esp_log.h" // ESP-IDF 日志模块

// 定义一个二值信号量句柄
SemaphoreHandle_t bin_sem;

// 任务A:周期性释放信号量
void taskA(void* param)
{
while (1)
{
// 向信号量发送“释放”信号,允许其他任务继续执行
xSemaphoreGive(bin_sem);

// 每隔1秒释放一次
vTaskDelay(pdMS_TO_TICKS(1000));
}
}

// 任务B:等待信号量被释放后执行
void taskB(void *param)
{
while (1)
{
// 尝试获取信号量,如果没拿到就阻塞(无限等待)
if(pdTRUE == xSemaphoreTake(bin_sem, portMAX_DELAY))
{
// 成功获取信号量后打印信息
ESP_LOGI("bin", "task B take binsem success");
}
}
}

// 系统入口函数
void app_main(void)
{
// 创建一个初始为空的二值信号量
bin_sem = xSemaphoreCreateBinary();

// 创建任务A,运行在核心1,优先级为3
xTaskCreatePinnedToCore(taskA, "taskA", 2048, NULL, 3, NULL, 1);

// 创建任务B,运行在核心1,优先级为4(高于任务A)
xTaskCreatePinnedToCore(taskB, "taskB", 2048, NULL, 4, NULL, 1);
}

互斥锁

![[Pasted image 20250518105647.png]]
优先级:A>B>C,
任务C与任务A优先级翻转,先C后B

实例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_log.h"
#include "driver/gpio.h"
#include "dht11.h" // DHT11 传感器头文件,需自行实现或引用

// 定义一个互斥信号量句柄
SemaphoreHandle_t dht11_mutex;

// 任务A,读取温湿度并打印
void taskA(void* param) {
int temp, humidity;
while (1) {
// 请求互斥信号量,独占访问DHT11
xSemaphoreTake(dht11_mutex, portMAX_DELAY);
// 延时500ms,确保DHT11准备好
vTaskDelay(pdMS_TO_TICKS(500));
// 如果成功读取DHT11数据
if (DHT11_StartGet(&temp, &humidity)) {
// 打印温度和湿度(温度以整数形式除以10)
ESP_LOGI("dht11", "taskA-->temp:%d, humidity:%d%%", temp / 10, humidity);
}
// 释放互斥信号量
xSemaphoreGive(dht11_mutex);
// 任务延时1000ms
vTaskDelay(pdMS_TO_TICKS(1000));
}
}

// 任务B,功能与任务A相同
void taskB(void *param) {
int temp, humidity;
while (1) {
xSemaphoreTake(dht11_mutex, portMAX_DELAY);
vTaskDelay(pdMS_TO_TICKS(500));
if (DHT11_StartGet(&temp, &humidity)) {
ESP_LOGI("dht11", "taskB-->temp:%d, humidity:%d%%", temp / 10, humidity);
}
xSemaphoreGive(dht11_mutex);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}

// 主函数
void app_main(void) {
// 创建一个二值信号量(用于互斥访问)
dht11_mutex = xSemaphoreCreateBinary();

// 注意:创建二值信号量后需要先释放一次,否则不能使用
xSemaphoreGive(dht11_mutex);

// 创建任务A,绑定到核心1,优先级为3,堆栈大小为2048字节
xTaskCreatePinnedToCore(taskA, "taskA", 2048, NULL, 3, NULL, 1);

// 创建任务B,绑定到核心1,优先级为3,堆栈大小为2048字节
xTaskCreatePinnedToCore(taskB, "taskB", 2048, NULL, 3, NULL, 1);
}