AI语音智能体开发日记(四)在FreeRTOS中构建线程安全的UART2通信模块
相关链接AI语音智能体开发日记一如何为“小智”服务器启用并调试 License 功能-CSDN博客AI语音智能体开发日记二解决 Wi-Fi 配网小程序的兼容性问题-CSDN博客AI语音智能体开发日记三解决小程序配网中的蓝牙命名与MAC地址获取问题-CSDN博客AI语音智能体开发日记四在FreeRTOS中构建线程安全的UART2通信模块-CSDN博客AI语音智能体开发日记五为智能设备注入“灵魂”——详解MCP工具的注册与使用-CSDN博客AI语音智能体开发日记六为智能体注入旋律——七牛云音乐服务的接入与避坑指南-CSDN博客AI语音智能体开发日记七搞定功放控制——详解GX8006平台Mute电平配置-CSDN博客AI语音智能体开发日记八LVGL 8.4.0 移植实战——从零构建嵌入式GUI-CSDN博客AI语音智能体开发日记九LVGL 8.4.0 中文字体配置全攻略-CSDN博客AI语音智能体开发日记十LVGL 图标字体实战——从 FontAwesome 到屏幕显示-CSDN博客AI语音智能体开发日记十一为智能设备“声”临其境——详解音频资源自动化生成流程-CSDN博客AI语音智能体开发日记十二GX8006 固件定制指南——从双唤醒词到 UART 音频传输-CSDN博客AI语音智能体开发日记十三一次由寄存器溢出引发的串口波特率“玄学”问题排查-CSDN博客AI语音智能体开发日记十四为语音智能体打造 LCD 表情动画位图BMP显示-CSDN博客AI语音智能体开发日记十五智能体LCD屏幕GIF动画显示方案——从GIF到BMP的完整实战-CSDN博客AI语音智能体开发日记十六智能体OTA失败的“401未授权”玄学问题排查-CSDN博客AI语音智能体开发日记十七智能体“失语“ -- 大量MCP指令与LCD内存分配引发的问题-CSDN博客AI语音智能体开发日记十八智能体服务器xiaozhi-esp32-server源码部署指南-CSDN博客AI语音智能体开发日记十九智能体服务器xiaozhi-esp32-server配置与调试-CSDN博客推荐链接AI语音智能体架构解析一系统架构全景图-CSDN博客AI语音智能体架构解析二大模型AI 的大脑-CSDN博客AI语音智能体架构解析三智控台指挥中心-CSDN博客AI语音智能体架构解析四AI 语音终端执行器官-CSDN博客AI语音智能体架构解析五小程序/APP遥控器-CSDN博客推荐链接AI 应用 图文 解说 (一) -- 百度智能云 实现 语音 聊天-CSDN博客AI 应用 图文 解说 (二) -- 百度智能云 ASR LIM TTS 语音AI助手程序 -CSDN博客开发手记在FreeRTOS中构建线程安全的UART2通信模块在嵌入式开发中串口通信是调试和数据交互最常用的方式。但在多任务的FreeRTOS环境下如果多个任务同时尝试通过串口发送数据很容易出现数据交错、混乱的问题。今天就来记录一下如何在我们的lightning项目中通过引入互斥锁Mutex来构建一个线程安全的UART2发送模块。需求背景我们的项目需要增加一个通过UART2进行数据发送的功能。这个功能不仅要求能正常收发数据还必须保证在FreeRTOS多任务环境下的稳定性防止因多个任务同时调用发送函数而导致的数据混乱。解决方案分步实现整个实现过程可以分为四个主要步骤GPIO引脚配置、FreeRTOS发送函数构建、主函数调用以及状态指示LED的配置。第一步配置UART2的GPIO引脚首先我们需要在底层硬件抽象层HAL中配置UART2所使用的GPIO引脚。根据原理图我们选择PA1作为RX接收PA4作为TX发送。在project/ln_model_public/bsp/serial_hw.c文件中找到uart_io_pin_request函数并添加对SER_PORT_UART2的支持1// 文件: project/ln_model_public/bsp/serial_hw.c 2 3static void uart_io_pin_request(struct Serial *serial) 4{ 5 // ... 其他UART的配置 ... 6 7 else if (serial-port_id SER_PORT_UART2) 8 { 9 /******************zrh add******************/ 10 // 配置 PA1 为 UART2 的 RX 功能 11 hal_gpio_pin_afio_select(GPIOA_BASE, GPIO_PIN_1, UART2_RX); 12 // 配置 PA4 为 UART2 的 TX 功能 13 hal_gpio_pin_afio_select(GPIOA_BASE, GPIO_PIN_4, UART2_TX); 14 15 // 使能 PA1 和 PA4 的复用功能 16 hal_gpio_pin_afio_en(GPIOA_BASE, GPIO_PIN_1, HAL_ENABLE); 17 hal_gpio_pin_afio_en(GPIOA_BASE, GPIO_PIN_4, HAL_ENABLE); 18 /*******************************************/ 19 } 20}这段代码的作用是将PA1和PA4引脚的功能复用AFIO为UART2的接收和发送端并启用该功能。第二步构建线程安全的发送函数这是整个功能的核心。我们需要在project/ln_model_public/app/servers/qiniu/mcp_server/mcp_tools/smart_toilet/uart.c文件中实现初始化、数据发送和互斥锁保护。1// 文件: .../smart_toilet/uart.c 2 3#define LOG_PORT_BAUDRATE CFG_UART_BAUDRATE_LOG 4 5// 定义一个全局的串口句柄 6Serial_t cmd_Serial; 7// 定义一个互斥锁句柄用于保护串口写操作 8static OS_Mutex_t uart_write_mutex; 9 10// 串口初始化函数 11int uart_init(void) 12{ 13 // 初始化 cmd_Serial指定使用 UART2并设置波特率 14 serial_init(cmd_Serial, SER_PORT_UART2, LOG_PORT_BAUDRATE, NULL); 15 return 0; 16} 17 18// 互斥锁初始化函数 19void uart_write_mutex_init(void) 20{ 21 OS_MutexCreate(uart_write_mutex); 22} 23 24// 基础的串口写函数 25int cmd_stdio_write(char *buf, size_t size) 26{ 27 int ret 0; 28 // 调用底层的 serial_write 函数进行实际的数据发送 29 ret serial_write(cmd_Serial, (const void *)buf, size); 30 return ret; 31} 32 33// 线程安全的串口写函数 34void safe_cmd_uart_write(char *buf, size_t size) 35{ 36 // 判断调度器是否已经运行 37 if (OS_ThreadIsSchedulerRunning()) { 38 // 如果调度器已运行检查互斥锁是否有效无效则创建 39 if (!OS_MutexIsValid(uart_write_mutex)) { 40 OS_MutexCreate(uart_write_mutex); 41 } 42 // 获取互斥锁如果已被其他任务占用则等待 43 OS_MutexLock(uart_write_mutex, OS_WAIT_FOREVER); 44 } 45 46 // 执行实际的发送操作 47 cmd_stdio_write(buf, size); 48 49 // 发送完成后释放互斥锁 50 if (OS_ThreadIsSchedulerRunning()) { 51 OS_MutexUnlock(uart_write_mutex); 52 } 53}关键点分析uart_init: 负责初始化指定的串口UART2。safe_cmd_uart_write: 这是提供给其他任务调用的接口。它在发送数据前会先尝试获取互斥锁uart_write_mutex。这确保了在任何时刻只有一个任务能够执行cmd_stdio_write从而避免了数据交错。发送完成后立即释放锁。第三步在主函数中调用初始化最后我们需要在系统启动时调用我们刚刚创建的初始化函数。在project/ln_model_public/app/main.c文件的main函数中添加如下调用1// 文件: project/ln_model_public/app/main.c 2 3int main(int argc, char *argv[]) 4{ 5 // ... 系统时钟、中断等初始化 ... 6 7 log_init(); 8 9 /******************zrh add******************/ 10 // 初始化UART 11 uart_init(); 12 // 初始化UART写操作的互斥锁 13 uart_write_mutex_init(); 14 /*******************************************/ 15 16 // ... 其他初始化 ... 17}确保在系统调度器启动前完成这些初始化工作。第四步配置网络状态指示LED为了方便调试我们可以配置一个LED来指示网络状态。在project/ln_model_public/app/usr_app.c文件中定义LED所使用的GPIO引脚1// 文件: project/ln_model_public/app/usr_app.c 2 3// 定义网络状态指示灯的端口和引脚 4#define CONFIG_NET_STATUS_PORT (GPIOB_BASE) 5#define CONFIG_NET_STATUS_PIN (GPIO_PIN_6)这里我们将网络状态指示灯配置在了PB6引脚上。总结通过以上四个步骤我们成功地在项目中实现了一个功能完整且线程安全的UART2通信模块。硬件层正确配置了UART2的GPIO引脚。软件层利用FreeRTOS的互斥锁机制封装了安全的发送函数解决了多任务环境下的资源竞争问题。系统集成在main函数中完成了模块的初始化并配置了状态指示灯便于后续调试。这个模式是嵌入式开发中处理共享资源如串口、I2C总线等的经典做法非常值得掌握。

