a作為主機(上位機軟體),b作為從機(stm32)硬體和電機連線,a和b之間通過串列埠通訊,使a能間接的控制電機正反轉,速度等。
協議初定:
問題一:怎麼判斷幀資料開始資訊?
通過定義乙個固定的幀頭,作為資料開始訊號。記為0x01。問題二:如何判斷幀的長度?
幀的長度可以選擇固定長度或可變長度。固定長度邏輯簡單,檢測到幀頭後,往後讀取固定的長度即可。可變長度靈活度高,一幀資料可以攜帶更多的資訊量。那麼可以在幀頭後增加乙個位元組作為長度,記為0***,以便從機判斷幀長。問題三:資料格式?
資料格式按需編寫,這裡用16bit功能+16bit資料的方式。一組資料共4個位元組。問題四:如何校驗幀完整性?
可以用兩種方式:至此:我們可以將通訊協議制定下來:1、增加幀尾作為資料結束標誌,驗證幀尾就知道資料是否完整。但是存在資料=幀尾、通訊異常的情況,這時候可能提取到了錯誤的資料。
2、採用通用校驗方式,工業控制一般使用crc16-modbus。這裡增加兩個位元組作為檢驗碼。這種方式可以保證資料不會出錯。
幀頭幀長
功能1資料1
功能2資料2
功能…資料…
crc16高位
crc16低位
0x01
len0***
0***
0***
0***
0***
0***
crc_h
crc_l
在理想狀態下,從機在串列埠中斷裡面判斷幀頭,然後迴圈往後讀取len
長度的位元組到陣列裡面去,最後驗證一下crc是否一致即可。
但實際使用往往面對更複雜的情形:
這個問題其實就是要解決兩件事情:什麼時候接收資料?什麼時候處理資料?假設提取資料的函式為:
userextractframedata();
該函式執行時間為1us。那麼由簡入繁看看幾種方式:
1、中斷接收中斷處理。(弊端太明顯不再贅述)
2、中斷儲存到buff,中斷外處理buff,處理完後buff清空。
uint8_t recvbuff[50]
;uint8_t recvindex=0;
void
usart1_irqhandler
(void
)//串列埠1中斷服務函式
}void
userextractframedata()
}
當傳輸速率》userextractframedata()
處理速度時,必然會導致丟資料。因為recvindex
被清0了,這篇文章重點不是這個,這裡不再贅述。
3、使用環形緩衝區。環形緩衝區原理網上能找到很多,具體實現方式可以看這裡 c環形緩衝區實現
使用環形緩衝區就可以很好的解決這個問題,將接收和處理徹底解耦,接收資料自動填入緩衝區,處理資料自動從緩衝區讀取資料。當瞬間傳輸速率很大時,資料被儲存到緩衝區不會丟失,等到傳輸空閒時就有足夠的時間去處理。
void
usart1_irqhandler
(void
)//串列埠1中斷服務程式
}void
userextractframedata()
}
至此通過crc和緩衝區,我們已經可以保證資料的完整性和正確性了,只需要從緩衝區拿資料出來比對協議就可以了。
那麼接下來再分析一下更加複雜的情形:
問題六:假如主機採用的是一對多的方式,那麼必然有大量的無效資料和類似資料,如何處理?
處理方式有很多,這裡推薦一種位元組流的處理方式。問題七:假設資料長度較長,傳輸時間》1us,傳輸資料到一半時,進入了處理資料的函式,處理函式由於沒有接收到處理思路:從緩衝區複製乙個位元組,如果是幀頭,繼續複製乙個位元組判斷長度n,然後繼續往後複製乙個位元組,判斷是否是正確的功能碼,再然後繼續往後複製n個位元組,直到判斷crc是否通過。只要遇到錯誤就讀取幀頭不處理即可。
無論主機傳送多少資料,記憶體消耗只是環形緩衝區大小+有效資料大小。未檢測到幀頭前,處理速度》傳輸速率,所以環形緩衝區的大小可以不用設很大。但是有一種極端情況,就是主機傳送的資料含有大量的幀頭,且幀頭後的功能碼檢測也是通過的,那就沒救了,只能增大緩衝區大小。
經過驗證可以高效率提取有效資料。3kb位元組中提取最長32byte的有效資料,時間消耗100ms~220ms左右,主要是傳輸過程占用的時間。記憶體消耗僅100+32byte。
因為是給別人做的專案,這部分**就不貼了~
len
長度的資料而判斷為資料不完整錯誤,如何處理?這個問題很好解決,我們可以再增加乙個緩衝區pbuff
,先將資料搬到pbuff
,直到接收到了len
長度的資料,再去處理pbuff
即可。但這不是最好的解決方法,假如資料大小是1kb,那麼環形緩衝區大小需要》1kb,再來乙個
pbuff
也需要1kb記憶體,增加了一倍記憶體消耗。因此在c環形緩衝區實現這裡,我增加兩個介面
uint8_t ringbuffcopybyte(uint8_t *pdata);
uint8_t ringbuffcopydata(uint8_t len, uint8_t *pdata);
處理函式將環形緩衝區資料複製到內部進行處理,處理結束後才會讀掉n個位元組,缺點是程式執行時間有所增大。
c 環形緩衝區
public class circularbuffer icollection,ienumerable,icollection,ienumerable public circularbuffer int capacity,bool allowoverflow public bool allowove...
環形緩衝區
include include include include include define buffsize 1024 1024 define min x,y x y x y pthread mutex t lock pthread mutex initializer struct cycle b...
環形緩衝區
define print buf size 16 1024 static char g pcnetprintbuf 環形緩衝區的首位址 static int g ireadpos 0 環形緩衝區讀的位置 static int g iwritepos 0 環形緩衝區寫的位置 intinit 判斷環形緩...