痛苦!數(shù)據(jù)流過(guò)大?數(shù)據(jù)轉(zhuǎn)換各種組包拆包?指針及數(shù)組你試過(guò)沒(méi)!
今天的是干貨,是真的干。作為一個(gè)從業(yè)4年,工齡6年的嵌入式開(kāi)發(fā)程序員,在做通訊設(shè)備領(lǐng)域時(shí)最痛苦的事莫過(guò)于數(shù)據(jù)流過(guò)大問(wèn)題,以及數(shù)據(jù)轉(zhuǎn)換時(shí)各種組包拆包等問(wèn)題,特別是在控制器內(nèi)存資源有限時(shí)。這種問(wèn)題更加突出。
以太網(wǎng)數(shù)據(jù)收發(fā)時(shí)以太網(wǎng)的協(xié)議棧占用內(nèi)存約20Kbyte,單個(gè)SOCKET傳輸數(shù)據(jù)時(shí)最少預(yù)留了532byte字節(jié)的緩存空間,當(dāng)取出網(wǎng)絡(luò)下傳的數(shù)據(jù)時(shí),需要拆掉網(wǎng)絡(luò)傳輸頭并在末尾增加CRC,串口上行數(shù)據(jù)時(shí),需要增加網(wǎng)絡(luò)傳輸數(shù)據(jù)頭以及去掉末尾CRC值,如果此時(shí)碰到慣用for循環(huán)copy數(shù)據(jù)或者使用memcpy函數(shù)進(jìn)行數(shù)據(jù)組包的大佬,內(nèi)存空間基本就是捉襟見(jiàn)肘。
解決以上問(wèn)題的辦法之一就是使用指針配合數(shù)組進(jìn)行組包與拆包,如下圖;
預(yù)留包頭46字節(jié) | 數(shù)據(jù)部分536字節(jié) | 末尾預(yù)留10字節(jié) |
網(wǎng)絡(luò)端向串口發(fā)送:聲明數(shù)組時(shí)申明比實(shí)際數(shù)據(jù)所需空間更大的數(shù)組unsigned char Buff[592],以及一個(gè)指針unsigned char *datapoint;將datapoint指向Buff[46]的位置,讀入數(shù)據(jù),將數(shù)據(jù)從指針datapoint指向的位置開(kāi)始存入數(shù)組,同時(shí)使用另外的變量unsigned int length存儲(chǔ)當(dāng)次讀入的數(shù)據(jù)的長(zhǎng)度,進(jìn)行數(shù)據(jù)拆包操作時(shí)(去包頭6字節(jié)),直接將指針datapoint指向Buff[52]的位置,隨后將計(jì)算所得CRC(2byte)值從Buff[46 + length]位置存入數(shù)組,并得出最終需要傳輸?shù)拈L(zhǎng)度length+2,串口發(fā)送數(shù)據(jù)只需要輸入起始地址datapoint,長(zhǎng)度length,將數(shù)據(jù)存入串口發(fā)送環(huán)形隊(duì)列即可完成發(fā)送。
代碼如下
unsigned char Buff[592];
unsigned char *datapoint;
unsigned int length;
datapoint = & Buff[46];//指針指向數(shù)組中間
net_dataread(datapoint,& length);//讀取數(shù)據(jù),獲得數(shù)據(jù)長(zhǎng)度
CRC(&Buff[46+length],datapoint,& length);//獲取校驗(yàn)值并存入數(shù)組
Uart_send(datapoint,length+2);
串口向網(wǎng)絡(luò)發(fā)送時(shí),數(shù)據(jù)從環(huán)形隊(duì)列讀出,需要加上TCP modbus協(xié)議的包頭部分(6byte),去掉CRC校驗(yàn),同樣聲明數(shù)組以及指針、長(zhǎng)度變量,將datapoint指向Buff[46]的位置,讀入數(shù)據(jù),將數(shù)據(jù)從指針datapoint指向的位置開(kāi)始存入數(shù)組;將指針指向當(dāng)前指向地址的前6個(gè)地址位置存入6字節(jié),然后按照新的datapoint位置,長(zhǎng)度length+4將數(shù)據(jù)從網(wǎng)絡(luò)發(fā)出;
代碼如下
unsigned char Buff[592];
unsigned char *datapoint;
unsigned int length;
datapoint = & Buff[46];//指針指向數(shù)組中間
uart_read(datapoint,& length);//讀取數(shù)據(jù),獲得數(shù)據(jù)長(zhǎng)度
datapoint = datapoint-6;
memcpy(datapoint,包頭暫存數(shù)組首地址,6);
Uart_send(datapoint,length+4);
以上實(shí)例簡(jiǎn)單說(shuō)明了利用指針組包的簡(jiǎn)單應(yīng)用,但是在實(shí)際應(yīng)用中可能由于設(shè)備需要使用多種協(xié)議,組包方式不同,例如包頭之前加入注冊(cè)包等,數(shù)據(jù)實(shí)際讀取完成之后不是直接操作而是直接傳入子函數(shù),進(jìn)行組包與拆包,此時(shí)僅需要傳入datapoint與長(zhǎng)度,進(jìn)子函數(shù),由于datapoint指向的數(shù)組前后均有預(yù)留空間,子函數(shù)內(nèi)依然可以使用指針,且在Buff[]數(shù)組的范圍內(nèi),指針可以前后自由移動(dòng),在不需要進(jìn)行大量數(shù)據(jù)拷貝的前提下完成數(shù)組的拆組包過(guò)程,同時(shí)也避免了反復(fù)拷貝數(shù)據(jù)對(duì)空間的浪費(fèi)。
以上就是指針的簡(jiǎn)單應(yīng)用之一,指針除了對(duì)數(shù)組,還可以對(duì)函數(shù)操作,結(jié)合結(jié)構(gòu)體,基本上可以在C語(yǔ)言中實(shí)現(xiàn)類(lèi)似C++中類(lèi)功能。
今天的分享就到這里啦,EBYTE每一天都致力于更好的助力物聯(lián)化、智能化、自動(dòng)化的發(fā)展,提升資源利用率,更多產(chǎn)品及相關(guān)資料,感興趣的小伙伴可以登錄我們的億佰特官網(wǎng)進(jìn)行了解,也可以直接撥打400電話咨詢技術(shù)專員!
7 X 24 銷(xiāo)售服務(wù)熱線
4000-330-990深圳辦事處柯經(jīng)理:18218726658 杭州辦事處戴經(jīng)理:17512568697
常州辦事處崔經(jīng)理:15906110783 南京辦事處葛經(jīng)理:17626012283
業(yè)務(wù)郵箱:support@cdebyte.com
全國(guó)銷(xiāo)售投訴電話:19934352316
地址:四川省成都市高新西區(qū)西區(qū)大道199號(hào)B5棟(前臺(tái)座機(jī):028-61543675)
?? 成都億佰特電子科技有限公司【版權(quán)所有】 蜀ICP備13019384號(hào)-3