? 串口通信是非常非常常見的一種通信方式,必須掌握的。可以從如下幾個(gè)方面掌握串口通信:
? 在了解原理之前,我們先看看串口要如何使用,如下圖,只要選擇正確的串口號(hào),把收發(fā)雙方的波特率、校驗(yàn)位、數(shù)據(jù)位、停止位配置成一致,這么就可以實(shí)現(xiàn)雙方通信。
那么配置的這些參數(shù)分別代表什么意思呢?
串口號(hào):唯一標(biāo)識(shí)一個(gè)串口,當(dāng)設(shè)備存在多個(gè)串口時(shí),可以用其標(biāo)識(shí)每個(gè)串口。
波特率:每秒鐘傳輸?shù)臄?shù)據(jù)位數(shù)。表示數(shù)據(jù)傳輸?shù)乃俾?,單位bps(位每秒)。比如115200bps就表示1s可以傳輸115200bits的數(shù)據(jù)。
校驗(yàn)位:
? even 每個(gè)字節(jié)傳送整個(gè)過(guò)程中bit為1的個(gè)數(shù)是偶數(shù)個(gè)(校驗(yàn)位調(diào)整個(gè)數(shù))
? odd 每個(gè)字節(jié)穿送整個(gè)過(guò)程中bit為1的個(gè)數(shù)是奇數(shù)個(gè)(校驗(yàn)位調(diào)整個(gè)數(shù))
? none 沒有校驗(yàn)位
? space 校驗(yàn)位總為0
? mark 校驗(yàn)位總為1
數(shù)據(jù)位:5678共4個(gè)選擇,這是歷史原因,如下
? 5:用于電報(bào)機(jī)傳26個(gè)英文字母,5位足以
? 6:用于電報(bào)機(jī),識(shí)別大小寫字母,增加一個(gè)大小寫位
? 7:用于電腦,ASCII碼7位
? 8:用于電腦,DBCS碼用于兼容ASCII和支持中文雙字節(jié)
停止位:
? 停止位是按長(zhǎng)度來(lái)算的。串行異步通信從計(jì)時(shí)開始,以單位時(shí)間為間隔(一個(gè)單位時(shí)間就是波特率的倒數(shù)),依次接受所規(guī)定的數(shù)據(jù)位和奇偶校驗(yàn)位,并拼裝成一個(gè)字符的并行字節(jié);此后應(yīng)接收到規(guī)定長(zhǎng)度的停止位“1”。所以說(shuō),停止位都是“1”,1.5是它的長(zhǎng)度,即停止位的高電平保持1.5個(gè)單位時(shí)間長(zhǎng)度。一般來(lái)講,停止位有1,1.5,2個(gè)單位時(shí)間三種長(zhǎng)度。
? 下面我們看下串行協(xié)議的幀格式,如圖
一個(gè)幀由4部分組成,起始位 數(shù)據(jù)位 校驗(yàn)位 停止位,正好跟上面的配置一一對(duì)應(yīng),其中,起始位必須是低電平,停止位必須是高電平。
至此,也大致明白串口是怎么回事了。
? 下面幾種都是串口,只是電平標(biāo)準(zhǔn)不同,導(dǎo)致其應(yīng)用場(chǎng)景存在差異,通信協(xié)議和配置都是相同的,通信原理是相同的,軟件實(shí)現(xiàn)相同,硬件電路存在差異。
TTL:
接線方式如圖
高電平表示邏輯1, 低電平表示邏輯零

