RT thread邮箱知识点讲解

张开发
2026/6/2 1:57:53 15 分钟阅读
RT thread邮箱知识点讲解
底层物理结构固定大小的 32 位数组在系统内核中一个邮箱对象在物理内存里表现为一个固定长度的环形缓冲区。 最核心的物理限制是这个缓冲区里的每一个数据格一封邮件大小被严格写死为 4 个字节。0.邮箱在rt thread中的作用1传递指针如果有1000份的数据需要传输直接把对应数据的内存地址传给对方让对方从地址上读取方便快捷2缓冲作用邮箱本身自带一个缓冲队列。发送线程生产得快可以先把“信件”排队塞进邮箱然后继续干活接收线程处理得慢也。关系只要邮箱没满数据就不会丢。3自动休眠与唤醒 当邮箱里没有信件时调用rt_mb_recv的接收线程会自动挂起把宝贵的 CPU 资源让给其他线程。一旦发送线程投递了新邮件操作系统会瞬间把接收线程唤醒。4中断与线程之间的通信在嵌入式底层开发中硬件中断ISR比如按键按下、串口收到数据要求“快进快出”绝对不能在中断里执行耗时的操作或死等。可以瞬间把状态码放入邮箱中。其他线程去读取该数据。主要函数1. 创建邮箱rt_mb_create作用在系统动态堆内存Heap中分配邮箱控制块并根据你指定的大小开辟一块连续的物理内存作为环形缓冲区。rt_mailbox_t rt_mb_create(const char *name, rt_size_t size, rt_uint8_t flag);参数输入name邮箱的名称字符串如mail_A。size邮箱的容量能装多少封邮件。如果你填10系统会在底层分配10 * 4 40个字节的缓冲区。flag阻塞唤醒规则。RT_IPC_FLAG_FIFO先进先出。多个线程等邮件时谁先来排队谁先拿到。RT_IPC_FLAG_PRIO优先级唤醒。优先级最高的线程优先拿到邮件。返回值成功返回邮箱控制块的句柄rt_mailbox_t类型的指针。失败返回RT_NULL通常是因为动态内存不足。2. 发送邮件rt_mb_send作用将一个 32 位的数据或地址写入邮箱的环形缓冲区。如果此时有线程正在阻塞等待该邮箱内核会立即触发调度将其唤醒。rt_err_t rt_mb_send(rt_mailbox_t mb, rt_ubase_t value);参数输入mb你要操作的邮箱句柄。value你要发送的数据。由于参数类型被强制限定为rt_ubase_t32 位整数如果你要发送的是指针必须进行强制类型转换例如(rt_ubase_t)data_ptr否则编译器会报错。返回值RT_EOK发送成功。-RT_EFULL邮箱已经满了。物理规则与使用场景 该函数执行极快不包含任何阻塞逻辑因此它是完全中断安全的被大量应用于硬件中断服务函数ISR中向线程传递底层数据。3. 接收邮件rt_mb_recv作用从邮箱的环形缓冲区中读取最早进入的一封邮件4 个字节。如果邮箱为空当前线程将被挂起进入阻塞状态。rt_err_t rt_mb_recv(rt_mailbox_t mb, rt_ubase_t *value, rt_int32_t timeout);参数输入mb邮箱句柄。value需要提供一个存放数据的内存物理地址。内核在底层会执行写指令把邮箱里的 4 字节数据直接写进这个地址里。这就是为什么如果你的局部变量本身是指针struct all_data *data你还必须用data对它再次取地址把它所在的栈地址提供给内核。timeout超时等待时间单位Tick。RT_WAITING_FOREVER永久死等直到拿到邮件。0非阻塞读取。有邮件就读没有立刻返回报错。正整数最多挂起等待该数值的节拍数。返回值RT_EOK成功接收到一封邮件数据已经被写入你提供的value地址中。-RT_ETIMEOUT超时时间已到但邮箱依然为空。-RT_ERROR发生其他内核级错误。例子假设有8个字节的数据要进行传输邮箱的邮件最大是4字节这时候我们可以传入数据的指针。其他接收线程可以读取地址去找到数据的值。假设现在有温湿度数据8个字节通过把结构体的指针传入到邮箱中其他线程通过rt_mb_recv读取。#include rtthread.h #include rtdevice.h #include board.h #include stdlib.h // 提供 malloc 和 free 函数的声明支持 // 定义全局的线程控制块指针和邮箱控制块指针 rt_thread_t send_data_t; rt_thread_t rec_data_t; rt_mailbox_t box_c; // 定义用于传递数据的结构体模板 struct all_data { int wendu; // 温度 int shidu; // 湿度 }; // 数据写入函数用于给传入的结构体指针指向的内存赋值 void all_data_write(struct all_data *data) { >1(struct all_data *)malloc(sizeof(struct all_data))如何理解malloc的工作是在堆区划出一块指定大小比如 8 字节的内存然后把这块内存的首地址返回。但是申请这块内存是用来存整数、存字符还是存你自定义的结构体 未知。因此malloc的返回值类型是void *无类型指针也叫万能指针。(struct all_data *)malloc返回的地址4字节是温湿度结构体指针注意a如果使用全局变量来存储传感器数据发送线程在第二次循环时更新了数据但接收线程可能还没来得及处理第一次的数据。这会导致接收线程读到的是被覆盖后的数据。b没用while的情况下如果使用局部变量在函数结束时内存被系统回收这时候时候发过去的地址读取时会出现乱码情况。如果在while循环中数据过快读取也会造成重复覆盖数据。c使用malloc的优势每次循环都会在堆区申请一块全新且独立的内存。发送线程把数据写进新内存后把指针扔进邮箱。这样发送线程就可以继续去申请下一块内存绝对不会覆盖之前还未被接收的数据。2 rt_mb_recv(box_c,(rt_ubase_t *)data, RT_WAITING_FOREVER);如何理解rt_mb_send_wait(, (rt_base_t)data,)发送过来的是温湿度结构体的指针接收的时候要用一个变量去接收这个指针struct all_data *data定义结构体指针变量在内存中分配地址存这个指针变量rt_mb_recv中间的参数要传入的是地址data把存放data指针的地址取出来这时候data等于发送过来的温湿度结构体的指针(rt_ubase_t *)类型强制转换

更多文章