UART串行通信简介

一、认识UART

1.UART(Universal Asynchronous Receiver/Transmitter,通用异步收发器)是一种双向、串行、异步的通信总线,仅用一根数据接收线和一根数据发送线就能实现全双工通信。典型的串口通信使用3根线完成,分别是:发送线(TX)、接收线(RX)和地线(GND),通信时必须将双方的TX和RX交叉连接并且GND相连(共用同一个地)才可正常通信,如下图所示:

二、串行、并行通信

这里简单介绍一下UART使用的串行通信方式:两个MCU互相收发数据常见的通信方式主要有串行通信和并行通信两种方式!

假设我们要发送198给另一台MCU,首先需要将198转换成机器能够识别的二进制也就是11000110

1.此时使用串行通信方式,我们只需要使用一根线交叉连接两个MCU的Tx-Rx,再使用一根线进行共地,我们就可以依次将八位数据发送给另一台MCU。

2.若使用并行通信,则需要八根线分别发送八位数据,并且为了保证数据的同步性,还需要另外接一根时钟信号线!虽然发送速率较快,但线路成本较高且抗干扰能力较弱。

三、UART通信过程

1.三要素:波特率、数据长度、开始/停止位

要想使用UART收发数据,必须设置好这三个基础设置。

2.数据发送过程

设置好三要素后,我们就可以进行简单的数据发送。下面简单介绍一下发送过程中三要素的作用:

(1)波特率:不同的波特率代表着我们发送数据的速度不同,数据的收发需要波特率的同步,也就是两端的波特率要设置成相同数值。(通常使用较多的设备波特率为9600、115200等)

这里我们假设波特率为9600,也就是说设备每秒发送9600位,一个数据位就需要104微秒;

(2)数据长度:数据帧包含所传输的实际数据。如果使用奇偶校验位,数据帧长度可以是5 位到 8 位。如果不使用奇偶校验位,数据帧长度可以是9 位。在大多数情况下,数据以最低有效位优先方式发送

(3)开始/停止位:开始位以下降沿为标志,也就是从高电平转变到低电平;当不传输数据时, UART 数据传输线通常保持高电压电平。若要开始数据传输,发送UART 会将传输线从高电平拉到低电平并保持1 个时钟周期。当接收 UART 检测到高到低电压跃迁时,便开始以波特率对应的频率读取数据帧中的位。停止位以上升沿为标志,也就是从低电平转变到高电平;为了表示数据包结束,发送 UART 将数据传输线从低电压驱动到高电压并保持1 到 2 位时间。

上图的52us是指,通常在收发数据时,我们会在检测到开始位后等待52us,避免数据的不稳定性。

3.额外说一下奇偶校验位:奇偶性描述数字是偶数还是奇数。通过奇偶校验位,接收 UART判断传输期间是否有数据发生改变。电磁辐射、不一致的波特率或长距离数据传输都可能改变数据位。
校验位可以配置成 1 位偶校验或 1 位奇校验或无校验位。
接收UART 读取数据帧后,将统计数值为 1 的位,检查总数是偶数还是奇数。如果奇偶校验位为0 (偶数奇偶校验),则数据帧中的1或逻辑高位总计应为偶数。如果奇偶校验位为 1 (奇数奇偶校验),则数据帧中的1 或逻辑高位总计应为奇数。
当奇偶校验位与数据匹配时,UART 认为传输未出错。但是,如果奇偶校验位为0 ,而总和为奇数,或者奇偶校验位为 1 ,而总和为偶数,则UART 认为数据帧中的位已改变。

四、UART使用(以STM32为例)

1.接线:

        任何 UART 双向通信至少需要 3 个引脚,数据发送引脚 TXD,数据接收引脚 RXD,数 据参考地 GND。这里特别需要注意的是连接方法,设备 A 和设备 B 信号需要交叉连接。如 果电平不同,需要电平转换芯片。

 串口1的初始化:引脚为PA9\PA10;

void Init_Uart1(uint32_t baud)    //baud为波特率
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
#if EN_USART1_RX //如果使能了接收
NVIC_InitTypeDef NVIC_InitStructure;
#endif
/* 串口 1 TX = PA9 RX = PA10 */
/* 第 1 步: 配置 GPIO */
/* 打开 GPIO 时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/* 打开 UART 时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
/* 配置 USART Tx 为复用功能 */ //USART1_TX GPIOA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 GPIOA.9
 
/* 配置 USART Rx 为复用功能 */ //USART1_RX GPIOA.10 初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 GPIOA.10 
/* 第 2 步: 配置串口硬件参数 */
USART_InitStructure.USART_BaudRate = baud; /* 波特率 */
USART_InitStructure.USART_WordLength = USART_WordLength_8b; /* 字长为 8 位数据格式 */
USART_InitStructure.USART_StopBits = USART_StopBits_1; /* 一个停止位 */
USART_InitStructure.USART_Parity = USART_Parity_No; /* 无奇偶校验位 */
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; /* 无硬件数据流控制 */
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; /* 收发模式 */
USART_Init(USART1, &USART_InitStructure); /* 初始化串口 1 */
#if EN_USART1_RX //如果使能了接收
/* 第 3 步: Usart1 NVIC 配置 */
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3 ; //抢占优先级 3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级 3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化 VIC 寄存器
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); /* 开启串口接受中断 */
USART_ITConfig(USART1, USART_IT_IDLE, ENABLE); /* 开启串口空闲中断 */
#endif
/* 第 4 步: 使能串口 1 */
USART_Cmd(USART1, ENABLE); /* 使能串口 */
}

中断服务函数:

void USART1_IRQHandler(void) //串口 1 中断服务程序
{
uint8_t Res=Res;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到一个字节数据)
{
USART_RX_BUF[RxCounter++]=USART1->DR;//把接收到的字节保存
}
if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) //接收中断(接收到 1 帧数据)
{
Res=USART1->SR;//读 SR 寄存器
Res=USART1->DR;//读 DR 寄存器(先读 SR,再读 DR,就是为了清除 IDLE 中断)
ReceiveState=1;//标记接收状态置位
}
}

 状态清零函数:

void Uart0_STA_Clr(void)
{
RxCounter = 0;//串口 BUF 计数清零
ReceiveState = 0;//接收状态清零
}

为使用printf()打印的重定向函数:(记得包含stdio.h头文件)

int fputc(int ch, FILE *f)
{ 
while((USART1->SR&0X40)==0){};//;//循环发送,直到发送完毕 
 USART1->DR = (u8) ch; 
return ch;
}

 数据发送函数:(16进制)

void USART1_Send_Data(uint8_t *buf,uint8_t len)
{
uint8_t t;
 for(t=0;t<len;t++) //循环发送数据
{ 
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); 
USART_SendData(USART1,buf[t]);
}
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
}

下图为常用串口助手的设置界面⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇


   

有需要源代码的朋友可以私,自己学习笔记记录,有错误欢迎大家指正!!!

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值