通用異步收發傳輸器(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 }