在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

嵌入式開發模塊指南:通用接收狀態機模塊

技術讓夢想更偉大 ? 來源:CSDN-夏日白云 ? 2023-03-28 09:28 ? 次閱讀

前言

在軟件開發的過程中,只要涉及到通信,就會涉及到數據接收機的編寫,通信協議雖然多種多樣,但是數據包的形式確是很相似的(暫時沒看到特別復雜,此模塊解決不了的),為此可以把其中通用的部分抽象出來,然后就成了這個模塊。

模塊相關概念和邏輯

接收機狀態

接收機有兩個基本狀態:

狀態A:preRx 等待幀頭中,這個時候接收機會不斷判斷是否收到了特殊序列、幀頭和強幀尾。如果收到了幀頭,則(默認)會把幀頭填入緩沖區的最前面,然后進入狀態B。

狀態B:Rxing 等待幀尾中,收到的數據會按序填入接收緩沖區,同時不斷查找幀尾、強幀頭以及強特殊序列,不管找到了哪一個都會觸發flush。如果,找到的是強幀頭,則仍然在狀態B,否則恢復狀態A。

不管在哪一個狀態下,如果接受緩沖區滿了,都會觸發flush并回到狀態A。

標志字符序列

接收機定義了以下標志序列類型:

類型 模塊中標記 描述
幀頭 header 只在狀態A起作用;找到時會導致之前接收區內的數據被flush,然后默認會填入接收區的最前面,可以通過選項來改變這個行為,然后接收機進入狀態B。
強幀頭 strong-header 在狀態B也會起作用,其他行為與普通幀頭一樣
幀尾 ender 只在狀態B起作用;找到時會導致當前接收區內的數據被flush,默認會處于回調時給用戶的buffer的最后面,可以通過選項來改變這個行為,然后接收機回到狀態A。
強幀頭 strong-header 在狀態A也會起作用,其他行為與普通幀尾一樣
特殊序列 unique 只在狀態A起作用;找到時會導致之前接收區內的數據被flush,然后自己被填入接收區內后再次觸發flush,然后接收機回到狀態A。
強特殊序列 strong-unique 在狀態B也會起作用,其他行為與特殊序列一樣

對應模塊中的結構體為:

//receiveflag
typedefstructRXFLAG_STRUCT{
uint8_tconst*pBuf;
uint8_tlen;
uint8_toption;
}RXFLAG_STRUCT;
typedefRXFLAG_STRUCTconst*RxFlag;
1234567

一般的流程中,初始化接收機前,用戶需要準備好接收機使用的所有標志序列,標志好每個序列的類型。模塊提供宏函數以抽象這個過程:

//voidRxFlag_Init(RXFLAG_STRUCT*flag,uint8_tconst*buf,uint8_tlen,uint8_topt);
//toinitializeareceiveflag
//flagpointtothetargetRXFLAG_STRUCT.
//bufpointertotheflagbuffer
//sizesizeofflag
//optseeRXFLAG_OPTION_XXXXX,bitmode
#defineRxFlag_Init(flag,buf,size,opt)
{(flag)->pBuf=(buf);(flag)->len=(size);(flag)->option=(opt);}

flush

每當接收機根據標志字符序列找到一個完整或不完整的數據包時,接收機會進行回調以通知用戶處理這個數據包,這個行為被稱為flush,這個回調函數叫做onFlushed。

此函數的原型如下

typedefvoid(*RXMAC_FLUSH_EVENT)(RxMacsender,RxMacPtrbuf,uint16_tlen,RxStatestate,
RxFlagHorU,RxFlagEnder);

整個數據包為buf指向的長度為len的區域。

數據包的狀態可以通過state參數得知,RX_STATE 的類型定義如下

typedefstructRXSTATE_STRUCT{
unsignedintheaderFound:1;//1:havegetheader
unsignedintenderFound:1;//1:havegetender
unsignedintisFull:1;//1:thebufferisfull
unsignedintuniqueFound:1;//1:thisisuniqueflag.
}RxState;

通過判斷每個標志位是否置1,可以得知當前數據包的狀態。
如果headerFound == 1,說明數據包是有幀頭的,可以通過pHorU獲得幀頭
如果enderFound == 1,說明數據包是有幀尾的,可以通過pEnder獲得幀尾
如果isFull == 1,說明此數據包是因為接收區滿了放不下了而產生的回調,在一些需要根據某個字段來判斷數據包真正大小的協議里,可以通過調整接收緩沖區的大小來恰當的產生flush。
如果UniqueFound == 1,說明此數據包是標志序列,這時緩沖區內的內容等于pHorU指向的那個標志序列

接收機類

V1.0版本中要求用戶自己分配結構體的空間,為了更加面向對象,現已改為動態分配,而把具體結構體和對應方法封裝在模塊內部。

typedefstructRXMAC_STRUCT*RxMac;

模塊提供Create函數來創建接收機實例并返回指向實例的指針。

//tocreateaninstanceofRxMac
//flags標志字符串結構體的數組
//flagsCnt標志字符串結構體的個數
//buf用戶提供給接收機用的緩沖區
//bufLen緩沖區的大小(起碼應該要能放的下最長的標志字符串)
//onFeeded在每次被Feed時觸發
//onGetHeader獲得頭標志位時觸發。
//onFlushed收到一幀數據時的回調函數
RxMacRxMac_Create(RXFLAG_STRUCTconstflags[],uint8_tflagsCnt,RxMacPtrbuf,uint16_tbufLen,
RXMAC_FILTERonFeeded,RXMAC_FLAG_EVENTonGetHeader,RXMAC_FLUSH_EVENTonFlushed);

調用實例的方法時把這個指針作為第一個參數以模擬面向對象操作。

過濾器

接收機每次被feed時,都會觸發onFeeded事件(可以在配置中取消這個事件以節省點代碼)。原型如下:

typedefvoid(*RXMAC_FILTER)(RxMacsender,uint8_t*pCurChar,uint16_tbytesCnt);

pCurChar :指向接收區中剛收到的字符
bytesCnt :這個字符是接收區中的第幾個字符

此時,接收機已經將其放入接收區但是還沒進一步進行判斷,用戶可以修改字符/配置接收機以改變接收機的行為,比如將收到的字母全變為小寫?;蛘吒鶕盏降臄祿頉Q定還要收多少數據。

onGetHeader事件

當找到任意幀頭時會觸發。

接收機運行邏輯

接收機的運作邏輯如下:

6fb489b2-ccde-11ed-bfe3-dac502259ad0.pngimg

邊際條件

標志序列盡量不要有重合,如果同時可能匹配兩個標志序列,最終行為是未定義的,不保證正確執行,最終結果可能與標志序列的位置以及類型有關系。

同一個標志串可以同時是多種類型,比如同時是幀頭與幀尾,但要小心類型間不要有沖突,否則不保證正確執行。

對于標志序列匹配到一半發生了接收緩沖區滿,從而導致發生標志序列匹配時,接收緩沖區中只有半個標志序列的情況:
如果標志序列是(強)特殊序列或(強)幀頭的情況,可以保證功能正常運行。
如果標志序列是強幀尾的情況,緩沖區內會只剩下后半段的幀尾,但可以根據pEnder參數來得知真正的幀尾。
幀尾不會發生這種邊際條件。

相關代碼

此模塊使用了我自己寫的Buffer模塊作為內部緩沖區來判斷標志字符串。
[嵌入式開發模塊]環形緩沖區/循環隊列 C語言實現

接收機代碼

RxMac.h

/*
*******************************************************************************************
*
*
*UniversalReceiveStateMachine
*通用接收狀態機
*
*File:RxMac.h
*By:LinShijun(https://blog.csdn.net/lin_strong)
*Date:2019/03/07
*version:2.1
*History:2018/05/291.0theprototype
*2019/01/232.0modifythetypenamestomorereadableones,thoughpreserve
*theold-styleforforwardcompatibility;
*changeinitmethodtocreatemethodwhichusemalloctoalloc
*instance,andthecorrespondingdestroymethod.
*changetheinternalbuffermodulefromRINGQUEUEtoBufferArray,
*sousernolongerneedtoknowtheinternalflagsmanagementand
*allocatethespaceforit.
*addRxMac_FeedDatasmethodforconvenient.
*2019/03/072.1somemodificationtothemallocconfiguration
*
*NOTE(s):1.thereceiveprocesshastwobasicstate
*A.preRx:whenhaven'tfoundanyheader,theRxMacwillsearchfortheunique
*flag,headerandstrong-ender.Onlywhenaheaderisfoundwillcome
*tonextstep.
*B.Rxing:theRxMacwillputthesuccessivebytesintothebuffer,andsearch
*forthestrong-unique,strong-header,ender.
*2.themoduleisdrivedbytheRxMac_FeedData(),usershouldgetthethechar
*fromdatastreamandpassthedataonebyonetotheRxMacthroughRxMac_FeedData()
*orRxMac_FeedDatas().
*3.eachtimeRxMacfindaframe(completeorincomplete),itwillcalltheonFlushed
*tonotifytheresults;usercanjudgetheframethroughthestateparameter;
*state.headerFound==1:findanyheader,theheaderispassedbyHorU
*state.enderFound==1:findanyender,theenderispassedbyEnder
*state.isFull==1:thebufferisfull,maybeyoushouldcheckheaderFound
*toseewhetheraheaderhasbeenfound.
*state.uniqueFound==1:findanyuniqueflag.Inthiscase,otherparameterswill
*alwaysbe0,thedatainthebufferwillbetheflag,
*andtheuniqueflagispassedbyHorU.
*4.Tousethismodule,foreachreceivemachine:
*A.definemalloctoconfigurethemodule,seeCONFIGURATION
*B.allocatethespaceforbufferandFLAGS.
*RXFLAG_STRUCTflags[2];
*uint8_tbuf[300];
*C.settheflagsaccordingtotheprotocol,definethecallbackfunctions
*accordingtoyourneed.
*staticvoidonGetHeader(RxMacsender,RxFlagpFlag){......};
*staticvoidonFlushed(RxMacsender,RxMacPtrpBuf,uint16_tlen,
*RxStatestate,RxFlagHorU,RxFlagEnder){......};
*constuint8_tHeaderFlag[]="Header";
*constuint8_tEnderFlag[]="
";
*RxFlag_Init(flags,HeaderFlag,StrSize(HeaderFlag),RXFLAG_OPTION_HEADER);
*RxFlag_Init(&flags[1],EnderFlag,StrSize(EnderFlag),RXFLAG_OPTION_ENDER|
*RXFLAG_OPTION_NOTFILL_ENDER);
*D.createthereceivemachine:
*RxMacmac;
*mac=RxMac_Create(flags,sizeof(flags)/sizeof(flags[0]),buf,300,NULL,
*onGetHeader,onFlushed);
*E.feedthereceivemachine:
*while(1){
*c=GetNextChar();
*RxMac_FeedData(mac,c);
*}
*F.destroythereceivemachineifneed.
*RxMac_Destroy(mac);
*******************************************************************************************
*/

