月经不来是什么原因导致的| 软笔是什么| 头臂长是什么意思| 月经推迟什么原因引起的| 润色是什么意思| 法益是什么意思| 音什么笑什么成语| 柿子像什么| 肺脓肿是什么病严重吗| 发烧看什么科室| 婧五行属什么| 腹泻吃什么食物| afp是什么传染病| 空调买什么牌子的好| 山楂和什么泡水喝最好| 敬谢不敏是什么意思| 争奇斗艳的斗是什么意思| naco3是什么| 紧急避孕药什么时候吃最有效| 可可粉是什么东西| 可以是什么意思| 怀孕有什么特征| 食管炎吃什么药| 筋头巴脑是什么肉| 栀子花黄叶是什么原因| 什么地诉说| 打呼噜吃什么药| 切诺是什么药| 兔子的眼睛为什么是红色的| 大腿根部痒用什么药膏| 马上风为什么拔不出来| 火花是什么意思| 痰带血丝是什么原因| 倾字五行属什么| 睡不着觉吃什么药效果好| ipl是什么意思| 反复口腔溃疡是什么病的前兆| 1942年属什么生肖| 高血压看什么科| 五月初五是什么星座| 热忱是什么意思| 霜降是什么意思| 节气是什么意思| 三高挂号挂什么科| 喝苹果醋有什么好处| 干咳嗽吃什么药| 胆固醇高对身体有什么危害| 嘴唇裂口是什么原因| 梦见狗打架是什么意思| 213什么意思| 赢荡为什么传位嬴稷| 天才是指什么生肖| 苏小小属什么生肖| 湘潭市花是什么| 荨麻疹不能吃什么食物| norm什么意思| 额头凉凉的是什么原因| 晚上梦见蛇是什么预兆| 7月份可以种什么菜| 用什么泡脚能减肥| 很多条腿的虫子叫什么| 水样便腹泻是什么引起| 癌症有什么症状| 前庭神经炎挂什么科| 51是什么意思| 乌鸡白凤丸适合什么人吃| 电话停机是什么意思| 市政府办公室主任是什么级别| 佛龛是什么| 玫瑰花代表什么意思| 抗日战争什么时候开始的| 为什么洗澡后皮肤会痒| 辟谷可以吃什么| 菲字五行属什么| 月经为什么来了一点又不来了| 养狗养不活是什么兆头| value是什么意思| 什么茶叶好喝又香又甜| 导滞是什么意思| SEX是什么| 包皮是什么| 腿肿脚肿是什么病的前兆| 未亡人什么意思| 正念是什么| 全脂牛奶和脱脂牛奶有什么区别| 多多包涵是什么意思| 回春是什么意思| 白眼球有红血丝是什么原因| 2000年是属什么生肖| 什么是理科什么是文科| 口苦挂什么科最好| 痰多吃什么化痰| 吃什么补铁快| 雌二醇高说明什么| 癖是什么意思| cpi指数是什么意思| 查抗体是做什么检查| 梦见自己手机丢了是什么意思| 人参不能和什么一起吃| 北京户口有什么用| 大姨妈有黑色血块是什么原因| 木危读什么| 杨梅有什么功效和作用| 钉钉是什么| electrolux是什么牌子| 束手无策是什么意思| 汗毛旺盛是什么原因| 氯偏低是什么原因| 吃什么可以治拉肚子| 子宫肌瘤有什么症状表现| 新西兰现在是什么季节| 斯德哥尔摩是什么意思| NPY什么意思| o型血和ab型血生的孩子是什么血型| 梦见眼镜蛇是什么预兆| 股癣是什么样的| 中成药是什么| 属龙是什么星座| 动手术后吃什么对伤口恢复比较快| 涤纶是什么布料| 什么叫211大学| 阳光照耀是什么意思| 早搏的症状是什么表现| 凭什么姐| 高位破水是什么意思| 金鱼可以和什么鱼混养| 白色五行属什么| 粘鞋子用什么胶水最好| 美国为什么不敢打朝鲜| 泰安有什么好吃的| 笑靥如花什么意思| 菜鸟裹裹是什么快递| 三朵花代表什么意思| 左眼皮跳是什么预兆女| 鼻涕臭是什么原因| 九八年属什么生肖| 麦粒肿吃什么药| 可悲可叹是什么意思| 攒局什么意思| 末伏是什么意思| 尿是绿色的是什么原因| 口大是什么字| 乌龟的天敌是什么动物| 经期可以喝什么| 突然勃不起来是什么原因造成的| 人为什么会有狐臭| 什么是配速| 杨八妹属什么生肖| 杜撰是什么意思| 地奥心血康软胶囊主治什么病| 孕妇梦见老鼠是什么意思| 吃什么补血效果最好| nc是什么意思| 睡眠障碍应该挂什么科室| 聚首一堂是指什么生肖| 短杆菌是什么意思| 梦见和老公结婚是什么意思| 56年属什么生肖| 武夷山岩茶属于什么茶| 健康证是什么样的| 牙龈出血挂什么科| 唐僧姓什么| sephora是什么牌子| 什么自语| 衍生物是什么意思| 倒数第二颗牙齿叫什么| BS是什么意思啊| 接档是什么意思| 花容月貌是什么意思| 冥想什么意思| 畸形是什么意思| 黄色配什么颜色最搭| 胰头占位是什么病| 狗懒子是什么意思| 肾萎缩吃什么药好| 肉桂是什么| 阴虱用什么药最有效| 减张缝合是什么意思| 宋朝之前是什么朝代| 肌肉僵硬是什么原因引起的| 事急从权是什么意思| 精神衰弱吃什么能改善| 多动症吃什么药| 平的反义词是什么| 什么态度| 罢免是什么意思| 女性性冷淡是什么原因| 月经期肚子疼是什么原因| 尿血应该挂什么科| 花中隐士是什么花| 桫椤是什么植物| 美国为什么打越南| 2004年是什么命| 足跟疼挂什么科室| 白细胞高说明什么| 唇红齿白是什么生肖| 七月13号是什么星座| 丢是什么意思| 拼图用什么软件| 什么老什么老| 内裤上有黄色分泌物是什么原因| 红曲粉是什么东西| 射手座和什么星座最配| 12.6是什么星座| 心脏支架最怕什么| 眩晕呕吐是什么病| 111是什么意思| 梦见花开是什么预兆| 脚底长痣有什么说法| 6.25什么星座| 房间消毒杀菌用什么好| 王八吃什么| u18什么意思| 内痔用什么药治最好效果最快| 甲状腺是什么原因引起的| 十面埋伏是什么生肖| 脑供血不足会导致什么后果| 总想喝水是什么原因| 最贵的烟是什么牌子| 庚日是什么意思啊| 嬴稷是秦始皇的什么人| 后脑两侧痛是什么原因| 胆红素阴性是什么意思| 微信英文名叫什么| 上市公司是什么意思| 女方什么人不能送亲| 什么样的女人招人嫉妒| 缺维生素c会得什么病| 什么人不能吃人参| 乳头很痒是什么原因| 拔智齿挂什么科| 四季常青财运旺是什么生肖| 身体老是出汗是什么原因| 天空为什么会打雷| 什么是原生家庭| 小腿经常抽筋是什么原因| 参加白事回来注意什么| 宋朝之后是什么朝代| 1941年是什么年| 苯甲酸钠是什么东西| 嘴唇肿了是什么原因| 扁桃体为什么会发炎| 肩膀酸胀是什么原因| 珠五行属什么| 什么远什么长| 下体有异味是什么原因| 热的什么| 眼镜是什么时候发明的| 脸上发麻是什么原因| 手抖是什么毛病| 五音指什么| 肠胃不舒服挂什么科| 什么什么自语| 出挑是什么意思| 仔细的什么| 者加羽念什么| 老虎菜为什么叫老虎菜| amo是什么意思| 气血不足吃什么食物好| 木羽念什么| 尿黄是什么原因男性| 什么的仪式| shipped是什么意思| 甲状腺是什么科| 百度

新闻中心

EEPW首页 > 嵌入式系统 > 设计应用 > 基于 STM32F4 的串口通信驱动实现详解(环形缓冲区版)

《中国记者》杂志

作者:嵌入式芯视野 时间:2025-08-04 来源:今日头条 收藏
百度 佛教寺院利用微信公众号、认证微博、各大互联网平台自媒体号,转发分享,急速传播。

在嵌入式系统开发中,串口通信(UART)是最常用的基础通信方式之一。为了解决串口数据读写的不连续性问题,通常会配合环形缓冲区使用,以实现高效、稳定的数据收发缓存管理。

本文介绍一个基于 STM32F4 系列 MCU 编写的,采用中断方式配合发送/接收缓冲区,并封装为控制台接口,便于在系统中调用。

一、串口缓冲区定义与初始化

串口收发数据通常不直接读写寄存器,而是通过缓冲机制管理数据流。本例中使用了两个环形缓冲区 rxbuf 和 txbuf,分别用于接收和发送:

static unsigned char rxbuf[TTY_RXBUF_SIZE];  // 接收缓冲区static unsigned char txbuf[TTY_TXBUF_SIZE];  // 发送缓冲区static ring_buf_t rbsend, rbrecv;            // 缓冲区控制结构体

并在串口初始化时调用 ring_buf_init() 对缓冲区进行初始化。

