UART
(一)通信方式
1.串行通信与并行通信
(1)串行通信
- 数据逐位发送
(2)并行通信
- 多位同时发送
2.同步通信与异步通信
(1)同步通信
- 在同一个时钟信号下进行数据传输
(2)异步通信
- 在不同的时钟信号下进行数据传输
3.单工、半双工、全双工通信
(1)单工通信
- 单向传输,收/发
(2)半双工通信
- 双向传输,可发可收,但不能同时进行
(3)全双工通信
- 双向传输,同时收发
(二)UART基本原理
1.通信方式
(1)异步串行通信
(2)半双工通信
2.UART时序
- 时钟高电平空闲(数据发送)
- 时钟低电平采样(数据接收)
3.数据帧
(1)目的:减小发送与接收的时序误差
(2)数据帧格式
-
idle:准备通信,电平拉高
-
start:开始通信,电平拉低
-
data:数据位(7/8)
- LSB:低位数据发送
- MSB:高位数据发送
-
Parity:奇偶校验位,检验数据
- 奇校验:奇偶校验位置0或1,使得数据位与奇偶校验位1的个数为奇数
- 偶校验:奇偶校验位置0或1,使得数据位与奇偶校验位1的个数为偶数
-
stop:停止通信,电平拉高
4.过采样(oversampling)与时钟误差
(1)目的:减小误码率
(2)原因:虽然有了数据帧可以大幅度减小误码率,但在数据帧内的少许数据可能产生误差
(3)过采样
- 在嵌入式arm微控制器中,发送时钟频率为接收时钟的1/16
- 重复检测接收数据16次,取中间几次投票确定
- 时钟误差(5%左右)
(三)编程
1.编程流程
(1)GPIO复用为UART模式
(2)UART功能配置
- 波特率(时钟信号)
- 数据帧各模式设置
(3)UART模块使能
(4)UART中断配置
- 中断优先级
- 中断使能
(5)数据收发
- 查询模式
- 中断模式
2.编程实例
(1)寄存器编程
#include "msp.h"
#include "driverlib.h"
/*
The recommended eUSCI_A initialization/reconfiguration process is:
1. Set UCSWRST.
2. Initialize all eUSCI_A registers with UCSWRST = 1 (including UCAxCTL1).
3. Configure ports.
4. Clear UCSWRST with software.
5. Enable interrupts (optional) with UCRXIE or UCTXIE.
*/
int main()
{
WDTCTL = WDTPW + WDTHOLD; //关闭看门狗
//GPIO复用为HFXT
PJ->SEL1 &=~(BIT2 | BIT3);
PJ->SEL0 |= (BIT2 | BIT3);
//解锁时钟寄存器(0x695A)
CS->KEY = CS_KEY;
//HCLK 16MHz
CS->CTL2 |= CS_CTL2_HFXTFREQ_2 | CS_CTL2_HFXTDRIVE | CS_CTL2_HFXT_EN;
//SMCLK 4MHz
CS->CTL1 |= CS_CTL1_DIVS_2 | CS_CTL1_SELS_5;
//SMCLK 时钟源使能
CS->CLKEN |= CS_CLKEN_SMCLK_EN;
//锁住时钟寄存器(0xA569)
CS->KEY = CS_KEY_KEY_OFS;
//GPIO复用为UART
P1->SEL0 |= (BIT2 | BIT3);
P1->SEL1 &=~ (BIT2 | BIT3);
//UART模块复位(在复位状态下控制相关寄存器才能配置)
EUSCI_A0->CTLW0 |= EUSCI_A_CTLW0_SWRST;
//时钟源选择
EUSCI_A0->CTLW0 |= EUSCI_A_CTLW0_SSEL__SMCLK;
//波特率:4MHz 9600 (4000000 / (16 * 9600) = 26
EUSCI_A0->BRW = 26;
//校验位使能,默认配置(8位数据(低位优先) + 1位停止位 + 偶检验)
EUSCI_A0->CTLW0 |= EUSCI_A_CTLW0_PEN;
//过采样使能
EUSCI_A0->MCTLW |= EUSCI_A_MCTLW_OS16;
//释放复位
EUSCI_A0->CTLW0 &= ~EUSCI_A_CTLW0_SWRST;
//清除接收中断标志位
EUSCI_A0->IFG &=~EUSCI_A_IFG_RXIFG;
//接收中断使能
EUSCI_A0->IE |= EUSCI_A_IE_RXIE;
while(1);
}
void EUSCIA0_IRQHandler(void)
{
//接收中断使能
if(EUSCI_A0->IFG & EUSCI_A_IFG_RXIFG)
{
//清除接收中断标志位
EUSCI_A0->IFG &=~EUSCI_A_IFG_RXIFG;
//数据回传(发送 = 接收)
EUSCI_A0->TXBUF = EUSCI_A0->RXBUF;
}
}
(2)库函数编程
#include "msp.h"
#include <ti/devices/msp432p4xx/driverlib/driverlib.h>
void main(void)
{
/* Halting WDT */
MAP_WDT_A_holdTimer();
//GPIO复用为HFXT
GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_PJ,GPIO_PIN3 | GPIO_PIN2,GPIO_PRIMARY_MODULE_FUNCTION);
//HCLK 16MHz
CS_setExternalClockSourceFrequency(32000,16000000);
CS_startHFXT(false);
//SMCLK 4MHz
CS_initClockSignal(CS_SMCLK,CS_HFXTCLK_SELECT, CS_CLOCK_DIVIDER_4);
CS_enableClockRequest(CS_SMCLK);
//GPIO复用为UART
MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1,GPIO_PIN2 | GPIO_PIN3, GPIO_PRIMARY_MODULE_FUNCTION);
//UART功能配置
eUSCI_UART_ConfigV1 uartConfig;
uartConfig.uartMode = EUSCI_A_UART_MODE;
uartConfig.selectClockSource = EUSCI_A_UART_CLOCKSOURCE_SMCLK;
uartConfig.overSampling = EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION;
uartConfig.clockPrescalar = 26;
uartConfig.firstModReg = 0;
uartConfig.secondModReg = 0;
uartConfig.msborLsbFirst = EUSCI_A_UART_LSB_FIRST;
uartConfig.dataLength = EUSCI_A_UART_8_BIT_LEN;
uartConfig.parity = EUSCI_A_UART_ODD_PARITY;
uartConfig.numberofStopBits = EUSCI_A_UART_ONE_STOP_BIT;
UART_initModule(EUSCI_A0_BASE, &uartConfig);
//接收中断使能
UART_enableInterrupt(EUSCI_A0_BASE, EUSCI_A_UART_RECEIVE_INTERRUPT);
//UART使能
UART_enableModule(EUSCI_A0_BASE);
while(1);
}
void EUSCIA0_IRQHandler(void)
{
uint32_t status = UART_getEnabledInterruptStatus(EUSCI_A0_BASE);
if(status & EUSCI_A_UART_RECEIVE_INTERRUPT_FLAG)
{
UART_clearInterruptFlag(EUSCI_A0_BASE,EUSCI_A_UART_RECEIVE_INTERRUPT_FLAG);
UART_transmitData(EUSCI_A0_BASE, MAP_UART_receiveData(EUSCI_A0_BASE));
}
}