#ifndefRX_MAC_H
#defineRX_MAC_H

/*
*******************************************************************************************
*INCLUDES
*******************************************************************************************
*/

#include

/*
*******************************************************************************************
*CONFIGURATION配置
*******************************************************************************************
*/
//#defineRXMAC_ARGUMENT_CHECK_DISABLEtodisabletheargumentcheckfunctionsofthismodule
//#defineRXMAC_ARGUMENT_CHECK_DISABLE

//#defineRXMAC_NOTFILL_DISABLEtodisablethenotFilloption
//#defineRXMAC_NOTFILL_DISABLE

//#defineRXMAC_ONFEEDED_DISABLEtodisabletheonFeededevent.
//#defineRXMAC_ONFEEDED_DISABLE

//#defineRXMAC_SINGLETON_ENtousesingletonpattern,soargumentpRxMacofinterfacesis
//useless,anduserdon'tneedtoallocatespaceforRX_MAC,butyoustillneedtoallocate
//bufferandcallinit();
//#defineRXMAC_SINGLETON_EN

//#defineRXMAC_BUF_RPAGEifyouwantreceivemachineusethepagedarrayasbuffer.
//anddon'tforgettodefineCODEWARRIORmalloc
//#defineRXMAC_BUF_RPAGE
/*
*******************************************************************************************
*ADDRESSINGMODE尋址模式
*******************************************************************************************
*/

#ifdefRXMAC_BUF_RPAGE
#ifdefCODEWARRIOR
#defineRXMAC_BUF_ADDRESSING_MODE__rptr
#endif
#endif

#ifndefRXMAC_BUF_ADDRESSING_MODE
#defineRXMAC_BUF_ADDRESSING_MODE
#endif
typedefuint8_t*RXMAC_BUF_ADDRESSING_MODERxMacPtr;

/*
*********************************************************************************************
*ERRORCODE
*********************************************************************************************
*/

#defineRXMAC_ERR_NONE0
#defineRXMAC_ERR_ARGUMENT1
#defineRXMAC_ERR_POINTERNULL2
#defineRXMAC_ERR_UNKNOWN3
#defineRXMAC_ERR_INIT4

/*
*********************************************************************************************
*RECEIVEFLAGSTRUCT
*********************************************************************************************
*/

//normalheader,RxMacwillonlycheckitinStepA
#defineRXFLAG_OPTION_HEADER0x01
//strongheader,RxMacwillalwayscheckit.
#defineRXFLAG_OPTION_STRONG_HEADER0x03
//theheaderwillnotbefilledintobufferwhenfound.(onlyvalidwhenisheader)
#defineRXFLAG_OPTION_NOTFILL_HEADER0x04
//normalender,RxMacwillonlycheckitinStepB
#defineRXFLAG_OPTION_ENDER0x08
//strongheader,RxMacwillalwayscheckit.
#defineRXFLAG_OPTION_STRONG_ENDER0x18
//theenderwillnotbefilledintobufferwhenfound.(onlyvalidwhenisender)
#defineRXFLAG_OPTION_NOTFILL_ENDER0x20
//normalunique,RxMacwillonlycheckitinStepA
#defineRXFLAG_OPTION_UNIQUE0x40
//strongunique,RxMacwillalwayscheckit.
#defineRXFLAG_OPTION_STRONG_UNIQUE0xC0

//receiveflag
typedefstructRXFLAG_STRUCT{
uint8_tconst*pBuf;
uint8_tlen;
uint8_toption;
}RXFLAG_STRUCT;
typedefRXFLAG_STRUCTconst*RxFlag;

//voidRxFlag_Init(RXFLAG_STRUCT*flag,uint8_tconst*buf,uint8_tlen,uint8_topt);
//toinitializeareceiveflag
//flagpointtothetargetRXFLAG_STRUCT.
//bufpointertotheflagbuffer
//sizesizeofflag
//optseeRXFLAG_OPTION_XXXXX,bitmode
#defineRxFlag_Init(flag,buf,size,opt)
{(flag)->pBuf=(buf);(flag)->len=(size);(flag)->option=(opt);}


/*
*********************************************************************************************
*TYPEDEFINITION
*********************************************************************************************
*/

typedefstructRXSTATE_STRUCT{
unsignedintheaderFound:1;//1:havegetheader
unsignedintenderFound:1;//1:havegetender
unsignedintisFull:1;//1:thebufferisfull
unsignedintuniqueFound:1;//1:thisisuniqueflag.
}RxState;

typedefstructRXMAC_STRUCT*RxMac;

typedefvoid(*RXMAC_FLUSH_EVENT)(RxMacsender,RxMacPtrbuf,uint16_tlen,RxStatestate,
RxFlagHorU,RxFlagEnder);
typedefvoid(*RXMAC_FLAG_EVENT)(RxMacsender,RxFlagflag);
typedefvoid(*RXMAC_FILTER)(RxMacsender,uint8_t*pCurChar,uint16_tbytesCnt);

/*
*******************************************************************************************
*FUNCTIONDECLARATION
*******************************************************************************************
*/

//tocreateaninstanceofRxMac
//flags標志字符串結構體的數組
//flagsCnt標志字符串結構體的個數
//buf用戶提供給接收機用的緩沖區
//bufLen緩沖區的大小(起碼應該要能放的下最長的標志字符串)
//onFeeded在每次被Feed時觸發
//onGetHeader獲得頭標志位時觸發。
//onFlushed收到一幀數據時的回調函數
RxMacRxMac_Create(RXFLAG_STRUCTconstflags[],uint8_tflagsCnt,RxMacPtrbuf,uint16_tbufLen,RXMAC_FILTERonFeeded,RXMAC_FLAG_EVENTonGetHeader,RXMAC_FLUSH_EVENTonFlushed);
//todestroytheRxMac
voidRxMac_Destroy(RxMacmac);
//向接收機內喂字節
voidRxMac_FeedDatas(RxMacmac,uint8_tconst*buf,uint16_tlen);
voidRxMac_FeedData(RxMacmac,uint8_tc);
//重置接收區長度為最長那個長度
//uint8_tRxMac_ResetRxSize(RxMacmac);
//設置最大接收到多少個字節
uint8_tRxMac_SetRxSize(RxMacmac,uint16_tsize);
//重置接收機的狀態
uint8_tRxMac_ResetState(RxMacmac);
//強制接收機flush
uint8_tRxMac_Flush(RxMacmac);
//設置onFeeded
uint8_tRxMac_SetOnFeeded(RxMacmac,RXMAC_FILTERonFeeded);
//設置onGetHeader
uint8_tRxMac_SetOnGetHeader(RxMacmac,RXMAC_FLAG_EVENTonGetHeader);
//設置onFlushed
uint8_tRxMac_SetOnFlushed(RxMacmac,RXMAC_FLUSH_EVENTonFlushed);

#include"RxMacPrivate.h"

#endif//ofRX_MAC_H

RxMacPrivate.h

/*
*******************************************************************************************
*
*
*PrivateDeclarationsforUniversalReceiveStateMachine
*
*File:RxMacPrivate.h
*By:LinShijun(https://blog.csdn.net/lin_strong)
*Date:2019/03/07
*version:2.1
*History:
*NOTE(s):
*******************************************************************************************
*/


/*
*******************************************************************************************
*FUNCTIONDECLARATION
*******************************************************************************************
*/
//打印內部緩沖區,返回緩沖區的長度
uint16_t_RxMac_printBuffer(RxMacmac,uint8_t*buf);

/*
*******************************************************************************************
*RECEIVEFLAGSTRUCT
*******************************************************************************************
*/

