![judy的头像 judy的头像](https://cdn.eetrend.com/files/styles/picture200/public/letter-avatars/u-108.png?itok=R3QiYnQQ)
UART(Universal Asynchronous Receiver and Transmitter)通用异步收发器(异步串行通信口)是MCU的一个重要的数字接口,市面上很多的传感器、通信模块等外围器件都采用了UART接口,同时工程师在软件开发调试过程中UART打印输出作为一种最直观的输出方式可以检查程序的运行情况,所以UART在MCU中的作用不言而喻。
首先普及一下并行通信、串行通信(同步通信和异步通信)两种通信方式的特点:
并行通信:并行通信是指数据的各个位同时传送,可以字或字节为单位并行进行。
-传输原理:数据各个位同时传输。
-优点:速度快,位数多
-缺点:占用引脚资源多,线路复杂,成本高
串行通信:串行通信是指使用一条数据线,将数据一位一位地依次传输,每一位数据占据一个固定的时间长度,其只需要少数几条线就可以在系统间交换信息。
-传输原理:数据按位顺序传输。
-优点:占用引脚资源少,传输线少
-缺点:速度相对较慢,耗时长
串行通信的通信方式又分为:同步通信和异步通信两种方式
同步通信:带时钟同步信号传输,发送方和接收方时钟需要建立连接,使双方的时钟
到完全同步。比如:SPI,IIC通信接口等。
异步通信:接收器和发送器使用各自的时钟,不带时钟同步信号。每一个字符要用起始位和停止位作为字符开始和结束的标志,以字符为单位的一个个地发送和接收。比如:UART通信接口等。
MM32系列MCU的通用异步收发器(UART)提供了一种灵活的方法与使用工业标准 NRZ 异步串行数据格式的外部设备之间进行全双工数据交换。UART 利用分数波特率发生器提供宽范围的波特率选择。它支持同步单向通信和半双工单线通信,以及调制解调器(CTS/RTS)操作。
有很多工程师在使用UART时,在设计PCB的UART接口时,一直对UART采用两线、三线、四线的问题一直都是很模糊情况,在这里我简单讲一下这个问题。
有些客户采用两线主要是单工模式,两线分别是:GND, TX 或者 RX,相当于MCU是做发送或者接收功能,将接收设备和发送设备共地,是要把参考电压调节成一致,避免接收设备和发送设备双方对高低电平的判断不一致的情况。
采用两线主要是双工模式,三线分别是:GND,TX,RX,接收设备和发送设备都是双向通信设备,且都有各自的供电电源,只需要将双方的基准电压调节一致就可以实现双方的串口通信功能,客户在使用ISP下载程序时一般都采用这种方式,预留一个三线接口。
采用四线主要是通信双方有一方需要为另一方提供电源,供另一方芯片运行,所以四线分别为:GND,TX,RX,VDD。
GND:共地,提供基准电压。
RX:接收数据串行输入。通过过采样技术来区别数据和噪音,从而恢复数据。
TX:发送数据串行输出。当发送器被禁止时,输出引脚恢复到它的I/O端口配置。当发送器被激活,并且不发送数据时,TX引脚处于高电平。在单线和智能卡模式里,此I/O口被同时用于数据的发送和接收。
VDD:供电源。
一般的通信模块还会有另外两个引脚在硬件流控模式中需要使用:
nCTS:清除发送,若是高电平,在当前数据传输结束时阻断下一次的数据发送。
nRTS:发送请求,若是低电平,表明 UART 准备好接收数据。
两个UART间的通信接线方法
![MM32 UART中断通信](http://mcu.eetrend.com/files/2017-10/wen_zhang_/100008514-28516-1.jpg)
两个UART间的硬件流控
![MM32 UART中断通信](http://mcu.eetrend.com/files/2017-10/wen_zhang_/100008514-28517-2.jpg)
UART特征:
字长可以通过编程 UART_CCR 寄存器中的 CHAR 位,选择 5 ~ 8 位。在起始位期间, TX 脚处于低电平,在停止位期间处于高电平。
空闲符号被视为完全由‘1’组成的一个完整的数据帧,后面跟着包含了数据的下一帧的开始位(‘1’的位数也包括了停止位的位数)。
断开符号被视为在一个帧周期内全部收到‘0’(包括停止位期间,也是‘0’)。在断开帧结束时,发送器再插入 1 或 2 个停止位(‘1’)来应答起始位。
发送和接收由一个共用的波特率发生器驱动,当发送器和接收器的使能位分别置位时,分别为其产生时钟。
UART时序
![MM32 UART中断通信](http://mcu.eetrend.com/files/2017-10/wen_zhang_/100008514-28518-3.jpg)
串口设置的步骤可分为如下几个流程:
1) 串口复位,GPIO复位
2) 串口时钟使能, GPIO 时钟使能
3) GPIO 端口模式设置
4) 串口参数初始化
5) 开启中断并且初始化 NVIC(如果需要开启中断才需要这个步骤)
6) 编写中断处理函数
1、串口复位,GPIO复位
在系统开始配置外设时,建议先执行复位相对应的外设,然后重新配置该外设,使其达到自己所期望的工作模式。
UART_DeInit(UART1);//复位串口1
GPIO_DeInit(GPIOA);//复位GPIOA
2、串口时钟使能, GPIO 时钟使能
串口1(UART1)是挂载在 APB2 下面的外设,GPIOA的时钟是挂载在AHB上,所以使能函数为:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_UART1, ENABLE);//使能UART1
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);//使能GPIOA的时钟
3、GPIO 端口模式设置
在上一章节讲述了GPIO的使用,使用GPIO的UART功能需要配置端口复用功能,根据DS_MM32L073_Ver1.7手册表4.PA端口功能复用可知PA9和PA10的UART功能的复用配置AF1。
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_1);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_1);
外设的GPIO配置:
![MM32 UART中断通信](http://mcu.eetrend.com/files/2017-10/wen_zhang_/100008514-28519-4.jpg)
接下来的两段代码就是将 TX(PA9)设置为推挽复用输出模式,将 RX(PA10)设置为浮空输入模式:
GPIO_InitTypeDef GPIO_InitStructure;
//UART1_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
//UART1_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
4、串口参数初始化
4.1、分数波特率发生器
接收器和发送器的波特率在 BRR 的整数寄存器和 FRA 的小数寄存器中的值应设置成相同。
Tx/Rx 波特率 = fCK /(16 *UARTDIV )
这里的 fCK 是给外设的时钟(PCLK1 用于 UART2, PCLK2 用于 UART1)。UARTDIV 是一个无符号的定点数。这 16 位的值设置在 UART_BRR 寄存器。
例:如果BaudRate=9600,PCLK2=72MHz
则UARTDIV= 468.75
4.2、字长配置
字长可以通过编程 UART_CCR 寄存器中的 CHAR 位,选择 5 ~ 8 位。
4.3、奇偶校验位
奇偶控制(发送时生成一个奇偶位,接收时进行奇偶校验)可以通过设置 UART_CCR 寄存器上的 PEN位而激活。如果奇偶校验出错,无效数据不会从移位寄存器传送到 UART_RDR 寄存器。
偶校验:校验位使得一帧中的数据以及校验位中‘1’的个数为偶数。
例如:数据 = 00110101,有 4 个‘1’,如果选择偶校验(在 UART_CCR 中的 PSEL = 0),校验位将是‘0’。
奇校验:此校验位使得一帧中的数据以及校验位中‘1’的个数为奇数。
例如:数据=00110101,有 4 个‘1’,如果选择奇校验(在 UART_CCR 中的 PSEL = 1),校验位将是‘1’。
传输模式:如果 UART_CCR 的 PEN 位被置位,写进数据寄存器的数据的 MSB 位被校验位替换后发送出去(如果选择偶校验偶数个‘1’,如果选择奇校验奇数个‘1’)。如果奇偶校验失败, UART_ISR 寄存器中的 RXPERR_INTF 标志被置‘1’,并且如果 RXPERREN 在被预先设置的话,中断产生。
4.4、硬件数据流流控
RTS 流控制
如果 RTS 流控制被使能,只要 UART 接收器准备好接收新的数据, nRTS 就变成有效(接低电平)。当接收寄存器内有数据到达时, nRTS 被释放,由此表明希望在当前帧结束时停止数据传输。下图是一个启用 RTS 流控制的通信的例子。
![MM32 UART中断通信](http://mcu.eetrend.com/files/2017-10/wen_zhang_/100008514-28520-5.jpg)
CTS 流控制
如果 CTS 流控制被使能,发送器在发送下一帧前检查 nCTS 输入。如果 nCTS 有效(被拉成低电平),则下一个数据被发送(假设那个数据是准备发送的),否则下一帧数据不被发出去。若 nCTS 在传输期间被变成无效,当前的传输完成后停止发送。下图是一个 CTS 流控制被启用的通信的例子。
![MM32 UART中断通信](http://mcu.eetrend.com/files/2017-10/wen_zhang_/100008514-28521-6.jpg)
UART_InitTypeDef UART_InitStructure;
UART_InitStructure.UART_BaudRate = 115200;//波特率设置
UART_InitStructure.UART_WordLength= UART_WordLength_8b;//字长为8
UART_InitStructure.UART_StopBits = UART_StopBits_1;//一个停止位
UART_InitStructure.UART_Parity = UART_Parity_No;//无奇偶校验位
UART_InitStructure.UART_HardwareFlowControl=UART_HardwareFlowControl_None;//无硬件数据流流控
UART_InitStructure.UART_Mode = UART_Mode_Rx | UART_Mode_Tx;//开启收发模式
UART_Init(UART1, &UART_InitStructure); //初始化串口
UART_Cmd(UART1, ENABLE); //UART1使能
4.5、开启中断并且初始化 NVIC(如果需要开启中断才需要这个步骤)
NVIC_InitTypeDef NVIC_InitStructure;
UART_ITConfig(UART1, UART_IT_RXIEN, ENABLE);//开启串口接收中断
NVIC_InitStructure.NVIC_IRQChannel = UART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
4.6、编写中断处理函数
void UART1_IRQHandler(void) //中断服务函数
{
u8 Res;
if(UART_GetITStatus(UART1, UART_IT_RXIEN) != RESET) //接收中断产生
{
UART_ClearITPendingBit(UART1,UART_IT_RXIEN);//清中断标志
Res =UART_ReceiveData(UART1);
UART_SendData (Res);
}
}
按照上述配置完成后,在main函数中将上述函数调用,将程序下载到MiniBorad中,打开串口助手,在对话框中输入您需要输入的内容,MCU的UART将您发送的数据转发并且打印在串口助手对话框,可以在显示串口看到您输入的内容。打印结果如下图所示:
![MM32 UART中断通信](http://mcu.eetrend.com/files/2017-10/wen_zhang_/100008514-28522-7.jpg)
转自: 灵动微电子