UART学习
UART基本概念
在编写具体程序之前,可以先了解下UART大致的概念,之后再在example内寻找例程进行分析。最后再参照手册就可以做出具体的东西了
通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),通常称作UART。它将要传输的资料在串行通信与并行通信之间加以转换。作为把并行输入信号转成串行输出信号的芯片,UART通常被集成于其他通讯接口的连结上。在嵌入式设计中,UART用于主机与辅助设备通信,如汽车音响与外接AP之间的通信,与PC机通信包括与监控调试器和其它器件,如EEPROM通信。
可以理解为一种输入并行信号,输出串行信号的用于串口通信的传输器。也可以理解为是通信协议的一种
可以把单片机进行通信的过程分为三个部分:即获取信息
→ 编码
→解码
当获取信息后编码时,除了原来的八位数据,还有起始位和中止位。
b0?–
b8?代表着每一位的时间长度。定义波特率为一位时间长度的倒数,即:
?
bautrate=
bit?time1?
而带宽可以理解为数据位(看几位数据)与帧位(包括起始结束)的比值
而对于MSP432来说,共有四对串口通信的地址,如下图所示
可发现这与GPIO口的引脚是重叠的。为了让芯片明白是怎么样的引脚,所有uart的定义都有PXSEL1=1且PXSEL0=1,这样就可以区分开了。下图是发送的UART端口的示意图。
可以发现包括四部分:寄存器,数据,状态标志字,起始和终止位
下面来进行传输过程中的分析
两个缓冲寄存器是起到暂存的作用的。比如当TXIFG=1时,数据先写入的TRANSMIT REGISTER,将数据写入上面的段(P1.3)并加上起始位和终止位。之后进行传输至P1.2对应的口。
八位数据被读入段(P1.2)后检查起始和终止位是否未出错,若不出错就把数据传至RECEIVE REGISTER
之后若RXIFG=0,就进行读取数据的工作。
需要注意的是这里传送的数据为0x61,即一位字符的地址
一般有4个基本参数,可以通过TI公司给出的转换器,只需输入波特率和时钟频率,以及是USCI/EUSCI模式就可以计算出参数。这些参数在初始设置中需要用到
UART例程1
下面来看一个关于UART的基本例程,路径为以下:D:\TI\simplelink_msp432p4_sdk_3_40_01_02\examples\nortos\MSP_EXP432P401R\driverlib\uart_pc_echo_12mhz_brclk\uart_pc_echo_12mhz_brclk.c
代码如下。先上代码再解释
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | /* DriverLib Includes */ #include <ti/devices/msp432p4xx/driverlib/driverlib.h> /* Standard Includes */ #include <stdint.h> #include <stdbool.h> //![Simple UART Config] /* UART Configuration Parameter. These are the configuration parameters to * make the eUSCI A UART module to operate with a 9600 baud rate. These * values were calculated using the online calculator that TI provides * at: *http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSP430BaudRateConverter/index.html */ /*关于串口的基本配置*/ const eUSCI_UART_ConfigV1 uartConfig = { EUSCI_A_UART_CLOCKSOURCE_SMCLK, // SMCLK Clock Source 78, // BRDIV = 78 2, // UCxBRF = 2 0, // UCxBRS = 0 EUSCI_A_UART_NO_PARITY, // No Parity EUSCI_A_UART_LSB_FIRST, // LSB First EUSCI_A_UART_ONE_STOP_BIT, // One stop bit EUSCI_A_UART_MODE, // UART mode EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION, // Oversampling EUSCI_A_UART_8_BIT_LEN // 8 bit data length }; //![Simple UART Config] int main(void) { //关闭看门狗 MAP_WDT_A_holdTimer(); //选择P1.2和P1.3为UART功能引脚 MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1, GPIO_PIN2 | GPIO_PIN3, GPIO_PRIMARY_MODULE_FUNCTION); /* Setting DCO to 12MHz (改后面的数字,xMHZ)*/ CS_setDCOCenteredFrequency(CS_DCO_FREQUENCY_12); //![Simple UART Example] //配置UART模块 MAP_UART_initModule(EUSCI_A0_BASE, &uartConfig); //使能UART模块 MAP_UART_enableModule(EUSCI_A0_BASE); //中断使能 MAP_UART_enableInterrupt(EUSCI_A0_BASE, EUSCI_A_UART_RECEIVE_INTERRUPT); MAP_Interrupt_enableInterrupt(INT_EUSCIA0); MAP_Interrupt_enableSleepOnIsrExit(); MAP_Interrupt_enableMaster(); while(1) { MAP_PCM_gotoLPM0(); } } //用户配置的中断服务程序 void EUSCIA0_IRQHandler(void) { uint32_t status = MAP_UART_getEnabledInterruptStatus(EUSCI_A0_BASE);//获取中断标志位 //如果接收到的中断,进行信息传递 if(status & EUSCI_A_UART_RECEIVE_INTERRUPT_FLAG) { MAP_UART_transmitData(EUSCI_A0_BASE, MAP_UART_receiveData(EUSCI_A0_BASE)); } } |
因为为12MHZ且波特率为9600,得出来的参数(78,2,0,8)需要反映在程序的初始设置块中。
注意前三个参数之间用逗号连接
1 2 3 4 5 6 7 8 9 10 11 12 13 | const eUSCI_UART_ConfigV1 uartConfig = { EUSCI_A_UART_CLOCKSOURCE_SMCLK, // SMCLK Clock Source 78, // BRDIV = 78 2, // UCxBRF = 2 0, // UCxBRS = 0 EUSCI_A_UART_NO_PARITY, // No Parity EUSCI_A_UART_LSB_FIRST, // LSB First EUSCI_A_UART_ONE_STOP_BIT, // One stop bit EUSCI_A_UART_MODE, // UART mode EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION, // Oversampling EUSCI_A_UART_8_BIT_LEN // 8 bit data length }; |
在主函数中,首先需要配置关闭看门狗,选择UART功能引脚,配置时钟频率,配置UART,使能UART。完成这些后进入中断服务程序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | int main(void) { //关闭看门狗 MAP_WDT_A_holdTimer(); //选择P1.2和P1.3为UART功能引脚 MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1, GPIO_PIN2 | GPIO_PIN3, GPIO_PRIMARY_MODULE_FUNCTION); /* Setting DCO to 12MHz (改后面的数字,xMHZ)*/ CS_setDCOCenteredFrequency(CS_DCO_FREQUENCY_12); //![Simple UART Example] //配置UART模块 MAP_UART_initModule(EUSCI_A0_BASE, &uartConfig); //使能UART模块 MAP_UART_enableModule(EUSCI_A0_BASE); //中断使能 MAP_UART_enableInterrupt(EUSCI_A0_BASE, EUSCI_A_UART_RECEIVE_INTERRUPT); MAP_Interrupt_enableInterrupt(INT_EUSCIA0); MAP_Interrupt_enableSleepOnIsrExit(); MAP_Interrupt_enableMaster(); while(1) { MAP_PCM_gotoLPM0(); } } |
在中断服务程序中,流程同前面的GPIO中断例程分析:即先定义出一个中断状态变量。如果有多个接口,就一次性获取这些接口的中断状态。再使用清理终端标志位的函数清掉获取来的标志位后按位和中断标志位相与,这个的目的是判断是否接收到了中断。如果接收到了的话进行相应的中断传递。
1 2 3 4 5 6 7 8 9 10 11 | //用户配置的中断服务程序 void EUSCIA0_IRQHandler(void) { uint32_t status = MAP_UART_getEnabledInterruptStatus(EUSCI_A0_BASE);//获取中断状态 //如果接收到的中断,进行信息传递 if(status & EUSCI_A_UART_RECEIVE_INTERRUPT_FLAG) { MAP_UART_transmitData(EUSCI_A0_BASE, MAP_UART_receiveData(EUSCI_A0_BASE)); } } |
这个历程的功能是返回用户在terminal上输入的值
点击这个按键后,choose terminal选择至serial terminal模式,之后系统会自动配置,点确定即可。
这里系统只可以检测英文,不支持中文字符。配置好terminal后点Toggle command input field按钮,出来相应的输入框
之后输入英文字符就可,如输入HELLO WORLD!后在上面的框中会显示相同的字符
UART例程2
注意这里定义的是字符。在MSP432中可以定义变量的大小,如uint_32 uint_8等
思路是定义两个八字节的变量,对应输出和输入,起名为TXDATA(再传输给电脑屏幕的)和RXDATA(用于接收用户给的字符),再借助已经封装好的receive函数传入数据。
再在定义引脚阶段给出对LED灯引脚的定义,如果TXDATA不等于RXDATA就让灯亮
由于好奇再看一下这个receivedata函数
1 2 3 4 5 6 7 8 9 | uint8_t UART_receiveData(uint32_t moduleInstance) { /* If interrupts are not used, poll for flags */ if (!BITBAND_PERI(EUSCI_A_CMSIS(moduleInstance)->IE, EUSCI_A_IE_RXIE_OFS)) while (!BITBAND_PERI(EUSCI_A_CMSIS(moduleInstance)->IFG, EUSCI_A_IFG_RXIFG_OFS)) ; return EUSCI_A_CMSIS(moduleInstance)->RXBUF; } |
发现用到了一些标志位,在这里不做多的了解,会用即可,知道这里是相关的电平检测就好。
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | /* DriverLib Includes */ #include <ti/devices/msp432p4xx/driverlib/driverlib.h> /* Standard Includes */ #include <stdint.h> #include <stdbool.h> //定义不同大小的数据 uint8_t TXData = 1; uint8_t RXData = 0; /* UART Configuration Parameter. These are the configuration parameters to * make the eUSCI A UART module to operate with a 115200 baud rate. These * values were calculated using the online calculator that TI provides * at: * http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSP430BaudRateConverter/index.html */ //三个参数分别为13 0 37 8 const eUSCI_UART_ConfigV1 uartConfig = { EUSCI_A_UART_CLOCKSOURCE_SMCLK, // SMCLK Clock Source 13, // BRDIV = 13 0, // UCxBRF = 0 37, // UCxBRS = 37 EUSCI_A_UART_NO_PARITY, // No Parity EUSCI_A_UART_MSB_FIRST, // MSB First EUSCI_A_UART_ONE_STOP_BIT, // One stop bit EUSCI_A_UART_MODE, // UART mode EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION, // Oversampling EUSCI_A_UART_8_BIT_LEN // 8 bit data length }; int main(void) { //看门狗 MAP_WDT_A_holdTimer(); /* Selecting P1.2 and P1.3 in UART mode and P1.0 as output (LED) */ MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1, GPIO_PIN2 | GPIO_PIN3, GPIO_PRIMARY_MODULE_FUNCTION); MAP_GPIO_setAsOutputPin(GPIO_PORT_P1, GPIO_PIN0); MAP_GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN0); /* Setting DCO to 24MHz (upping Vcore) */ FlashCtl_setWaitState(FLASH_BANK0, 1); FlashCtl_setWaitState(FLASH_BANK1, 1); MAP_PCM_setCoreVoltageLevel(PCM_VCORE1); CS_setDCOCenteredFrequency(CS_DCO_FREQUENCY_24); /* Configuring UART Module */ MAP_UART_initModule(EUSCI_A2_BASE, &uartConfig); /* Enable UART module */ MAP_UART_enableModule(EUSCI_A2_BASE); /* Enabling interrupts */ MAP_UART_enableInterrupt(EUSCI_A2_BASE, EUSCI_A_UART_RECEIVE_INTERRUPT); MAP_Interrupt_enableInterrupt(INT_EUSCIA2); MAP_Interrupt_enableSleepOnIsrExit(); while(1) { MAP_UART_transmitData(EUSCI_A2_BASE, TXData); MAP_Interrupt_enableSleepOnIsrExit(); MAP_PCM_gotoLPM0InterruptSafe(); } } /* EUSCI A0 UART ISR - Echos data back to PC host */ void EUSCIA2_IRQHandler(void) { uint32_t status = MAP_UART_getEnabledInterruptStatus(EUSCI_A2_BASE); if(status & EUSCI_A_UART_RECEIVE_INTERRUPT_FLAG) { RXData = MAP_UART_receiveData(EUSCI_A2_BASE); if(RXData != TXData) // Check value { MAP_GPIO_setOutputHighOnPin(GPIO_PORT_P1, GPIO_PIN0); while(1); // Trap CPU } TXData++; MAP_Interrupt_disableSleepOnIsrExit(); } } |
部分资料来源:
1.https://training.ti.com/node/1136685?keyMatch=RSLK&tisearch=Search-CN-everything
2.https://space.bilibili.com/434210374/