//structofRXFLAG_STRUCT.option
/*typedefstructRXFLAG_OPTION{
unsignedintisHeader:1;//1:theflagistheheadoftheframe
unsignedintstrong_H:1;//1:strong-header,RxMacwill
unsignedintnotfill_H:1;//0:filltheflagintothebufferwhenfoundasheader
unsignedintisEnder:1;//1:theflagistheendoftheframe
unsignedintstrong_E:1;//
unsignedintnotfill_E:1;//0:filltheflagintothebufferwhenfoundasender
unsignedintisUnique:1;//1:theflagisauniqueflagwhichistreatedassingleframe.
unsignedintstrong_U:1;//0:whenreceivingaframe,RxMacwillnot
};//*/
//normalheader,RxMacwillonlycheckitinStepA
#defineRXFLAG_OPTBIT_HEADER0x01
//strongheader,RxMacwillalwayscheckit.
#defineRXFLAG_OPTBIT_STRONG_HEADER0x02
//theheaderwillnotbefilledintobufferwhenfound.(onlyvalidwhenisheader)
#defineRXFLAG_OPTBIT_NOTFILL_HEADER0x04
//normalender,RxMacwillonlycheckitinStepB
#defineRXFLAG_OPTBIT_ENDER0x08
//strongheader,RxMacwillalwayscheckit.
#defineRXFLAG_OPTBIT_STRONG_ENDER0x10
//theenderwillnotbefilledintobufferwhenfound.(onlyvalidwhenisender)
#defineRXFLAG_OPTBIT_NOTFILL_ENDER0x20
//normalunique,RxMacwillonlycheckitinStepA
#defineRXFLAG_OPTBIT_UNIQUE0x40
//strongunique,RxMacwillalwayscheckit.
#defineRXFLAG_OPTBIT_STRONG_UNIQUE0x80

#defineSTATEMASK_STEPA
(RXFLAG_OPTBIT_HEADER|RXFLAG_OPTBIT_UNIQUE|RXFLAG_OPTBIT_STRONG_ENDER)
#defineSTATEMASK_STEPB
(RXFLAG_OPTBIT_STRONG_UNIQUE|RXFLAG_OPTBIT_ENDER|RXFLAG_OPTBIT_STRONG_HEADER)
#defineRXFLAGMASK_USUHSH
(RXFLAG_OPTBIT_HEADER|RXFLAG_OPTBIT_STRONG_HEADER|
RXFLAG_OPTBIT_UNIQUE|RXFLAG_OPTBIT_STRONG_UNIQUE)

//BOOL_RxFlag_isHeader(RxFlagflag);
#define_RxFlag_isHeader(flag)
((flag)->option&(RXFLAG_OPTION_STRONG_HEADER|RXFLAG_OPTION_HEADER))
//BOOL_RxFlag_isEnder(RxFlagflag);
#define_RxFlag_isEnder(flag)
((flag)->option&(RXFLAG_OPTION_STRONG_ENDER|RXFLAG_OPTION_ENDER))
//BOOL_RxFlag_isUnique(RxFlagflag);
#define_RxFlag_isUnique(flag)
((flag)->option&(RXFLAG_OPTION_STRONG_UNIQUE|RXFLAG_OPTION_UNIQUE))
//BOOL_RxFlag_dontFillHeader(RxFlagflag);
#define_RxFlag_dontFillHeader(flag)
((flag)->option&RXFLAG_OPTBIT_NOTFILL_HEADER)
//BOOL_RxFlag_dontFillEnder(RxFlagflag);
#define_RxFlag_dontFillEnder(flag)
((flag)->option&RXFLAG_OPTBIT_NOTFILL_ENDER)

/*
*******************************************************************************************
*FORWARDCOMPATIBILITY
*******************************************************************************************
*/
//以下僅為前向兼容
typedefRxMacPtrpRB_BYTE;
typedefRXFLAG_STRUCTRX_FLAG,*pRX_FLAG;
typedefRxMacpRX_MAC;
typedefRxStateRX_STATE;
#defineFLAG_OPTION_HEADERRXFLAG_OPTION_HEADER
#defineFLAG_OPTION_STRONG_HEADERRXFLAG_OPTION_STRONG_HEADER
#defineFLAG_OPTION_NOTFILL_HEADERRXFLAG_OPTION_NOTFILL_HEADER
#defineFLAG_OPTION_ENDERRXFLAG_OPTION_ENDER
#defineFLAG_OPTION_STRONG_ENDERRXFLAG_OPTION_STRONG_ENDER
#defineFLAG_OPTION_NOTFILL_ENDERRXFLAG_OPTION_NOTFILL_ENDER
#defineFLAG_OPTION_UNIQUERXFLAG_OPTION_UNIQUE
#defineFLAG_OPTION_STRONG_UNIQUERXFLAG_OPTION_STRONG_UNIQUE
#defineRX_FLAG_INITRxFlag_Init

RxMac.c

/*
*******************************************************************************************
*
*
*ImplementationoftheUniversalReceiveStateMachine
*通用接收狀態機
*
*File:RxMac.c
*By:LinShijun(https://blog.csdn.net/lin_strong)
*Date:2019/03/07
*version:2.1
*History:2018/05/291.0theprototype
*2019/01/232.0InadditiontothecontentinRxMac.h:
*abstracttheflagmanagementpartasRxFlagMgrandthe
*correspondingmethods.
*refactorthecode.
*2019/03/072.1somemodificationtothemallocconfiguration
*NOTE(s):
*
*******************************************************************************************
*/

/*
*******************************************************************************************
*INCLUDES
*******************************************************************************************
*/
#include
#include
#include
#include"RxMac.h"
#include"BufferMallocArray.h"

/*
*******************************************************************************************
*RECEIVEFLAGSMANAGER
*******************************************************************************************
*/

typedefstructRXFLAGMGR_STRUCT{
//buffertoholdthepre-datawhichhasn'tmatchedanyflag.
BufferUINT8IndexedBufForFlag;
//theflagarraytobematched.
RxFlagFlags;
//countofflags.
uint8_tFlagsCnt;
//currentstate,inwhichheaderFoundwillinfluencethematchbehavior.
//controlledbythechildclass.
RxStatestate;
}RXFLAGMGR_STRUCT;

staticRxFlag_RxFlagMgr_GetNextMatchedAtThisState(RxMacmac,uint8_tnextByte);
staticBOOL_RxFlagMgr_Init(RxMacmac,RxFlagflags,uint8_tflagsCnt,uint8_tmaxLen);
staticvoid_RxFlagMgr_Destroy(RxMacmac);
staticvoid_RxFlagMgr_Reset(RxMacmac);

/*
*******************************************************************************************
*STRUCTDIFINITION
*******************************************************************************************
*/

typedefstructRXMAC_STRUCT{
//managetheflagmatches.
RXFLAGMGR_STRUCTFlagMgr;
//recordtheHeaderorUniqueflag.
RxFlagpHorU;
//internalbuffertoholddata.
RxMacPtrpRxBuf;
//lengthoftheinternalbuffer
uint16_tRxBufSize;
//Countofthebytesintheinternalbuffer/theindexfornextfeededbyte
uint16_tRxCnt;
RXMAC_FILTERonFeeded;
RXMAC_FLAG_EVENTonGetHeader;
RXMAC_FLUSH_EVENTonFlushed;
}RXMAC_STRUCT;

/*
*******************************************************************************************
*LOCALFUNCITONDECLARATION
*******************************************************************************************
*/
#ifndefRXMAC_SINGLETON_EN
#define_pMacmac
#define_BufForFlag(_pMac->FlagMgr.BufForFlag)
#define_Flags(_pMac->FlagMgr.Flags)
#define_FlagsCnt(_pMac->FlagMgr.FlagsCnt)
#define_state(_pMac->FlagMgr.state)
#define_pHorU(_pMac->pHorU)
#define_pRxBuf(_pMac->pRxBuf)
#define_RxBufSize(_pMac->RxBufSize)
#define_RxCnt(_pMac->RxCnt)
#define_fonFeeded(_pMac->onFeeded)
#define_fonGetHeader(_pMac->onGetHeader)
#define_fonFlushed(_pMac->onFlushed)
#define_RxMac_Destroy()(free(mac))
#else
staticRXMAC_STRUCT_mac;
//單例模式中,這個指針用于標識是否單例已初始化過
staticRxMac_pMac=NULL;
#define_BufForFlag(_mac.FlagMgr.BufForFlag)
#define_Flags(_mac.FlagMgr.Flags)
#define_FlagsCnt(_mac.FlagMgr.FlagsCnt)
#define_state(_mac.FlagMgr.state)
#define_pHorU(_mac.pHorU)
#define_pRxBuf(_mac.pRxBuf)
#define_RxBufSize(_mac.RxBufSize)
#define_RxCnt(_mac.RxCnt)
#define_fonFeeded(_mac.onFeeded)
#define_fonGetHeader(_mac.onGetHeader)
#define_fonFlushed(_mac.onFlushed)
#define_RxMac_Destroy()(_pMac=NULL)
#endif

#define_stateByte(*(uint8_t*)(&_state))
#define_isRxBufFull()(_RxCnt>=_RxBufSize)

#ifndefRXMAC_ONFEEDED_DISABLE
#define_onFeeded(pChar,cnt)if(_fonFeeded!=NULL)_fonFeeded(_pMac,pChar,cnt);
#else
#define_onFeeded(pChar,cnt)
#endif
#define_onGetHeader(headerFlag)if(_fonGetHeader!=NULL)_fonGetHeader(_pMac,headerFlag);

#undef_DONT_CHECK_MAC
#ifdefRXMAC_ARGUMENT_CHECK_DISABLE
#define_DONT_CHECK_MAC
#endif
#ifdefRXMAC_SINGLETON_EN
#define_DONT_CHECK_MAC
#endif

#ifdef_DONT_CHECK_MAC
#define_checkMacNotNull()
#define_checkMacNotNull_void()
#else
#define_checkMacNotNull()if(_pMac==NULL)returnRXMAC_ERR_POINTERNULL;
#define_checkMacNotNull_void()if(_pMac==NULL)return;
#endif