RS232和RS485對(duì)比
?
? 我們知道串口的作用是為CPU和其它設(shè)備之間提供通信,本質(zhì)上是把數(shù)據(jù)從其他設(shè)備搬移到自身MCU的內(nèi)存中去,如上圖,MCU為實(shí)現(xiàn)串口功能會(huì)做如上的模塊劃分。
GPIO
串口總線狀態(tài),默認(rèn)是高電平,所以Tx應(yīng)該是上拉輸出,Rx應(yīng)該是浮空輸入。
移位器
我們知道串口是一位位傳輸?shù)模砸莆黄骷纯梢詫?shí)現(xiàn)串口的收發(fā)。
數(shù)據(jù)寄存器
用于存儲(chǔ)將要發(fā)送和接收的數(shù)據(jù),其實(shí)只要收發(fā)共用一個(gè)字節(jié)就足以。
時(shí)鐘
上述的運(yùn)行過(guò)程都需要在固定時(shí)鐘下才能正確運(yùn)行,例如波特率。
數(shù)據(jù)由寄存器搬移到內(nèi)存
狀態(tài)寄存器
配置寄存器
? 上述情況那么多,代表不同的配置,肯定需要幾組配置寄存器。例如,中斷的使能控制等
? 如果明白了原理,那么自然就知道該如何配置一個(gè)串口了,無(wú)非就是從芯片手冊(cè)中找到相應(yīng)的寄存器進(jìn)行配置而已。
? 在”串口發(fā)送“例子中,已經(jīng)接觸了串口的發(fā)送功能,現(xiàn)在我們把這個(gè)例子再度深入,實(shí)現(xiàn)串口的接收功能。實(shí)現(xiàn)一個(gè)回顯功能,即PC通過(guò)串口向GD32寫入數(shù)據(jù),然后GD32把數(shù)據(jù)原封不動(dòng)返回給PC。
VOID DRV_UART1_PollTest(VOID){ U8 ch = 0; while (1) { if (USART_GetBitState(USART1, USART_FLAG_RBNE) != RESET) { ch = (U8)USART_DataReceive(USART1); UART1_SendChar(ch); } }}VOID DRV_UART1_PollInit(VOID){ UART1_GpioInit(); UART1_Config(); USART_Enable(USART1, ENABLE);}
效果如圖
注:中斷優(yōu)先級(jí)部分,我會(huì)抽單獨(dú)章節(jié)分析。
必須注意下面這兩個(gè)函數(shù)的區(qū)別,
USART_GetBitState(USART1, USART_FLAG_RBNE); /* 非中斷使用 */USART_GetIntBitState(USART1, USART_INT_RBNE);/* 中斷內(nèi)使用 */
中斷方式處理代碼如下:
VOID USART1_IRQHandler(VOID){ if (USART_GetIntBitState(USART1, USART_INT_RBNE) != RESET) { if (gUart1RxCount >= DRV_UART1_BUFLEN) { memset(gUart1RxBuf, 0, sizeof(gUart1RxBuf)); gUart1RxCount = 0; } gUart1RxBuf[gUart1RxCount] = (U8)USART_DataReceive(USART1); gUart1RxCount ; } if (USART_GetIntBitState(USART1, USART_INT_IDLEF) != RESET) { gUart1RxBufFlag ; }}VOID DRV_UART1_InterruptTest(VOID){ U8 rxCount = 0; while (1) { if (gUart1RxBufFlag > 0) { for (rxCount = 0; rxCount < gUart1RxCount; rxCount ) { UART1_SendChar(gUart1RxBuf[rxCount]); } memset(gUart1RxBuf, 0, sizeof(gUart1RxBuf)); gUart1RxCount = 0; gUart1RxBufFlag = 0; } }}VOID DRV_UART1_InterruptInit(VOID){ UART1_GpioInit(); UART1_Config(); UART1_NvicConfiguration(); USART_Enable(USART1, ENABLE); USART_INT_Set(USART1, USART_INT_RBNE, ENABLE); USART_INT_Set(USART1, USART_INT_IDLEF, ENABLE);}
? 注:DMA細(xì)節(jié)我會(huì)抽單獨(dú)章節(jié)分析,此處只寫一個(gè)DMA輪詢方式的例子。
static VOID UART1_DmaRxConfig(IN U8 *buf, IN U32 len){ DMA_InitPara DMA_InitStructure; DMA_Enable(DMA1_CHANNEL5, DISABLE); /* USART1 RX DMA1 Channel (triggered by USART1 Rx event) Config */ DMA_DeInit(DMA1_CHANNEL5); DMA_InitStructure.DMA_PeripheralBaseAddr = (U32) &(USART1->DR); DMA_InitStructure.DMA_MemoryBaseAddr = (U32)buf; DMA_InitStructure.DMA_DIR = DMA_DIR_PERIPHERALSRC; DMA_InitStructure.DMA_BufferSize = len; DMA_InitStructure.DMA_PeripheralInc = DMA_PERIPHERALINC_DISABLE; DMA_InitStructure.DMA_MemoryInc = DMA_MEMORYINC_ENABLE; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PERIPHERALDATASIZE_BYTE; DMA_InitStructure.DMA_MemoryDataSize = DMA_MEMORYDATASIZE_BYTE; DMA_InitStructure.DMA_Mode = DMA_MODE_NORMAL; DMA_InitStructure.DMA_Priority = DMA_PRIORITY_VERYHIGH; DMA_InitStructure.DMA_MTOM = DMA_MEMTOMEM_DISABLE; DMA_Init(DMA1_CHANNEL5, &DMA_InitStructure); DMA_Enable(DMA1_CHANNEL5, ENABLE);}VOID DRV_UART1_DmaInit(VOID){ UART1_GpioInit(); UART1_Config(); RCC_AHBPeriphClock_Enable(RCC_AHBPERIPH_DMA1, ENABLE); UART1_DmaRxConfig(gUart1RxBuf, DRV_UART1_BUFLEN); USART_Enable(USART1, ENABLE); USART_DMA_Enable(USART1, (USART_DMAREQ_TX | USART_DMAREQ_RX), ENABLE);}static VOID UART1_DmaSend(IN U8 *buf, IN U32 len){ DMA_InitPara DMA_InitStructure; DMA_Enable(DMA1_CHANNEL4, DISABLE); /* USART1_Tx_DMA_Channel (triggered by USART1 Tx event) Config */ DMA_DeInit(DMA1_CHANNEL4); DMA_InitStructure.DMA_PeripheralBaseAddr = (U32) &(USART1->DR); DMA_InitStructure.DMA_MemoryBaseAddr = (U32)buf; DMA_InitStructure.DMA_DIR = DMA_DIR_PERIPHERALDST; DMA_InitStructure.DMA_BufferSize = len; DMA_InitStructure.DMA_PeripheralInc = DMA_PERIPHERALINC_DISABLE; DMA_InitStructure.DMA_MemoryInc = DMA_MEMORYINC_ENABLE; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PERIPHERALDATASIZE_BYTE; DMA_InitStructure.DMA_MemoryDataSize = DMA_MEMORYDATASIZE_BYTE; DMA_InitStructure.DMA_Mode = DMA_MODE_NORMAL; DMA_InitStructure.DMA_Priority = DMA_PRIORITY_VERYHIGH; DMA_InitStructure.DMA_MTOM = DMA_MEMTOMEM_DISABLE; DMA_Init(DMA1_CHANNEL4, &DMA_InitStructure); DMA_Enable(DMA1_CHANNEL4, ENABLE); while (DMA_GetBitState(DMA1_FLAG_TC4) == RESET) { }}VOID DRV_UART1_DmaTest(VOID){ while (1) { if (USART_GetBitState(USART1, USART_FLAG_IDLEF) != RESET) { UART1_DmaSend(gUart1RxBuf, DRV_UART1_BUFLEN); memset(gUart1RxBuf, 0, DRV_UART1_BUFLEN); UART1_DmaRxConfig(gUart1RxBuf, DRV_UART1_BUFLEN); USART_DataReceive(USART1); /* 清除USART_FLAG_IDLEF */ } }}
? 串口是一種非常常見的通信總線,必須掌握。如果上面的原理和例子理解了,我相信用GPIO口虛擬一個(gè)窗口并不是什么難事。
https://github.com/YaFood/GD32F103/tree/master/TestUART
來(lái)源:http://www.icode9.com/content-4-246651.html