舉個例子,
主機發送給從機的數據
幀頭 命令 參數1 參數2 參數3 參數4 校驗和 幀尾
從機回復的數據
回復幀頭 應答命令 結果1 結果2 結果3 結果4 校驗和 回復幀尾
在從機接收到幀頭和命令後,並不進行處理,而是暫存起來,知道接收到幀尾,並接校驗通過後,才真正執行。
假如從收到幀頭起,壹定的時間內,還沒有收到完整的幀,或者幀校驗失敗,那麽從機用特殊的格式回復。
當然,超時時間也可以不從幀頭算,從上壹個字節算也可以。
這樣的幀結構就能保證通訊的正確性,壹般來講,幀越長,通訊效率越高,但是占用暫存空間越打,而且出錯的可能越大,出錯後付出的代價也越大,實時性也越差,而且幀長度超過壹定值後,通訊效率也不會再明顯增加。
幀越短,通訊效率越低,但是靈活。
像上面的例子,幀長度是8,通訊效率是62.5%。如果將幀長度改為16,通訊效率變為81.25%
下面是源代碼:
直接拷貝就能夠編譯通過了。當然要把寄存器改了。只有幾行需要改的哈:
#include "tot.h"
#define GOOD_PARSE 0
#define BADID_PARSE 1
#define BADLEN_PARSE 2
short parsed;
char *pbuf;
void tsip_input_proc(TSIPPKT *rpt,unsigned char inbyte);
void rpt_packet(TSIPPKT *rpt,int *obuf);
void tsip_input_proc(TSIPPKT *rpt,unsigned char inbyte)
{
switch(rpt->status)
{
case TSIP_PARSED_DLE_1:
switch(inbyte)
{
case 0:
case ETX: // illegal data
rpt->len=0;
rpt->status=TSIP_PARSED_EMPTY;
break;
case DLE: // try normal message start again
rpt->len=0;
rpt->status=TSIP_PARSED_DLE_1;
break;
default: // legal ID ;start message
rpt->len=0;
rpt->status=TSIP_PARSED_DATA;
rpt->codes=inbyte;
break;
}
break;
case TSIP_PARSED_DATA:
switch(inbyte)
{
case DLE: // expect DLE or ETX next
rpt->status=TSIP_PARSED_DLE_2;
break;
default: // normal data byte
rpt->buf[rpt->len]=inbyte;
rpt->len++;
break;
}
break;
case TSIP_PARSED_DLE_2:
switch(inbyte)
{
case DLE: // normal data byte
rpt->buf[rpt->len]=inbyte;
rpt->len++;
rpt->status=TSIP_PARSED_DATA;
break;
case ETX: // end of message,return TURE here
rpt->status=TSIP_PARSED_FULL;
break;
default: // error:treat as TSIP_PARSED_DLE_1,start new report packet
rpt->codes=inbyte;
rpt->len=0;
rpt->status=TSIP_PARSED_DATA;
break;
}
break;
case TSIP_PARSED_FULL:
case TSIP_PARSED_EMPTY:
default:
switch(inbyte)
{
case DLE: // normal message start
rpt->len=0;
rpt->status=TSIP_PARSED_DLE_1;
break;
default: // error:ignore inbyte
rpt->len=0;
rpt->status=TSIP_PARSED_EMPTY;
break;
}
break;
}
if(rpt->len>MAX_RPTBUF) // error:start new report packet
{
rpt->status=TSIP_PARSED_EMPTY;
rpt->len=0;
}
}
//串口字符交換*******************************************************************/
int bGetShort(char *bp)
{
int outval;
char *optr;
optr=(char *)&outval;
*optr=*bp<<8 & 0xFF00;
*optr=*(++bp) | *optr;
return outval;
}
//串口報文
int rpt_0x14(TSIPPKT *rpt,int output[1])
{
char *buf;
buf=rpt->buf;
if(rpt->len!=2)return 0;
output[0]=bGetShort(&buf[0]);
return 1;
}
void rpt_packet(TSIPPKT *rpt,int *obuf)
{
parsed=GOOD_PARSE;
switch(rpt->codes)
{
case 20:
rpt_0x14(rpt,obuf);
break;
default:
parsed=BADID_PARSE;
break;
}
}
//發送
void send_cmd(TSIPPKT *cmd, void sendb(char))
{
char *cbuf, *cbufend;
sendb (DLE);
sendb (cmd->codes);
cbufend = cmd->buf + cmd->len;
for (cbuf = cmd->buf; cbuf < cbufend; cbuf++) {
if (*cbuf == DLE) sendb (DLE);
sendb (*cbuf);
}
sendb (DLE);
sendb (ETX);
}
void sendb(char outbyte)
{
//ScibRegs.SCITXBUF=outbyte;
}
//字符交換
void bPutShort(unsigned int *in, char *out)
{
char *inptr;
inptr=(char *)in;
*out= (*inptr>>8) & 0x00FF;
*(++out) = *inptr & 0x00FF;
}
//命令
void cmd_0x0(TSIPPKT *cmd,SCICALOUT *out)
{
bPutShort(&(out->ve),&(cmd->buf[0]));
cmd->len = 2;
cmd->codes =37;
}
//串口使用中斷方式接收,發送不采用中斷
int input[MAX_RPTBUF];
void SCIRXD_ISR(void)
{
tsip_input_proc(&rpt,ScibRegs.SCIRXBUF.bit.RXDT);// analyse
if (rpt.status == TSIP_PARSED_FULL) // receive complete
{
rpt_packet(&rpt,input); // output reports
rpt.status=TSIP_PARSED_EMPTY; // prepare for next
}
ScibRegs.SCIFFRX.bit.RXFFOVRCLR=1; // Clear Overflow flag
ScibRegs.SCIFFRX.bit.RXFFINTCLR=1; // Clear Interrupt flag
PieCtrlRegs.PIEACK.all|= PIEACK_GROUP9; // Issue PIE ack
}
//發送調用方式
// cmd_100x0(&cmd);
// send_cmd(&cmd,&sendb);
//發送調用方式
// cmd_100x0(&cmd);
// send_cmd(&cmd,&sendb);
上面的就是源代碼。。記住把寄存器改了哦。無論是單片機還是上位機都可以用這個哈。