diff --git "a/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_1/node.md" "b/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_1/node.md" new file mode 100644 index 0000000000000000000000000000000000000000..4290ac40b58a987c0b5b147d94ff84421618abf3 --- /dev/null +++ "b/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_1/node.md" @@ -0,0 +1,11 @@ +# RT-Thread 学习笔记 + +## 1. RT-Thread 简介 +RT-Thread 是一个开源的嵌入式实时操作系统,适用于 ARM Cortex-M、Cortex-A、RISC-V 等多种架构。它具有内核小巧、组件丰富、易于移植等特点。 + +## 2. 基本概念 +- **线程(Thread)**:RT-Thread 的基本执行单元。 +- **调度器(Scheduler)**:负责线程的切换和管理。 +- **信号量、消息队列、邮箱**:用于线程间通信和同步。 +- **定时器**:用于定时任务处理。 + diff --git "a/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_2/min.c" "b/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_2/min.c" new file mode 100644 index 0000000000000000000000000000000000000000..713d50fd00412ac1b8119d67e85fdbde02115491 --- /dev/null +++ "b/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_2/min.c" @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2018-11-06 SummerGift first version + * 2018-11-19 flybreak add stm32f407-atk-explorer bsp + */ + +#include +#include +#include + +/* 线程优先级定义(值越小优先级越高) */ +#define HIGH_PRIORITY 10 // 高优先级线程 +#define MID_PRIORITY 20 // 中优先级线程 +#define LOW_PRIORITY 30 // 低优先级线程 + +/* 线程栈大小 */ +#define THREAD_STACK_SIZE 512 + +/* 时间片 */ +#define THREAD_TIMESLICE 10 // 时间片大小(系统节拍数) + +// 线程计数变量 +static int h_cnt, m_cnt, l_cnt; + +/* 高优先级线程函数 */ +static void high_thread(void *p) +{ + while (1) + { + h_cnt++; + rt_kprintf("H%d\n", h_cnt); + rt_thread_mdelay(100); + } +} + +/* 中优先级线程函数 */ +static void mid_thread(void *p) +{ + while (1) + { + m_cnt++; + rt_kprintf("M%d\n", m_cnt); + rt_thread_mdelay(200); + } +} + +/* 低优先级线程函数 */ +static void low_thread(void *p) +{ + while (1) + { + l_cnt++; + rt_kprintf("L%d\n", l_cnt); + rt_thread_mdelay(500); + } +} + +int main(void) +{ + rt_thread_t tid; // 线程句柄 + + // 高优先级线程 + tid = rt_thread_create("high", high_thread, RT_NULL, 512, HIGH_PRIORITY, 10); + if (tid != RT_NULL) + rt_thread_startup(tid); + else + rt_kprintf("High thread create failed!\n"); + + // 中优先级线程 + tid = rt_thread_create("mid", mid_thread, RT_NULL, 512, MID_PRIORITY, 10); + if (tid != RT_NULL) + rt_thread_startup(tid); + else + rt_kprintf("Mid thread create failed!\n"); + + // 优先级线程 + tid = rt_thread_create("low", low_thread, RT_NULL, 512, LOW_PRIORITY , 10); + if (tid != RT_NULL) + rt_thread_startup(tid); + else + rt_kprintf("Low thread create failed!\n"); + + return RT_EOK; +} diff --git "a/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_2/\347\254\224\350\256\260.txt" "b/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_2/\347\254\224\350\256\260.txt" new file mode 100644 index 0000000000000000000000000000000000000000..d1d50acba4b8ddf5ca89e35a2eaad490ee84b27f --- /dev/null +++ "b/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_2/\347\254\224\350\256\260.txt" @@ -0,0 +1 @@ +lala,lal \ No newline at end of file diff --git "a/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_3/event.c" "b/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_3/event.c" new file mode 100644 index 0000000000000000000000000000000000000000..e25ab31976fbb6504ae875d234b22e9df7c10535 --- /dev/null +++ "b/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_3/event.c" @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +// 定义事件控制块 +static struct rt_event evt; + +// 线程控制块 +static rt_thread_t tid1 = RT_NULL; +static rt_thread_t tid2 = RT_NULL; + +// 线程1:等待事件 +static void thread1_entry(void *parameter) +{ + rt_uint32_t recved; + + while (1) + { + // 等待事件0x01和0x02都同时出现 (AND模式) + rt_err_t result = rt_event_recv(&evt, + 0x01 | 0x02, // 等待的事件掩码 + RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR, // 需要两个事件同时满足并清除 + RT_WAITING_FOREVER, // 一直等待 + &recved); // 实际接收到的事件 + + if (result == RT_EOK) + { + rt_kprintf("Thread1: received events 0x%02X\n", recved); + } + } +} + +// 线程2:发送事件 +static void thread2_entry(void *parameter) +{ + while (1) + { + rt_kprintf("Thread2: sending event 0x01\n"); + rt_event_send(&evt, 0x01); // 发送事件标志0x01 + rt_thread_mdelay(500); + + rt_kprintf("Thread2: sending event 0x02\n"); + rt_event_send(&evt, 0x02); // 发送事件标志0x02 + rt_thread_mdelay(1000); + } +} + +// 初始化函数,应用入口 +int event_sample_init(void) +{ + // 初始化事件 + rt_event_init(&evt, "evt", RT_IPC_FLAG_FIFO); // FIFO调度,先进先出 + + // 创建线程1优先级较高 + tid1 = rt_thread_create("t1", + thread1_entry, RT_NULL, + 512, 20, 10); + if (tid1 != RT_NULL) + rt_thread_startup(tid1); + + // 创建线程2优先级稍低 + tid2 = rt_thread_create("t2", + thread2_entry, RT_NULL, + 512, 21, 10); + if (tid2 != RT_NULL) + rt_thread_startup(tid2); + + return 0; +} + +int main() +{ + event_sample_init(); + /* 主循环 */ + while (1) + { + + rt_thread_mdelay(1000); + } +} diff --git "a/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_3/mailbox.c" "b/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_3/mailbox.c" new file mode 100644 index 0000000000000000000000000000000000000000..aefc401c04987f426c91a83d73797cd07f3c0e7f --- /dev/null +++ "b/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_3/mailbox.c" @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include + +#include + +#include + +#define MAILBOX_SIZE 8 // 邮箱最多能存放 8 条消息 + +static struct rt_mailbox mb; +static char* mb_pool[MAILBOX_SIZE]; // 邮箱实际的消息池:存储的是指针 + +// 小明线程:发送消息 +void thread_xiaoming_entry(void* parameter) +{ + char* messages[] = { + "小明:你好,小王!", + "小明:任务完成了!", + "小明:该吃饭了!", + "小明:早点休息吧!", + }; + + int count = sizeof(messages) / sizeof(messages[0]); + int index = 0; + + while (1) + { + // 每次发送一条消息 + rt_mb_send(&mb, (rt_ubase_t)messages[index]); + rt_kprintf("小明发送了消息:%s\n", messages[index]); + + index = (index + 1) % count; + + rt_thread_mdelay(1000); // 延迟 1 秒 + } +} + +// 小王线程:接收消息 +void thread_xiaowang_entry(void* parameter) +{ + rt_ubase_t msg_ptr; + + while (1) + { + if (rt_mb_recv(&mb, &msg_ptr, RT_WAITING_FOREVER) == RT_EOK) + { + // 将指针转回字符串 + char* received_msg = (char*)msg_ptr; + rt_kprintf("小王收到消息:%s\n", received_msg); + } + } +} + +// 主函数:初始化邮箱和线程 +int main(void) +{ + // 初始化邮箱,名字为 "mbt",大小为 MAILBOX_SIZE + rt_mb_init(&mb, "mbt", (rt_ubase_t*)mb_pool, MAILBOX_SIZE, RT_IPC_FLAG_FIFO); + + // 创建小明线程 + rt_thread_t t1 = rt_thread_create("xiaoming", thread_xiaoming_entry, RT_NULL, + 1024, 20, 10); + if (t1 != RT_NULL) rt_thread_startup(t1); + + // 创建小王线程 + rt_thread_t t2 = rt_thread_create("xiaowang", thread_xiaowang_entry, RT_NULL, + 1024, 21, 10); + if (t2 != RT_NULL) rt_thread_startup(t2); + + return 0; +} diff --git "a/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_3/mutex_sample.c" "b/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_3/mutex_sample.c" new file mode 100644 index 0000000000000000000000000000000000000000..17194ab2e7a048b2287e6d3ffd9428effbc179a4 --- /dev/null +++ "b/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_3/mutex_sample.c" @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +/* 定义LED引脚:PC13 */ +#define LED0_PIN GET_PIN(C, 13) + +/* 共享资源:由互斥量保护的计数器 */ +static int protected_counter = 0; + +/* 线程句柄 */ +rt_thread_t thread1 = RT_NULL; // 使用互斥量的线程1 +rt_thread_t thread2 = RT_NULL; // 使用互斥量的线程2 +rt_thread_t thread3 = RT_NULL; // 使用互斥量的线程3 + +/* 互斥量句柄 */ +static rt_mutex_t mutex = RT_NULL; + +/* 线程1入口:使用互斥量操作protected_counter(+1) */ +static void thread1_entry(void *parameter) +{ + while (1) + { + /* 获取互斥量 */ + rt_mutex_take(mutex, RT_WAITING_FOREVER); + + /* 临界区操作:受保护的计数器 */ + protected_counter++; + rt_kprintf("Thread1 - Protected: %d\n", + protected_counter); + rt_pin_write(LED0_PIN, PIN_LOW); + rt_thread_mdelay(200); + + /* 释放互斥量 */ + rt_mutex_release(mutex); + rt_pin_write(LED0_PIN, PIN_HIGH); + + rt_thread_mdelay(100); + } +} + +/* 线程2入口:使用互斥量操作protected_counter(+1) */ +static void thread2_entry(void *parameter) +{ + while (1) + { + /* 获取互斥量 */ + rt_mutex_take(mutex, RT_WAITING_FOREVER); + + /* 临界区操作:受保护的计数器 */ + protected_counter++; + rt_kprintf("Thread2 - Protected: %d\n", + protected_counter); + rt_pin_write(LED0_PIN, PIN_LOW); + rt_thread_mdelay(200); + + /* 释放互斥量 */ + rt_mutex_release(mutex); + rt_pin_write(LED0_PIN, PIN_HIGH); + + rt_thread_mdelay(100); + } +} + +/* 线程3入口:使用互斥量操作protected_counter(+10) */ +static void thread3_entry(void *parameter) +{ + while (1) + { + rt_mutex_take(mutex, RT_WAITING_FOREVER); + + protected_counter += 10; + rt_kprintf("Thread3 - Protected: %d\n", + protected_counter); + + // 释放互斥量 + rt_mutex_release(mutex); + + rt_thread_mdelay(300); + } +} + +int main(void) +{ + /* 初始化LED引脚 */ + rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT); + rt_pin_write(LED0_PIN, PIN_HIGH); + + /* 创建互斥量 */ + mutex = rt_mutex_create("counter_mutex", RT_IPC_FLAG_FIFO); + if (mutex == RT_NULL) + { + rt_kprintf("Failed to create mutex!\n"); + return -1; + } + rt_kprintf("Mutex created successfully!\n"); + + /* 创建线程1 */ + thread1 = rt_thread_create("thread1", + thread1_entry, + RT_NULL, + 1024, + 10, + 10); + if (thread1 != RT_NULL) rt_thread_startup(thread1); + + /* 创建线程2 */ + thread2 = rt_thread_create("thread2", + thread2_entry, + RT_NULL, + 1024, + 10, + 10); + if (thread2 != RT_NULL) rt_thread_startup(thread2); + + /* 创建线程3 */ + thread3 = rt_thread_create("thread3", + thread3_entry, + RT_NULL, + 1024, + 10, + 10); + if (thread3 != RT_NULL) rt_thread_startup(thread3); + + /* 主循环 */ + while (1) + { + rt_thread_mdelay(1000); + } +} diff --git "a/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_3/queue.c" "b/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_3/queue.c" new file mode 100644 index 0000000000000000000000000000000000000000..a4f938f51f26ea296cc966011eea327bb3bdaefd --- /dev/null +++ "b/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_3/queue.c" @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include + +#include + + +#define THREAD_STACK_SIZE 512 +#define THREAD_PRIORITY 20 +#define THREAD_TICK 10 + +#define QUEUE_MSG_SIZE 32 // 每条消息最多 32 字节 +#define QUEUE_MSG_COUNT 8 // 队列容量 8 条消息 + +static struct rt_messagequeue mq; // 消息队列对象 +static char msg_pool[QUEUE_MSG_SIZE * QUEUE_MSG_COUNT]; // 消息缓冲区 + +static void sender_thread(void *param) +{ +static char msg1[] = "小明:明天开会"; +static char msg2[] = "小明:请查收文件"; +static char msg3[] = "小明:项目进度报告"; +static char msg4[] = "小明:中午聚餐别迟到"; + + char *messages[] = { msg1, msg2, msg3, msg4 }; + int index = 0; + + while (1) + { + // 发送消息到队列 + rt_err_t result = rt_mq_send(&mq, messages[index], rt_strlen(messages[index]) + 1); + if (result == RT_EOK) + { + rt_kprintf("[小明] 已发送邮件:%s\n", messages[index]); + } + else + { + rt_kprintf("[小明] 邮件发送失败:%d\n", result); + } + + index = (index + 1) % (sizeof(messages) / sizeof(messages[0])); + rt_thread_mdelay(1000); // 1秒发送一次 + } +} + +static void receiver_thread(void *param) +{ + char buffer[QUEUE_MSG_SIZE]; + + while (1) + { + // 接收消息(阻塞接收) + rt_err_t result = rt_mq_recv(&mq, buffer, sizeof(buffer), RT_WAITING_FOREVER); + if (result == RT_EOK) + { + rt_kprintf("[小王] 收到邮件:%s\n", buffer); + } + } +} + +int main(void) +{ + // 初始化消息队列 + rt_mq_init(&mq, + "msgq", // 名称 + msg_pool, // 缓冲区 + QUEUE_MSG_SIZE, // 每条消息大小 + sizeof(msg_pool), // 缓冲区总大小 + RT_IPC_FLAG_FIFO); // 先进先出方式 + + // 创建发送线程 + rt_thread_t tid1 = rt_thread_create("sender", sender_thread, RT_NULL, + THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TICK); + if (tid1 != RT_NULL) rt_thread_startup(tid1); + + // 创建接收线程 + rt_thread_t tid2 = rt_thread_create("receiver", receiver_thread, RT_NULL, + THREAD_STACK_SIZE, THREAD_PRIORITY + 1, THREAD_TICK); + if (tid2 != RT_NULL) rt_thread_startup(tid2); + + return 0; +} \ No newline at end of file diff --git "a/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_3/semaphore.c" "b/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_3/semaphore.c" new file mode 100644 index 0000000000000000000000000000000000000000..a29b741ed9278041f18dd2ea2b5ae42854fd9f33 --- /dev/null +++ "b/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_3/semaphore.c" @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2019-03-08 obito0 first version + * 2023-12-03 Meco Man support nano version + */ + +#include +#include +#include +#ifndef RT_USING_NANO +#include +#include +#endif /* RT_USING_NANO */ + +/* 定义LED0引脚:PC13 */ +#define LED0_PIN GET_PIN(C, 13) + +rt_thread_t thread1 = RT_NULL; +rt_thread_t thread2 = RT_NULL; +static rt_sem_t semaphore = RT_NULL; // 用于演示的信号量 + +/* 线程1入口函数:获取信号量并打印信息 */ +static void thread1_entry(void *parameter) +{ + rt_err_t result; + + while (1) + { + // 等待信号量,超时时间设置为5000ms + result = rt_sem_take(semaphore, 5000); + + if (result == RT_EOK) + { + rt_kprintf("Thread 1 acquired semaphore successfully!\n"); + + // 获取成功后控制LED闪烁一次 + rt_pin_write(LED0_PIN, PIN_LOW); // 点亮LED + rt_thread_mdelay(500); + rt_pin_write(LED0_PIN, PIN_HIGH); // 熄灭LED + rt_thread_mdelay(500); + rt_pin_write(LED0_PIN, PIN_LOW); + rt_thread_mdelay(500); + rt_pin_write(LED0_PIN, PIN_HIGH); + rt_kprintf("YES YES YES!\n"); + } + else if (result == RT_ETIMEOUT) + { + rt_kprintf("Thread 1 timeout waiting for semaphore!\n"); + } + else + { + rt_kprintf("Thread 1 failed to acquire semaphore, error code: %d\n", result); + } + + rt_thread_mdelay(100); // 稍微延时,让出CPU + } +} + +/* MSH命令函数:释放信号量 */ +static void release_semaphore(void) +{ + rt_err_t result; + + if (semaphore != RT_NULL) + { + result = rt_sem_release(semaphore); + if (result == RT_EOK) + { + rt_kprintf("Semaphore released successfully!\n"); + } + else + { + rt_kprintf("Failed to release semaphore, error code: %d\n", result); + } + } + else + { + rt_kprintf("Semaphore not initialized!\n"); + } +} +MSH_CMD_EXPORT(release_semaphore, 123); //通过msh释放掉信号量 + +int main(void) +{ + // 初始化LED引脚 + rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT); + rt_pin_write(LED0_PIN, PIN_HIGH); // 初始熄灭LED + + // 创建信号量,初始值为0 + semaphore = rt_sem_create("sem", 0, RT_IPC_FLAG_FIFO); + if (semaphore == RT_NULL) + { + rt_kprintf("Failed to create semaphore!\n"); + return -1; + } + rt_kprintf("Semaphore created successfully!\n"); + + // 创建并启动线程1,用于获取信号量 + thread1 = rt_thread_create("thread1", + thread1_entry, + RT_NULL, + 1024, + 10, + 10); + if (thread1 != RT_NULL) + { + rt_thread_startup(thread1); + rt_kprintf("Thread 1 created and started successfully!\n"); + } + else + { + rt_kprintf("Failed to create Thread 1!\n"); + rt_sem_delete(semaphore); + return -1; + } + + // 主循环保持系统运行 + while (1) + { + rt_thread_mdelay(1000); // 主线程延时 + } +} diff --git "a/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_3/signal.c" "b/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_3/signal.c" new file mode 100644 index 0000000000000000000000000000000000000000..6b485d6fd0b4021eb58d8540c7937e369edb2fcd --- /dev/null +++ "b/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_3/signal.c" @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include + +#include + +#define THREAD_STACK_SIZE 512 +#define THREAD_PRIORITY 10 +#define THREAD_TIMESLICE 10 + +static rt_sem_t temp_sem = RT_NULL; // 信号量句柄 +static int temperature = 25; // 初始温度25度 + +// 模拟温度采集线程 +static void temp_sensor_thread(void *param) +{ + while (1) + { + rt_thread_mdelay(1000); // 延时1秒模拟采样间隔 + temperature++; + + rt_kprintf("当前温度: %d°C\n", temperature); + + if (temperature >= 30) + { + // 温度达到30度,发送信号量通知开空调 + rt_sem_release(temp_sem); + } + } +} + +// 空调控制线程,等待信号量开启空调 +static void ac_control_thread(void *param) +{ + while (1) + { + // 等待信号量,无限等待 + rt_sem_take(temp_sem, RT_WAITING_FOREVER); + + rt_kprintf("温度达到30度,开启空调!\n"); + + // 模拟空调开启后温度下降 + temperature = 25; + } +} + +int main(void) +{ + // 创建信号量,初始计数为0 + temp_sem = rt_sem_create("temp_sem", 0, RT_IPC_FLAG_FIFO); + if (temp_sem == RT_NULL) + { + rt_kprintf("信号量创建失败!\n"); + return -1; + } + + // 创建线程 + rt_thread_t sensor_tid = rt_thread_create("temp_sensor", + temp_sensor_thread, RT_NULL, + THREAD_STACK_SIZE, + THREAD_PRIORITY, THREAD_TIMESLICE); + rt_thread_t ac_tid = rt_thread_create("ac_ctrl", + ac_control_thread, RT_NULL, + THREAD_STACK_SIZE, + THREAD_PRIORITY - 1, THREAD_TIMESLICE); + + if (sensor_tid != RT_NULL) + rt_thread_startup(sensor_tid); + if (ac_tid != RT_NULL) + rt_thread_startup(ac_tid); + + return 0; +} \ No newline at end of file diff --git "a/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_3/\347\254\224\350\256\260.md" "b/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_3/\347\254\224\350\256\260.md" new file mode 100644 index 0000000000000000000000000000000000000000..ad302f13807a6351f19008dd7281f69e6c814582 --- /dev/null +++ "b/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_3/\347\254\224\350\256\260.md" @@ -0,0 +1,379 @@ + +*** + +# RT-Thread IPC 组件学习笔记 + +## 一、核心组件概览 + +RT-Thread 中的 IPC(进程 / 线程间通信)组件,用于解决 **多线程协作** 问题,核心组件包括: + + + +| 组件类型 | 核心作用 | 类比模型 | +| -------------- | -------------------------- | --------------- | +| 信号量(Semaphore) | 控制资源访问权限(如 “允许 3 个线程同时访问”) | 抢票模型(限制并发数) | +| 互斥量(Mutex) | 保护共享资源(临界区互斥) | 门锁(同一时间仅一人进入) | +| 事件(Event) | 多条件触发、异步通知 | 开关(满足条件后触发) | +| 邮箱(Mailbox) | 传递指针 / 地址(轻量级消息传递) | 快递柜(存地址,自己取内容) | +| 消息队列(Queue) | 传递数据内容(支持多字节、结构体) | 邮局(拷贝数据,直接传递内容) | + +## 二、组件对比速查表 + + + +| 组件 | 核心作用 | 典型场景 | 数据传递方式 | 关键特点 | +| -------- | ----------------- | ----------------- | ---------- | ------------------- | +| **信号量** | 控制资源数量(如 “3 个资源”) | 线程同步、限流(如连接池) | 无实际数据传递 | 支持计数,适合 “生产者 - 消费者” | +| **互斥量** | 保护共享资源(临界区) | 多线程访问同一变量 / 硬件 | 无数据传递 | 支持优先级继承,防优先级翻转 | +| **事件** | 多条件触发、异步通知 | 线程等待 “多个条件满足” | 事件位(二进制标志) | 无状态,支持 “或 / 与” 等待 | +| **邮箱** | 传递指针(地址) | 线程间传递简单数据 / 结构体地址 | 指针传递 | 轻量级,需手动管理内存 | +| **消息队列** | 传递数据内容(值传递) | 线程间传递字符串、结构体内容 | 拷贝数据到队列缓冲区 | 支持 FIFO,无需手动管理内存 | + +## 三、关键 API 与用法 + +### 1. 信号量(Semaphore) + +**作用**:控制资源并发访问数(如 “最多 3 个线程同时访问”)。 + + + +* **创建 / 初始化**: + + + +``` +// 动态创建(计数=3,FIFO 等待) + +rt\_sem\_t sem = rt\_sem\_create("sem", 3, RT\_IPC\_FLAG\_FIFO); + +// 静态初始化(需提前定义 rt\_sem\_t sem;) + +rt\_sem\_init(\&sem, "sem", 3, RT\_IPC\_FLAG\_FIFO); +``` + + + +* **获取 / 释放资源**: + + + +``` +rt\_sem\_take(sem, RT\_WAITING\_FOREVER); // 申请资源(计数-1,永久等待) + +rt\_sem\_release(sem); // 释放资源(计数+1) +``` + +### 2. 互斥量(Mutex) + +**作用**:保护共享资源(如全局变量、硬件寄存器),防止多线程冲突。 + + + +* **创建 / 初始化**: + + + +``` +// 动态创建(FIFO 等待) + +rt\_mutex\_t mutex = rt\_mutex\_create("mutex", RT\_IPC\_FLAG\_FIFO); + +// 静态初始化(需提前定义 rt\_mutex\_t mutex;) + +rt\_mutex\_init(\&mutex, "mutex", RT\_IPC\_FLAG\_FIFO); +``` + + + +* **加锁 / 解锁**: + + + +``` +rt\_mutex\_take(mutex, RT\_WAITING\_FOREVER); // 加锁(进入临界区) + +rt\_mutex\_release(mutex); // 解锁(退出临界区) +``` + +### 3. 事件(Event) + +**作用**:线程等待 “多个条件任意 / 全部满足”(如 “按键按下 **或** 定时器超时”)。 + + + +* **创建 / 初始化**: + + + +``` +// 动态创建(FIFO 等待) + +rt\_event\_t event = rt\_event\_create("event", RT\_IPC\_FLAG\_FIFO); + +// 静态初始化(需提前定义 rt\_event\_t event;) + +rt\_event\_init(\&event, "event", RT\_IPC\_FLAG\_FIFO); +``` + + + +* **发送 / 等待事件**: + + + +``` +rt\_event\_send(event, 0x01 | 0x02); // 发送事件位(0x01、0x02) + +// 等待 0x01 或 0x02 事件(满足任意一个则唤醒) + +rt\_event\_recv(event, 0x01 | 0x02, RT\_EVENT\_OR, RT\_WAITING\_FOREVER, \&recved); +``` + +### 4. 邮箱(Mailbox) + +**作用**:轻量级传递指针 / 地址(适合小数据、需手动管理内存)。 + + + +* **创建 / 初始化**: + + + +``` +// 动态创建(队列长度=10,FIFO 等待) + +rt\_mailbox\_t mbox = rt\_mailbox\_create("mbox", 10, RT\_IPC\_FLAG\_FIFO); + +// 静态初始化(需提前定义 msg\_pool 缓冲区) + +rt\_mailbox\_init(\&mbox, "mbox", msg\_pool, MSG\_SIZE, sizeof(msg\_pool), RT\_IPC\_FLAG\_FIFO); +``` + + + +* **发送 / 接收指针**: + + + +``` +rt\_mailbox\_send(mbox, (rt\_uint32\_t)\&data); // 发送数据地址 + +rt\_mailbox\_recv(mbox, \&msg, RT\_WAITING\_FOREVER); // 接收地址 +``` + +### 5. 消息队列(Queue) + +**作用**:可靠传递数据内容(自动拷贝数据,适合字符串、结构体)。 + + + +* **创建 / 初始化**: + + + +``` +// 动态创建(单条消息大小=MSG\_SIZE,队列长度=10,FIFO 等待) + +rt\_mq\_t mq = rt\_mq\_create("mq", MSG\_SIZE, 10, RT\_IPC\_FLAG\_FIFO); + +// 静态初始化(需提前定义 msg\_pool 缓冲区) + +rt\_mq\_init(\&mq, "mq", msg\_pool, MSG\_SIZE, sizeof(msg\_pool), RT\_IPC\_FLAG\_FIFO); +``` + + + +* **发送 / 接收数据**: + + + +``` +rt\_mq\_send(mq, \&data, sizeof(data)); // 拷贝数据到队列 + +// 从队列拷贝数据到 recv\_buf + +rt\_mq\_recv(mq, \&recv\_buf, sizeof(recv\_buf), RT\_WAITING\_FOREVER); +``` + +## 四、典型场景实践 + +### 1. 信号量:资源限流 + +**需求**:最多允许 3 个线程同时访问某共享资源(如网络连接池)。 + + + +``` +rt\_sem\_t sem = rt\_sem\_create("sem", 3, RT\_IPC\_FLAG\_FIFO); // 初始化 3 个资源 + +void thread\_entry(void \*arg) { + + rt\_sem\_take(sem, RT\_WAITING\_FOREVER); // 申请资源(计数-1) + + // 访问共享资源(如网络连接)... + + rt\_sem\_release(sem); // 释放资源(计数+1) + +} +``` + +### 2. 互斥量:保护共享变量 + +**需求**:多线程安全修改全局变量 `count`。 + + + +``` +rt\_mutex\_t mutex = rt\_mutex\_create("mutex", RT\_IPC\_FLAG\_FIFO); + +int count = 0; + +void thread\_entry(void \*arg) { + + rt\_mutex\_take(mutex, RT\_WAITING\_FOREVER); // 加锁 + + count++; // 临界区操作(安全修改) + + rt\_mutex\_release(mutex); // 解锁 + +} +``` + +### 3. 事件:多条件触发 + +**需求**:线程等待 “按键按下” **或** “定时器超时” 事件。 + + + +``` +rt\_event\_t event = rt\_event\_create("event", RT\_IPC\_FLAG\_FIFO); + +// 线程 1:等待事件 + +void thread\_wait(void \*arg) { + + rt\_uint32\_t recved; + + // 等待 0x01(按键)或 0x02(定时器)事件 + + rt\_event\_recv(event, 0x01 | 0x02, RT\_EVENT\_OR, RT\_WAITING\_FOREVER, \&recved); + + if (recved & 0x01) rt\_kprintf("按键按下\n"); + + if (recved & 0x02) rt\_kprintf("定时器超时\n"); + +} + +// 线程 2:发送事件 + +void thread\_send(void \*arg) { + + rt\_event\_send(event, 0x01); // 按键按下事件 + + rt\_event\_send(event, 0x02); // 定时器超时事件 + +} +``` + +### 4. 邮箱:传递指针 + +**需求**:线程间传递结构体地址(轻量级通信)。 + + + +``` +struct Data { int id; char msg\[10]; }; + +struct Data data = {1, "hello"}; + +rt\_mailbox\_t mbox = rt\_mailbox\_create("mbox", 10, RT\_IPC\_FLAG\_FIFO); + +// 发送线程 + +void thread\_send(void \*arg) { + + rt\_mailbox\_send(mbox, (rt\_uint32\_t)\&data); // 发送结构体地址 + +} + +// 接收线程 + +void thread\_recv(void \*arg) { + + struct Data \*recv\_data; + + rt\_mailbox\_recv(mbox, \&recv\_data, RT\_WAITING\_FOREVER); // 接收地址 + + rt\_kprintf("ID: %d, Msg: %s\n", recv\_data->id, recv\_data->msg); + +} +``` + +### 5. 消息队列:传递数据内容 + +**需求**:线程间传递字符串(自动拷贝,安全可靠)。 + + + +``` +char send\_buf\[] = "RT-Thread"; + +rt\_mq\_t mq = rt\_mq\_create("mq", sizeof(send\_buf), 10, RT\_IPC\_FLAG\_FIFO); + +// 发送线程 + +void thread\_send(void \*arg) { + + rt\_mq\_send(mq, send\_buf, sizeof(send\_buf)); // 拷贝数据到队列 + +} + +// 接收线程 + +void thread\_recv(void \*arg) { + + char recv\_buf\[20]; + + rt\_mq\_recv(mq, recv\_buf, sizeof(recv\_buf), RT\_WAITING\_FOREVER); // 拷贝数据 + + rt\_kprintf("Received: %s\n", recv\_buf); + +} +``` + +## 五、避坑指南 + + + +1. **互斥量 vs 信号量**: + +* 互斥量**必须由同一线程释放**(其他线程释放会导致错误);信号量**可由任意线程释放**。 + +* 互斥量适合保护临界区(如全局变量),信号量适合控制资源数量(如连接池)。 + +1. **邮箱的内存管理**: + +* 邮箱传递的是**指针**,需确保发送后数据未被销毁(建议用**静态变量、全局变量**或**动态分配内存**)。 + +1. **消息队列的拷贝机制**: + +* 消息队列会**拷贝数据**到队列缓冲区,发送后修改原数据**不影响已发送的消息**(数据独立)。 + +1. **事件的无状态性**: + +* 事件发送后如果没有线程等待,事件会**直接丢失**(需注意异步通知的可靠性,可结合信号量增强可靠性)。 + +## 六、总结 + + + +| 需求场景 | 推荐组件 | 关键优势 | +| ------------ | ---- | ----------------- | +| 简单同步(如资源计数) | 信号量 | 支持计数,灵活控制并发 | +| 临界区保护(如全局变量) | 互斥量 | 支持优先级继承,防优先级翻转 | +| 多条件触发 / 异步通知 | 事件 | 无状态,支持 “或 / 与” 等待 | +| 轻量级指针传递 | 邮箱 | 高效,适合小数据 | +| 可靠的数据内容传递 | 消息队列 | 自动拷贝,无需手动管理内存 | + +这些组件是 RT-Thread 多线程编程的基石,**结合实际场景选择合适的 IPC 机制**,可高效解决线程协作问题! +