🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
>[success] **技术支持说明** > 1.**客服**提供简单的技术支持,一般自主学习为主 > 2.可到官方问答社区中提问:[**去提问**](https://bbs.csdn.net/forums/nb-iot) > 3.工程师**会尽快**解答社区问题,但他们是一线开发,【**难以保证**】解答时效,解答辛苦,感谢理解! <br/> ## **串口通信基础理论** #### **1\. USART** 全称为Universal Synchronous/Asynchronous Receiver/Transmitter,即通用串行 同步/异步 接收/发送器。 <br/> #### **2\. 并行通信和串行通信** * 并行通信是指同时发送各个数据位(bit),使用并行通信发送8个位数据的示意图如下。 ![](https://img.kancloud.cn/9f/62/9f62b739d9573a1c7b2c7371c055285e_294x338.png =200x) ### * 串行通信是指一个接一个地发送各个数据位,通过串行通信发送8位数据的示意图如下: ![](https://img.kancloud.cn/06/af/06af56f52e028758c4bde695c59138c4_832x252.png =500x) ### 一般地,并行通信的速度比串行通信的速度更快,但所需要的数据引脚也更多。 <br/> #### **3.异步通信与同步通信** 举个简单的例子说明异步通信与同步通信的区别, * 发短信: 属于异步通信,随时可以发,而且每次只能发送一条消息; * 打电话: 属于同步通信,必须对方接通后才能通话,对方接通后,想聊多久都可以。 ### **异步通信的特点** 1.接收设备时刻做好接收数据的准备 2.发送设备随时可以发送数据 3.发送设备每次只能发送一个字符,且字符的组成格式规定如下:   A. 1位起始位,规定为低电0   B. 5~8位数据位,即要传送的有效信息   C. 1位奇偶校验位   D. 1~2位停止位,规定为高电平1 ### 异步通信的示意图如下。 ![](https://img.kancloud.cn/72/1f/721f6ad4ae6a6ee8b8ccb93122d3231d_830x262.png =500x) ### 数据帧格式如下。 ![](https://img.kancloud.cn/96/64/966402c3e28753c61f37a4b161bb1e73_736x214.png =500x) ### **同步通信的特点** 1.发送设备在发送消息前必须先和接收设备做时钟频率同步。 2.发送设备每次发送的是数据块(可以理解为很多个字节),且消息格式如下:   A. 2个同步字符作为一个数据块(信息帧)的起始标志;   B. n个连续传送的数据   C. 2个字节循环冗余校验码(CRC) ### 同步通信的示意图如下。 ![](https://img.kancloud.cn/fa/ab/faab57776f32a479bc301aa3c3516b0c_498x332.png =400x) ### 数据帧格式如下。 ![](https://img.kancloud.cn/e1/75/e1758cef916d74353a7caa21481fdf4e_832x108.png =500x) <br/> #### **4\. UART** 串口通信,是一种串行异步收发的通信模式。配套的开发板具备串口通信能力,开发者可以用来与上位机通信。 <br/> ## **串口通信 API 设计** 串口通信功能应该提供初始化、发送和接收信息API,如图所示。 ![](https://img.kancloud.cn/0d/86/0d86905051567e2dc0e9c31e51cee57c_466x474.png =250x) ### 其中的接收串口信息与按键类似,都是被动输入的,同样地可以使用注册回调的思想,即上层应用在HAL中注册已给回调函数,一旦HAL检测到需要接收串口信息,就会回调给上层应用。 <br/> **编写代码** 笔者在本节课配套的源代码中新建了 hal\_uart.h 和 hal\_uart.c文件,如图所示。 ![](https://img.kancloud.cn/5b/06/5b0638e7ca01c06640295b8c822d48a2_254x542.png =250x) ### 打开本节课配套的工程,笔者把hal\_uart.c以及必要的标准库文件添加进工程了,如图所示。 ![](https://img.kancloud.cn/cf/9d/cf9ddc338baeddcf223ef013e407ff66_375x618.png =250x) <br/> hal_uart.h的代码如下: ### ``` #ifndef __HAL_UART_H__ #define __HAL_UART_H__ /* * 串口通信初始化 * * @param baudrate - 串口通信波特率 */ void halUartInit(unsigned long baudrate); /* * 注册接收串口信息的回调函数 * * @param onIRQ - 回调函数,接收到到串口信息时自动调用此函数 */ void halUartSetIRQCallback(void (*onIRQ)(unsigned char byte)); /* * 通过串口发送信息 * * @param buf - 待发送的信息的存储地址 * @param len - 待发送的信息的数据长度 */ void halUartWrite(unsigned char *buf, unsigned int len); #endif /* #ifndef __HAL_UART_H__ */ ``` <br/> hal_uart.c文件的代码如下: ``` #include "hal_uart.h" #include "stm32f0xx_usart.h" //保存串口通信回调函数 static void (*halUartOnIRQ)(unsigned char byte) = 0; static void halUartGpioInit(void); static void halUartParamInit(unsigned long baudrate); static void halUartIRQInit(void); /* * 串口通信初始化 * * @param baudrate - 串口通信波特率 */ void halUartInit(unsigned long baudrate) { halUartGpioInit(); halUartParamInit(baudrate); halUartIRQInit(); } /* * 注册接收串口信息的回调函数 * * @param onIRQ - 回调函数,接收到到串口信息时自动调用此函数 */ void halUartSetIRQCallback(void (*onIRQ)(unsigned char byte)) { halUartOnIRQ = onIRQ; } /* * 通过串口发送信息 * * @param buf - 待发送的信息的存储地址 * @param len - 待发送的信息的数据长度 */ void halUartWrite(unsigned char *buf, unsigned int len) { for (unsigned int i = 0; i < len; i++) { USART_SendData(USART1, buf[i]); while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); } } /* * 初始化串口通信相关的GPIO */ void halUartGpioInit() { GPIO_InitTypeDef uart1Tx; GPIO_InitTypeDef uart1Rx; /* TX */ uart1Tx.GPIO_Pin = GPIO_Pin_9, uart1Tx.GPIO_Speed = GPIO_Speed_10MHz, uart1Tx.GPIO_Mode = GPIO_Mode_AF, uart1Tx.GPIO_PuPd = GPIO_PuPd_NOPULL, /* RX */ uart1Rx.GPIO_Pin = GPIO_Pin_10, uart1Rx.GPIO_Speed = GPIO_Speed_10MHz, uart1Rx.GPIO_Mode = GPIO_Mode_AF, uart1Rx.GPIO_PuPd = GPIO_PuPd_NOPULL, RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1); GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_1); GPIO_Init(GPIOA, &uart1Tx); GPIO_Init(GPIOA, &uart1Rx); } /* * 初始化串口通信配置 */ void halUartParamInit(unsigned long baudrate) { USART_InitTypeDef uartConfig; uartConfig.USART_BaudRate = baudrate; uartConfig.USART_WordLength = USART_WordLength_8b; uartConfig.USART_Parity = USART_Parity_No; uartConfig.USART_StopBits = USART_StopBits_1; uartConfig.USART_HardwareFlowControl = USART_HardwareFlowControl_None; uartConfig.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); USART_Init(USART1, &uartConfig); USART_Cmd(USART1, ENABLE); } /* * 初始化串口通信的中断请求 */ void halUartIRQInit() { NVIC_InitTypeDef uartNVIC; uartNVIC.NVIC_IRQChannel = USART1_IRQn; uartNVIC.NVIC_IRQChannelPriority = 0; uartNVIC.NVIC_IRQChannelCmd = ENABLE; USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); USART_ITConfig(USART1, USART_IT_TC, ENABLE); NVIC_Init(&uartNVIC); } /* * 串口通信中断处理函数。当串口接收到数据时,便会自动产生中断并执行此函数 */ void USART1_IRQHandler(void) { unsigned char byte = 0; if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) { byte = USART_ReceiveData(USART1); // Auto to clear RXNE flag when read! if (halUartOnIRQ != 0) halUartOnIRQ(byte);//执行串口通信回调函数 } else{ USART_ClearFlag(USART1,USART_FLAG_TC);//清理中断标志 } } ``` 上述的初始化代码较为复杂,读者暂时可以直接套用上述代码,留作后期再深入学习相关原理。 <br/> ## **使用串口通信 HAL API** 编写好串口通信 HAL API后,串口通信的使用非常简单。在配套工程的main.c文件中添加如下代码: ### ``` /* * 通过串口接收到信息时的回调函数 * @param byte - 接收到的数据 */ static void onUartIRQ(unsigned char byte) { halUartWrite(&byte, 1);//把接收到的数据原封不动地发送回去 } int main(void) { halSystemInit();//系统初始化 halUartInit(115200);//串口通信初始化,并设置波特率为115200 halUartSetIRQCallback(onUartIRQ);//注册串口通信回调函数,当通过串口接收到信息时自动调用此函数 /* Infinite loop */ while (1) {} } ``` <br/> #### **代码测试** 1.编译链接工程代码,把生成的Hex文件烧录到开发板中; 2.按如图所示把开发板的拨码开关的第1~4位打到右边,第5、6位打到左边 ![](https://img.kancloud.cn/34/9c/349cceae4177926416445b6daf932d24_664x827.png =200x) ### 3.打开串口助手,给开发板发送数据,可以看到发送的数据原封不动地发送回来了,如图所示。 ![](https://img.kancloud.cn/64/51/6451e971725cf5abfbde6e77ef8a1da4_723x639.png =500x) <br/> <br/> ## **商务合作** 如有以下需求,可扫码添加管理员好友,注明“**商务合作**” * 项目定制开发,技术范围:**NB-IoT**、**CATn(4G)**、**WiFi**、**ZigBee**、**BLE Mesh**以及**STM32**、**嵌入式Linux**等; * 入驻平台,成为讲师; * 接项目赚外快; * 善学坊官网:[www.sxf-iot.com](https://www.sxf-iot.com/) ![](https://img.kancloud.cn/ca/73/ca739f92cab220a3059378642e3bd502_430x430.png =150x) (非商务合作**勿扰**,此处**非**技术支持)