Arduino Serail.readString() 解析

-已Arduino Leonardo為例
-已處理字元,字串為主
-"Arduino Leonardo"並沒有硬體的UART FIFO Buffer, 所以整個readString()之所以可以暫存字元,是靠中斷轉存字元到宣告的buffer中.


1.Serail.readString()相關的程式在那?



























Arduino中, UART通訊相關的"Serial"物件實體,主要是實做在"HardwareSerial"類別中,除了"Serail"外,不同的Arduino平台,可能還會有其他同樣是"HardwareSerial"類別的的物件實體以用來支援多組UART. 而"HardwareSerial"類別本身又是繼承自"stream"類別.所以有部分"HardwareSerial"本身有部分的功能已經實作在"stream",另外也有部分的功能還是需要在"HardwareSerial"中實做.

以上圖為例:
- "stream"中已實做的方法: "readStream()", "setTimeout()"...等
- "stream"中已宣告為虛擬,需在"HardwareSerial"中實做: "read()","available"...等
- UART專屬功能,需"HardwareSerial"實做: "begin()","rx_complete_irq()"

所以如果想解析"readString()"方法在Arduino中的運作方式,可從分析這些類別所在的相關檔案.


2. Arduino怎麼知道有資料進來了? 硬體buffer只有一個字元,怎麼暫存字串資料?
 



















當UART硬體收到字元(一個BYTE)時,會觸發rx_complete_irq(), 這時會把UART硬體暫存器的字元儲存到軟體宣告的RAM空間中(rx_buffer[ ]). 如果"rx_complete_irq()"中沒有做這件事,那當下一個字元來得時後,就會覆蓋掉原先UART硬體中已存在的資料. (有些其他廠牌的SoC或MCU有硬體FIFO Buffer,可協助處例這個問題). 以上圖的例子 'H','E','L','L','O'來說字元間會相隔0.833ms,所以rx_complete_irq()必須在這段時間內完成將硬體暫存器字元搬到軟體宣告的rx_buffer[ ]中.

此例中的"0.833ms"是以9600bps鮑率為例.
9600bps == 1200 bytes/s
所以每個字元間的間距為1/1200=> 約0.833ms



4. setTimeout()設定的時間指得是那段時間?


 "readString()",主要的流程就是讀取"rx_buffer[ ]"中還沒讀過的字元,並將這些字元組合成字串,"readString()"運行中是隨時有可能遇到新的字元剛過UART送達,此時"readString()"會暫停在目前的步驟 "rx_complete_irq()"在此時會被觸發補充新的字元到"rx_buffer[ ]".如果"readString()" 發現所有的字元都已讀過,則會等待一段時間,確認沒有新資料進來後,則會回傳已經組合好的字串.而這段等待的時間要多長就是"setTimeout()"所指定的內容, 太短可能會整串字串還沒送完就停止讀取,太長可能會造成程式時間效能下降. 後續的字元也是這樣,直到字元'O'讀取完後,"readString()"會發現已經3ms沒有新資料,所以timeout後結束流程,回傳完整字串"HELLO".

以上圖為例"setTimeout()"設定為3ms, "readString()",開始運行時'H'和'E'已經在"rx_buffer[ ]"中. 所以立刻可以被"readString()"讀取,之後會等待一段時間,但在0.833ms內(低於3ms),第一個'L'就送到,經由"rx_complete_irq()"儲存到rx_buffer[ ]中.






















5. timeout時間內如果下一筆字串就送來了怎麼辦?
建議盡量避免這種狀況!!可以的話可以讓Arduino回復一個代表字串以收到的訊息給發送端後,發送端再進行下一個字串的傳送.

留言

這個網誌中的熱門文章

Arduino ANN溫度控制實驗計畫

[馬尼拉]菲律賓職籃PBA!!

Arduino使用EEPROM練習(1)