二、串口初始化函数 uart_init

static void uart_init(int baudrate)

该函数用于初始化 USART1,并完成如下步骤:

  1. 初始化收发缓冲区控制结构体。

  2. 打开 GPIOA 和 USART1 时钟。

  3. 配置 USART1 的引脚复用功能(PA9 → TX,PA10 → RX)。

  4. 配置 GPIO 模式(复用模式,无上下拉)。

  5. 配置串口参数(波特率等)。

  6. 配置 NVIC 中断优先级并使能 USART1 中断。

通过将底层串口配置封装在 uart_init() 中,使得后续调用更加简洁。


三、串口写函数 uart_write

static unsigned int uart_write(const void *buf, unsigned int len)

此函数负责将要发送的数据写入发送缓冲区,并开启发送中断:

  • 通过 ring_buf_put() 将数据写入 rbsend。

  • 开启 USART_IT_TXE 发送中断。

  • 返回实际写入字节数。

由于发送在中断中进行,所以只需触发中断即可自动依次发送缓冲区数据。


四、串口读函数 uart_read

static unsigned int uart_read(void *buf, unsigned int len)

用于从接收缓冲区读取数据:

  • 通过 ring_buf_get() 从 rbrecv 中取出数据放入 buf。

  • 返回实际读取长度。

适用于非阻塞方式的读取调用。


五、缓冲区状态查询函数

代码中定义了以下缓冲区状态查询接口:

static bool tx_isfull(void);   // 判断发送缓冲区是否满bool tx_isempty(void);         // 判断发送缓冲区是否为空bool rx_isempty(void);         // 判断接收缓冲区是否为空

这些函数用于上层逻辑判断是否可以继续发送、是否有接收数据等,提升串口使用灵活性。


六、TTY 接口结构体封装

串口驱动最终以一个结构体 tty_t 形式暴露接口:

const tty_t tty = {
    uart_init,
    uart_write,
    uart_read,
    tx_isfull,
    tx_isempty,
    rx_isempty
};

这种方式便于统一管理串口控制接口,适合在大型项目中引入“控制台抽象层”统一管理多个串口。


七、串口中断处理函数 USART1_IRQHandler

这是串口驱动的核心部分,负责响应 USART1 的收发中断:

void USART1_IRQHandler(void)

主要包含以下处理逻辑:

  1. 接收中断 RXNE:

  2. 从接收寄存器读取数据。

  3. 存入接收缓冲区 rbrecv。

  4. 发送中断 TXE:

  5. 从发送缓冲区 rbsend 中取出下一个字节发送。

  6. 若无数据可发,关闭发送中断。

  7. 溢出错误中断 ORE_RX:

  8. 读取一次数据清除溢出标志位。

通过中断方式处理串口收发,不仅避免了阻塞操作,还能在高速数据传输中保持系统响应性。


八、总结

本驱动模块实现了一个完整的串口通信功能,具备如下特点:

  • 支持发送与接收双缓冲。

  • 使用中断驱动方式收发数据。

  • 提供状态判断接口,便于上层调用。

  • 封装为 tty_t 控制台结构,支持模块化应用。

其设计适用于嵌入式系统中多个串口同时工作的场景,也适合作为 CLI 控制台、调试口或上位机通信口的底层驱动支撑。结合环形缓冲区,可有效避免数据丢失或阻塞,是一种常用、稳定的串口通信实现方式。

开源代码:

#include "stm32f4xx.h"#include "ringbuffer.h"#include "tty.h"#include "public.h"   #include <string.h>#if (TTY_RXBUF_SIZE & (TTY_RXBUF_SIZE - 1)) != 0 
    #error "TTY_RXBUF_SIZE must be power of 2!"#endif#if (TTY_TXBUF_SIZE & (TTY_TXBUF_SIZE - 1)) != 0 
    #error "TTY_RXBUF_SIZE must be power of 2!"#endifstatic unsigned char rxbuf[TTY_RXBUF_SIZE];         /*接收缓冲区 */static unsigned char txbuf[TTY_TXBUF_SIZE];         /*发送缓冲区 */static ring_buf_t rbsend, rbrecv;                   /*收发缓冲区管理*//*
 * @brief     串口初始化
 * @param[in]   baudrate - 波特率
 * @return      none
 */static void uart_init(int baudrate){
    ring_buf_init(&rbsend, txbuf, sizeof(txbuf));/*初始化环形缓冲区 */
    ring_buf_init(&rbrecv, rxbuf, sizeof(rxbuf)); 
    
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA , ENABLE);
    
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);  
    
    gpio_conf(GPIOA, GPIO_Mode_AF, GPIO_PuPd_NOPULL, 
              GPIO_Pin_9 | GPIO_Pin_10);
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    uart_conf(USART1, baudrate);                    /*串口配置*/
    
    nvic_conf(USART1_IRQn, 1, 1);
    
}/*
 * @brief     向串口发送缓冲区内写入数据并启动发送
 * @param[in]   buf       -  数据缓存
 * @param[in]   len       -  数据长度
 * @return      实际写入长度(如果此时缓冲区满,则返回len)
 */static unsigned int uart_write(const void *buf, unsigned int len){   
    unsigned int ret;
    ret = ring_buf_put(&rbsend, (unsigned char *)buf, len);  
    USART_ITConfig(USART1, USART_IT_TXE, ENABLE);    return ret; 
}/*
 * @brief     读取串口接收缓冲区的数据
 * @param[in]   buf       -  数据缓存
 * @param[in]   len       -  数据长度
 * @return      (实际读取长度)如果接收缓冲区的有效数据大于len则返回len否则返回缓冲
 *              区有效数据的长度
 */static unsigned int uart_read(void *buf, unsigned int len){    return ring_buf_get(&rbrecv, (unsigned char *)buf, len);
}/*发送缓冲区满*/static bool tx_isfull(void){    return ring_buf_len(&rbsend) == TTY_TXBUF_SIZE;
}/*发送缓冲区空*/bool tx_isempty(void){    return ring_buf_len(&rbsend) == 0;
}/*接收缓冲区空*/bool rx_isempty(void){    return ring_buf_len(&rbrecv) == 0;
}/*控制台接口定义 -------------------------------------------------------------*/const tty_t tty = {
    uart_init,
    uart_write,
    uart_read,
    tx_isfull,
    tx_isempty,
    rx_isempty
};/*
 * @brief     串口1收发中断
 * @param[in]   none
 * @return      none
 */void USART1_IRQHandler(void){     
    unsigned char data;    if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
        data = USART_ReceiveData(USART1);
        ring_buf_put(&rbrecv, &data, 1);           /*将数据放入接收缓冲区*/             
    }    if (USART_GetITStatus(USART1, USART_IT_TXE) != RESET) {        if (ring_buf_get(&rbsend, &data, 1))      /*从缓冲区中取出数据---*/
            USART_SendData(USART1, data);            
        else{
            USART_ITConfig(USART1, USART_IT_TXE, DISABLE);    
        }
    }    if (USART_GetITStatus(USART1, USART_IT_ORE_RX) != RESET) {
        data = USART_ReceiveData(USART1);        
    }
}



关键词: 串口通信驱动

评论


技术专区

关闭
为什么会打雷 什么马奔腾 什么叫骨折 羊肚是羊的什么部位 例假期间吃什么好
曼龙鱼能和什么鱼混养 怀孕排卵试纸显示什么 琪是什么意思 脱水什么意思 织物是什么材质
哈密瓜不能和什么一起吃 为什么总是做噩梦 表现优异是什么意思 画龙点睛是什么意思 透析是什么病
鼻息肉长什么样 急性青光眼是什么症状 什么样人穿棉麻好看 冲喜是什么意思 香蕉为什么不能放冰箱
湾湾是什么意思hcv9jop6ns2r.cn 塑化剂是什么0735v.com 任督二脉是什么意思xinjiangjialails.com 站姐是什么意思hcv7jop9ns4r.cn 尿酸吃什么药hcv8jop6ns5r.cn
什么是糖化血红蛋白hcv7jop9ns4r.cn 没有什么了不起hcv9jop8ns0r.cn 什么牌子的充电宝好hcv8jop6ns3r.cn 上午八点是什么时辰hcv8jop0ns4r.cn 未扪及是什么意思hcv8jop1ns7r.cn
肺活量5000什么水平hcv8jop0ns4r.cn 钡餐造影能查出什么hcv9jop2ns0r.cn 人得了猫藓用什么药膏hcv7jop5ns0r.cn nac是什么意思hcv9jop5ns4r.cn 手抖是什么原因hcv8jop7ns4r.cn
爱上一个人是什么感觉xinjiangjialails.com 埋伏是什么意思inbungee.com pi是什么意思hcv8jop4ns1r.cn 嗜酸性粒细胞偏低是什么原因hcv9jop6ns4r.cn 收缩压偏高是什么意思cj623037.com
百度