通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),通常称作UART,是一种异步收发传输器。该总线可双向通信,可以实现去全双工传输和接收。将资料由串行通信与并行通信间作传输转换,作为并行输入成为串行输出的芯片,通常集成于其他通讯接口的连结上。其原理就是,串并转换和并串转换。
1.UART的工作原理

- 发送数据过程:空闲状态,线路处于高电位;当收到发送数据指令后,拉低线路一个数据位的时间T,接着数据按低位到高位依次发送,数据发送完毕后,接着发送奇偶校验位和停止位(停止位为高电位),一帧资料发送结束。
- 接收数据过程:空闲状态,线路处于高电位;当检测到线路的下降沿(线路电位由高电位变为低电位)时说明线路有数据传输,按照约定的波特率从低位到高位接收数据,数据接收完毕后,接着接收并比较奇偶校验位是否正确,如果正确则通知后续设备准备接收数据或存入缓存。


2.关于UART的FIFO
3.UART与COM口的区别
嵌入式中说的串口,一般是指UART口, 但是我们经常搞不清楚它和COM口的区别, 以及RS232, TTL等关系, 实际上UART,COM指的物理接口形式(硬件), 而TTL、RS-232是指的电平标准(电信号).
UART有4个pin(VCC, GND, RX, TX), 用的TTL电平, 低电平为0(0V),高电平为1(3.3V或以上)。
COM口是我们台式机上面常用的口(下图),9个pin, 用的RS232电平, 它是负逻辑电平,它定义+5~+12V为低电平,而-12~-5V为高电平
引脚介绍(COM口比较多pin,但是常用的也是这几个):
VCC:供电pin,一般是3.3v,在我们的板子上没有过电保护,这个pin一般不接更安全
GND:接地pin,有的时候rx接受数据有问题,就要接上这个pin,一般也可不接
RX:接收数据pin
TX:发送数据pin,
接设备的时候,一般只接GND RX TX。不会接Vcc或者+3.3v的电源线,避免与目标设备上的供电冲突。
4.UART工作模式
TMS320C6748有三个硬件串口,Uart0、Uart1、Uart2.每个串口有轮询模式(POLL)、中断模式(INT)、直接数据访问模式(DMA)。 先来分析下串口三种不同工作模式的实现机制及优缺点:
(1)轮询模式
轮询方式是对I/O设备的程序轮流查询,是早期的计算机系统对I/O设备的一种管理方式。它定时对各种设备轮流询问一遍有无处理要求。轮流询问之后,有要求的,则加以处理。在处理I/O设备的要求之后,处理机返回继续工作。
尽管轮询需要时间,但轮询要比I/O设备的速度要快得多一遍不会发生不能及时处理的问题。
当然,再快的处理机,能处理的输入输出设备的数量也是有一定限度的。而且,程序轮询占据了一部分CPU处理时间,是一种效率较低的方式,在DSP程序中很少应用。
(2)中断方式
处理器的高速和输入输出设备的低速是一种矛盾,是设备管理要解决的一个重要问题。为了提高整体效率,减少在程序直接控制方式中CPU之间的数据传送,是很必要的。
中断方式的优缺点:
I/O设备中断方式使处理器的利用率提高,且能支持多通道程序和I/O设备的并行操作。不过,中断方式仍然存在一些问题。首先,MCU要配置各种各样的输入输出设备。如果这些IO设备都通过中断处理方式并行操作,那么中断次数的急剧会造成CPU无法响应中断和出现数据丢失现象。
其次,如果IO控制器的数据缓冲区比较小,在缓冲区装满数据之后将会发生中断。那么,在数据传送过程中,发生中断的机会增多,这将耗去大量CPU处理时间。
(3)直接内存存储(DMA)方式
直接内存存储技术是指,数据在内存与IO设备间直接进行成块传输。
DMA有两个技术特征,首先是直接传送,其次是块传送。
所谓直接传送,即在内存与IO设备间传送一个数据块的过程中,不需要CPU的任何干涉,只需要CPU在过程开始时向设备发出“传送数据”的命令,然后通过中断来得知过程是否结束和下次操作是否准备就绪。
DMA与中断的区别
(1) 中断方式是数据缓冲区寄存器满之后发出中断,要求CPU进行中断处理,而DMA方式则是在所要求传送的数据块全部传送结束时要求CPU进行中断处理。这就大大减少了CPU进行中断处理的次数。
(2) 中断方式的数据传送是在中断处理时由CPU控制完成的,而DMA方式则是在DMA控制器的控制下,不经过CPU控制。这就排除了因并行设备过多而来不及处理以及因速度不匹配而造成数据丢失等现象。
DMA方式的优缺点
DMA方式中,由于IO设备直接同内存发生块的数据交换,因此效率比较高。
DMA控制器功能的强弱,是决定DMA效率的关键因素。DMA控制器需要为每次数据传送做大量的工作,数据传送单位的增大意味着传送次数的减少。另外,DMA方式窃取了时钟周期,CPU处理效率低了,要想尽量少地窃取时钟周期,就要设法提高DMA控制器的性能,这样可以较少地影响CPU处理效率。
下面讲解TMS320C6748三种工作方式程序:
`1 POLL工作方式
1 int main(void) 2 { 3 4 PSCInit(); // 外设使能配置 5 GPIOBankPinMuxSet(); // GPIO 管脚复用配置 6 7 UARTInit(); // UART 初始化 8 9 unsigned char i; // 发送字符串 10 for(i = 0; i < 34; i++) 11 UARTCharPut(SOC_UART_1_REGS, Send); 12 13 unsigned char Receive; // 接收缓存 14 // 主循环 15 for(;;) 16 { 17 Receive=UARTCharGet(SOC_UART_1_REGS); 18 UARTCharPut(SOC_UART_1_REGS, Receive+1); 19 } 20 }
从DSP串口 Poll模式程序可以看到,Poll模式使用比较简单,容易上手。
2 中断方式
1 int main(void) 2 { 3 // 外设使能配置 4 PSCInit(); 5 6 // GPIO 管脚复用配置 7 GPIOBankPinMuxSet(); 8 9 10 // DSP 中断初始化 11 InterruptInit(); 12 13 // UART 初始化 14 UARTInit(); 15 16 // UART 中断初始化 17 UARTInterruptInit(); 18 19 // 主循环 20 for(;;) 21 { 22 } 23 } 24 25 void UARTIsr() 26 { 27 static unsigned int length = sizeof(txArray); 28 static unsigned int count = 0; 29 unsigned char rxData = 0; 30 unsigned int int_id = 0; 31 32 // 确定中断源 33 int_id = UARTIntStatus(SOC_UART_0_REGS); 34 35 // 清除 UART2 系统中断 36 IntEventClear(SYS_INT_UART0_INT); 37 38 // 发送中断 39 if(UART_INTID_TX_EMPTY == int_id) 40 { 41 if(0 < length) 42 { 43 // 写一个字节到 THR 44 UARTCharPutNonBlocking(SOC_UART_0_REGS, txArray[count]); 45 length--; 46 count++; 47 } 48 if(0 == length) 49 { 50 // 禁用发送中断 51 UARTIntDisable(SOC_UART_0_REGS, UART_INT_TX_EMPTY); 52 } 53 } 54 55 // 接收中断 56 if(UART_INTID_RX_DATA == int_id) 57 { 58 rxData = UARTCharGetNonBlocking(SOC_UART_0_REGS); 59 UARTCharPutNonBlocking(SOC_UART_0_REGS, rxData); 60 } 61 62 // 接收错误 63 if(UART_INTID_RX_LINE_STAT == int_id) 64 { 65 while(UARTRxErrorGet(SOC_UART_0_REGS)) 66 { 67 // 从 RBR 读一个字节 UARTCharGetNonBlocking(SOC_UART_0_REGS); 68 } 69 } 70 return; 71 }
3 DMA模式

1 int main(void) 2 { 3 // 外设使能配置 4 PSCInit(); 5 6 // DSP 中断初始化 7 InterruptInit(); 8 9 // EDMA3 中断初始化 10 EDMA3InterruptInit(); 11 12 // EDMA3 初始化 13 EDMA3UARTInit(); 14 15 // 初始化串口终端 使用串口2 16 UARTStdioInit(); 17 18 // 申请串口 EDMA3 发送通道 19 EDMA3RequestChannel(SOC_EDMA30CC_0_REGS, EDMA3_CHANNEL_TYPE_DMA, 20 EDMA3_CHA_UART2_TX, EDMA3_CHA_UART2_TX, 21 EVT_QUEUE_NUM); 22 23 // 注册回调函数 24 cb_Fxn[EDMA3_CHA_UART2_TX] = &callback; 25 26 // 申请串口 EDMA3 接收通道 27 EDMA3RequestChannel(SOC_EDMA30CC_0_REGS, EDMA3_CHANNEL_TYPE_DMA, 28 EDMA3_CHA_UART2_RX, EDMA3_CHA_UART2_RX, 29 EVT_QUEUE_NUM); 30 31 // 注册回调函数 32 cb_Fxn[EDMA3_CHA_UART2_RX] = &callback; 33 34 volatile char enter[] = "Tronlong UART2 EDMA3 Application......\n\rPlease Enter 20 bytes from keyboard\r\n"; 35 volatile char buffer[RX_BUFFER_SIZE]; 36 unsigned int buffLength = 0; 37 38 // 发送数据 39 buffLength = strlen((const char *)enter); 40 UartTransmitData(EDMA3_CHA_UART2_TX, EDMA3_CHA_UART2_TX, enter, buffLength); 41 42 // 使能串口 DMA 模式 43 UARTDMAEnable(SOC_UART_2_REGS, UART_RX_TRIG_LEVEL_1 | \ 44 UART_DMAMODE | \ 45 UART_FIFO_MODE ); 46 47 // 等待从回调函数返回 48 while(flag == 0); 49 flag = 0; 50 51 // 接收数据 52 UartReceiveData(EDMA3_CHA_UART2_RX, EDMA3_CHA_UART2_RX, buffer); 53 54 // 使能串口 DMA 模式 55 UARTDMAEnable(SOC_UART_2_REGS, UART_RX_TRIG_LEVEL_1 | \ 56 UART_DMAMODE | \ 57 UART_FIFO_MODE ); 58 59 // 等待从回调函数返回 60 while(flag == 0); 61 flag = 0; 62 63 // 发送数据 64 UartTransmitData(EDMA3_CHA_UART2_TX, EDMA3_CHA_UART2_TX, buffer, RX_BUFFER_SIZE); 65 66 // 使能串口 DMA 模式 67 UARTDMAEnable(SOC_UART_2_REGS, UART_RX_TRIG_LEVEL_1 | \ 68 UART_DMAMODE | \ 69 UART_FIFO_MODE ); 70 71 // 等待从回调函数返回 72 while(flag == 0); 73 flag = 0; 74 75 // 释放 EDMA3 通道 76 EDMA3FreeChannel(SOC_EDMA30CC_0_REGS, EDMA3_CHANNEL_TYPE_DMA, 77 EDMA3_CHA_UART2_TX, EDMA3_TRIG_MODE_EVENT, 78 EDMA3_CHA_UART2_TX, EVT_QUEUE_NUM); 79 80 EDMA3FreeChannel(SOC_EDMA30CC_0_REGS, EDMA3_CHANNEL_TYPE_DMA, 81 EDMA3_CHA_UART2_RX, EDMA3_TRIG_MODE_EVENT, 82 EDMA3_CHA_UART2_RX, EVT_QUEUE_NUM); 83 84 // 主循环 85 for(;;) 86 { 87 88 } 89 } 90 91 92 void Edma3ComplHandlerIsr(void) 93 { 94 volatile unsigned int pendingIrqs; 95 volatile unsigned int isIPR = 0; 96 97 unsigned int indexl; 98 unsigned int Cnt = 0; 99 100 indexl = 1; 101 102 IntEventClear(SYS_INT_EDMA3_0_CC0_INT1); 103 104 isIPR = HWREG(SOC_EDMA30CC_0_REGS + EDMA3CC_S_IPR(1)); 105 if(isIPR) 106 { 107 while((Cnt < EDMA3CC_COMPL_HANDLER_RETRY_COUNT)&& (indexl != 0u)) 108 { 109 indexl = 0u; 110 pendingIrqs = HWREG(SOC_EDMA30CC_0_REGS + EDMA3CC_S_IPR(1)); 111 112 while(pendingIrqs) 113 { 114 if((pendingIrqs & 1u) == TRUE) 115 { 116 HWREG(SOC_EDMA30CC_0_REGS + EDMA3CC_S_ICR(1)) = (1u << indexl); 117 118 (*cb_Fxn[indexl])(indexl, EDMA3_XFER_COMPLETE); 119 } 120 ++indexl; 121 pendingIrqs >>= 1u; 122 } 123 Cnt++; 124 } 125 } 126 } 127 128 void Edma3CCErrHandlerIsr() 129 { 130 volatile unsigned int pendingIrqs = 0; 131 unsigned int regionNum = 0; 132 unsigned int evtqueNum = 0; 133 unsigned int index = 1; 134 unsigned int Cnt = 0; 135 136 IntEventClear(SYS_INT_EDMA3_0_CC0_ERRINT); 137 138 if((HWREG(SOC_EDMA30CC_0_REGS + EDMA3CC_EMR) != 0 ) || \ 139 (HWREG(SOC_EDMA30CC_0_REGS + EDMA3CC_QEMR) != 0) || \ 140 (HWREG(SOC_EDMA30CC_0_REGS + EDMA3CC_CCERR) != 0)) 141 { 142 while((Cnt < EDMA3CC_ERR_HANDLER_RETRY_COUNT) && (index != 0u)) 143 { 144 index = 0u; 145 pendingIrqs = HWREG(SOC_EDMA30CC_0_REGS + EDMA3CC_EMR); 146 while(pendingIrqs) 147 { 148 if((pendingIrqs & 1u) == TRUE) 149 { 150 HWREG(SOC_EDMA30CC_0_REGS + EDMA3CC_EMCR) = (1u<<index); 151 HWREG(SOC_EDMA30CC_0_REGS + EDMA3CC_S_SECR(regionNum)) = (1u<<index); 152 } 153 154 ++index; 155 pendingIrqs >>= 1u; 156 } 157 158 index = 0u; 159 pendingIrqs = HWREG(SOC_EDMA30CC_0_REGS + EDMA3CC_QEMR); 160 161 while(pendingIrqs) 162 { 163 if((pendingIrqs & 1u)==TRUE) 164 { 165 HWREG(SOC_EDMA30CC_0_REGS + EDMA3CC_QEMCR) = (1u<<index); 166 HWREG(SOC_EDMA30CC_0_REGS + EDMA3CC_S_QSECR(0)) = (1u<<index); 167 } 168 169 ++index; 170 pendingIrqs >>= 1u; 171 } 172 173 index = 0u; 174 pendingIrqs = HWREG(SOC_EDMA30CC_0_REGS + EDMA3CC_CCERR); 175 176 if(pendingIrqs != 0u) 177 { 178 for(evtqueNum = 0u; evtqueNum < EDMA3_0_NUM_EVTQUE; evtqueNum++) 179 { 180 if((pendingIrqs & (1u << evtqueNum)) != 0u) 181 { 182 HWREG(SOC_EDMA30CC_0_REGS + EDMA3CC_CCERRCLR) = (1u << evtqueNum); 183 } 184 } 185 186 if ((pendingIrqs & (1 << EDMA3CC_CCERR_TCCERR_SHIFT)) != 0u) 187 { 188 HWREG(SOC_EDMA30CC_0_REGS + EDMA3CC_CCERRCLR) = \ 189 (0x01u << EDMA3CC_CCERR_TCCERR_SHIFT); 190 } 191 192 ++index; 193 } 194 195 Cnt++; 196 } 197 } 198 } 199 200 /****************************************************************************/ 201 /* */ 202 /* 发送数据 */ 203 /* */ 204 /****************************************************************************/ 205 void UartTransmitData(unsigned int tccNum, unsigned int chNum, 206 volatile char *buffer, unsigned int buffLength) 207 { 208 EDMA3CCPaRAMEntry paramSet; 209 210 // 配置参数 RAM 211 paramSet.srcAddr = (unsigned int)buffer; 212 // 接收缓存寄存器 / 发送保持寄存器 地址 213 paramSet.destAddr = SOC_UART_2_REGS + 0; 214 paramSet.aCnt = MAX_ACNT; 215 paramSet.bCnt = (unsigned short)buffLength; 216 paramSet.cCnt = MAX_CCNT; 217 218 // 源索引自增系数 1 即一个字节 219 paramSet.srcBIdx = (short)1u; 220 221 // 目标索引自增系数 222 paramSet.destBIdx = (short)0u; 223 224 // 异步传输模式 225 paramSet.srcCIdx = (short)0u; 226 paramSet.destCIdx = (short)0u; 227 paramSet.linkAddr = (unsigned short)0xFFFFu; 228 paramSet.bCntReload = (unsigned short)0u; 229 paramSet.opt = 0x00000000u; 230 paramSet.opt |= (EDMA3CC_OPT_DAM ); 231 paramSet.opt |= ((tccNum << EDMA3CC_OPT_TCC_SHIFT) & EDMA3CC_OPT_TCC); 232 paramSet.opt |= (1 << EDMA3CC_OPT_TCINTEN_SHIFT); 233 234 // 写参数 RAM 235 EDMA3SetPaRAM(SOC_EDMA30CC_0_REGS, chNum, ¶mSet); 236 237 // 使能 EDMA3 通道 238 EDMA3EnableTransfer(SOC_EDMA30CC_0_REGS, chNum, EDMA3_TRIG_MODE_EVENT); 239 } 240 241 /****************************************************************************/ 242 /* */ 243 /* 接收数据 */ 244 /* */ 245 /****************************************************************************/ 246 void UartReceiveData(unsigned int tccNum, unsigned int chNum, 247 volatile char *buffer) 248 { 249 EDMA3CCPaRAMEntry paramSet; 250 251 // 配置参数 RAM 252 // 接收缓存寄存器 / 发送保持寄存器 地址 253 paramSet.srcAddr = SOC_UART_2_REGS + 0; 254 paramSet.destAddr = (unsigned int)buffer; 255 paramSet.aCnt = MAX_ACNT; 256 paramSet.bCnt = RX_BUFFER_SIZE; 257 paramSet.cCnt = MAX_CCNT; 258 259 // 源索引自增系数 260 paramSet.srcBIdx = 0; 261 // 目标索引自增系数 1 即一个字节 262 paramSet.destBIdx = 1; 263 264 // 异步模式 265 paramSet.srcCIdx = 0; 266 paramSet.destCIdx = 0; 267 paramSet.linkAddr = (unsigned short)0xFFFFu; 268 paramSet.bCntReload = 0; 269 paramSet.opt = 0x00000000u; 270 paramSet.opt |= ((EDMA3CC_OPT_SAM) << EDMA3CC_OPT_SAM_SHIFT); 271 paramSet.opt |= ((tccNum << EDMA3CC_OPT_TCC_SHIFT) & EDMA3CC_OPT_TCC); 272 paramSet.opt |= (1 << EDMA3CC_OPT_TCINTEN_SHIFT); 273 274 // 写参数 RAM 275 EDMA3SetPaRAM(SOC_EDMA30CC_0_REGS, chNum, ¶mSet); 276 277 // 使能 EDMA3 通道 278 EDMA3EnableTransfer(SOC_EDMA30CC_0_REGS, chNum, EDMA3_TRIG_MODE_EVENT); 279 } 280 281 /****************************************************************************/ 282 /* */ 283 /* 回调函数 */ 284 /* */ 285 /****************************************************************************/ 286 void callback(unsigned int tccNum, unsigned int status) 287 { 288 UARTDMADisable(SOC_UART_2_REGS, (UART_RX_TRIG_LEVEL_1 | UART_FIFO_MODE)); 289 290 flag = 1; 291 }