#ifdefRXMAC_BUF_RPAGE
#ifdefCODEWARRIOR
staticRxMacPtr_memcpy_internal(RxMacPtrdest,RxMacPtrsrc,size_tn);
#definememcpy(dest,src,n)_memcpy_internal(dest,src,n)
#endif
#endif
//沖刷緩沖區
staticvoid_flush(RxMacmac,RxFlagender);
//往接收機緩沖區內放數據
staticvoid_BufIn(RxMacmac,RxMacPtrbuf,uint16_tlen);

staticvoid_RxMac_FlushIfFull(RxMacmac);
staticvoid_RxMac_RecordAndFlushPreBytesIfGotHeaderOrUnique(RxMacmac,RxFlagflagJustGot);
staticvoid_RxMac_GetHeaderProcess(RxMacmac,RxFlagflagJustGot);
staticvoid_RxMac_GetUniqueProcess(RxMacmac,RxFlagflagJustGot);
staticvoid_RxMac_GetEnderProcess(RxMacmac,RxFlagflagJustGot);
/*
*******************************************************************************************
*RxMac_Create()
*
*Description:Tocreateareceivemachineinstance.創建一個接收機實例
*
*Arguments:flagspointertotheflags(anarray);指向標志串(數組)的指針
*flagsCntthecountoftheflags;有多少個標志串;
*bufpointertothebufferprovidedtotheRxMac;提供給接收機使用的緩存
*bufLenthesizeofthebuffer.緩存的大小
*onFeededthecallbackfuncthatwillbecalledeverytimefeeded,you
*canmodifythefeededbyteinthiscallback.
*每次被feed時會調用的回調函數,如改變對應數據值會影響標志位的判斷
*onGetHeaderthecallbackfuncthatwillbecalledwhenfindaheader.
*當發現幀頭時會調用的回調函數
*onFlushedthecallbackfuncthatwillbecalledwhenflushed.
*當Flush時會調用的回調函數
*
*Return:Pointertothecreatedinstance.
*NULLifanyerror.
*
*Note(s):1.sizeofbuffershouldbiggerthanthelongestflag,ortheflagwillbe
*useless.
*2.ifflagsCnt>0,flagscan'tpointtoNULL.
*3.youmustprovideabuffer.
*4.ifyouenabletheRXMAC_SINGLETON_EN,multi-createwillpointertothe
*sameinstanceinitializedasthelastcreate.
*
*voidonGetHeader(RxMacsender,RxFlagflag):
*senderthepointertotheRxMacwhichcallthisfunction
*flagtheheadermatched
*
*voidonFeeded(RxMacsender,uint8_t*pCurChar,uint16_tbytesCnt):
*senderthepointertotheRxMacwhichcallthisfunction
*pCurCharpointtothebytejustreceived,youcanchangeitbeforeanyotherprocess.
*bytesCntthenumberofbytesinthebufferincludingthecharjustfeeded.
*
*voidonFlushed(RxMacsender,RxMacPtrpBuf,uint16_tlen,RxStatestate,RxFlagHorU,
*RxFlagEnder);
*senderthepointertotheRxMacwhichcallthisfunction
*bufthepointertotheframe.
*lenthelengthofframe.
*statethestateofframe.
*HorUpointtotheheaderflagifstate.headerFound==1,oruniqueflagif
*state.uniqueFound==1.
*Enderpointtotheenderflagifstate.enderFound==1.
*******************************************************************************************
*/
RxMacRxMac_Create(RXFLAG_STRUCTconstflags[],uint8_tflagsCnt,RxMacPtrbuf,uint16_tbufLen,RXMAC_FILTERonFeeded,RXMAC_FLAG_EVENTonGetHeader,RXMAC_FLUSH_EVENTonFlushed){
uint8_ti,maxLen=0;
#ifndefRXMAC_SINGLETON_EN
RxMacmac;
#endif
#ifndefRXMAC_ARGUMENT_CHECK_DISABLE
if((flags==NULL&&flagsCnt>0)||buf==NULL)
returnNULL;
#endif
//findoutthemaxlengthofflags.
for(i=0;imaxLen)
maxLen=flags[i].len;
}
#ifndefRXMAC_ARGUMENT_CHECK_DISABLE
if(bufLen0)
*p++=*src++;
returndest;
}

staticvoid_BufIn(RxMacmac,RxMacPtrbuf,uint16_tlen){
memcpy(_pRxBuf+_RxCnt,buf,len);
_RxCnt+=len;
}

staticvoid_flush(RxMacmac,RxFlagender){
//觸發回調
if((_RxCnt>0||ender!=NULL)&&_fonFlushed!=NULL)
_fonFlushed(_pMac,_pRxBuf,_RxCnt,_state,_pHorU,ender);
//復位接收機
_RxCnt=0;
_stateByte=0;
_pHorU=NULL;
}

BOOLBufferUINT8Indexed_BackMatch(BufferUINT8Indexedbuf,uint8_tconst*toMatch,uint16_tlen){
uint16_tcnt=_Buffer_getCount(buf);
if(len>cnt)
returnFALSE;
while(len>0){
if(_BufferUINT8Indexed_get(buf,--cnt)!=toMatch[--len])
returnFALSE;
}
returnTRUE;
}


staticvoid_RxMac_FlushIfFull(RxMacmac){
if(_isRxBufFull()){
_state.isFull=1;
_flush(_pMac,NULL);
}
}

staticvoid_RxMac_RecordAndFlushPreBytesIfGotHeaderOrUnique(RxMacmac,RxFlagflagJustGot){
if(flagJustGot->option&RXFLAGMASK_USUHSH){
if(_RxCnt>flagJustGot->len){
_RxCnt-=flagJustGot->len;
_flush(_pMac,NULL);
}else{
_RxCnt=0;
}
_pHorU=flagJustGot;
}
}

staticvoid_RxMac_GetHeaderProcess(RxMacmac,RxFlagflagJustGot){
#ifndefRXMAC_NOTFILL_DISABLE
if(!_RxFlag_dontFillHeader(flagJustGot))
#endif
_BufIn(_pMac,(RxMacPtr)flagJustGot->pBuf,flagJustGot->len);
_state.headerFound=1;
_onGetHeader(flagJustGot);
_RxMac_FlushIfFull(mac);
}

staticvoid_RxMac_GetUniqueProcess(RxMacmac,RxFlagflagJustGot){
_state.uniqueFound=1;
_BufIn(_pMac,(RxMacPtr)flagJustGot->pBuf,flagJustGot->len);
_flush(_pMac,NULL);
}

staticvoid_RxMac_GetEnderProcess(RxMacmac,RxFlagflagJustGot){
_state.enderFound=1;
if(_RxCntlen){//ifpartoftheflaghasbeenmanuallyflushed.
_RxCnt=0;//restorethebuffer.
_BufIn(_pMac,(RxMacPtr)flagJustGot->pBuf,flagJustGot->len);
}
#ifndefRXMAC_NOTFILL_DISABLE
if(_RxFlag_dontFillEnder(flagJustGot))
if(_RxCnt>flagJustGot->len)
_RxCnt-=flagJustGot->len;
else
_RxCnt=0;
#endif
_flush(_pMac,flagJustGot);
}

