[導讀] 單片機開發串口是應用最爲普遍的通訊接口,也是最爲簡單的通訊接口之一,可是其中的一些要點你是否明瞭呢?來看看本人對串口的一些總結,固然這個總結並不能面面俱到,只是將我的認爲具備共性以及相對比較重要的點作了些梳理。算法
首先這玩意兒分兩種:編程
線上空閒、無數據狀態爲常高電平,故邏輯低定義爲起始位。微信
起始位:老是1位異步
數據位:常見的有8位或9位。函數
校驗位學習
中止位:ui
波特率:bit rate 就是位/秒的概念,就是1秒傳多少位的概念。常見的波特率有哪些呢?
編碼
這裏須注意的要點:設計
一個有效字節的傳輸時間怎麼算?調試
好比9600下,1位起始位,8位數據位,奇校驗,1位中止位,則
爲何要理解清楚這個概念呢,由於在應用中須要計算數據吞吐率問題,就好比一個應用是數據採集串口傳輸問題,須要計算採集的位速率須要小於或等於傳輸波特率,不然數據就來不及傳。固然若是說你有足夠大的緩衝區能夠臨時存儲,可是若是進來太快,而傳出速度跟不上,多大的緩衝都會滿!
校驗位有用嗎?當你的傳輸介質處於一個有干擾的場景下,校驗位就能夠從物理層檢測出錯誤。
理解數據編碼方式有啥意義呢?好比在調試中你能夠利用邏輯分析直接去解析收發線上的數據報文。
應用電路設計的時候RX-TX相連,不少初學者容易在這裏踩坑!
常見的傳輸位序爲低有效位在前。
對於波特率而言須要注意波特率發生器有可能帶來誤碼問題
兩邊分別表明兩個通訊的設備,單從UART編程的角度講收發不須要物理同步握手,想發就發。圖中箭頭表明數據信息流向。RX表示接收數據,TX表示發送數據。數據老是從發送端傳遞到接收端,這就是爲啥RX鏈接TX,TX連RX的緣由。
同步簡單說,收發不可自如,不能夠想發就發,收發須要利用硬件IO口進行握手,RTS/CTS就是用於同步的握手信號:
這個對於普通應用而言並不常見,這裏不作詳細展開,須要用到的時候只須要對應收發時控制握手信號便可。
對於不一樣的單片機,其硬件體系各異,寄存器也差別很大,可是從收發編程策略角度而言,常見有下面三種方式:
這裏以僞代碼方式描述一下:
/*查詢發送字節*/ void uart_send_byte( uint8 ch ) { /*若是當前串口狀態寄存器非空閒,則一直等待*/ /*注意while循環後的分號,表示循環體爲空操做*/ while( !UART_IS_IDLE() ); /*此時將發送字節寫入發送寄存器*/ UART_TX_REG = ch; } /*發送一個緩衝區*/ void uart_send_buffer( uint8 *pBuf,uint8 size ) { uint8 i = 0; /* 異常參數處理*/ if( pBuf == NULL ) return; for( i=0; i<size;i++ ) { send_byte( pBuf[i] ); } }
對於接收而言,如採用查詢模式則幾乎是沒有任何應用價值,由於外部數據不知道何時會到來,因此查詢接受就不描述了,這裏描述一下中斷接收。
static uint8 rx_index = 0; void uart_rx_isr( void ) { /* 接收報文處理 */ rx_buffer[rx_index++] = UART_RX_REG; }
中斷接收須要考慮的幾個要點:
#define FRAME_SIZE (128u) static uint8 tx_buffer[FRAME_SIZE]; static uint8 tx_index = 0; static uint8 tx_length = 0; static uint8 rx_buffer[FRAME_SIZE]; static uint8 rx_index = 0; static bool rx_frame_done = false; void prepare_frame( uint8 * pBuf, uint8 size ) { /*將待傳的報文按照協議封裝*/ /*可能須要處理的事情,好比幀頭、幀尾、校驗等*/ } bool uart_start_sending( uint8 * pBuf, uint8 size ) { if( pBuf == NULL ) return false; memcpy( tx_buffer,pBuf,size ); tx_index = 0; tx_length = size; /*使能發送中斷,向發送寄存器寫入一個字節,進入連續發送模式*/ ENABLE_TX_INT = 1; UART_TX_REG = tx_buffer[tx_index++]; } void uart_tx_isr( void ) { if( tx_index<tx_length ) { UART_TX_REG = tx_buffer[tx_index++]; } else { /*發送完畢,關閉發送中斷*/ DISABLE_TX_INT = 1; } } void uart_rx_isr( void ) { /*處理接收,待接收到完整的幀就設置幀完成標記*/ /*因爲應用各有不一樣,這裏就沒法描述實現了*/ }
還須要考慮的是,對於UART硬件層面的出錯處置,以STM32爲例,就可能有下面的錯誤可能發生:
另外不一樣的單片機其底層硬件實現差別也不較大,好比有的硬件發送緩衝是單字節的緩衝,有的則具備FIFO,這些在選型編程時都須要綜合考慮。
DMA發送模式而言,大體分這樣幾步:
DMA接收模式而言,大體分這樣幾步:
單片機串口是一個須要好好掌握的內容,這裏總結了一些我的經驗,儘可能將一些我的共性的東西總結出來。至於實際實現而言,因爲芯片體系差別較多,具體代碼各異。但我的認爲處置的思路方法倒是基本一致。因此本文除了描述串口自己的細節而言,想表達的一個額外的觀點是: