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校验位的计算函数,可供大家参考。