如何来编写一个串口收发程序

介绍串口(uart通用异步收发器,ttl)通讯是一种设备间的串行全双工通讯方式。由于uart是异步传输,没有传输同步时钟,为了保证数据的正确性,uart采用16倍数据波特率的时钟进行采样。因为它简便捷,因此大部分电子设备都支持该通讯方式工程师在调试设备时也经常使用该方式输出调试信息。
本文详细的介绍如何来编写一个串口收发程序,我们采用常用的收发逻辑,发送直接编写函数进行实现,而接收使用中断进行完成。接收中断使用接收到一个字节和一帧数据两种中断触发方式。
usart中断usart 有多个中断请求事件。
之所以介绍这个usart中断请求,是因为很多人在初学阶段,对串口怎么判断串口中断的状态不太了解,所以我这里重点来介绍一下。
一般在我们开始和配置完串口中断后,进入串口中断处理程序的情况会有很多,我们也可以自己选择打开哪些串口中断情况。一般情况下,我们在接受时主要使用的中断事件标志是rxne和idle。
rxne是接收中断,每接收一个字节都会出发这个中断,也是我们用的最频繁的中断请求。
idle 是空闲中断,每接收完一帧数据,总线就会暂时空闲,就会触发这个中断。
串口状态串口的状态可以通过状态寄存器 usart_sr 读取。usart_sr 的各位描述如下:
这里我们关注一下两个位,第 5、6 位 rxne 和 tc。
rxne(读数据寄存器非空),当该位被置 1 的时候,就是提示已经有数据被接收到了,且可以读出来了。这时候我们要做的就是尽快去读取 usart_dr,通过读 usart_dr 可以该位清零,也可以向该位写 0,直接清除。
tc(发送完成),当该位被置位的时候,表示 usart_dr 内的数据已经被发送完成了。果设置了这个位的中断,则会产生中断。该位也有两种清零方式:
读 usart_sr,usart_dr。直接向该位写 0。实例需求分析本项目主要编写一个串口收发的实例。使用stm32f103c8t6充当mcu,在pc上使用串口调试助手充当上位机。每次pc向mcu下发一帧数据, mcu每接收一个字节数据,检查一下数据中是否有指令0x23,当接收到指令0x23的时候,mcu向上位机发送“pc”。当一帧数据接收完毕后,mcu向上位机发送“receive a frame data”.
串口初始化串口初始化的一般步骤可以总结为如下几个步骤:
串口时钟使能,gpio 时钟使能。设置引脚复用器映射:调用 gpio_pinafconfig 函数。gpio 初始化设置:要设置模式为复用功能。串口参数初始化:设置波特率,字长,奇偶校验等参数。开启中断并且初始化 nvic,使能中断(如果需要开启中断才需要这个步骤)。使能串口。#include usart.h#include #include stm32f1xx_hal.huart_handletypedef huart3void mx_usart3_uart_init(void) huart3.instance = usart3; huart3.init.baudrate = 115200; huart3.init.wordlength = uart_wordlength_8b; huart3.init.stopbits = uart_stopbits_1; huart3.init.parity = uart_parity_none; huart3.init.mode = uart_mode_tx_rx; huart3.init.hwflowctl = uart_hwcontrol_none; huart3.init.oversampling = uart_oversampling_16; if (hal_uart_init(&huart3) != hal_ok) { error_handler() __hal_uart_enable_it(&huart3,uart_it_rxne);//接收中断使能 __hal_uart_enable_it(&huart3,uart_it_idle);//空闲中断使能 }void hal_uart_mspinit(uart_handletypedef* uarthandle) gpio_inittypedef gpio_initstruct = {0}; if(uarthandle->instance==usart3) { __hal_rcc_usart3_clk_enable() __hal_rcc_gpiob_clk_enable(); /**usart3 gpio configuration pb10 ------> usart3_tx pb11 ------> usart3_rx */ gpio_initstruct.pin = gpio_pin_10; gpio_initstruct.mode = gpio_mode_af_pp; gpio_initstruct.speed = gpio_speed_freq_high; hal_gpio_init(gpiob, &gpio_initstruct) gpio_initstruct.pin = gpio_pin_11; gpio_initstruct.mode = gpio_mode_input; gpio_initstruct.pull = gpio_nopull; hal_gpio_init(gpiob, &gpio_initstruct); hal_nvic_setpriority(usart3_irqn, 5, 0); hal_nvic_enableirq(usart3_irqn);我们平时需要改的其实就是串口的一些参数配置。
baudrate:波特率wordlength;:字长stopbits:停止位parity:奇偶校验mode:收/发模式设置hwflowctl:硬件流设置oversampling:过采样设置串口发送串口发送这里使用的非中断发送方式。
/******************************************************************************* * @函数名称 usart_send * @函数说明 发送信息 * @输入参数 _uart:串口号 data:要发送的信息的首地址 len:发送的长度 * @输出参数 无 * @返回参数 无*******************************************************************************/void usart_send(usart_typedef *_uart,uint8_t *data,uint8_t len){ for(int i;i这是一个阻塞的发送函数,无需重复判断串口是否发送完成。发送每个字符,直到遇空字符才停止发送。其中第一个参数是串口号,第二个参数是要发送的数据起始地址,第三个是要发送的数据长度,第四个超时时间(超过此长度仍未发送成功则阻塞完毕,停止发送,函数执行完毕)。
串口接收这里串口接收使用的是中断的方式。
中断的类别在文章的最上边已经介绍过。我们在初始化时设定触发中断的类型。本文中设置的
__hal_uart_enable_it(&huart3,uart_it_rxne);//接收中断使能__hal_uart_enable_it(&huart3,uart_it_idle);//空闲中断使能代表只有接收数据和空闲中断会触发。
在stm32f1xx_it.c中有我们的串口中断处理函数。我们将这个函数进行重构。
void usart3_irqhandler(void){ uint8_t res;if(__hal_uart_get_flag(&huart3,uart_flag_rxne)!=reset{ hal_uart_receive(&huart3,&res,1,0xffff); if(res==0x23) printf(pc);}else if(__hal_uart_get_flag(&huart3,uart_flag_idle)!=reset)//空闲中断(代表这一帧数据传输完了){ printf(receive a frame data.); __hal_uart_clear_idleflag(&huart3);}这里面的几个重点,我们来一一介绍。
首先是判断标志位,我们使用hal库中的__hal_uart_get_flag()函数,里面有两个参数,前者是串口句柄,后者是具体哪个标志位。
if(__hal_uart_get_flag(&huart3,uart_flag_rxne)!=reset)用来检测是否检测到有单个字节的中断。
if(__hal_uart_get_flag(&huart3,uart_flag_idle)!=reset)用来检测是否有空闲中断(代表这一帧数据传输完了)。
重定向printf和scanf还有一点需要注意的,使用 fput 和 fgetc 函数达到重定向 c 语言标准库输入输出函数必须在 mdk 的工程选项把“use microlib”勾选上, micorolib 是缺省 c 库的备选库,它对标准 c 库进行了高度优化使代码更少,占用更少资源
为使用 printf、 scanf 函数需要在文件中包含 stdio.h 头文件。
/** * 函数功能: 重定向c库函数printf * 输入参数: 无 * 返 回 值: 无 * 说 明:无 */int fputc(int ch, file *f){ hal_uart_transmit(&huart3, (uint8_t *)&ch, 1, 0xffff); return ch;}/** * 函数功能: 重定向c库函数getchar,scanf * 输入参数: 无 * 返 回 值: 无 * 说 明:无 */int fgetc(file *f){ uint8_t ch = 0; hal_uart_receive(&huart3, &ch, 1, 0xffff); return ch;}效果pc下发:11 22 33 44
pc下发:12 23 34 45

木蚁机器人宣布完成近亿元融资
OPPO Enco X2怎么样?拔高TWS耳机音质上限
导热塑料均匀快速散热是首选优势
美国总统特朗普发布了5G相关战略宣称美国将成为5G时代真正领导者
四极塑料外壳式断路器的特点
如何来编写一个串口收发程序
3种MongoDB的高可用架构介绍
关于生化培养箱BPC-70F的产品简述
综合能源服务是多种能源的结合吗,它未来该如何转型发展
功率放大器基于应力波时间反演法的土壤含水率监测中的应用
Barix 基于 IP 的音频解决方案为2010年英联邦运动
瑞萨电子推出全新RA MCU家族产品RA8
3种伺服电机控制方式
百度和沧州签署战略合作协议,获首批30张自动驾驶载人测试牌照
大学有线电视光传输案例-中国纪检监察学院有线电视光传输系统应用浅议
侧面捆扎机
扫描仪使用步骤
C语言指针作为形参怎么改变其指向的地址
一款具有pwm调光能力的led驱动器推荐
共模信号和差模信号