1、UART协议规范
UART(Universal Asynchronous Receiver/Transmitter)
,通用异步收发传输器,是一种通用的串行、异步通信总线。
异步:不带时钟同步信号SCL线,需要波特率来控制传输速率,双方波特率要一致才能正确传输如UART。
而对于同步来说,当接收方检测到时钟线的上升沿或者下降沿时,就知道需要准备接收数据。
异步通信和同步通信详解参考郭天祥老师视频
用途:调试、外接GPS、WIFI等设备
例如:GPS模块通过UART接口向微控制器发送位置数据(如经度、纬度、速度、时间等)
标准通信波特率有 9600bps、115200bps
UART最少需要三根线
TX:发送数据端,要接对面的RX
RX:接收数据端,要接对面的TX
GND:地
起始位:低电平(0)
数据位:通常为8位
校验位:分为奇校验和偶校验类型,如果是奇校验,当数据位的1的个数为奇,该位置1。
停止位:逻辑高电平(1) ,停止位的长度和数量(通常1位、1.5位或2位)在UART配置中可以设置
发送过程:MUC内核将数据传入uart的缓冲区FIFO,经串行输出移位寄存器
输出给外部设备
图中是对字符c
进行数据传输,十进制99,0x63转换为0110 0011。
串口传输时,首先引脚拉低后,维持波特率输出一位的时间后,开始传输数据,一个字节,从最低位开始逐位传输;后选择奇校验位,因为传输的1的个数为偶数,故为0;最后一位为停止位1。
补充:UART中的硬件流控制引脚,RTS(请求发送,Request to Send)和CTS(清除发送,Clear to Send)。
UART0_RTS:发送设备在发送数据之前会将RTS信号线拉低,以告知接收设备它有数据准备好发送。
UART0_CTS:接收设备在接收数据之前会将CTS信号线拉低,以告知发送设备它可以开始发送数据。
4、UART内部机制
CPU和串口的频率差异很大,所以一般情况下CPU会一次性输出大批字节数到uart的缓冲区FIFO中,串口再根据波特率用TX引脚发送给外端。
要发送数据时,CPU控制内存要发送的数据通过FIFO传给UART单位,UART里面的移位器,依次将数据发送出去,在发送完成后产生中断提醒CPU传输完成。
接收数据时,获取接收引脚的电平,逐位放进接收移位器,再放入FIFO,写入内存。在接收完成后产生中断提醒CPU传输完成。
3、基于TTL的UART通讯
5VTTL电平标准
2.4V~5V:逻辑1。
0~0.4V: 逻辑0。
TTL信号的抗干扰能力较差,所以其通信距离很短,一般只能用于一个电路板上的两个不同芯片之间的通信。
4、基于RS232的UART通讯
RS232电气接口标准:
指的是RS232电平标准的UART
RS-232使用RXD、TXD、GND三条线,全双工
,点对点通信
RS232传输距离有限,最大传输距离标准值为50米,实际上也只能用在15
米左右。
电平标准:负逻辑方式。
逻辑1 两线电压差为-3~-15V
逻辑0 两线电压差为+3 ~+15V
TTL转RS232:处理器一般都是TTL信号不符合RS232标准,所以一般外部添加电路对信号电平进行转换两个器件之间通信的时候,两个器件都需要添加电平转换芯片
5、基于RS485的UART通讯
RS485电气接口标准:
485接口原理:串口是一种接口标准,规定了接口的电气标准,即物理层的一个标准他们重新定义了电压,阻抗。
RS485是2线,半双工,多点通信
,采用差分信号
。
RS-485接口是采用平衡驱动器和差分接收器的组合,抗共模干扰能力增强,即抗噪声干扰性好;接口电平低,不易损坏芯片。
RS-485最大的通信距离理论上约为1200M
,最大传输速率为10Mb/s
。
逻辑1 两线电压差为+(2~6)V
逻辑0 两线电压差为-(2~6)V
例如:接口芯片 MAX485
另外,RS485允许总线上连接多达128收发器,而TTL或者RS232则是点对点的连接。
信号在发送之前,通过RS485的收发器把单端信号转换成差分信号,再发送到总线上进行传输;同样在接收之前,总线上的差分信号通过收发器的转换变成单端信号再送给UART控制器进行接收。
在RS485总线上,如果希望进行全双工的双向通讯,需要两对差分信号线(即4根信号线)。
6、TTL转USB
通过USB与电脑传输数据,调试场景使用最多的。
7、STM32中UART的使用
/**
******************************************************************************
* @file bsp_debug_usart.c
* @author fire
* @version V1.0
* @date 2015-xx-xx
* @brief 重定向c库printf函数到usart端口,中断接收模式
******************************************************************************
* @attention
*
* 实验平台:秉火 STM32 F429 开发板
* 论坛 :http://www.firebbs.cn
* 淘宝 :https://fire-stm32.taobao.com
*
******************************************************************************
*/
#include "./usart/bsp_debug_usart.h"
/**
* @brief DEBUG_USART GPIO 配置,工作模式配置。115200 8-N-1 ,中断接收模式
* @param 无
* @retval 无
*/
void Debug_USART_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_AHB1PeriphClockCmd(DEBUG_USART_RX_GPIO_CLK|DEBUG_USART_TX_GPIO_CLK,ENABLE);
/* 使能 USART 时钟 */
RCC_APB2PeriphClockCmd(DEBUG_USART_CLK, ENABLE);
/* GPIO初始化 */
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
/* 配置Tx引脚为复用功能 */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_PIN ;
GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);
/* 配置Rx引脚为复用功能 */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_PIN;
GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
/* 连接 PXx 到 USARTx_Tx*/
GPIO_PinAFConfig(DEBUG_USART_RX_GPIO_PORT,DEBUG_USART_RX_SOURCE,DEBUG_USART_RX_AF);
/* 连接 PXx 到 USARTx__Rx*/
GPIO_PinAFConfig(DEBUG_USART_TX_GPIO_PORT,DEBUG_USART_TX_SOURCE,DEBUG_USART_TX_AF);
/* 配置串DEBUG_USART 模式 */
/* 波特率设置:DEBUG_USART_BAUDRATE */
USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
/* 字长(数据位+校验位):8 */
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
/* 停止位:1个停止位 */
USART_InitStructure.USART_StopBits = USART_StopBits_1;
/* 校验位选择:不使用校验 */
USART_InitStructure.USART_Parity = USART_Parity_No;
/* 硬件流控制:不使用硬件流 */
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
/* USART模式控制:同时使能接收和发送 */
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
/* 完成USART初始化配置 */
USART_Init(DEBUG_USART, &USART_InitStructure);
/* 使能串口 */
USART_Cmd(DEBUG_USART, ENABLE);
}
/***************** 发送一个字符 **********************/
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
{
/* 发送一个字节数据到USART */
USART_SendData(pUSARTx,ch);
/* 等待发送数据寄存器为空 */
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}
/***************** 发送字符串 **********************/
void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
{
unsigned int k=0;
do {
Usart_SendByte( pUSARTx, *(str + k) );
k++;
} while(*(str + k)!='\0');
/* 等待发送完成 */
while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET){
}
}
/***************** 发送一个16位数 **********************/
void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch)
{
uint8_t temp_h, temp_l;
/* 取出高八位 */
temp_h = (ch&0XFF00)>>8;
/* 取出低八位 */
temp_l = ch&0XFF;
/* 发送高八位 */
USART_SendData(pUSARTx,temp_h);
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
/* 发送低八位 */
USART_SendData(pUSARTx,temp_l);
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}
///重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{
/* 发送一个字节数据到串口 */
USART_SendData(DEBUG_USART, (uint8_t) ch);
/* 等待发送完毕 */
while (USART_GetFlagStatus(DEBUG_USART, USART_FLAG_TXE) == RESET);
return (ch);
}
///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{
/* 等待串口输入数据 */
while (USART_GetFlagStatus(DEBUG_USART, USART_FLAG_RXNE) == RESET);
return (int)USART_ReceiveData(DEBUG_USART);
}
/*********************************************END OF FILE**********************/