相关新闻

Elasticsearch Reindex 实战指南:从机制解析到性能调优避坑

Elasticsearch Reindex 实战指南:从机制解析到性能调优避坑

1. 为什么需要 reindex:五个让我踩过坑的典型场景先给没接触过的朋友一个基本认知:reindex 不是某个数据库独享的功能,主流存储引擎基本都有类似的能力。我最早接触是在 Elasticsearch 上,后面在消息队列、关系型数据库分库分表扩…

2026/10/12 2:07:10 阅读更多 →
固定资产管理系统怎么选?从生命周期、折旧到RFID与盘点落地全拆解

固定资产管理系统怎么选?从生命周期、折旧到RFID与盘点落地全拆解

固定资产管理软件这个词,做企业服务和IT的人都绕不开,但真正被问住的时候往往在客户现场:对方拿出采购清单,说要买一套固定资产管理系统,理由是盘点太累了、审计总找麻烦、资产管理岗的人换了好几拨每次都从头理。你会…

2026/10/12 2:07:10 阅读更多 →
C语言实现广度优先搜索:马走日遍历算法详解

C语言实现广度优先搜索:马走日遍历算法详解

1. 项目背景与需求拆解1.1 什么是“之马遍历”?初次看到“广度优先搜索(之马遍历)C语言”这个标题,很多人可能会先愣一下。“之马”其实是象棋中“马走日”的另一种叫法,也叫“日字跳”或“骑士走法”。把一只马放在88…

2026/10/12 2:07:10 阅读更多 →

最新新闻

嵌入式Linux安卓驱动开发:供需、实战与面试全攻略

嵌入式Linux安卓驱动开发:供需、实战与面试全攻略

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 2:53:39 阅读更多 →
共享Buffer却带宽没降?DDR流量的五大根因与排查实战

共享Buffer却带宽没降?DDR流量的五大根因与排查实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 2:53:39 阅读更多 →
OTFS信道估计实战:压缩感知与相位旋转在高速移动通信中的应用

OTFS信道估计实战:压缩感知与相位旋转在高速移动通信中的应用

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 2:53:39 阅读更多 →
Qt5.9 C++开发指南章节代码实战:从环境搭建到工程避坑

Qt5.9 C++开发指南章节代码实战:从环境搭建到工程避坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 2:53:39 阅读更多 →
Linux进程虚拟地址空间:从页表映射到段错误排查

Linux进程虚拟地址空间:从页表映射到段错误排查

搞Linux服务端开发的人,迟早会遇到这么一幕:程序跑着跑着突然Segmentation Fault,或者free的时候报double free,又或者top里看到某个进程的VIRT高得离谱,但RES却很低。很多人第一反应是查代码、查日志,但真…

2026/10/12 2:53:39 阅读更多 →
ESP32 上实现 ONVIF 相机:从组件搭建到 NVR 添加实战

ESP32 上实现 ONVIF 相机:从组件搭建到 NVR 添加实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 2:52:39 阅读更多 →

日新闻

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

在数码相机、高清显示屏与现代矢量图形技术高度发达的今天,画面可以做到绝对的锐利、平滑与无瑕。然而,当一张秋日手账插画或拍立得照片过于“平整无瑕”时,往往会散发出一种冰冷生硬的“数码塑料感(Digital Plasticity&#xff0…

2026/10/12 0:00:59 阅读更多 →
活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

在现代网页与移动端设计中,横排(Horizontal Layout)早已经成为了绝对的主流。然而,当我们翻开泛黄的线装古籍、宋版木刻诗集,或是欣赏一张茶道雅集的手写便签时,那种**自上而下纵向书写、自右向左逐列铺展&…

2026/10/12 0:00:59 阅读更多 →
周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

每到周日的晚上八点到十点,很多人心里都会悄悄亮起一盏警示灯。 在心理学上,这种现象有一个专门的称谓——“周日夜晚焦虑症(Sunday Scaries)”。明天又是周一,闹钟又要重新在七点响彻卧房;脑海里仿佛有一个…

2026/10/12 0:00:59 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/12 0:16:30 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/12 0:16:43 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 10:45:37 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:53 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:54 阅读更多 →