From c3c2126553f480ac9782d7c8e0c7bab3aa4c353a Mon Sep 17 00:00:00 2001 From: luyu121 <319931274@qq.com> Date: Mon, 21 Jul 2025 21:54:30 +0800 Subject: [PATCH 1/9] =?UTF-8?q?node=20=E6=96=87=E4=BB=B6=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lu_jing_han/node.md" | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 "2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/node.md" diff --git "a/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/node.md" "b/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/node.md" new file mode 100644 index 0000000..4290ac4 --- /dev/null +++ "b/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/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)**:负责线程的切换和管理。 +- **信号量、消息队列、邮箱**:用于线程间通信和同步。 +- **定时器**:用于定时任务处理。 + -- Gitee From 81b8727d4e53cba3268dad5f6f7d2d942eec73b1 Mon Sep 17 00:00:00 2001 From: luyu121 <319931274@qq.com> Date: Tue, 22 Jul 2025 21:03:37 +0800 Subject: [PATCH 2/9] =?UTF-8?q?=E7=AC=94=E8=AE=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lu_jing_han/day_2/\347\254\224\350\256\260.txt" | 1 + 1 file changed, 1 insertion(+) create mode 100644 "2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_2/\347\254\224\350\256\260.txt" 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 0000000..533805d --- /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 \ No newline at end of file -- Gitee From 428b4239058e76ecb29def90d6c838108030af05 Mon Sep 17 00:00:00 2001 From: luyu121 <319931274@qq.com> Date: Tue, 22 Jul 2025 21:13:15 +0800 Subject: [PATCH 3/9] =?UTF-8?q?=E6=8F=90=E4=BA=A4=20day=5F2=20=E9=87=8C?= =?UTF-8?q?=E7=9A=84=20min.c=20=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lu_jing_han/day_2/min.c" | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 "2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_2/min.c" 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 0000000..e69de29 -- Gitee From 7df010b8b1ce5db7d7e4363b8eed80a6820cf41e Mon Sep 17 00:00:00 2001 From: luyu121 <319931274@qq.com> Date: Tue, 22 Jul 2025 21:20:44 +0800 Subject: [PATCH 4/9] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=9B=AE=E5=BD=95?= =?UTF-8?q?=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lu_jing_han/day_1/node.md" | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 "2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_1/node.md" 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 0000000..4290ac4 --- /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)**:负责线程的切换和管理。 +- **信号量、消息队列、邮箱**:用于线程间通信和同步。 +- **定时器**:用于定时任务处理。 + -- Gitee From c41edbb944a857dbde1f6ae6a7348859604e4f4e Mon Sep 17 00:00:00 2001 From: luyu121 <319931274@qq.com> Date: Tue, 22 Jul 2025 21:25:59 +0800 Subject: [PATCH 5/9] =?UTF-8?q?=E5=B0=86=20node.md=20=E7=A7=BB=E5=8A=A8?= =?UTF-8?q?=E5=88=B0=20day=5F1=20=E6=96=87=E4=BB=B6=E5=A4=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lu_jing_han/node.md" | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 "2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/node.md" diff --git "a/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/node.md" "b/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/node.md" deleted file mode 100644 index 4290ac4..0000000 --- "a/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/node.md" +++ /dev/null @@ -1,11 +0,0 @@ -# RT-Thread 学习笔记 - -## 1. RT-Thread 简介 -RT-Thread 是一个开源的嵌入式实时操作系统,适用于 ARM Cortex-M、Cortex-A、RISC-V 等多种架构。它具有内核小巧、组件丰富、易于移植等特点。 - -## 2. 基本概念 -- **线程(Thread)**:RT-Thread 的基本执行单元。 -- **调度器(Scheduler)**:负责线程的切换和管理。 -- **信号量、消息队列、邮箱**:用于线程间通信和同步。 -- **定时器**:用于定时任务处理。 - -- Gitee From e3081fac4a7e729fc931ce5df989db2aca358711 Mon Sep 17 00:00:00 2001 From: luyu121 <319931274@qq.com> Date: Wed, 23 Jul 2025 00:38:49 +0800 Subject: [PATCH 6/9] =?UTF-8?q?=E7=AC=AC=E4=BA=8C=E6=AC=A1=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lu_jing_han/day_2/min.c" | 89 +++++++++++++++++++ .../day_2/\347\254\224\350\256\260.txt" | 55 +++++++++++- 2 files changed, 143 insertions(+), 1 deletion(-) 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" index e69de29..713d50f 100644 --- "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" @@ -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" index 533805d..1632fe0 100644 --- "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" @@ -1 +1,54 @@ -lala \ No newline at end of file +一、线程创建(动态 & 静态)​ +(一)动态创建​ +函数:rt_thread_create​ +特点:​ +从堆中分配线程控制块、栈空间,灵活但依赖堆内存。​ +示例:​ +rt_thread_t tid = rt_thread_create ("thread_name",​ +thread_entry,​ +RT_NULL,​ +STACK_SIZE,​ +PRIORITY,​ +TIMESLICE);​ +if (tid != RT_NULL) rt_thread_startup (tid);​ +适用场景:内存充足、需灵活创建 / 销毁线程的场景(如动态任务加载)。​ +(二)静态创建​ +函数:rt_thread_init + rt_thread_startup​ +特点:​ +需预先定义线程控制块、栈数组(用静态内存),不依赖堆。​ +示例:​ +struct rt_thread static_thread;​ +rt_uint8_t static_stack [STACK_SIZE];​ +rt_thread_init (&static_thread, "static_th",​ +thread_entry, RT_NULL,​ +static_stack, STACK_SIZE,​ +PRIORITY, TIMESLICE);​ +rt_thread_startup (&static_thread);​ +适用场景:内存紧张、对内存分配确定性要求高的场景(如裸机移植、关键任务)。​ +二、内核定时器(软 / 硬定时器)​ +(一)软件定时器​ +原理:由 RT-Thread 内核模拟,依赖系统时钟节拍(rt_tick)。​ + +特点:精度中等(受线程调度影响),灵活、资源占用小。​ +(二)硬件定时器​ +原理:基于芯片硬件定时器外设,由硬件触发中断。​ + +特点:精度极高(微秒级),但需占用硬件资源,适合高精度定时(如 PWM 输出、编码器计数)。​ +三、优先级与调度​ +(一)优先级​ +范围:RT-Thread 中优先级 0(最高)~ RT_THREAD_PRIORITY_MAX(默认 255,最低 )。​ +作用:高优先级线程可抢占低优先级线程(优先级翻转需用互斥锁解决)。​ +示例:​ +#define HIGH_PRIO 10​ +#define LOW_PRIO 30​ +// 高优先级线程可打断低优先级线程运行​ +(二)时间片​ +原理:同优先级线程轮流执行,时间片决定单次执行时长(单位:系统节拍 )。​ +设置:rt_thread_create 的 timeslice 参数(如 10 表示 10 个节拍时长 )。​ +效果:同优先级线程按时间片 “轮流执行”,避免单个线程长期占用 CPU。​ +四、总结​ +知识点 核心要点 适用场景​ +线程动态创建 堆分配、灵活创建,依赖 rt_thread_create 需动态管理线程(如任务加载)​ +线程静态创建 静态内存、确定性高,依赖 rt_thread_init + rt_thread_startup 内存紧张、关键任务​​ +优先级与时间片 优先级决定抢占,时间片决定同优先级线程轮流执行 所有多线程场景,需平衡实时性与公平性​ +通过理解线程创建方式、定时器类型、优先级调度,可高效构建 RT-Thread 多任务系统,适配不同场景需求(如实时控制、低功耗定时)。 \ No newline at end of file -- Gitee From 89ee3e4b09b2b6659012117ef26f55d8216d3a9c Mon Sep 17 00:00:00 2001 From: luyu121 <319931274@qq.com> Date: Wed, 23 Jul 2025 01:07:00 +0800 Subject: [PATCH 7/9] =?UTF-8?q?=E7=AC=AC=E4=BA=8C=E6=AC=A1=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A=EF=BC=9A=E6=8F=90=E4=BA=A4=20min.c=20=E5=92=8C?= =?UTF-8?q?=E7=AC=94=E8=AE=B0.txt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../day_2/\347\254\224\350\256\260.txt" | 55 +------------------ 1 file changed, 1 insertion(+), 54 deletions(-) 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" index 1632fe0..d1d50ac 100644 --- "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" @@ -1,54 +1 @@ -一、线程创建(动态 & 静态)​ -(一)动态创建​ -函数:rt_thread_create​ -特点:​ -从堆中分配线程控制块、栈空间,灵活但依赖堆内存。​ -示例:​ -rt_thread_t tid = rt_thread_create ("thread_name",​ -thread_entry,​ -RT_NULL,​ -STACK_SIZE,​ -PRIORITY,​ -TIMESLICE);​ -if (tid != RT_NULL) rt_thread_startup (tid);​ -适用场景:内存充足、需灵活创建 / 销毁线程的场景(如动态任务加载)。​ -(二)静态创建​ -函数:rt_thread_init + rt_thread_startup​ -特点:​ -需预先定义线程控制块、栈数组(用静态内存),不依赖堆。​ -示例:​ -struct rt_thread static_thread;​ -rt_uint8_t static_stack [STACK_SIZE];​ -rt_thread_init (&static_thread, "static_th",​ -thread_entry, RT_NULL,​ -static_stack, STACK_SIZE,​ -PRIORITY, TIMESLICE);​ -rt_thread_startup (&static_thread);​ -适用场景:内存紧张、对内存分配确定性要求高的场景(如裸机移植、关键任务)。​ -二、内核定时器(软 / 硬定时器)​ -(一)软件定时器​ -原理:由 RT-Thread 内核模拟,依赖系统时钟节拍(rt_tick)。​ - -特点:精度中等(受线程调度影响),灵活、资源占用小。​ -(二)硬件定时器​ -原理:基于芯片硬件定时器外设,由硬件触发中断。​ - -特点:精度极高(微秒级),但需占用硬件资源,适合高精度定时(如 PWM 输出、编码器计数)。​ -三、优先级与调度​ -(一)优先级​ -范围:RT-Thread 中优先级 0(最高)~ RT_THREAD_PRIORITY_MAX(默认 255,最低 )。​ -作用:高优先级线程可抢占低优先级线程(优先级翻转需用互斥锁解决)。​ -示例:​ -#define HIGH_PRIO 10​ -#define LOW_PRIO 30​ -// 高优先级线程可打断低优先级线程运行​ -(二)时间片​ -原理:同优先级线程轮流执行,时间片决定单次执行时长(单位:系统节拍 )。​ -设置:rt_thread_create 的 timeslice 参数(如 10 表示 10 个节拍时长 )。​ -效果:同优先级线程按时间片 “轮流执行”,避免单个线程长期占用 CPU。​ -四、总结​ -知识点 核心要点 适用场景​ -线程动态创建 堆分配、灵活创建,依赖 rt_thread_create 需动态管理线程(如任务加载)​ -线程静态创建 静态内存、确定性高,依赖 rt_thread_init + rt_thread_startup 内存紧张、关键任务​​ -优先级与时间片 优先级决定抢占,时间片决定同优先级线程轮流执行 所有多线程场景,需平衡实时性与公平性​ -通过理解线程创建方式、定时器类型、优先级调度,可高效构建 RT-Thread 多任务系统,适配不同场景需求(如实时控制、低功耗定时)。 \ No newline at end of file +lala,lal \ No newline at end of file -- Gitee From 99f23999062223919fc04e778ba961c5b163e2f9 Mon Sep 17 00:00:00 2001 From: luyu121 <319931274@qq.com> Date: Wed, 23 Jul 2025 23:50:49 +0800 Subject: [PATCH 8/9] day3 --- .../lu_jing_han/day_3/event.c" | 86 ++++ .../lu_jing_han/day_3/mailbox.c" | 80 ++++ .../lu_jing_han/day_3/mutex_sample.c" | 136 +++++++ .../lu_jing_han/day_3/queue.c" | 90 +++++ .../lu_jing_han/day_3/semaphore.c" | 127 ++++++ .../lu_jing_han/day_3/signal.c" | 81 ++++ .../day_3/\347\254\224\350\256\260.md" | 379 ++++++++++++++++++ 7 files changed, 979 insertions(+) create mode 100644 "2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_3/event.c" create mode 100644 "2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_3/mailbox.c" create mode 100644 "2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_3/mutex_sample.c" create mode 100644 "2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_3/queue.c" create mode 100644 "2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_3/semaphore.c" create mode 100644 "2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_3/signal.c" create mode 100644 "2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_3/\347\254\224\350\256\260.md" 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 0000000..e25ab31 --- /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 0000000..aefc401 --- /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 0000000..17194ab --- /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 0000000..a4f938f --- /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 0000000..a29b741 --- /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 0000000..6b485d6 --- /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 0000000..ad302f1 --- /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 机制**,可高效解决线程协作问题! + -- Gitee From 356be27b40eabb7d74a3217782731eb9433e3d9c Mon Sep 17 00:00:00 2001 From: luyu121 <319931274@qq.com> Date: Fri, 25 Jul 2025 21:55:23 +0800 Subject: [PATCH 9/9] day_4 --- .../lu_jing_han/day_4/main.c" | 249 ++++++++++++++++++ .../day_4/\347\254\224\350\256\260.md" | 136 ++++++++++ 2 files changed, 385 insertions(+) create mode 100644 "2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_4/main.c" create mode 100644 "2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_4/\347\254\224\350\256\260.md" diff --git "a/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_4/main.c" "b/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_4/main.c" new file mode 100644 index 0000000..7926e0f --- /dev/null +++ "b/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_4/main.c" @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include + +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* 定义PC13引脚为LED控制引脚 */ +#define LED_PIN GET_PIN(C, 13) + +/* 模拟一个字符设备缓冲区 */ +#define CHAR_DEV_BUFSZ 64 +static char char_buffer[CHAR_DEV_BUFSZ]; +static rt_size_t char_buffer_pos = 0; + +/* 设备对象结构体 */ +static struct rt_device char_dev; + +/* LED控制函数 */ +static void led_init(void) +{ + /* 配置LED引脚为输出模式 */ + rt_pin_mode(LED_PIN, PIN_MODE_OUTPUT); + /* 默认关闭LED */ + rt_pin_write(LED_PIN, PIN_HIGH); +} + +static void led_on(void) +{ + rt_pin_write(LED_PIN, PIN_LOW); + LOG_D("LED turned on"); +} + +static void led_off(void) +{ + rt_pin_write(LED_PIN, PIN_HIGH); + LOG_D("LED turned off"); +} + + + +static rt_err_t char_dev_init(rt_device_t dev) +{ + LOG_D("char device init"); + /* 初始化LED */ + led_init(); + /* 初始化缓冲区 */ + char_buffer_pos = 0; + rt_memset(char_buffer, 0, sizeof(char_buffer)); + return RT_EOK; +} + +static rt_err_t char_dev_open(rt_device_t dev, rt_uint16_t oflag) +{ + LOG_D("char device open, flag = 0x%x", oflag); + return RT_EOK; +} + +static rt_err_t char_dev_close(rt_device_t dev) +{ + LOG_D("char device close"); + return RT_EOK; +} + +static rt_ssize_t char_dev_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) +{ + LOG_D("char device read: pos=%d, size=%d", pos, size); + + if (pos >= char_buffer_pos) + return 0; + + rt_size_t available = char_buffer_pos - pos; + if (size > available) + size = available; + + rt_memcpy(buffer, &char_buffer[pos], size); + return size; +} + +static rt_ssize_t char_dev_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) +{ + LOG_D("char device write: pos=%d, size=%d", pos, size); + + // 处理LED控制命令 + if (size > 0) + { + char cmd = ((char *)buffer)[0]; + switch(cmd) + { + case '1': + led_on(); + break; + case '0': + led_off(); + break; + default: + LOG_D("Unknown command: %c", cmd); + break; + } + } + + // 处理缓冲区写入 + if (pos >= CHAR_DEV_BUFSZ) + return 0; + + rt_size_t writable = CHAR_DEV_BUFSZ - pos; + if (size > writable) + size = writable; + + rt_memcpy(&char_buffer[pos], buffer, size); + char_buffer_pos = pos + size; + return size; +} + + +static rt_err_t char_dev_control(rt_device_t dev, int cmd, void *args) +{ + LOG_D("char device control, cmd = %d", cmd); + switch (cmd) + { + case 1: + led_on(); + break; + case 2: + led_off(); + break; + default: + return -RT_ERROR; + } + return RT_EOK; +} + +/* --------------------- 注册设备 --------------------- */ + void msh_led_control_cmd(int argc, char **argv) +{ + if (argc != 2) + { + rt_kprintf("Usage: msh_led_control [0|1]\n"); + return; + } + rt_device_t dev = rt_device_find("mychar"); + if (dev == RT_NULL) + { + rt_kprintf("Can't find mychar device!\n"); + return; + } + int cmd = 0; + if (strcmp(argv[1], "1") == 0) + { + cmd = 1; + } + else if (strcmp(argv[1], "0") == 0) + { + cmd = 2; + } + else + { + rt_kprintf("Invalid argument, use 0 or 1\n"); + return; + } + rt_device_control(dev, cmd, RT_NULL); +} +MSH_CMD_EXPORT(msh_led_control_cmd, control LED on or off); + + + +int rt_hw_char_device_init(void) +{ + /* 设置设备类型为字符设备 */ + char_dev.type = RT_Device_Class_Char; + + /* 初始化回调函数 */ + char_dev.init = char_dev_init; + char_dev.open = char_dev_open; + char_dev.close = char_dev_close; + char_dev.read = char_dev_read; + char_dev.write = char_dev_write; + char_dev.control = char_dev_control; + + + /* 注册设备到 RT-Thread */ + rt_err_t ret = rt_device_register(&char_dev, "mychar", RT_DEVICE_FLAG_RDWR); + if (ret == RT_EOK) + { + LOG_I("char device registered successfully"); + } + else + { + LOG_E("char device register failed"); + } + + return ret; +} +/* 导出到自动初始化 */ +INIT_DEVICE_EXPORT(rt_hw_char_device_init); + +int main(void) +{ + rt_device_t dev; + char buf[1]; + + LOG_I("Character device with LED control example"); + + // 查找设备 + dev = rt_device_find("mychar"); + if (dev == RT_NULL) + { + LOG_E("Can't find mychar device!"); + return -1; + } + + // 打开设备 + if (rt_device_open(dev, RT_DEVICE_FLAG_RDWR) != RT_EOK) + { + LOG_E("Can't open mychar device!"); + return -1; + } + + // 循环控制LED闪烁 + while (1) + { +// buf[0] = '1'; // 点亮LED +// rt_device_write(dev, 0, buf, 1); +// rt_thread_mdelay(500); +// +// buf[0] = '0'; // 熄灭LED +// rt_device_write(dev, 0, buf, 1); + rt_thread_mdelay(500); +// } +// +// // 关闭设备 +// rt_device_close(dev); +// return 0; +} +} diff --git "a/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_4/\347\254\224\350\256\260.md" "b/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_4/\347\254\224\350\256\260.md" new file mode 100644 index 0000000..a62753b --- /dev/null +++ "b/2025/\347\254\2541\347\273\204(STM32H750-ART-PI)/lu_jing_han/day_4/\347\254\224\350\256\260.md" @@ -0,0 +1,136 @@ + +# RT-Thread 字符设备 + +## 一、功能概述 + +本示例展示了如何基于 RT-Thread 实现一个简单的字符设备 `mychar`,通过写入不同字符(如 `'1'`、`'0'`)来控制开发板上的 LED(连接在 PC13 引脚)。该设备还实现了基本的设备操作函数如初始化、打开、关闭、读写等。 + +--- + +## 二、硬件定义与宏配置 + +```c +#define LED_PIN GET_PIN(C, 13) +#define CHAR_DEV_BUFSZ 64 +static char char_buffer[CHAR_DEV_BUFSZ]; +static rt_size_t char_buffer_pos = 0; +``` + +- `LED_PIN`: 指定 LED 所在的引脚(PC13)。 +- `CHAR_DEV_BUFSZ`: 缓冲区大小为 64 字节。 +- `char_buffer`: 用于模拟设备的数据缓冲区。 +- `char_buffer_pos`: 当前写入位置。 + +--- + +## 三、LED 控制函数 + +```c +static void led_init(void) +static void led_on(void) +static void led_off(void) +``` + +- `led_init()`:初始化 PC13 为输出引脚,默认输出高电平,熄灭 LED。 +- `led_on()`:将引脚拉低点亮 LED。 +- `led_off()`:将引脚拉高关闭 LED。 + +--- + +## 四、字符设备操作函数 + +### 1. 初始化 + +```c +static rt_err_t char_dev_init(rt_device_t dev) +``` +- 初始化 LED 和缓冲区。 + +### 2. 打开与关闭 + +```c +static rt_err_t char_dev_open(rt_device_t dev, rt_uint16_t oflag) +static rt_err_t char_dev_close(rt_device_t dev) +``` +- 可用于后续扩展,目前只打印调试信息。 + +### 3. 读操作 + +```c +static rt_ssize_t char_dev_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) +``` +- 从 `char_buffer` 中读取数据,支持位置读取。 + +### 4. 写操作(控制 LED) + +```c +static rt_ssize_t char_dev_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) +``` +- 判断首字节是否为 `'1'` 或 `'0'`,以控制 LED。 +- 写入的数据也会存入 `char_buffer`。 + +### 5. 控制命令接口 + +```c +static rt_err_t char_dev_control(rt_device_t dev, int cmd, void *args) +``` + +- `cmd = 1`:点亮 LED; +- `cmd = 2`:熄灭 LED。 + +--- + +## 五、设备注册与导出 + +```c +int rt_hw_char_device_init(void) +INIT_DEVICE_EXPORT(rt_hw_char_device_init); +``` + +- 设置 `char_dev` 的回调函数与类型,并通过 `rt_device_register` 注册设备名为 `"mychar"`。 +- 通过 `INIT_DEVICE_EXPORT()` 宏使其自动初始化。 + +--- + +## 六、MSH 命令控制函数 + +```c +void msh_led_control_cmd(int argc, char **argv) +MSH_CMD_EXPORT(msh_led_control_cmd, control LED on or off); +``` + +- 运行命令:`msh_led_control 1` → 点亮 LED +- 运行命令:`msh_led_control 0` → 熄灭 LED + +--- + +## 七、main 函数(测试用途) + +```c +int main(void) +``` + +- 在 `main()` 中找到并打开设备 `"mychar"`; +- 测试写入 `'1'` 和 `'0'` 控制 LED; +- 提供注释好的 LED 闪烁循环逻辑(默认注释掉,可启用测试)。 + +--- + +## 八、调试信息与日志支持 + +程序使用 `ulog.h` 中的 `LOG_D()`、`LOG_I()`、`LOG_E()` 输出日志,便于调试运行状态: + +- 初始化、打开、读写、控制等操作都会输出调试信息。 + +--- + +## 九、使用说明总结 + +- 可通过串口终端或 FinSH 运行 `msh_led_control` 命令控制 LED。 +- 也可通过写入字符设备的方式控制: + ```c + char buf[1] = {'1'}; // 点亮 + rt_device_write(dev, 0, buf, 1); + ``` + + -- Gitee