当前位置: 首页 > news >正文

STM32F103串口非阻塞收发

预期效果:波特率9600bps,PC发送200字节/100ms,发送一万字节,MCU原封不动发回来。

接收

肯定要用DMA啦。DMA用循环模式,就是说把接收缓冲当成一个队列,满了或者到了一半,就更新一下队列的头尾指针。还有串口的空闲事件,也要用上,外面来的数据要是停了能及时响应处理。
image

缓冲区长一点比较好,因为太短的话外来数据老是覆盖掉不久前的内容,长一点的话能给足你复制数据的时间。

读数据的话,就用类似uint16_t read_uart(uint8_t *buf, uint16_t len)的原型就行。本来想着加一个参数uint16_t timeout_ticks的:要是len参数太大,缓冲区内容不够就让它先等等。后来一想需要原地硬等,就又变成了阻塞式,不合适。所以还是立即返回比较好,实际拿到多少数据就返回多少。

具体讲呢,主要是两个地方。一个是上面的那个函数,另一个就是在void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)里面,判断一下这个事件的类型。

这个事件类型是个枚举值。这里只需要更新这个队列的尾指针rxbuf_wp就行。除此之外还有个标志,给外部用的。我现在的做法是主循环检查它,决定要不要读。也可以把它塞进read_uart函数里面,当时候没数据就等一会儿,给read_uart一个参数来决定要不要它等待。

现在先这样吧,以后上RTOS了直接用同步工具了,信号量什么的。当然也可以延时等待,毕竟任务调度还是能保证把时间分给别的任务的。这里就是裸机,学习一下这种机制就行,没必要那么深入。整一个全局标志,你写我读,没啥毛病。
image

这里就直接更新队列指针,不复制了,等到啥时候发现有数据了,has_data不为零了,就调用read_uart,那时候咱再复制。DMA队列是循环的,指针到末尾了别忘了回绕回来。
image
函数里面就是先看队列里面有多少数据了,看看够不够取。不够取的话能取多少取多少,就是变量【J】。然后就是复制数据出来到参数buf指向的内存区里。

这儿分两种情况,就是队列数据区是一整块儿【rp..wp】,还是【0..wp】一块【rp..END】一块。如果是前者,那就一次复制就完事儿了。如果后者,又分情况,右边那一块儿地方数据多不多,够不够取。要是不够取,复制完【rp..END】还得接着复制【0..N】才行。反正变量【J】检查过,队列里总数据量肯定是够的。要是【rp..END】够取,那和【rp..wp】这种情况是一模一样的操作。

复制完数据之后,更新一下读指针和标志,返回【J】的值。

有一个问题:这函数执行一半,那边DMA往里头扔数据咋办?我读的rxbuf_wp就失效了?

这确实是个问题。本来想用__disable_irq,觉得没啥必要,只要原子操作就行。后来又觉得写__DSB,DMB内存屏障宏会好一点。再后来终于明白,因为我测试用的stm32f103c8t6属于黑铁段位,这个芯片串行执行指令,读写指令相当于原子操作,根本不配用内存屏障。最后怕编译器打乱顺序,直接无脑加 volatile 就完事儿了,也不想搞那么复杂。

重点就是缓冲区得稍微大一点。不能说这边正复制数据呢,那边儿DMA把我数据给覆盖了。

这方法就这样儿,没办法。DMA自己要用一个缓冲区,你为了非阻塞,还是不定长数据,而且更离谱的是上层还想着要能流式处理。还能咋样呢?裸机又没有硬件FIFO,就只能牺牲内存了呗。

简直拉完了

你算算,dma底层发送得要缓存吧,接收得要缓存吧。你读取可以直接从DMA缓存区复制,只要人家不给你覆盖。但是发送的时候为了避免两次挨得太近HAL库函数给你返回BUSY忙状态,得再要一个队列吧。然后read_uart的参数,是不是又是一个缓冲区?一共三个缓存区,你的队列还得保证一次至少能放得下两帧。

有这功夫,我为啥不直接一个1KB缓存,用HAL_UARTEx_ReceiveToIdle()呢?我就赌你一次发不了那么多,赌你连续发送连一个IDLE frame都没有。最多用户缓冲再占1KB。BUG又少效率又高。既然让内存硬扛,那不如一开始就贯彻到底。

发送

ST给的HAL库函数能DMA发送。但是两次发送挨得太近的话第二次会返回HAL_BUSY,因为第一次还没完成。也就是说,你得自己维护一个队列,每次DMA发送完了,让它自己到里面去取一块数据发出去。前面讲过了,得要一个队列。无语的是这队列不能小了。太小你上层write_uart老是堵住,执行不下去,因为队列给写满了,DMA还在忙。

不管怎么样吧,就这个DMA加队列的思路,简单实现一下。

image

