485通訊資料幀結束標誌位判斷方法和485通訊主要函式
技術標籤:485通訊
485通訊資料幀結束判斷標誌位如何判斷:
在485通訊中,如何去判斷一幀資料接收結束呢?
首先要知道的是,在每幀資料中,每個位元組之間的資料傳送間隔時間一定會小於每幀資料的之間的傳送間隔時間。也就是說對於接收資料來說在位元組之間每個資料幀之間的接收時間是不一樣的,資料幀之間的接收時間要大於資料幀之中每個位元組的接收時間的。那麼就可以利用這兩種資料的間隔時間的區別來進行區分是否一幀資料接收完畢。
在485通訊的接收過程中,所以看起來是一幀一幀資料接收的,但是實際情況還是每個位元組每個位元組來進行接收的,那麼如果新增一個定時器,來對每次接收位元組的時間來進行計時,在傳送資料幀的時間固定的情況下,就可以實現對每幀資料的位元組傳送間隔時間和每幀資料的接收間隔時間,而每幀資料的接收時間一定會遠遠大於每幀資料中的每個位元組的接收時間的,甚至可以說一幀資料傳送下來的時間一般都會遠小於每幀資料的傳送間隔時間。
所以在實際應用中,每次接收到位元組時,都對當前的計數值進行清零操作。那麼只要還在接收資料,當前計數值都不會超過單個位元組的接收時間,而當計數值達到一定值的時候,這個值要遠遠超過單次接收位元組的時間的時候,就可以判斷沒有資料傳送過來,進而認為當前資料接收完畢,此時可以設定接收標誌位方便操作。
下面分享主要函式。
串列埠中斷函式:
void USART1_IRQHandler(void)
{
u8 res;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收到資料
{
res =USART_ReceiveData (USART1); //讀取接收到的資料
RS485_RX_BUF[RS485_RX_CNT]=res; //記錄接收到的值
RS485_RX_CNT++; //接收資料增加1
timout=0; //定時器計數值清零
if(RS485_RX_CNT==1) //接收到的第一個資料時,開始計數
timrun=1;
}
}
此時也可以看出計數器只有在接收到資料時才開始計數工作,這也避免了不關閉計數器導致計數器平常工作導致技術暫存器溢位而差生的誤判操作。
資料處理函式:
void RS485_Receive_Data()
{
u8 rxlen= RS485_RX_CNT;
if(reflag==0) //沒有收到MODbus的資料包
{
return ; //沒有收到處理指令,繼續等待下一條資料
}
MOBUS_CRC=GetModbusCRC16(RS485_RX_BUF,rxlen-2);//計算的校驗碼
MOBUS_RCCRC=RS485_RX_BUF[rxlen-1]+RS485_RX_BUF[rxlen-2]*256;//收到的校驗碼
if(MOBUS_CRC==MOBUS_RCCRC)//接收到了資料,且接收完成了
{
if(RS485_RX_BUF[0]==0xAA)
{
RS485_Send_Data(RS485_RX_BUF,rxlen);
}
}
RS485_RX_CNT=0; //清零
reflag=0;
}
reflag標誌位是接收資料標誌位,當其置一時,代表著接收資料完畢,可以開始處理資料,如果未接收完畢,則會利用return跳出當前函式,不執行後續操作,等待下次判斷。
定時器計數函式:
void TIM3_IRQHandler(void) //TIM3中斷
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //檢查指定的TIM中斷髮生與否:TIM 中斷源
if(timrun!=0) //串列埠傳送資料是否結束,結束就讓定時器定時
{
timout++; //定時器定時1毫秒,並開始記時
if(timout>=8) //間隔時間達到了時間,假設為8T,實際3.5T即可
{
timrun=0; //關閉定時器--停止定時
reflag=1; //收到一幀資料,開始處理資料
}
}
TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除TIMx的中斷待處理位:TIM 中斷源
}
當接收到第一個資料時,開始計數。當其計數值達到一定值時,便代表著資料接收完畢,關閉計數功能,將接收標誌位置一。
校驗位計算函式:
unsigned short GetModbusCRC16(unsigned char *cp,unsigned int leng)
{
unsigned int j,i,crc=0xFFFF;
if (leng<=0)
{
return 0;
}
for (j = 0; j < leng; j++)
{
crc = crc^(unsigned int)(cp[j]);
for(i = 0; i < 8; i++)
{
if ((crc&1)!=0 )
{
crc=(crc>>1)^0xA001;
}
else
{
crc=crc>>1;
}
}
}
return (unsigned short )crc;
}
該函式是ModbusCRC16校驗位的計算函式,可供大家參考。