diff --git "a/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\344\275\234\344\270\232/\347\254\254\344\272\214\345\244\251\344\275\234\344\270\232/README.md" "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\344\275\234\344\270\232/\347\254\254\344\272\214\345\244\251\344\275\234\344\270\232/README.md" new file mode 100644 index 0000000000000000000000000000000000000000..12411ef495c6315612e941fda59868be73da4960 --- /dev/null +++ "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\344\275\234\344\270\232/\347\254\254\344\272\214\345\244\251\344\275\234\344\270\232/README.md" @@ -0,0 +1,186 @@ +# 【DAY2】RT-Thread 启动流程、内核基础与多线程编程 + +- **目标平台**:STM32F407 星火号(`stm32f407-rtspark`) +- **提交仓库**:`https://gitee.com/rtthread/rsoc-rtt` +- **作业交付物**:理论总结与实验报告(`README.md`)+ 可编译源码(`*.c`)通过 Gitee PR 提交。 + +## Part 1:理论知识梳理文档(写入作业目录 `README.md`) + +### 1. STM32F407 启动流程与 RT-Thread 引导机制 + +#### **启动路径** +详细画出/写出从上电复位 `Reset_Handler` 到进入 `main()` 的完整调用链。 + +![alt text](RTT.png) + +概念解释: + +Rest_Handler是系统上电复位后第一个执行入口,是一段汇编代码,位于芯片启动文件startup_stm32f407xx.s中。是stm32复位后第一个软件执行点,负责完成从硬件复位状态到C语言运行环境的最小必要初始化,最终把控制权交给C代码 + +启动文件执行后,**在入口函数中调用rtthread_setup()** + +系统的线程由调度器分配 rt_system_scheduler_init()初始化线程调度器 + +信号量不需要时可以关掉 + +application_init 创建一个线程, main thread是系统中的一个线程,不是裸机中的 + +系统线程定时器的线程也是可选的,如果打开可以创建一个叫timer的线程 + +idle初始化,idle比较重要,空闲线程,系统空转时 + +启动调度器之后上面的调度器开始调度。RTT时抢占式优先级的调度策略,在整个调度链表中找优先级最高的(小号高)执行优先级最高的线程 + +组件初始化设计RTT的自动初始化机制,通过宏实现(下一道题,自动化初始化原理)。rt_components_init(),进行组件的初始化。在main函数实际调用之前,发现有函数就去调用(自动初始化机制,不需要人手动初始化,是系统初始化的) + +然后就进入main函数了 + +这里的C代码是__main,C库,是系统代码。从上电到用户代码的链如下: + ```plain +Reset_Handler (汇编) + └── 直接跳转 ──► __main (C 库,系统代码) + └── 初始化 C 环境后 ──► 调用main()或$Sub$$main() + └── 最终 ──► 用户函数的main() + ``` + + +#### **自动初始化原理** +解释 `INIT_BOARD_EXPORT` 与 `INIT_APP_EXPORT` 的底层实现原理。 + +将函数指针放入特定的数据段,启动时遍历调用 + +补充: +两个宏分别作用于板级初始化和应用初始化。板级初始化阶段内核尚未完全就绪,进行硬件驱动的初始化(UART、GPIO、Timer)应用初始化阶段内核已经完成初始化,调度器即将启动,用于应用系统、文件系统和网络协议栈的初始化。 + + + +### 2. 内核基础与对象模型 + +#### **对象容器与控制块** +简述 RT-Thread 面向对象的设计思想,线程控制块(`struct rt_thread`)中关键成员(如 `stat`、`current_priority`、`init_tick`、`sp`)的作用。 +1. 面向对象设计思想 + RTT采用C语言模拟面向对象设计 + + 基类: + ```c + struct rt_object //所有内核对象的公共属性 + ``` + + 派生:其他内核对象均集成自rt_object + + 容器管理:所有对象按类型分类挂入对象容器链表(rt_object_container),支持遍历、查找和统计 + + 线程控制块由结构体`struct rt_thread`定义并形成**线程内核对象**,在基类的基础上增加了线程状态、优先级等组件,在链接(通过**双向链表**)到内核对象容器中进行管理 + ![alt text]({E29355FB-A696-469A-B788-46A6F6B290B2}.png) + + 每个线程中有线程控制块,线程栈和每个线程的入口函数。 + + ![text]({9E05C824-346A-4509-9270-2FE1EC2DCE46}.png) + + RTT线程控制块`struct rt_thread`定义和属性如下: + ```c + struct rt_thread{ + struct rt_object parent; //继承rt_object + + void *sp; //栈指针,上下文切换时保存/恢复 CPU 寄存器到线程私有栈 + void *entry; //入口函数指针 + void *paramter; + void *stact_addr; //栈起始地址,线程私有栈底地址,用于栈溢出检测。每个线程有自己的线程栈 + rt_uint32_t stack_size; //栈大小 + + rt_err_t error; + rt_uint8_t stat; //线程状态,决定调度器行为(就绪/运行/挂起/关闭/初始) + + rt_uint8_t current_priority; + rt_uint8_t init_priority; + rt_uint32_t number_mask; + + rt_ubase_t init_tick; //线程初始化计数值(初始时间片) + rt_ubase_t remaining_tick; //线程剩余计数值(剩余时间片) + + struct rt_timer thread_timer; //内置线程定时器,用于延时 + + void(*cleanup)(struct rt_thread *tid); //线程退出清除函数 + rt_uint32_t user_data; //用户数据 + } + ``` + + +#### **内存分配方式** +对比静态对象与动态对象的区别(分配位置、生命周期、释放机制),分析为什么某些高可靠场景强制使用静态线程。 +| 对比维度 | 静态对象 | 动态对象| +| --- | -------- | -- | +| **分配位置** | 编译期确定,存储在 `.data`/`.bss` 段或用户指定的全局数组 | 运行时从 **内存堆(Heap)** 或 **内存池(Memory Pool)** 分配 | +| **生命周期** | 与程序同生命周期,除非显式删除 | 创建时分配,删除时释放 | +| **释放机制** | `rt_thread_delete()` / `rt_sem_delete()` 仅从调度器/容器中移除,**内存不回收** | `rt_thread_delete()` / `rt_sem_delete()` 释放内存回堆/池 | +| **API 前缀** | `rt_thread_init()` / `rt_sem_init()` | `rt_thread_create()` / `rt_sem_create() | +| **内存确定性** | **编译期可知**,无运行时分配失败风险 | 依赖堆状态,存在**内存碎片**和**分配失败**风险 | +| **适用场景** | 高可靠、资源受限、硬实时系统 | 功能复杂、对象数量动态变化的应 | + + +### 3. 线程状态机与调度算法 + +#### **五态模型** +绘制或描述 RT-Thread 线程状态(初始态、就绪态、运行态、挂起态、关闭态)及触发状态转换的典型 API。 + + | 起始状态 | 目标状态 | 触发函数 / 条件 | + | -------- | -------- | ------------------------------------------------------------ | + | 无 | 初始状态 | 动态`rt_thread_create()`静态`rt_thread_init()` | + | 初始状态 | 就绪状态 | `rt_thread_startup()` | + | 就绪状态 | 运行状态 | 被调度器选中执行(调度器调度) | + | 运行状态 | 挂起状态 | 阻塞函数 | + | 挂起状态 | 就绪状态 | 唤醒函数 | + | 就绪状态 | 挂起状态 | `rt_thread_suspend()` | + | 运行状态 | 关闭状态 | `rt_thread_exit()` | + | 挂起状态 | 关闭状态 | `rt_thread_delete()` / `rt_thread_detach()` | + +#### **调度机制剖析** + + - **抢占式调度**:通过优先级调度 + - **时间片轮转**:在优先级相同时,按时间片决定进程的执行时间 + +## Part 2:多线程实战编程(C 语言实现) +串口截图 +![alt text](image.png) +硬件运行图片 + +1. 未按下,两个线程运行,两灯闪烁 + ![alt text](image-2.png) +2. 按下按键,线程1挂起,只有LED_B闪烁 + ![alt text](image-1.png) +3. 再次按下按键,两灯恢复闪烁 +### 任务说明 + +1. **工作线程 1(动态创建 `th_led1`)**: + - 优先级 `16`,时间片 `5 ticks`,栈 `1024 Bytes`。 + - 循环翻转板载 LED_R,每次执行打印计数与 `rt_tick_get()`。 +2. **工作线程 2(静态初始化 `th_led2`)**: + - 优先级 `16`,时间片 `5 ticks`,静态定义全局栈与 TCB。 + - 循环翻转板载 LED_B,每次执行打印计数。 +3. **监控与控制线程(动态创建 `th_monitor`)**: + - 优先级 `10`(高于工作线程),周期延时 `rt_thread_mdelay(2000)`。 + - 唤醒后获取并打印 `th_led1` 与 `th_led2` 的运行状态与剩余栈空间大小。 + - 结合板载按键检测(或按键中断):单次触发时调用 `rt_thread_suspend()` 挂起 `th_led1`;再次触发时调用 `rt_thread_resume()` 恢复。 +4. **系统集成与调试命令**: + - 使用 `INIT_APP_EXPORT()` 自动加载测试模块,禁止在 `main.c` 中硬编码调用。 + - 使用 `MSH_CMD_EXPORT()` 导出自定义查看命令(如 `thread_dump`)。 + +## Part 3:Gitee PR 提交与规范 + +### 1. 提交目录规范 + +``` +2026/<组别>/<姓名>/第二天作业 +├── README.md # 包含:Part 1 理论整理 + Part 2 实验结果分析与串口截图 +└── thread_study.c # 作业源码(含动/静态线程、自动初始化、MSH导出) +``` + +### 2. PR 提交流程与规范 + +1. Fork 官方仓库 [https://gitee.com/rtthread/rsoc-rtt](https://gitee.com/rtthread/rsoc-rtt) 到个人账号。 +2. 基于 `master` 新建分支:`day2-姓名拼音`。 +3. 编写代码、文档并进行本地 `scons` 编译验证与星火1号烧录测试。 +4. 提交 Commit。 +5. 向主仓库提交 Pull Request: + - **PR 标题**:`[作业提交] 内核与多线程培训 - <姓名>` + - **PR 内容**:附带理论文档简述、硬件运行现象照片及 FinSH 串口日志输出。 \ No newline at end of file diff --git "a/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\344\275\234\344\270\232/\347\254\254\344\272\214\345\244\251\344\275\234\344\270\232/RTT.png" "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\344\275\234\344\270\232/\347\254\254\344\272\214\345\244\251\344\275\234\344\270\232/RTT.png" new file mode 100644 index 0000000000000000000000000000000000000000..e2ab12c744149d5af12e31c7b94232f1f9b4046d Binary files /dev/null and "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\344\275\234\344\270\232/\347\254\254\344\272\214\345\244\251\344\275\234\344\270\232/RTT.png" differ diff --git "a/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\344\275\234\344\270\232/\347\254\254\344\272\214\345\244\251\344\275\234\344\270\232/image-1.png" "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\344\275\234\344\270\232/\347\254\254\344\272\214\345\244\251\344\275\234\344\270\232/image-1.png" new file mode 100644 index 0000000000000000000000000000000000000000..e8fc47ae73318b547d7479eb9fa527676839b8ef Binary files /dev/null and "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\344\275\234\344\270\232/\347\254\254\344\272\214\345\244\251\344\275\234\344\270\232/image-1.png" differ diff --git "a/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\344\275\234\344\270\232/\347\254\254\344\272\214\345\244\251\344\275\234\344\270\232/image-2.png" "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\344\275\234\344\270\232/\347\254\254\344\272\214\345\244\251\344\275\234\344\270\232/image-2.png" new file mode 100644 index 0000000000000000000000000000000000000000..d721b69624e07bb27e8c5fe8ef2890dd8c299102 Binary files /dev/null and "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\344\275\234\344\270\232/\347\254\254\344\272\214\345\244\251\344\275\234\344\270\232/image-2.png" differ diff --git "a/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\344\275\234\344\270\232/\347\254\254\344\272\214\345\244\251\344\275\234\344\270\232/image.png" "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\344\275\234\344\270\232/\347\254\254\344\272\214\345\244\251\344\275\234\344\270\232/image.png" new file mode 100644 index 0000000000000000000000000000000000000000..a67cde9e243bca362733b8ae0ac215d5db780a9a Binary files /dev/null and "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\344\275\234\344\270\232/\347\254\254\344\272\214\345\244\251\344\275\234\344\270\232/image.png" differ diff --git "a/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\344\275\234\344\270\232/\347\254\254\344\272\214\345\244\251\344\275\234\344\270\232/thread_study.c" "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\344\275\234\344\270\232/\347\254\254\344\272\214\345\244\251\344\275\234\344\270\232/thread_study.c" new file mode 100644 index 0000000000000000000000000000000000000000..f0f17e4c93b3a1bf165dda795981fbd3b6c741d1 --- /dev/null +++ "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\344\275\234\344\270\232/\347\254\254\344\272\214\345\244\251\344\275\234\344\270\232/thread_study.c" @@ -0,0 +1,349 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2026-08-19 d0ubleU0x00 the first version + */ + +/* + * 程序清单:多线程管理程序,创建动态、静态线程、监控、按键挂起和恢复 + * 命令调用格式:导出thread_dump到终端 + * 程序功能:创建两个LED工作线程和一个监控线程,支持按键挂起/恢复工作线程1 +*/ + + +#include +#include +#include +#include +#include + + + +#define LED_B_PIN GET_PIN(F,11) +#define LED_R_PIN GET_PIN(F,12) +#define KEY_PIN GET_PIN(C,0) + + +#define LED_ON_LEVEL PIN_LOW +#define LED_OFF_LEVEL PIN_HIGH + +/* + * 按键极性: + * 当前假设 PC5 使用内部上拉,按键按下接地,即低电平有效。 + * + * 如果按键是高电平有效,改: + * KEY_PIN_MODE -> PIN_MODE_INPUT_PULLDOWN + * KEY_IRQ_MODE -> PIN_IRQ_MODE_RISING + * KEY_PRESSED_LEVEL -> PIN_HIGH + */ +#define KEY_PIN_MODE PIN_MODE_INPUT_PULLUP +#define KEY_IRQ_MODE PIN_IRQ_MODE_FALLING +#define KEY_PRESSED_LEVEL PIN_LOW + + +/* 线程优先级 */ +#define LED_THREAD_PRIORITY 16 +#define MONITOR_THREAD_PRIORITY 16 + +/* ===================== 线程对象 ===================== */ + +/* 指向led线程的状态信号量的指针 */ +static rt_sem_t led_sem = RT_NULL; + +/* 工作线程 1:动态创建 */ +static rt_thread_t th_led1 = RT_NULL; + +/* 工作线程 2:静态初始化 */ +/* 使用静态线程时,线程的栈需要设置字节对齐 */ +ALIGN(RT_ALIGN_SIZE) +static rt_uint8_t th_led2_stack[1024]; +static struct rt_thread th_led2; + +/* 监控线程:动态创建 */ +static rt_thread_t th_monitor = RT_NULL; + + +/* 按键中断与线程通信的全局变量 */ +static volatile rt_uint32_t key_event_count = 0; /* 按键按下次数计数器 */ +static volatile rt_tick_t last_isr_tick = 0; /* 上次中断触发的系统时间 */ + + + + +/* ===================== 工具函数 ===================== */ + +static const char *thread_state_str(rt_uint8_t stat) +{ + stat &= RT_THREAD_STAT_MASK; + + switch (stat) + { + case RT_THREAD_INIT: + return "init"; + + case RT_THREAD_READY: + return "ready"; + + case RT_THREAD_RUNNING: + return "running"; + + case RT_THREAD_SUSPEND: + return "suspend"; + + case RT_THREAD_CLOSE: + return "close"; + + default: + return "unknown"; + } +} + +//当前-sp +static rt_uint32_t thread_stack_free(struct rt_thread *thread) +{ + if (thread == RT_NULL || thread->stack_addr == RT_NULL) + { + return 0; + } + + /* 使用当前栈指针 sp 计算剩余空间:sp 高于 stack_addr 的部分即为未使用区域 */ + if ((rt_uint32_t)thread->sp > (rt_uint32_t)thread->stack_addr) + { + return (rt_uint32_t)thread->sp - (rt_uint32_t)thread->stack_addr; + } + + return 0; +} + +static void print_thread_info(const char *tag, struct rt_thread *thread) +{ + if (thread == RT_NULL) + { + rt_kprintf("%-8s: thread not created\n", tag); + return; + } + + rt_kprintf("%-8s name=%.*s state=%-7s prio=%d tick=%u stack_free=%u/%u\n", + tag, + RT_NAME_MAX, + thread->name, + thread_state_str(thread->stat), + thread->current_priority, + (unsigned int)thread->init_tick, + (unsigned int)thread_stack_free(thread), + (unsigned int)thread->stack_size); +} + +static void print_all_status(void) +{ + rt_kprintf("[thread status]\n"); + print_thread_info("led1", th_led1); + print_thread_info("led2", &th_led2); + print_thread_info("monitor", th_monitor); +} + + +/* ===================== 按键中断服务函数 (ISR) ===================== */ +static void key_isr_handler(void *args) +{ + rt_tick_t current_tick = rt_tick_get(); + + /* 硬件级/ISR级软件消抖: + * 如果距离上次触发时间不到 20ms,认为是机械抖动,直接丢弃。 + */ + if ((current_tick - last_isr_tick) >= rt_tick_from_millisecond(20)) + { + last_isr_tick = current_tick; + key_event_count++; /* 有效按键次数 +1 */ + } +} +/* + * 就绪态延时。 + * + * 与 rt_thread_mdelay() 不同: + * rt_thread_mdelay() 会让线程进入 SUSPEND 状态, + * 而这里通过不断判断 tick 并调用 rt_thread_yield(), + * 使线程仍然处于 READY/RUNNING 状态。 + * + * 这样监控线程调用 rt_thread_suspend(th_led1) 更容易成功。 + */ +static void ready_delay_ms(rt_uint32_t ms) +{ + rt_tick_t start = rt_tick_get(); + rt_tick_t ticks = rt_tick_from_millisecond(ms); + + while ((rt_tick_get() - start) < ticks) + { + rt_thread_yield(); + } +} + +/* 线程th_led1的入口函数 */ +static void th_led1_entry(void *parameter) +{ + + static rt_uint8_t count = 0; + while(1) + { + if (rt_sem_take(led_sem, 0) == RT_EOK) + { + rt_kprintf("th_led1 suspend.\n"); + rt_thread_suspend(th_led1); //挂起th_led1 + } + else + { + count++; + rt_pin_write(LED_R_PIN, !rt_pin_read(LED_R_PIN)); + rt_kprintf("th_led1 count=%u tick=%u\n", + (unsigned int)count, + (unsigned int)rt_tick_get()); + ready_delay_ms(1000); + } + } +} + +/* 线程th_led2的入口函数 */ +static void th_led2_entry(void *parameter) +{ + + static rt_uint8_t count = 0; + while(1) + { + count++; + rt_pin_write(LED_B_PIN, !rt_pin_read(LED_B_PIN)); + rt_kprintf("th_led2 count=%u\n",(unsigned int)count); + ready_delay_ms(1000); + } +} + +/* 线程th_monitor的入口函数 */ +static void th_monitor_entry(void *parameter) +{ + rt_uint32_t key_cnt; + rt_base_t level; + while(1) + { + /* 关中断,安全地读取并清零计数器 (原子操作) */ + level = rt_hw_interrupt_disable(); + key_cnt = key_event_count; + key_event_count = 0; /* 读完就清零,防止重复处理 */ + rt_hw_interrupt_enable(level); + + /* 如果计数器大于 0,说明睡觉期间有人按了按键 */ + + if (key_cnt > 0) + { + rt_thread_mdelay(20); + if(rt_pin_read(KEY_PIN)==0) //按键消抖20ms + { + + //每次按下按键翻转一下线程th_led1的状态 + if((th_led1->stat &= RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND) + { + rt_kprintf("th_led1 resume.\n"); + rt_thread_resume(th_led1); //使线程恢复运行 + } + else + { + rt_sem_release(led_sem); //释放信号量 + } + rt_kprintf("[KEY] key event \n"); + } + + } + + // 打印状态 + print_all_status(); + rt_thread_mdelay(2000); + + } +} + + +static void gpio_init(void) +{ + + /* 初始化 LED 引脚 */ + rt_pin_mode(LED_R_PIN, PIN_MODE_OUTPUT); + rt_pin_mode(LED_B_PIN, PIN_MODE_OUTPUT); + + rt_pin_write(LED_R_PIN, LED_ON_LEVEL); + rt_pin_write(LED_B_PIN, LED_ON_LEVEL); + + /* 初始化按键中断 */ + rt_pin_mode(KEY_PIN, KEY_PIN_MODE); + rt_pin_attach_irq(KEY_PIN, KEY_IRQ_MODE, key_isr_handler, RT_NULL); + rt_pin_irq_enable(KEY_PIN, PIN_IRQ_ENABLE); + +} + + +/* ===================== 模块初始化 ===================== */ + +static int thread_study_init(void) +{ + /* 初始化GPIO*/ + gpio_init(); + /* 创建一个动态信号量,初始值是0 */ + led_sem = rt_sem_create("led_sem", 0, RT_IPC_FLAG_PRIO); + /* + * 工作线程 1:动态创建 + * 名称:th_led1 + * 优先级:16 + * 时间片:5 ticks + * 栈大小:1024 Bytes + */ + th_led1 = rt_thread_create("th_led1", + th_led1_entry, + RT_NULL, + 2048, + 16, + 5); + rt_thread_startup(th_led1);//动态线程不能用&符号 + /* + * 工作线程 2:静态初始化 + * 名称:th_led2 + * 优先级:16 + * 时间片:5 ticks + * 栈大小:1024 Bytes + */ + rt_thread_init(&th_led2, + "th_led2", + th_led2_entry, + RT_NULL, + th_led2_stack, + sizeof(th_led2_stack), + 16, + 5); + + rt_thread_startup(&th_led2); + + /* 监控线程:动态创建 */ + th_monitor = rt_thread_create("th_mon", + th_monitor_entry, + RT_NULL, + 2048, + 10, + 5); + rt_thread_startup(th_monitor); + rt_kprintf("thread_study init done\n"); + rt_kprintf("LED_R=PF12, LED_B=PF11, KEY=PC5\n"); + rt_kprintf("Press KEY to suspend/resume th_led1\n"); + + return 0; +} +INIT_APP_EXPORT(thread_study_init); + +/* ===================== MSH 调试命令 ===================== */ + +void thread_dump(void) +{ + print_all_status(); +} +MSH_CMD_EXPORT(thread_dump, dump thread study status); + + diff --git "a/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\344\275\234\344\270\232/\347\254\254\344\272\214\345\244\251\344\275\234\344\270\232/{9E05C824-346A-4509-9270-2FE1EC2DCE46}.png" "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\344\275\234\344\270\232/\347\254\254\344\272\214\345\244\251\344\275\234\344\270\232/{9E05C824-346A-4509-9270-2FE1EC2DCE46}.png" new file mode 100644 index 0000000000000000000000000000000000000000..17d796cbd1e8b8b5edf75c23b74692350b90a529 Binary files /dev/null and "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\344\275\234\344\270\232/\347\254\254\344\272\214\345\244\251\344\275\234\344\270\232/{9E05C824-346A-4509-9270-2FE1EC2DCE46}.png" differ diff --git "a/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\344\275\234\344\270\232/\347\254\254\344\272\214\345\244\251\344\275\234\344\270\232/{E29355FB-A696-469A-B788-46A6F6B290B2}.png" "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\344\275\234\344\270\232/\347\254\254\344\272\214\345\244\251\344\275\234\344\270\232/{E29355FB-A696-469A-B788-46A6F6B290B2}.png" new file mode 100644 index 0000000000000000000000000000000000000000..2f46656eda1ccce63b1dd4ca03880e7f65a516be Binary files /dev/null and "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\344\275\234\344\270\232/\347\254\254\344\272\214\345\244\251\344\275\234\344\270\232/{E29355FB-A696-469A-B788-46A6F6B290B2}.png" differ diff --git "a/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/image-1.png" "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/image-1.png" new file mode 100644 index 0000000000000000000000000000000000000000..156a8dfcd87b0c26ed6551003c12fa6d43808d75 Binary files /dev/null and "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/image-1.png" differ diff --git "a/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/image-2.png" "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/image-2.png" new file mode 100644 index 0000000000000000000000000000000000000000..0ef7eeff63e8416ef6c4238cc2230f96cd425ba7 Binary files /dev/null and "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/image-2.png" differ diff --git "a/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/image-3.png" "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/image-3.png" new file mode 100644 index 0000000000000000000000000000000000000000..0fcf8e6e340c228a1e9a03b5005a7dd938f43c2d Binary files /dev/null and "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/image-3.png" differ diff --git "a/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/image-4.png" "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/image-4.png" new file mode 100644 index 0000000000000000000000000000000000000000..b4cf007bacd5c7bbf6dd9f8a18d6da4374be6999 Binary files /dev/null and "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/image-4.png" differ diff --git "a/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/image-5.png" "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/image-5.png" new file mode 100644 index 0000000000000000000000000000000000000000..5712c15369fdc2b1ec6bec64d231a50fae604f92 Binary files /dev/null and "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/image-5.png" differ diff --git "a/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/image.png" "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/image.png" new file mode 100644 index 0000000000000000000000000000000000000000..1f990184102715531aa5cc74eae039cce5d73fa4 Binary files /dev/null and "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/image.png" differ diff --git "a/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/{6ABE2BB1-6288-4CF2-8744-544E15FB5AD7}.png" "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/{6ABE2BB1-6288-4CF2-8744-544E15FB5AD7}.png" new file mode 100644 index 0000000000000000000000000000000000000000..d24a0de7a113e5299274d564ab3e425c99e26dcf Binary files /dev/null and "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/{6ABE2BB1-6288-4CF2-8744-544E15FB5AD7}.png" differ diff --git "a/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/{96D9EC29-A393-4F21-B4E5-7ED0EEB5EC6D}.png" "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/{96D9EC29-A393-4F21-B4E5-7ED0EEB5EC6D}.png" new file mode 100644 index 0000000000000000000000000000000000000000..73820bea336b8c04a934b15dca9382e25fddb38c Binary files /dev/null and "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/{96D9EC29-A393-4F21-B4E5-7ED0EEB5EC6D}.png" differ diff --git "a/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/{A40AD466-BFCB-4C9D-BA52-92B2C9EE33E5}.png" "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/{A40AD466-BFCB-4C9D-BA52-92B2C9EE33E5}.png" new file mode 100644 index 0000000000000000000000000000000000000000..5acabee3d5837d604b6af478e87be306a28b2245 Binary files /dev/null and "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/{A40AD466-BFCB-4C9D-BA52-92B2C9EE33E5}.png" differ diff --git "a/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/{EE5B4AE8-0853-4784-B9B0-B7313B4470CE}.png" "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/{EE5B4AE8-0853-4784-B9B0-B7313B4470CE}.png" new file mode 100644 index 0000000000000000000000000000000000000000..c4c96d125f93dc758165a96988883129bd13f49f Binary files /dev/null and "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/{EE5B4AE8-0853-4784-B9B0-B7313B4470CE}.png" differ diff --git "a/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/\346\236\204\345\273\272\347\263\273\347\273\237.md" "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/\346\236\204\345\273\272\347\263\273\347\273\237.md" new file mode 100644 index 0000000000000000000000000000000000000000..a9c53b4a87beb173de4eceeae3c227486d427549 --- /dev/null +++ "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/\346\236\204\345\273\272\347\263\273\347\273\237.md" @@ -0,0 +1,38 @@ +# SCons +RTT使用scons命令编译和构建系统 + +文档地址:[text](https://www.rt-thread.org/document/site/#/development-tools/build-config-system/SCons) + +构建工具:根据一定的规则或指令,将源代码编译成可执行的二进制程序 + +SCons 由python编写的构建工具 + +脚本作用范围:当前src目录下的.c、.h文件,是分散式写的 + +## rtconfig.py 配置文件 +写了编译器和构建参数相关的内容 + +工具链的区分 +![alt text](image-2.png) + +工具链参数 +![alt text]({A40AD466-BFCB-4C9D-BA52-92B2C9EE33E5}.png) + +# SCons基本命令 + +使用`scons`命令编译BSP +可以加后缀 -j 多线程编译 + +![alt text]({96D9EC29-A393-4F21-B4E5-7ED0EEB5EC6D}.png) + +`scons -c` 清除编译目标 包括临时文件和目标文件 + +`scons --target=makefile(或者什么其他的内容)` scons根据当前的目录结构生成一个makefile或c脚本,也可以生成一些mdk的工程 + +`scons --dist`打包,变成一个比较精简的BSP,不相关的BSP文件都会被移除,并且可以拷贝此工程到任意目录下使用 + +`scons --verbose` 打印详细参数 + +# config文件 + + diff --git "a/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/\347\272\277\347\250\213\347\254\224\350\256\260.md" "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/\347\272\277\347\250\213\347\254\224\350\256\260.md" new file mode 100644 index 0000000000000000000000000000000000000000..edb4552bd7c527365f06e507be8cb6f1b080c6de --- /dev/null +++ "b/2026/\347\254\2544\347\273\204/\347\216\213\347\220\263/\347\254\224\350\256\260/\347\263\273\347\273\237\346\236\204\345\273\272\345\222\214\347\272\277\347\250\213/\347\272\277\347\250\213\347\254\224\350\256\260.md" @@ -0,0 +1,91 @@ +## 线程初始化 +有静态初始化和动态初始化 + +静态线程对象初始化,线程句柄(线程控制块指针)、线程栈由用户提供 +> 静态线程是指 线程控制块、线程运行栈一般都设置为全局变量,在编译时就被确定、分配处理,内核不负责动态分配内存空间 +> +> 用户提供的栈首地址要做系统对齐(ARM 上为4字节对齐)、 + +函数接口: +```c +rt_err rt_thread_init(struct rt_thread *thread, //线程控制块指针 + const char *name, //线程名称 + void(*entry)(void *parameter), //可以调用的参数 + void *parameter, + void *stack_start, //线程起始地址 + rt_uint32_t stack_size, + rt_uint8_t priority, //线程优先级,小数高 + rt_uint32_t tick); //调度方式,优先级相同时的时间片 + +``` +线程初始化接口参数: +![alt text](image-1.png) + +注意线程是由返回值的,编码时注意接收。如果没有足够分配线程的空间可能会分配失败 + +与linux的不同:**因为RTT没有MMU,直接使用物理地址,所以这里会有线程起始地址这个说法**,栈大小、位置由开发者显式指定,链接器在编译期就把地址写死了 + +静态编译的好处:有确定性,在编译时就知道系统资源的分配情况。动态初始化不知道申请空间的时机和次数等(尽量不要用递归,会分配很多空间) + +动态初始化线程,调用到这个函数时,系统会从动态堆内存中分配一个线程句柄以及相应栈大小参数的空间。分配出的栈空间按rtconfig.h中配置的RT_ALIGN_SIZE方式对齐 + +```c +rt_thread_t rt_thread_create( + const char* name, + void (*entry)(void* parameter), + void *parameter, + rt_uint32_t stack_size, + rt_uint8_t priority, + rt_uint32_t tick); +``` + +## 线程启动 +线程怎么让他工作 + +创建(初始化)的线程处于初始状态,没有变成就绪态,就未进入就绪线程的调度队列 + +创建成功后调用函数接口`rt_thread_startup`让该线程进入就绪状态。调用这个函数时,立即将线程状态改为就绪态,并放到相应优先级队列中调度。如果启动的这个线程优先级是最高的,将立即切换到这个线程。 + +```c +rt_err_t rt_thread_startup(rt_thread_t thread) //让线程起来 +``` +线程初始化示例 + +![]({6ABE2BB1-6288-4CF2-8744-544E15FB5AD7}.png) + +## 线程延时 +让出CPU使用权 +抢占式系统线程在不适用CPU时需要让出CPU使用权,让其他线程运行。这通过线程延时或睡眠实现 + +通过使用让线程延时/休眠的API实现,在指定的时间到达后重新运行 + +```c +rt_err_t rt_thread_delay(rt_tick_t tick); //以一个OS tick为单位(理解为时钟周期?) +rt_err_t rt_thread_delay(rt_int32_t ms);//以ms为单位,用32位整数表示 +``` + +# 代码实现:基于星火1号芯片的内核实例 +所有的启动流程都在/rt-thread/src/components.c文件中 + +自动初始化 +![]({EE5B4AE8-0853-4784-B9B0-B7313B4470CE}.png) + +# 作业:多线程实战编程 +使用C语言写函数实现创建线程 +点LED看标准版本中的设备驱动IO设备模型,根据[PIN设备使用示例](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/device/pin/pin?id=pin-%e8%ae%be%e5%a4%87%e4%bd%bf%e7%94%a8%e7%a4%ba%e4%be%8b)编写 + +## 任务说明 + +1. **工作线程 1(动态创建 `th_led1`)**: + - 优先级 `16`,时间片 `5 ticks`,栈 `1024 Bytes`。 + - 循环翻转板载 LED_R,每次执行打印计数与 `rt_tick_get()`。 +2. **工作线程 2(静态初始化 `th_led2`)**: + - 优先级 `16`,时间片 `5 ticks`,静态定义全局栈与 TCB。 + - 循环翻转板载 LED_B,每次执行打印计数。 +3. **监控与控制线程(动态创建 `th_monitor`)**: + - 优先级 `10`(高于工作线程),周期延时 `rt_thread_mdelay(2000)`。 + - 唤醒后获取并打印 `th_led1` 与 `th_led2` 的运行状态与剩余栈空间大小。 + - 结合板载按键检测(或按键中断):单次触发时调用 `rt_thread_suspend()` 挂起 `th_led1`;再次触发时调用 `rt_thread_resume()` 恢复。 +4. **系统集成与调试命令**: + - 使用 `INIT_APP_EXPORT()` (自动初始化)自动加载测试模块,禁止在 `main.c` 中硬编码调用。 + - 使用 `MSH_CMD_EXPORT()` 导出自定义查看命令(如 `thread_dump`)。 \ No newline at end of file