那里有一个等待超时的for循环,就是现在txbuf满了,发不了,停一下,再重新检查一下。其实可以让【rp】和【txbuf_rp】比较,就看它俩相不相同。变量【txbuf_rp】一旦动了,说明dma从这儿把数据取走,向外发送去了。这样就有空闲空间了,接下来就可以自由发挥了。比如设置一个阈值,规定dma给我腾出来至少64字节我write_uart才愿意继续跑。不然老在这里等你dma,成何体统?

里面那个函数uart_start_send(),它就是把队列里的数据复制出来,排好序,送DMA挨个儿发出去,算是一线干活的。
image

为啥要复制呢,就是把数据从队列里领出来,拼成一个连续的缓存里。这样DMA发送的时候既不会打乱顺序又不会占用原来write_uart用的txbuf。后续write_uart调用能直接往txbuf里面扔新数据,因为上一次的数据被复制到dma的txbuf2里面了。道理就是这么个道理,反正复制的时候注意是复制一块连续内存还是头尾两块儿就行了。

最后还有一个void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)。就看看txbuf里面还有没有东西能发的。要是有就继续干,没有就把忙状态清零告诉别人我dma干完活了。

下次执行write_uart时候,write_uart里面会重新调一次uart_start_send,dma又开始干活。别的地方不需要用这个标志。
image

其实这个判断【rp】和【wp】为真之后可以直接把他俩清零,回到初始状态。反正这个时候队列里要发的东西dma都发完了。不过既然是循环队列,那就无所谓啦。

效果

100ms定时发送,一次发190字节,也不算很快吧。主要是测试一下正确不正确,丢数据不丢。

image

一边发一边收,效果还行吧。就是太占内存,拉完了

http://www.jsqmd.com/news/900297/

相关文章:

  • 2026年最新:论文AI率从60%降至5%实测,10款降AI工具与手改技巧指南 - 降AI实验室
  • Windows Terminal 1.18终极指南:五大生产力功能深度解析与实战应用
  • 别再傻傻分不清!用Arduino和ESP32驱动电机,NPN三极管与N-MOS管实战选型指南
  • 2026年5月更新:宜兴有名的硝化菌公司深度剖析,聚焦宜兴橡树 - 2026年企业资讯
  • 护眼台灯哪个牌子的性价比高?家长公认性价比护眼灯品牌,不踩雷
  • 鸿蒙截屏/投屏/录屏状态检测:isCaptured 与 onCaptureStatusChange 实战
  • 2026年 宝钢HC900/1180CP吉帕钢推荐榜:高强度冷成型与轻量化解决方案的创新之选 - 品牌企业推荐师(官方)
  • 光电子神经形态计算:RTD神经元原理与应用
  • 别再只盯着皮尔逊了!用Python实战斯皮尔曼相关系数,搞定非线性数据关联分析
  • HC-276合金厂商那家好?资深采购员实地测评 - 品牌2025
  • 2026年5月常州企业快餐配送品牌公司业内推荐:为何“常州锦润餐饮管理有限公司”备受青睐? - 2026年企业资讯
  • 2026年隔离墩模具/挡土墙模具厂家推荐:流水槽/排水沟/化粪池/护坡模具优质选型与口碑解析 - 品牌企业推荐师(官方)
  • 6款论文降AI率平台实测:AI率直降安全线,学生党必入平价款
  • 百考通AI:开题报告智能生成,轻松输出专业内容
  • 化工领域热门推荐:Incoloy 800在高温高压下的表现如何? - 品牌2025
  • 2026年至今福建好的餐边柜制造商:如何精准选型避坑? - 2026年企业资讯
  • S32K3 eMIOS实战:从MCAL配置到PWM与ICU的精准控制
  • 基于 okbiye 的 AI 论文写作实践:毕业论文从选题到定稿的高效路径探索
  • 2026年高端制造新标杆:探秘深圳市聚德鑫特殊钢材的Inconel 718品质之道 - 品牌2025
  • 2026年 宝钢HC550/980DP双相钢/吉帕钢推荐榜单:超高强度与冷弯性能俱佳,冲压成形解决方案优选! - 品牌企业推荐师(官方)
  • 2026年 电磁离合器/电磁制动器/电磁刹车器推荐榜单:单片、多片与通电失电式全系优选解析 - 品牌企业推荐师(官方)
  • 从单工到全双工:RS232/RS422/RS485通信模式与典型应用场景解析
  • 2026年 3051DP差压变送器厂家推荐榜:TK-DZS-3051DP/天康智能变送器品牌与高精度优选 - 品牌企业推荐师(官方)
  • VLSI架构实现心电信号自适应压缩:在功耗与精度间动态平衡
  • Ensembl BioMart实战:快速搞定基因ID、Symbol与长度的匹配表(避坑TSV文件空格问题)
  • AR 智能眼镜智正优化警务领域的日常巡逻和排查麻烦的难点
  • ESP32-S3边缘AI能耗预测:3天数据实现月度精准预测
  • 告别熬夜改论文!okbiye AI 写作,让毕业论文从开题到定稿一键通关
  • PCA降维后数据还能‘还原’吗?用Python实战带你理解信息损失与数据重构(含误差分析)
  • 等保测评数据库安全相关检查