staticRxFlag_RxFlagMgr_GetNextMatchedAtThisState(RxMacmac,uint8_tnextByte){
uint8_ti,mask;
if(_Buffer_isFull(_BufForFlag))
BufferUINT8_FrontOut((BufferUINT8)_BufForFlag);
BufferUINT8_BackIn((BufferUINT8)_BufForFlag,nextByte);
//masktoidentifypossibleflag
mask=(_state.headerFound)?STATEMASK_STEPB:STATEMASK_STEPA;
for(i=0;i

測試/示例代碼

已略去非必要代碼

#include
#include"RxMac.h"

/*
*********************************************************************************************************
*LOCALFUNCTIONDECLARE
*********************************************************************************************************
*/

staticvoidonGetData(RxMacsender,uint8_t*pCurChar,uint16_tbytesCnt);
staticvoidonFlushed(RxMacsender,RxMacPtrbuf,uint16_tlen,RxStatestate,RxFlagHorU,RxFlagEnder);
staticvoidonGetHeader(RxMacsender,RxFlagflag);
staticvoidonGetHeader2(RxMacsender,RxFlagflag);

/*
*********************************************************************************************************
*LOVALVARIABLE
*********************************************************************************************************
*/
staticRxMacmac=NULL;
staticRXFLAG_STRUCTflags[4];
#defineBUF_SIZE20
staticuint8_tbuffer[BUF_SIZE];

//協議示例1:
//幀頭:HEADER或者START
//強幀尾:END
//強特殊串:12345
//
staticvoidprotocol1_init(void){
RX_FLAG_INIT(&flags[0],"HEADER",6,FLAG_OPTION_HEADER);
RX_FLAG_INIT(&flags[1],"START",5,FLAG_OPTION_HEADER);
RX_FLAG_INIT(&flags[2],"END",3,FLAG_OPTION_STRONG_ENDER);
RX_FLAG_INIT(&flags[3],"12345",5,FLAG_OPTION_STRONG_UNIQUE);
mac=RxMac_Create(flags,4,buffer,BUF_SIZE,NULL,onGetHeader,onFlushed);
}
//協議示例2:
//幀頭:START
//幀頭后的第1個字符表示后面還要接收多少個字符1-9,'4'表示4個,如果不是數字或為'0',則等待幀尾
//幀尾:END
//特殊串:NOW
//
staticvoidprotocol2_init(void){
RX_FLAG_INIT(&flags[0],"START",5,FLAG_OPTION_HEADER);
RX_FLAG_INIT(&flags[1],"END",3,FLAG_OPTION_ENDER);
RX_FLAG_INIT(&flags[2],"NOW",3,FLAG_OPTION_UNIQUE);
mac=RxMac_Create(flags,3,buffer,BUF_SIZE,NULL,onGetHeader2,onFlushed);
}
/*
*********************************************************************************************************
*CALLBACKFUNCITON
*********************************************************************************************************
*/

staticvoidonGetData(RxMacsender,uint8_t*pCurChar,uint16_tbytesCnt){
//因為發現幀頭后才掛載事件,所以下一次回掉正好是說明字符數的那個字符,否則還得根據bytesCnt來判斷當前位置
RxMac_SetOnFeeded(sender,NULL);
if(*pCurChar>'0'&&*pCurChar<=?'9'?){
????//?bytesCnt是當前收到了多少個字符,所以接收區大小為當前字符數加上還要接收的
????RxMac_SetRxSize(sender,*pCurChar?-?'0'?+?bytesCnt);
??}
}
static?void?onFlushed(RxMac?sender,RxMacPtr?buf,uint16_t?len,RxState?state,RxFlag?HorU,RxFlag?Ender){
??buf[len]?=?'?';
??printf("
Flushed:");
??if(state.headerFound)
????printf("headerFound,");
??if(state.enderFound)
????printf("enderFound,");
??if(state.isFull)
????printf("full,");
??if(state.uniqueFound)
????printf("unique,");
??printf("
Datas:%s
",buf);
??RxMac_SetRxSize(sender,BUF_SIZE);
}
static?void?onGetHeader(RxMac?sender,RxFlag?flag){
??printf("
FoundHeader:%s
",flag->pBuf);
}
staticvoidonGetHeader2(RxMacsender,RxFlagflag){
printf("
FoundHeader:%s
",flag->pBuf);
RxMac_SetOnFeeded(sender,onGetData);
}
/*
*********************************************************************************************************
*MAINFUNCTION
*********************************************************************************************************
*/

voidmain(void){
//選擇想要實驗的協議來初始化
protocol1_init();
//protocol2_init();
while(1){
c=getchar();
//回顯
putchar(c);
RxMac_FeedData(mac,c);
}
}

示例協議1測試結果6ff5a622-ccde-11ed-bfe3-dac502259ad0.png

示例協議2測試結果701c574a-ccde-11ed-bfe3-dac502259ad0.png可以看到,第二個協議中我們通過改變緩沖區大小成功控制了數據包的長度。

雖然這里的示例都是基于ASCII的,但這只是為了觀察起來方便,普通的基于二進制的協議也是可以使用這個模塊的。

v1.0代碼

舊版代碼中引用了我自己寫的(現已棄用)環形緩沖區模塊:
https://blog.csdn.net/lin_strong/article/details/73604561

接收機代碼

頭文件

/*
*********************************************************************************************************
*
*
*UniversalReceiveStateMachine
*通用接收狀態機
*
*File:RxMac.h
*
*By:LinShijun(https://blog.csdn.net/lin_strong)
*Date:2018/05/29
*version:1.0
*History:2018/05/29theprototype
*NOTE(s):1.thereceiveprocesshastwobasicstate
*A.preRx:whenhaven'tfoundanyheader,theRxMacwillsearchfortheunique
*flag,headerandstrong-ender.Onlywhenaheaderisfoundwillcome
*tonextstep.
*B.Rxing:theRxMacwillputthesuccessivebytesintothebuffer,andsearch
*forthestrong-unique,strong-header,ender.
*2.themoduleisdrivedbytheRxMac_FeedData(),usershouldgetthethechar
*fromdatastreamandpassthedataonebyonetotheRxMacthroughRxMac_FeedData()
*3.eachtimeRxMacfindaframe(completeorincomplete),itwillcalltheonFlushed
*tonotifytheresults;usercanjudgetheframethroughthestateparameter;
*state.headerFound==1:findanyheader,theheaderispassedbypHorU
*state.enderFound==1:findanyender,theenderispassedbypEnder
*state.isFull==1:thebufferisfull,maybeyoushouldcheckheaderFound
*toseewhetheraheaderhasbeenfound.
*state.uniqueFound==1:findanyuniqueflag.Inthiscase,otherparameterswill
*alwaysbe0&thedatasinthebufferwillbetheflag.
*4.Tousethismodule,foreachreceivemachine:
*A.allocatethespaceforbuffer,RxMac&FLAGS
*RX_MAC_Mac;
*RX_FLAGflags[2];
*INT8Ubuf[300];
*B.settheflagsaccordingtotheprotocol,definethecallbackfuncitons
*accordingtoyourneed.
*staticvoidonGetHeader(pRX_MACsender,pRX_FLAGpFlag){......};
*staticvoidonFlushed(pRX_MACsender,pRB_BYTEpBuf,INT16Ulen,
*RX_STATEstate,pRX_FLAGpHorU,pRX_FLAGpEnder){......};
*constINT8UHeaderFlag[]="Header";
*constINT8UEnderFlag[]="
";
*RX_FLAG_INIT(flags,HeaderFlag,StrSize(HeaderFlag),FLAG_OPTION_HEADER);
*RX_FLAG_INIT(&flags[1],EnderFlag,StrSize(EnderFlag),FLAG_OPTION_ENDER|
*FLAG_OPTION_NOTFILL_ENDER);
*C.initthereceivemachine:
*RxMac_Init(&_Mac,flags,2,6,buf,300,NULL,onGetHeader,onFlushed);
*D.feedthereceivemachine:
*while(1){
*c=GetNextChar();
*RxMac_FeedData(&_Mac,c);
*}
*********************************************************************************************************
*/

#ifndefRX_MAC_H
#defineRX_MAC_H


/*
*********************************************************************************************************
*INCLUDES
*********************************************************************************************************
*/
#include"RingQueue.h"
#include

//typedefunsignedcharINT8U;
//typedefunsignedshortINT16U;

/*
*********************************************************************************************************
*ADDRESSINGMODE尋址模式
*********************************************************************************************************
*/
//theaddressingmodeforbuffer
#defineRXMAC_BUF_ADDRESSING_MODERQ_ADDRESSING_MODE

typedefINT8URB_BYTE;
typedefRB_BYTE*RXMAC_BUF_ADDRESSING_MODEpRB_BYTE;
/*
*********************************************************************************************************
*CONFIGURATION配置
*********************************************************************************************************
*/

#defineRXMAC_ARGUMENT_CHECK_ENTRUE
#defineRXMAC_NOTFILL_ENTRUE

#defineRXMAC_ONFEEDED_ENTRUE//TRUE:enabletheonFeededfunction.

#defineRXMAC_SINGLETON_ENFALSE//TRUE:enablesingletonpattern,soargumentpRxMacofinterfaces
//isuseless,anduserdon'tneedtoallocatespaceforRX_MAC,
//butyoustillneedtoallocatebufferandcallinit();

/*
*********************************************************************************************************
*CONST
*********************************************************************************************************
*/

#defineRXMAC_ERR_NONE0
#defineRXMAC_ERR_ARGUMENT1
#defineRXMAC_ERR_POINTERNULL2
#defineRXMAC_ERR_UNKNOWN3
#defineRXMAC_ERR_INIT4
/*
*********************************************************************************************************
*TYPEDEFINITION
*********************************************************************************************************
*/

//structofRX_FLAG.option
/*typedefstructFLAG_OPTION{
unsignedintisHeader:1;//1:theflagistheheadoftheframe
unsignedintstrong_H:1;//1:strong-header,RxMacwill
unsignedintnotfill_H:1;//0:filltheflagintothebufferwhenfoundasheader
unsignedintisEnder:1;//1:theflagistheendoftheframe
unsignedintstrong_E:1;//
unsignedintnotfill_E:1;//0:filltheflagintothebufferwhenfoundasender
unsignedintisUnique:1;//1:theflagisauniqueflagwhichistreatedassingleframe.
unsignedintstrong_U:1;//0:whenreceivingaframe,RxMacwillnot
};//*/

//接收標志位
typedefstructrx_flag{
INT8Uconst*pBuf;
INT8Ulen;
INT8Uoption;
}RX_FLAG,*pRX_FLAG;

//normalheader,RxMacwillonlycheckitinStepA
#defineFLAG_OPTION_HEADER0x01
//strongheader,RxMacwillalwayscheckit.
#defineFLAG_OPTION_STRONG_HEADER0x03
//theheaderwillnotbefilledintobufferwhenfound.(onlyvalidwhenisheader)
#defineFLAG_OPTION_NOTFILL_HEADER0x04
//normalender,RxMacwillonlycheckitinStepB
#defineFLAG_OPTION_ENDER0x08
//strongheader,RxMacwillalwayscheckit.
#defineFLAG_OPTION_STRONG_ENDER0x18
//theenderwillnotbefilledintobufferwhenfound.(onlyvalidwhenisender)
#defineFLAG_OPTION_NOTFILL_ENDER0x20
//normalunique,RxMacwillonlycheckitinStepA
#defineFLAG_OPTION_UNIQUE0x40
//strongunique,RxMacwillalwayscheckit.
#defineFLAG_OPTION_STRONG_UNIQUE0xC0

typedefstructrx_state{
unsignedintheaderFound:1;//1:havegetheader
unsignedintenderFound:1;//1:havegetender
unsignedintisFull:1;//1:thebufferisfull
unsignedintuniqueFound:1;//1:thisisuniqueflag.
}RX_STATE;

typedefstructrx_macRX_MAC,*pRX_MAC;
typedefvoid(*RXMAC_FLUSH_EVENT)(pRX_MACsender,pRB_BYTEpBuf,INT16Ulen,RX_STATEstate,pRX_FLAGpHorU,pRX_FLAGpEnder);
typedefvoid(*RXMAC_FLAG_EVENT)(pRX_MACsender,pRX_FLAGpFlag);
typedefvoid(*RXMAC_FILTER)(pRX_MACsender,pRB_BYTEpCurChar,INT16UbytesCnt);

structrx_mac{
RING_QUEUEFlagQueue;//用于判斷標志串的環形緩沖區對象

pRX_FLAGFlags;//標志數組
INT8UFlagsCnt;//標志數組的個數
RX_STATEstate;//接收的狀態(內部使用)
pRX_FLAGpHorU;//內部使用

pRB_BYTEpRxBuf;//存放數據的緩沖區
INT16URxBufSize;//緩沖區的長度

pRB_BYTEpCur;//指向緩沖區內下一個填充字符的位置

RXMAC_FILTERonFeeded;//當被喂字符時觸發,返回指向緩沖區中剛剛喂進來的字符的指針以及是緩沖區內的第幾個字符

RXMAC_FLAG_EVENTonGetHeader;//獲得頭標志位時觸發。
RXMAC_FLUSH_EVENTonFlushed;//回調函數
};


/*
*********************************************************************************************************
*FUNCTIONDECLARATION
*********************************************************************************************************
*/
//tosettheflag'soption
//pbufpointertotheflagbuffer
//bufSizesizeofflag
//optseeFLAG_OPTION_XXXXX
#defineRX_FLAG_INIT(pFlag,pbuf,bufSize,opt)
(pFlag)->pBuf=(pbuf);(pFlag)->len=(bufSize);(pFlag)->option=(opt);

//toinittheRxMac
INT8URxMac_Init(pRX_MACpRxMac,//需要用戶自己申請個UNI_RX_MACHINE對象的空間
RX_FLAGFlags[],INT8UFlagsCnt,INT8UmaxLenOfFlags,//提供標志字符串的數組
pRB_BYTEpBuf,INT16UBufLen,//用戶需要提供緩沖區(緩存區大小起碼應該要能
//放的下最長的Flag+最長的幀,最后部分會分配給RQ)
RXMAC_FILTERonFeeded,//在每次被Feed時觸發
RXMAC_FLAG_EVENTonGetHeader,//獲得頭標志位時觸發。
RXMAC_FLUSH_EVENTonFlushed//收到一幀數據時的回調函數
);
//向接收機內喂字節
voidRxMac_FeedData(pRX_MACpRxMac,INT8Uc);
//重置接收區長度為最長那個長度
INT8URxMac_ResetRxSize(pRX_MACpRxMac);
//設置最大接收到多少個字節
INT8URxMac_SetRxSize(pRX_MACpRxMac,INT16Usize);
//重置接收機的狀態
INT8URxMac_ResetState(pRX_MACpRxMac);
//強制接收機flush
INT8URxMac_Flush(pRX_MACpRxMac);
//設置onFeeded
INT8URxMac_SetOnFeeded(pRX_MACpRxMac,RXMAC_FILTERonFeeded);
//設置onGetHeader
INT8URxMac_SetOnGetHeader(pRX_MACpRxMac,RXMAC_FLAG_EVENTonGetHeader);
//設置onFlushed
INT8URxMac_SetOnFlushed(pRX_MACpRxMac,RXMAC_FLUSH_EVENTonFlushed);

#endif//ofRX_MAC_H

源文件:

/*
*********************************************************************************************************
*
*
*UniversalReceiveStateMachine
*通用接收狀態機
*
*File:RxMac.c
*
*By:LinShijun(https://blog.csdn.net/lin_strong)
*Date:2018/05/29
*version:1.0
*History:
*NOTE(s):
*
*********************************************************************************************************
*/

/*
*********************************************************************************************************
*INCLUDES
*********************************************************************************************************
*/
#include"RxMac.h"

#include
#include
/*
*********************************************************************************************************
*CONSTANT
*********************************************************************************************************
*/
//normalheader,RxMacwillonlycheckitinStepA
#defineFLAG_OPTBIT_HEADER0x01
//strongheader,RxMacwillalwayscheckit.
#defineFLAG_OPTBIT_STRONG_HEADER0x02
//theheaderwillnotbefilledintobufferwhenfound.(onlyvalidwhenisheader)
#defineFLAG_OPTBIT_NOTFILL_HEADER0x04
//normalender,RxMacwillonlycheckitinStepB
#defineFLAG_OPTBIT_ENDER0x08
//strongheader,RxMacwillalwayscheckit.
#defineFLAG_OPTBIT_STRONG_ENDER0x10
//theenderwillnotbefilledintobufferwhenfound.(onlyvalidwhenisender)
#defineFLAG_OPTBIT_NOTFILL_ENDER0x20
//normalunique,RxMacwillonlycheckitinStepA
#defineFLAG_OPTBIT_UNIQUE0x40
//strongunique,RxMacwillalwayscheckit.
#defineFLAG_OPTBIT_STRONG_UNIQUE0x80

#defineSTATEMASK_STEPA(FLAG_OPTBIT_HEADER|FLAG_OPTBIT_UNIQUE|FLAG_OPTBIT_STRONG_ENDER)
#defineSTATEMASK_STEPB(FLAG_OPTBIT_STRONG_UNIQUE|FLAG_OPTBIT_ENDER|FLAG_OPTBIT_STRONG_HEADER)
#defineFLAGMASK_USUHSH(FLAG_OPTBIT_HEADER|FLAG_OPTBIT_STRONG_HEADER|FLAG_OPTION_UNIQUE|FLAG_OPTBIT_STRONG_UNIQUE)

/*
*********************************************************************************************************
*LOCALFUNCITONDECLARATION
*********************************************************************************************************
*/
#if(RXMAC_SINGLETON_EN==FALSE)
#define_pRxMacpRxMac
#else
staticRX_MAC_RxMac;
#define_pRxMac(&_RxMac)
#endif

#define_FlagQueue(_pRxMac->FlagQueue)
#define_Flags(_pRxMac->Flags)
#define_FlagsCnt(_pRxMac->FlagsCnt)
#define_state(_pRxMac->state)
#define_stateByte(*(INT8U*)(&_state))
#define_pHorU(_pRxMac->pHorU)
#define_pRxBuf(_pRxMac->pRxBuf)
#define_RxBufSize(_pRxMac->RxBufSize)
#define_pCur(_pRxMac->pCur)
#define_onFeeded(_pRxMac->onFeeded)
#define_onGetHeader(_pRxMac->onGetHeader)
#define_onFlushed(_pRxMac->onFlushed)
#define_isRxBufFull()((_pCur-_pRxBuf)>=_RxBufSize)


//因為不能保證用戶把數據放在非分頁區,只好自己實現一個,實際使用中如果確定在非分頁區可以把下面的宏替換為庫函數memcpy
staticpRB_BYTE_memcpy_internal(pRB_BYTEdest,pRB_BYTEsrc,size_tn);
#define_memcpy(dest,src,n)_memcpy_internal(dest,src,n)
//沖刷緩沖區
staticvoid_flush(pRX_MACpRxMac,pRX_FLAGender);
//往接收機緩沖區內放數據
staticvoid_BufIn(pRX_MACpRxMac,pRB_BYTEpBuf,INT16Ulen);

/*
*********************************************************************************************************
*RxMac_Init()
*
*Description:ToinitializeaRxMac.初始化接收機
*
*Arguments:pRxMacpointertotheRxMacstruct;指向接收機結構體的指針
*Flagspointertotheflags(anarray);指向標志串(數組)的指針
*FlagsCntthecountoftheflags;有多少個標志串;
*maxLenOfFlagsthemaxlengthofflags;標志字符串最長的長度
*pBufpointertothebufferprovidedtotheRxMac;提供給接收機使用的緩存
*BufLenthesizeofthebuffer.緩存的大小
*onFeededthecallbackfuncthatwillbecalledwhenfeeded.
*每次被feed時會調用的回調函數,如改變對應數據值會影響標志位的判斷
*onGetHeaderthecallbackfuncthatwillbecalledwhenfindaheader.
*當發現幀頭時會調用的回調函數
*onFlushedthecallbackfuncthatwillbecalledwhenflushed.
*當Flush時會調用的回調函數
*
*Return:RXMAC_ERR_NONEifsuccess
*RXMAC_ERR_ARGUMENTifthelengthoflongestFlagsbiggerthanBuflen,oroneofthemis0
*RXMAC_ERR_POINTERNULLifemptypointer
*
*Note(s):sizeofbuffershouldbiggerthanthelongestflagplusthelongestframe
*thatmaybereceived(soatleast2*maxLenOfFlags).
*thebufferisallocateasfollow:
*<----------------------??BufLen??---------------------->
*|RxBuffer||
*<-------------?RxBufSize?------------><-maxLenOfFlags->
*
*voidonGetHeader(pRX_MACsender,pRX_FLAGpFlag):
*senderthepointertotheRxMacwhichcallthisfunction
*pFlagtheheadermatched
*
*voidonFeeded(pRX_MACsender,pRB_BYTEpCurChar,INT16UbytesCnt):
*senderthepointertotheRxMacwhichcallthisfunction
*pCurCharpointtothecharinthebufferjustreceived.
*bytesCntthenumberofbytesinthebufferincludingthecharjustfeeded.
*
*voidonFlushed(pRX_MACsender,pRB_BYTEpBuf,INT16Ulen,RX_STATEstate,pRX_FLAGpHorU,
*pRX_FLAGpEnder);
*senderthepointertotheRxMacwhichcallthisfunction
*pBufthepointertotheframe.
*lenthelengthofframe.
*statethestateofframe.
*pHorUpointtotheheaderflagifstate.headerFound==1,oruniqueflagif
*state.uniqueFound==1.
*pEnderpointtotheenderflagifstate.enderFound==1.
*********************************************************************************************************
*/
INT8URxMac_Init
(pRX_MACpRxMac,RX_FLAGFlags[],INT8UFlagsCnt,INT8UmaxLenOfFlags,pRB_BYTEpBuf,INT16UBufLen,
RXMAC_FILTERonFeeded,RXMAC_FLAG_EVENTonGetHeader,RXMAC_FLUSH_EVENTonFlushed){
//INT8UmaxLen=0;
INT8Ui;
#if(RXMAC_ARGUMENT_CHECK_EN)
if(
#if(!RXMAC_SINGLETON_EN)
_pRxMac==NULL||
#endif
Flags==NULL||pBuf==NULL)
returnRXMAC_ERR_POINTERNULL;
#endif
//findoutthemaxlengthofflags.
//for(i=0;imaxLen)
//maxLen=Flags[i].len;
//}
#if(RXMAC_ARGUMENT_CHECK_EN)
if(maxLenOfFlags==0||(maxLenOfFlags*2)>BufLen||BufLen==0||FlagsCnt==0||
maxLenOfFlags==0)
returnRXMAC_ERR_ARGUMENT;
#endif
BufLen-=maxLenOfFlags;
//把buffer的最后一段分配給環形緩沖區
RingQueueInit(&_FlagQueue,pBuf+BufLen,maxLenOfFlags,&i);
_Flags=Flags;
_FlagsCnt=FlagsCnt;
_stateByte=0;
_pHorU=NULL;
_pRxBuf=pBuf;
_RxBufSize=BufLen;
_pCur=pBuf;
_onFeeded=onFeeded;
_onGetHeader=onGetHeader;
_onFlushed=onFlushed;
returnRXMAC_ERR_NONE;
}
/*
*********************************************************************************************************
*RxMac_FeedData()
*
*Description:TofeedRxMacthenextchar.用于給接收機下一個字符
*
*Arguments:pRxMacpointertotheRxMacstruct;指向接收機結構體的指針
*cthechartofeed;下一個字符
*
*Return:
*
*Note(s):
*********************************************************************************************************
*/
voidRxMac_FeedData(pRX_MACpRxMac,INT8Uc){
INT8Ui,mask;
pRX_FLAGpFlag=NULL;
#if(RXMAC_ONFEEDED_EN)
pRB_BYTEpCurChar=_pCur;
#endif
#if(RXMAC_ARGUMENT_CHECK_EN&&!RXMAC_SINGLETON_EN)
if(_pRxMac==NULL)
return;
#endif
*_pCur++=c;//填入緩沖區
#if(RXMAC_ONFEEDED_EN)
if(_onFeeded!=NULL)
_onFeeded(_pRxMac,pCurChar,_pCur-_pRxBuf);
RingQueueIn(&_FlagQueue,*pCurChar,RQ_OPTION_WHEN_FULL_DISCARD_FIRST,&i);
#else
RingQueueIn(&_FlagQueue,c,RQ_OPTION_WHEN_FULL_DISCARD_FIRST,&i);
#endif
//_state.headerFound==1說明在等待幀尾,否則在等待幀頭
mask=(_state.headerFound)?STATEMASK_STEPB:STATEMASK_STEPA;
//尋找匹配的標志串
for(i=0;i=0)){
RingQueueClear(&_FlagQueue);
pFlag=&_Flags[i];
break;
}
}
//如果沒有發現標志串,檢查下有沒滿了,滿了就Flush
if(pFlag==NULL){
if(_isRxBufFull()){
_state.isFull=1;
_flush(_pRxMac,NULL);
}
return;
}
//這4種標志串要_flush掉前面的東西
if(pFlag->option&FLAGMASK_USUHSH){
_pCur-=pFlag->len;
_flush(_pRxMac,NULL);
_pHorU=pFlag;
}
//如果是幀頭的處理
if(pFlag->option&(FLAG_OPTION_STRONG_HEADER|FLAG_OPTION_HEADER)){
#if(RXMAC_NOTFILL_EN==TRUE)
if(!(pFlag->option&FLAG_OPTION_NOTFILL_HEADER))
#endif
_BufIn(_pRxMac,(pRQTYPE)pFlag->pBuf,pFlag->len);
_state.headerFound=1;
if(_onGetHeader!=NULL)
_onGetHeader(_pRxMac,pFlag);
return;
}
//如果是Unique的處理
if(pFlag->option&(FLAG_OPTION_STRONG_UNIQUE|FLAG_OPTION_UNIQUE)){
_state.uniqueFound=1;
_BufIn(_pRxMac,(pRQTYPE)pFlag->pBuf,pFlag->len);
_flush(_pRxMac,NULL);
}else{//能到這里說明是幀尾
_state.enderFound=1;
#if(RXMAC_NOTFILL_EN==TRUE)
if(pFlag->option&FLAG_OPTION_NOTFILL_ENDER)
_pCur-=pFlag->len;
#endif
_flush(_pRxMac,pFlag);
}
return;
}
/*
*********************************************************************************************************
*RxMac_ResetRxSize()
*
*Description:resetthesizeofRxBuftothemaxsize.重置接收緩沖區
*
*Arguments:pRxMacpointertotheRxMacstruct;指向接收機結構體的指針
*
*Return:RXMAC_ERR_NONEifSuccess;
*RXMAC_ERR_POINTERNULLifpRxMac==NULL
*RXMAC_ERR_INITifRxMachasn'tinitedoranyerrorininitialization
*Note(s):
*********************************************************************************************************
*/
INT8URxMac_ResetRxSize(pRX_MACpRxMac){
intsize;
#if(RXMAC_ARGUMENT_CHECK_EN&&!RXMAC_SINGLETON_EN)
if(_pRxMac==NULL)
returnRXMAC_ERR_POINTERNULL;
#endif
size=_FlagQueue.RingBuf-_pRxBuf;
#if(RXMAC_ARGUMENT_CHECK_EN)
if(size0)
*p++=*src++;
returndest;
}

staticvoid_BufIn(pRX_MACpRxMac,pRB_BYTEpBuf,INT16Ulen){
_memcpy(_pCur,pBuf,len);
_pCur+=len;
}

staticvoid_flush(pRX_MACpRxMac,pRX_FLAGender){
//觸發回調
if(_pCur-_pRxBuf>0&&_onFlushed!=NULL)
_onFlushed(_pRxMac,_pRxBuf,_pCur-_pRxBuf,_state,_pHorU,ender);
//復位接收機
_pCur=_pRxBuf;
_stateByte=0;
_pHorU=NULL;
}

測試/示例代碼

/*
*********************************************************************************************************
*uC/OS-II
*TheReal-TimeKernel
*Framework
*
*By:LinShijun
*Note:ThisisaframeworkforuCos-iiprojectwithonlyS12CPU,nonefloat,bankedmemorymodel.
*Youcanusethisframeworkwithsamemodificationasthestartpointofyourproject.
*I'veremovedtheos_probemodule,sinceIthoughtituselessinmostcase.
*Thisframeworkisadaptedfromtheofficialrelease.
*********************************************************************************************************
*/

#include"includes.h"
#include"SCI_def.h"
#include"RxMac.h"
/*
*********************************************************************************************************
*STACKSPACEDECLARATION
*********************************************************************************************************
*/
staticOS_STKAppTaskStartStk[APP_TASK_START_STK_SIZE];

/*
*********************************************************************************************************
*TASKFUNCTIONDECLARATION
*********************************************************************************************************
*/

staticvoidAppTaskStart(void*p_arg);

/*
*********************************************************************************************************
*CALLBACKFUNCITON
*********************************************************************************************************
*/
voidonGetData(pRX_MACsender,pRB_BYTEpCurChar,INT16UbytesCnt){
//因為發現幀頭后才掛載事件,所以下一次回掉正好是說明字符數的那個字符,否則還得根據bytesCnt來判斷當前位置
RxMac_SetOnFeeded(sender,NULL);
if(*pCurChar>'0'&&*pCurChar<=?'9'?){
????//?bytesCnt是當前收到了多少個字符,所以接收區大小為當前字符數加上還要接收的
????RxMac_SetRxSize(sender,*pCurChar?-?'0'?+?bytesCnt);
??}
}
void?onFlushed(pRX_MAC?sender,pRB_BYTE?pBuf,INT16U?len,RX_STATE?state,pRX_FLAG?pHorU,pRX_FLAG?pEnder){
??SCI_PutCharsB(SCI0,"
Flushed:",9,0);
??if(state.headerFound)
????SCI_PutCharsB(SCI0,"headerFound,",12,0);
??if(state.enderFound)
????SCI_PutCharsB(SCI0,"enderFound,",11,0);
??if(state.isFull)
????SCI_PutCharsB(SCI0,"full,",5,0);
??if(state.uniqueFound)
????SCI_PutCharsB(SCI0,"unique,",7,0);
??SCI_PutCharsB(SCI0,"
Datas:",7,0);
??SCI_PutCharsB(SCI0,pBuf,len,0);
??SCI_PutCharsB(SCI0,"
",1,0);
??RxMac_ResetRxSize(sender);
}
void?onGetHeader(pRX_MAC?sender,pRX_FLAG?pFlag){
??SCI_PutCharsB(SCI0,"
FoundHeader:",13,0);
??SCI_PutCharsB(SCI0,pFlag->pBuf,pFlag->len,0);
SCI_PutCharsB(SCI0,"
",1,0);
}
voidonGetHeader2(pRX_MACsender,pRX_FLAGpFlag){
SCI_PutCharsB(SCI0,"
FoundHeader:",13,0);
SCI_PutCharsB(SCI0,pFlag->pBuf,pFlag->len,0);
SCI_PutCharsB(SCI0,"
",1,0);
RxMac_SetOnFeeded(sender,onGetData);
}
/*
*********************************************************************************************************
*FLAGS
*********************************************************************************************************
*/
RX_MAC_rxmac;
#defineBUF_SIZE20
INT8Ubuffer[BUF_SIZE];
RX_FLAGflags[4];

//協議示例1:
//幀頭:HEADER或者START
//強幀尾:END
//強特殊串:12345
//
staticvoidprotocol1_init(){
RX_FLAG_INIT(&flags[0],"HEADER",6,FLAG_OPTION_HEADER);
RX_FLAG_INIT(&flags[1],"START",5,FLAG_OPTION_HEADER);
RX_FLAG_INIT(&flags[2],"END",3,FLAG_OPTION_STRONG_ENDER);
RX_FLAG_INIT(&flags[3],"12345",5,FLAG_OPTION_STRONG_UNIQUE);
RxMac_Init(&_rxmac,flags,4,6,buffer,BUF_SIZE,NULL,onGetHeader,onFlushed);
}
//協議示例2:
//幀頭:START
//幀頭后的第1個字符表示后面還要接收多少個字符1-9,'4'表示4個,如果不是數字或為'0',則等待幀尾
//幀尾:END
//特殊串:NOW
//
staticvoidprotocol2_init(){
RX_FLAG_INIT(&flags[0],"START",5,FLAG_OPTION_HEADER);
RX_FLAG_INIT(&flags[1],"END",3,FLAG_OPTION_ENDER);
RX_FLAG_INIT(&flags[2],"NOW",3,FLAG_OPTION_UNIQUE);
RxMac_Init(&_rxmac,flags,3,5,buffer,BUF_SIZE,NULL,onGetHeader2,onFlushed);
}

/*
*********************************************************************************************************
*MAINFUNCTION
*********************************************************************************************************
*/


voidmain(void){
INT8Uerr;
BSP_IntDisAll();/*DisableALLinterruptstotheinterruptcontroller*/
OSInit();/*InitializeuC/OS-II*/

err=OSTaskCreate(AppTaskStart,
NULL,
(OS_STK*)&AppTaskStartStk[APP_TASK_START_STK_SIZE-1],
APP_TASK_START_PRIO);
OSStart();
}

staticvoidAppTaskStart(void*p_arg)
{
INT8Uc,err;
(void)p_arg;/*Preventcompilerwarning*/
BSP_Init();
SCI_Init(SCI0);
SCI_EnableTrans(SCI0);
SCI_EnableRecv(SCI0);
SCI_EnableRxInt(SCI0);
SCI_BufferInit();
//選擇想要實驗的協議來初始化
protocol1_init();
//protocol2_init();
while(DEF_TRUE)
{
//獲取下一個字符
c=SCI_GetCharB(SCI0,0,&err);
//回顯
SCI_PutCharB(SCI0,c,0);
//喂給接收機
RxMac_FeedData(&_rxmac,c);
}
}

審核編輯:湯梓紅

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 模塊
    +關注

    關注

    7

    文章

    2785

    瀏覽量

    49852
  • 嵌入式
    +關注

    關注

    5144

    文章

    19574

    瀏覽量

    315719
  • 接收機
    +關注

    關注

    8

    文章

    1221

    瀏覽量

    54287
  • 函數
    +關注

    關注

    3

    文章

    4374

    瀏覽量

    64389
  • 狀態機
    +關注

    關注

    2

    文章

    493

    瀏覽量

    28114

原文標題:[嵌入式開發模塊]通用接收狀態機模塊

文章出處:【微信號:技術讓夢想更偉大,微信公眾號:技術讓夢想更偉大】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦
    熱點推薦

    嵌入式軟件開發中常用的狀態機編程實現

    嵌入式軟件開發中,狀態機編程是一個十分重要的編程思想,它也是嵌入式開發中一個常用的編程框架。掌握了狀態機編程思想,可以更加邏輯清晰的實現復
    發表于 09-06 10:25 ?2687次閱讀

    基于狀態機嵌入式系統開發

    給大家分享下,基于狀態機嵌入式系統開發,慢慢看吧
    發表于 12-22 19:44

    基于ARM的嵌入式開發

    基于ARM的嵌入式開發:華清遠見/孫天澤基于ARM的嵌入式開發內容有:ARM簡介,基于ARM的嵌入式產品,ARM架構,基于ARM的嵌入式開發。
    發表于 10-04 08:49 ?83次下載

    嵌入式開發

    嵌入式開發就是指在嵌入式操作系統下進行開發,嵌入式Linux是以Linux為基礎的嵌入式作業系統。這里提供了
    發表于 12-20 13:21
    <b class='flag-5'>嵌入式開發</b>

    [嵌入式開發板]iTOP-4412以模塊的方式編譯內核驅動

    [嵌入式開發板]iTOP-4412以模塊的方式編譯驅動。
    發表于 03-15 09:31 ?21次下載

    嵌入式軟件中狀態機的抽象與實現

    文中提出了 在嵌入式軟件中把狀態機作為一個獨立模塊從控制模塊中抽象出來的思想 , 描述了 抽象出來的狀態機
    發表于 03-22 15:47 ?1次下載

    有限狀態機嵌入式系統中的實現及應用

    如何使嵌入式軟件代碼更加可靠 增強程序的可維護性 一直以來都是嵌入式程序員追 求的目標。論述了有限狀態機的原理和其實現方法;采用狀態機方法編寫了一個按鍵掃描程序介紹了
    發表于 03-22 15:40 ?1次下載

    LabVIEW ARM嵌入式開發模塊的詳細介紹和使用手冊中文資料概述

    LabVIEW ARM嵌入式開發模塊是一個完整的圖形化開發環境,由NI聯合Keil公司開發而成,使用這個模塊對ARM芯片
    發表于 06-19 08:00 ?17次下載
    LabVIEW ARM<b class='flag-5'>嵌入式開發</b><b class='flag-5'>模塊</b>的詳細介紹和使用手冊中文資料概述

    嵌入式LINUX系統內核和內核模塊調試

    嵌入式LINUX系統內核和內核模塊調試(嵌入式開發和硬件開發)-嵌入式LINUX系統內核和內核模塊
    發表于 07-30 13:55 ?10次下載
    <b class='flag-5'>嵌入式</b>LINUX系統內核和內核<b class='flag-5'>模塊</b>調試

    嵌入式開發(一):嵌入式開發新手入門

    本篇文章整理下嵌入式開發中一些入門的基礎技能,都是根據以往的工程經驗整理,適用于之前沒做過嵌入式開發的新手。嵌入式開發流程一般如下,一般是在PC的Windows系統下安裝Ubuntu
    發表于 10-14 10:58 ?79次下載
    <b class='flag-5'>嵌入式開發</b>(一):<b class='flag-5'>嵌入式開發</b>新手入門

    嵌入式開發資料免費分享

    嵌入式開發資料免費分享嵌入式工程師經驗分享:如何學習嵌入式開發截取文檔部分學習嵌入式工程師經驗分享的資料分享給大家,文檔上從、嵌入式系統的概
    發表于 10-21 11:07 ?47次下載
    <b class='flag-5'>嵌入式開發</b>資料免費分享

    嵌入式狀態機的設置

    狀態機嵌入式軟件中隨處可見,可能你會說狀態機有什么難的,不就是 switch 嗎?
    的頭像 發表于 11-02 09:04 ?1316次閱讀

    嵌入式狀態機的編程優點分析

    嵌入式狀態機編程是真的好用,寫出來的程序結構非常清晰!所以平時用的也比較多。
    的頭像 發表于 02-25 16:21 ?1042次閱讀

    嵌入式狀態機的設計與實現

    嵌入式狀態機是一種常用的軟件設計模式,它能夠提高代碼的可讀性和可維護性。狀態機是一個抽象的概念,它描述了一個系統或者組件的不同狀態以及在不同狀態
    的頭像 發表于 04-14 11:55 ?2225次閱讀

    單片開發嵌入式開發的區別

    單片開發嵌入式開發都是針對嵌入式系統的應用領域,但是兩者有著不同的特點和應用場景。在本文中,我們將探討單片
    的頭像 發表于 04-14 16:36 ?3094次閱讀
    主站蜘蛛池模板: 国产三级a三级三级野外 | 操操操干干| 四虎在线观看免费永久 | 天天做天天爱天天爽 | 激情五月激情综合色区 | 女人张开腿 让男人桶视频 女人张开腿等男人桶免费视频 | 狠狠干人人干 | 三级黄色片免费观看 | 黄 色 录像成 人播放免费99网 | 91亚洲国产成人久久精品网站 | 免费高清在线观看a网站 | 欧美成人免费全部观看天天性色 | 日本xxwwwxxxx网站| 四虎影午夜成年免费精品 | 久久香蕉精品视频 | 九九精品影院 | 黄网站在线观看永久免费 | 亚洲人成网站色在线观看 | 日一日操一操 | 天天摸天天做天天爽在线 | 久久精品午夜视频 | 美女毛片视频 | 国产人人澡| 国产精品亚洲玖玖玖在线靠爱 | 日本 韩国 三级 国产 欧美 | 国产精品夜夜春夜夜爽久久 | 天天操天天干天天爽 | 国产女人又爽又大 | 波多野结衣在线观看一区二区三区 | 欧美色穴| 日韩免费观看一级毛片看看 | 手机看片日韩永久福利盒子 | 在线免费观看黄色小视频 | 美女屁屁免费视频网站 | 日本日本69xxxx | 久久精品伊人波多野结 | 久久夜色精品国产亚洲 | 国语对白一区二区三区 | 沟沟人体一区二区 | 宅男午夜| seba51久久精品 |