diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\351\273\204\345\244\247\346\236\227/\344\275\234\344\270\232/day2.c" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\351\273\204\345\244\247\346\236\227/\344\275\234\344\270\232/day2.c" new file mode 100644 index 0000000000000000000000000000000000000000..841f4d02496ad092062da1857336c6cdd5f7a395 --- /dev/null +++ "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\351\273\204\345\244\247\346\236\227/\344\275\234\344\270\232/day2.c" @@ -0,0 +1,99 @@ +#include +#include +#include + +/* defined the LED0 pin: PF9 */ +#define LED0_PIN GET_PIN(F, 9) + +#define THREAD_PRIORITY_1 20 // 低优先级 +#define THREAD_PRIORITY_2 15 // 中优先级 +#define THREAD_PRIORITY_3 10 // 高优先级 +#define THREAD_STACK_SIZE 512 +#define THREAD_TIMESLICE 10 +//线程1入口函数 +void thread1_entry(void) +{ + int count = 0; + + while (1) + { + rt_kprintf("thread1 running\n"); + rt_thread_mdelay(100); + } +} +//线程2入口函数 +void thread2_entry(void) +{ + int count = 0; + while (1) + { + rt_kprintf("thread2 running\n"); + if (count % 5 == 0) + { + rt_thread_mdelay(50); + } + } +} +//线程3入口函数 +void thread3_entry(void) +{ + int count = 0; + while (1) + { + rt_kprintf("thread3 running\n"); + rt_thread_mdelay(50); + } +} + +int main(void) +{ + rt_thread_t tid1, tid2, tid3; + // 创建线程1 + tid1 = rt_thread_create("thread1", + thread1_entry, + RT_NULL, + THREAD_STACK_SIZE, + THREAD_PRIORITY_1, + THREAD_TIMESLICE); + // 创建线程2 + tid2 = rt_thread_create("thread2", + thread2_entry, + RT_NULL, + THREAD_STACK_SIZE, + THREAD_PRIORITY_2, + THREAD_TIMESLICE); + // 创建线程3 + tid3 = rt_thread_create("thread3", + thread3_entry, + RT_NULL, + THREAD_STACK_SIZE, + THREAD_PRIORITY_3, + THREAD_TIMESLICE); + // 如果线程创建成功,则启动线程 + if (tid1 != RT_NULL) + rt_thread_startup(tid1); + + if (tid2 != RT_NULL) + rt_thread_startup(tid2); + + if (tid3 != RT_NULL) + rt_thread_startup(tid3); + + return 0; + + + +// int count = 1; +// /* set LED0 pin mode to output */ +// rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT); +// +// while (count++) +// { +// rt_pin_write(LED0_PIN, PIN_HIGH); +// rt_thread_mdelay(500); +// rt_pin_write(LED0_PIN, PIN_LOW); +// rt_thread_mdelay(500); +// } +// +// return RT_EOK; +} \ No newline at end of file diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\351\273\204\345\244\247\346\236\227/\347\254\224\350\256\260/day1.md" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\351\273\204\345\244\247\346\236\227/\347\254\224\350\256\260/day1.md" new file mode 100644 index 0000000000000000000000000000000000000000..962118aaadd7cb25aaf5f4f039678fb08fb25079 --- /dev/null +++ "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\351\273\204\345\244\247\346\236\227/\347\254\224\350\256\260/day1.md" @@ -0,0 +1,27 @@ +环境搭建核心步骤 +安装 Git:用于拉取 RT-Thread 代码仓库(支持 GitHub 或国内镜像)。https://https://git-scm.com/ 选择合适版本安装 + +配置 ENV 工具:用于构建与配置 RT-Thread,需注册到系统(右键文件夹可直接打开),通过pkgs --update更新软件包。使用官网的安装包安装 + +安装 VS Code:用于代码编辑,右键文件夹可通过 VS Code 打开进行代码修改。 +代码拉取与编 +拉取代码:通过 Git 克隆 RT-Thread 仓库(git clone [https://gitee.com/rtthread/rt-thread.git])。 +编译步骤:进入 BSP(开发板支持包)目录 +右键打开 ENV,输入menuconfig配置(首次直接保存) +再输入scons -j4(根据线程数调整)编译,生成 ELF 文件后可通过终端运行。 + +新增文件 / 目录时,需创建SConscript脚本(定义编译规则),确保新文件被纳入构建系统,可通过递归搜索或直接指定文件路径实现。 + +git上传 +git init 初始化 +git status 查看当前管理文件的状态 +git add 添加要管理的文件 +git add . 暂存 +git commit -m 把文件提交到仓库 +git log 查看历史记录 +git branch 创建分支 +git checkout <分支名> 切换分支 +git remote add origin 《地址》添加存储仓库 +git push origin master 把本地仓库推到远程存储仓库中 + + diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\351\273\204\345\244\247\346\236\227/\347\254\224\350\256\260/day2.md" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\351\273\204\345\244\247\346\236\227/\347\254\224\350\256\260/day2.md" new file mode 100644 index 0000000000000000000000000000000000000000..43583f463482f75f7549e0c5d81f8fe62e7b3304 --- /dev/null +++ "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\351\273\204\345\244\247\346\236\227/\347\254\224\350\256\260/day2.md" @@ -0,0 +1,58 @@ +rt thread内核入门 + RT-thread启动流程:rtthread_startup() 函数是 RT-Thread 规定的统一启动入口,所以一般执行顺序是:系统先从启动文件开始运行,然后进入 RT-Thread 的启动函数 rtthread_startup() ,最后进入用户入口函数 main()。 + ![alt text](image-1.png) + 为了在进入 main() 之前完成 RT-Thread 系统功能初始化,我们使用了 MDK 的扩展功能 $Sub$$ 和 $Super$$。可以给 main 添加 $Sub$$ 的前缀符号作为一个新功能函数 $Sub$$main,这个 $Sub$$main 可以先调用一些要补充在 main 之前的功能函数(这里添加 RT-Thread 系统启动,进行系统一系列初始化),再调用 $Super$$main 转到 main() 函数执行,这样可以让用户不用去管 main() 之前的系统初始化操作。 + /* $Sub$$main 函数 */ +int $Sub$$main(void) +{ + rtthread_startup(); + return 0; +} +在这里 $Sub$$main 函数调用了 rtthread_startup() 函数,其中 rtthread_startup() 函数的代码如下所示: +![alt text]({42EEAFD0-2927-49DB-8DF5-9289A90007F0}.png) + +启动代码,大致可以分为四个部分: +(1)初始化硬件; +(2)初始化系统内核对象,例如定时器、调度器、信号; +(3)创建 main 线程,在 main 线程中对各类模块依次进行初始化; +(4)初始化定时器线程、空闲线程,并启动调度器。 +启动调度器之前,系统所创建的线程在执行 rt_thread_startup() 后并不会立马运行,它们会处于就绪状态等待系统调度;待启动调度器之后,系统才转入第一个线程开始运行,根据调度规则,选择的是就绪队列中优先级最高的线程。 + +rt_hw_board_init() 中完成系统时钟设置,为系统提供心跳、串口初始化,将系统输入输出终端绑定到这个串口,后续系统运行信息就会从串口打印出来。 + +main() 函数是 RT-Thread 的用户代码入口,用户可以在 main() 函数里添加自己的应用。 + +线程的工作机制 +线程控制块 +在 RT-Thread 中,线程控制块由结构体 struct rt_thread 表示,线程控制块是操作系统用于管理线程的一个数据结构,它会存放线程的一些信息,例如优先级、线程名称、线程状态等,也包含线程与线程之间连接用的链表结构,线程等待事件集合等。 +其中 init_priority 是线程创建时指定的线程优先级,在线程运行过程当中是不会被改变的(除非用户执行线程控制函数进行手动调整线程优先级)。cleanup 会在线程退出时,被空闲线程回调一次以执行用户设置的清理现场等工作。最后的一个成员 user_data 可由用户挂接一些数据信息到线程控制块中,以提供一种类似线程私有数据的实现方式 +线程状态切换 +![alt text](image.png) +线程通过调用函数 rt_thread_create/init() 进入到初始状态(RT_THREAD_INIT);初始状态的线程通过调用函数 rt_thread_startup() 进入到就绪状态(RT_THREAD_READY);就绪状态的线程被调度器调度后进入运行状态(RT_THREAD_RUNNING);当处于运行状态的线程调用 rt_thread_delay(),rt_sem_take(),rt_mutex_take(),rt_mb_recv() 等函数或者获取不到资源时,将进入到挂起状态(RT_THREAD_SUSPEND);处于挂起状态的线程,如果等待超时依然未能获得资源或由于其他线程释放了资源,那么它将返回到就绪状态。挂起状态的线程,如果调用 rt_thread_delete/detach() 函数,将更改为关闭状态(RT_THREAD_CLOSE);而运行状态的线程,如果运行结束,就会在线程的最后部分执行 rt_thread_exit() 函数,将状态更改为关闭状态。 + +线程管理方式 +![alt text](image-2.png) +线程创建 rt_thread_create() 的参数和返回值见下表: +![alt text]({5981996A-A6F9-479E-AB3F-CCFAD7D3CC4E}.png) +线程初始化接口 rt_thread_init() 的参数和返回值见下表: +![alt text]({4D5B7518-BCB5-486F-8D0F-8734781669B1}.png) + +调度器工作 +![alt text]({CDB819F2-29BE-4306-B093-8B7E3A6C9628}.png) + +优先级抢占调度 +![alt text]({96BE737A-B681-4595-891F-CA1A636EE12D}.png) + +启动线程 +创建(初始化)的线程状态处于初始状态,并未进入就绪线程的调度队列,我们可以在线程初始化 / 创建成功后调用下面的函数接口让该线程进入就绪态: +rt_err_t rt_thread_startup(rt_thread_t thread); +当调用这个函数时,将把线程的状态更改为就绪状态,并放到相应优先级队列中等待调度。如果新启动的线程优先级比当前线程优先级高,将立刻切换到这个线程。 + +获得当前线程 +在程序的运行过程中,相同的一段代码可能会被多个线程执行,在执行的时候可以通过下面的函数接口获得当前执行的线程句柄: +rt_thread_t rt_thread_self(void); + +挂起和恢复线程 +当线程调用 rt_thread_delay() 时,线程将主动挂起;当调用 rt_sem_take(),rt_mb_recv() 等函数时,资源不可使用也将导致线程挂起。处于挂起状态的线程,如果其等待的资源超时(超过其设定的等待时间),那么该线程将不再等待这些资源,并返回到就绪状态;或者,当其他线程释放掉该线程所等待的资源时,该线程也会返回到就绪状态。 + +注:一个线程尝试挂起另一个线程是一个非常危险的行为,因此RT-Thread对此函数有严格的使用限制:该函数只能使用来挂起当前线程(即自己挂起自己),不可以在线程A中尝试挂起线程B。而且在挂起线程自己后,需要立刻调用 rt_schedule() 函数进行手动的线程上下文切换。这是因为A线程在尝试挂起B线程时,A线程并不清楚B线程正在运行什么程序,一旦B线程正在使用例如互斥量、信号量等影响、阻塞其他线程(如C线程)的内核对象,如果此时其他线程也在等待这个内核对象,那么A线程尝试挂起B线程的操作将会引发其他线程(如C线程)的饥饿,严重危及系统的实时性。 diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\351\273\204\345\244\247\346\236\227/\347\254\224\350\256\260/image-1.png" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\351\273\204\345\244\247\346\236\227/\347\254\224\350\256\260/image-1.png" new file mode 100644 index 0000000000000000000000000000000000000000..47d980d2c81436135c3a4d5fdeddeba68820fe16 Binary files /dev/null and "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\351\273\204\345\244\247\346\236\227/\347\254\224\350\256\260/image-1.png" differ diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\351\273\204\345\244\247\346\236\227/\347\254\224\350\256\260/image-2.png" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\351\273\204\345\244\247\346\236\227/\347\254\224\350\256\260/image-2.png" new file mode 100644 index 0000000000000000000000000000000000000000..86c94b884206857fa7c17b556ab19dbaed2f58ae Binary files /dev/null and "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\351\273\204\345\244\247\346\236\227/\347\254\224\350\256\260/image-2.png" differ diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\351\273\204\345\244\247\346\236\227/\347\254\224\350\256\260/image.png" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\351\273\204\345\244\247\346\236\227/\347\254\224\350\256\260/image.png" new file mode 100644 index 0000000000000000000000000000000000000000..9b8fb40320065e264202b82b925d28456640bcb8 Binary files /dev/null and "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\351\273\204\345\244\247\346\236\227/\347\254\224\350\256\260/image.png" differ diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\351\273\204\345\244\247\346\236\227/\347\254\224\350\256\260/{42EEAFD0-2927-49DB-8DF5-9289A90007F0}.png" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\351\273\204\345\244\247\346\236\227/\347\254\224\350\256\260/{42EEAFD0-2927-49DB-8DF5-9289A90007F0}.png" new file mode 100644 index 0000000000000000000000000000000000000000..7764d51227056aee066077871f32317d9d10de1d Binary files /dev/null and "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\351\273\204\345\244\247\346\236\227/\347\254\224\350\256\260/{42EEAFD0-2927-49DB-8DF5-9289A90007F0}.png" differ diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\351\273\204\345\244\247\346\236\227/\347\254\224\350\256\260/{4D5B7518-BCB5-486F-8D0F-8734781669B1}.png" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\351\273\204\345\244\247\346\236\227/\347\254\224\350\256\260/{4D5B7518-BCB5-486F-8D0F-8734781669B1}.png" new file mode 100644 index 0000000000000000000000000000000000000000..79fc1ffd6efe647c02f1f81a1ab360fa987ece40 Binary files /dev/null and "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\351\273\204\345\244\247\346\236\227/\347\254\224\350\256\260/{4D5B7518-BCB5-486F-8D0F-8734781669B1}.png" differ diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\351\273\204\345\244\247\346\236\227/\347\254\224\350\256\260/{5981996A-A6F9-479E-AB3F-CCFAD7D3CC4E}.png" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\351\273\204\345\244\247\346\236\227/\347\254\224\350\256\260/{5981996A-A6F9-479E-AB3F-CCFAD7D3CC4E}.png" new file mode 100644 index 0000000000000000000000000000000000000000..a0b8a5f4c6d3de8128711df544b4ab9b2204e8e6 Binary files /dev/null and "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\351\273\204\345\244\247\346\236\227/\347\254\224\350\256\260/{5981996A-A6F9-479E-AB3F-CCFAD7D3CC4E}.png" differ diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\351\273\204\345\244\247\346\236\227/\347\254\224\350\256\260/{96BE737A-B681-4595-891F-CA1A636EE12D}.png" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\351\273\204\345\244\247\346\236\227/\347\254\224\350\256\260/{96BE737A-B681-4595-891F-CA1A636EE12D}.png" new file mode 100644 index 0000000000000000000000000000000000000000..ef6c3ae033495239e4dd9612dd3c7ec5490dc6fd Binary files /dev/null and "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\351\273\204\345\244\247\346\236\227/\347\254\224\350\256\260/{96BE737A-B681-4595-891F-CA1A636EE12D}.png" differ diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\351\273\204\345\244\247\346\236\227/\347\254\224\350\256\260/{CDB819F2-29BE-4306-B093-8B7E3A6C9628}.png" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\351\273\204\345\244\247\346\236\227/\347\254\224\350\256\260/{CDB819F2-29BE-4306-B093-8B7E3A6C9628}.png" new file mode 100644 index 0000000000000000000000000000000000000000..2da38e51c20a834ad35a5c9acf840d591bae2ef8 Binary files /dev/null and "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\351\273\204\345\244\247\346\236\227/\347\254\224\350\256\260/{CDB819F2-29BE-4306-B093-8B7E3A6C9628}.png" differ