>[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)
(非商务合作**勿扰**,此处**非**技术支持)
- 课程介绍
- 配套资源下载
- 配套开发套件简介
- 简介
- 硬件组成 & 技术参数
- 电路原理图 & PCB图
- 拨码开关使用说明
- 第一部分:无线通信 开发指南
- 1.1.1 NB-IoT:技术简介
- 1.1.2 NB:CH34x USB转串口驱动安装
- 1.1.3 NB:AT 指令开发与测试
- 1.1.4 NB:基础指令集简介
- 1.1.5 NB:云端服务器
- 1.1.5.1 PuTTY 简介与安装
- 1.1.5.2 登录云端服务器
- 1.1.6 NB:移远官方工具简介
- 1.1.7 NB:使用UDP协议与云端服务器通信
- 1.1.8 NB:使用TCP协议与云端服务器通信
- 1.1.9 NB:使用MQTT协议与云端服务器通信
- 进阶课程
- 第二部分:STM32 开发指南
- 2.1 搭建开发环境
- 2.1.1 Keil MDK 简介与安装
- 2.1.2 STM32 Pack 简介与安装
- 2.1.3 CH34x 驱动简介与安装
- 2.1.4 其他开发工具
- 2.2 STM32 开发基础
- 2.2.1 新建工程
- 2.2.2 实现第1个程序
- 2.2.3 Hex 文件烧录详解
- 2.3 移植官方标准工程模板
- 2.4 GPIO实验——LED灯
- 2.5 系统延时应用
- 2.6 GPIO实验——按键
- 2.7 GPIO中断实验——按键触发
- 2.8 使用定时器TIM3
- 2.9 串口通信实验
- 2.10 ADC 实验
- 2.11 OLED显示器实验
- 2.12 SDK 设计思想
- 2.13 SDK 架构解析
- 2.14 多任务应用
- 2.15 输入型任务:按键输入
- 2.16 输入型任务:串口接收
- 课外篇:项目实战
- 基于STM32+NB-IoT的温湿度采集
- 系统简介
- 系统搭建
- 系统详解
- 1.代码编译与架构说明
- 2.DHT11温湿度传感器
- 3. 数据通信任务说明
- 版权声明与免责声明