前言
串口通讯(Serial Communication)是一种设备间非常常用的串行通讯方式,因为它简单便捷,因此大部分电子设备都支持该通讯方式,电子工程师在调试设备时也经常使用该通讯方式输出调试信息。
一、USART硬件特征
1.物理层
- 物理层规定通讯系统中具有机械、电子功能部分的特性,确保原始数据在物理媒体的传输。
- 串口信号线中使用“RS-232 标准传输数据。由于 RS-232
电平标准的信号不能直接被寄存器直接识别,所以这些信号会经过一个“电平转换芯片”转换成控制器能识别的“TTL 标准”的电平信号,才能实现通讯。
2.协议层
- 串口通讯的数据包由发送设备通过自身的 TXD 接口传输到接收设备的 RXD 接口
- 串口通讯的协议层中,规定了数据包的内容,它由启始位、主体数据、校验位以及停止位组成,通讯双方的数据包格式要约定一致才能正常收发数据
- 波特率
一秒发送的bit常见有4800、9600、115200 等。 - 通讯的起始和停止信号
串口通讯的一个数据包从起始信号开始,直到停止信号结束。数据包的起始信号由一个逻辑 0 的数据位表示,而数据包的停止信号可由 0.5、1、1.5 或 2 个逻辑 1 的数据位表示,只要双方约定一致即可。 - 有效数据
在数据包的起始位之后紧接着的就是要传输的主体数据内容,也称为有效数据,有效数据的长度常被约定为 5、6、7 或 8 位长。 - 数据校验
在有效数据之后,有一个可选的数据校验位。由于数据通信相对更容易受到外部干扰导致传输数据出现偏差,可以在传输过程加上校验位来解决这个问题。校验方法有奇校验(odd)、偶校验(even)、0 校验(space)、1 校验(mark)以及无校验(noparity)。奇校验要求有效数据和校验位中“1”的个数为奇数,比如一个 8 位长的有效数据为:01101001,此时总共有 4 个“1”,为达到奇校验效果,校验位为“1”,最后传输的数据将是 8 位的有效数据加上 1 位的校验位总共 9 位。偶校验与奇校验要求刚好相反,要求帧数据和校验位中“1”的个数为偶数,比如数据帧:11001010,此时数据帧“1”的个数为 4 个,所以偶校验位为“0”。0 校验是不管有效数据中的内容是什么,校验位总为“0”,1 校验是校验位总为“1”。
二、STM32 的 USART 简介
USART 和UART
- 通用同步异步收发器(Universal Synchronous Asynchronous Receiver and Transmitter)是一个串行通信设备,可以灵活地与外部设备进行全双工数据交换
- UART(Universal Asynchronous Receiver and Transmitter),它是在 USART的
基础上裁剪掉了同步通信功能,只有异步通信 - 简单区分同步和异步就是看通信时需不需要对外提供时钟输 出,我们平时用的串口通信基本都是 UART。
三、编程实战
串口阻塞式发数据
while (1)
{
HAL_UART_Transmit(&huart1,TEMP,5,50);
}
根据编程实际自行查看函数库
串口非阻塞式发数据
下面将以实例讲解串口的应用
首先我们可以先在cubemx初始化模块代码这部分内容比较简单。然后在main.c中编写
uint8_t temp0[]="HELLO,WORLD!\r\n";
uint8_t temp1[]="LED1 OPEN!\r\n";
uint8_t temp2[]="LED1 CLOSE!\r\n";
uint8_t temp=0;
先定义字符串,变量声明
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_RESET);
HAL_UART_Transmit(&huart1,temp0,sizeof(temp0),10000);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_SET);
HAL_UART_Receive_IT(&huart1,&temp,1); //串口接收中断函数
main.c的初始化代码不用写在while里
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1)
{
if(temp == 0xA1)
{
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_5,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_RESET);
HAL_UART_Transmit(&huart1,temp1,sizeof(temp1),10000);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_SET);
HAL_UART_Receive_IT(&huart1,&temp,1);
}
else if(temp == 0xA2)
{
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_5,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_RESET);
HAL_UART_Transmit(&huart1,temp2,sizeof(temp2),10000);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_SET);
HAL_UART_Receive_IT(&huart1,&temp,1);
}
}
}
串口回调函数只要使用了串口中断函数直接编写回调函数的内容就可以进入中断并且执行回调函数的功能,因为每执行一次中断函数都会进入回调,所以这里需要使用两次 HAL_UART_Receive_IT(&huart1,&temp,1);
实践现象
需要工程文件可自行下载进行学习
总结
- 明白串口的基本硬件特征
- 会使用cubemx软件配置串口
- 理解常见的串口HAL库函数