单片机与威纶通触控屏通过RS485(1号线接B-,2号线接A+)通讯,协议采用modbus。
单片机做从机,威纶通触控屏做主机,只能主机访问从机,从机不能主动访问主机。站号对应着单片机的地址
Modbus 没有结束标志位,判断一帧数据是否传输完成取决于单片机是否在3.5个字符(大概4ms)的时间内收到数据,如果大于3.5个字符的时间内没有收到数据可以判定一帧数据接收完成。这个时候需要借助定时器,从没有接收到数据开始计时。
void TIM2_IRQHandler()//定时器2的中断服务子函数 1ms一次中断
{
u8 st;
st= TIM_GetFlagStatus(TIM2, TIM_FLAG_Update);
if(st==SET)
{
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
if(modbus.timrun!=0)
{
modbus.timout++;
if(modbus.timout>=8) //间隔时间达到了时间
{
modbus.timrun=0;//关闭定时器--停止定时,等到下次接受一帧新的数据时定时器才继续启动
modbus.reflag=1; //收到一帧数据,这个时候event函数才能向下运行
}
}
}
}
这是定时器中断服务函数,这里设定的时大于8ms没有收到数据表示一帧数据接收完成,
void USART2_IRQHandler() //MODBUS字节接收中断
{
u8 st,sbuf;
st=USART_GetITStatus(USART2, USART_IT_RXNE);
if(st==SET) //
{
sbuf=USART2->DR;
if( modbus.reflag==1) //有数据包正在处理,不接收新数据
{
return ;
}
modbus.rcbuf[modbus.recount++]=sbuf;
modbus.timout=0; //不断的对定时器中的modbus.timout做归0操作
if(modbus.recount==1) //收到主机发来的一帧数据的第一字节
{
modbus.timrun=1; //启动定时
}
}
}
void Mosbus_Event()
{
u16 crc;
u16 rccrc;
if(modbus.reflag==0) //没有收到MODbus的数据包
{
return ;
}
crc= crc16(&modbus.rcbuf[0], modbus.recount-2); //计算校验码
rccrc=modbus.rcbuf[modbus.recount-2]*256 + modbus.rcbuf[modbus.recount-1]; //收到的校验码
if(crc == rccrc) //数据包符号CRC校验规则
{
if(modbus.rcbuf[0] == modbus.myadd) //确认数据包是否是发给本设备的
{
switch(modbus.rcbuf[1]) //分析功能码
{
case 0: break;
case 1: break;
case 2: break;
case 3: Modbud_fun3(); break; //3号功能码处理
case 4: break;
case 5: break;
case 6: Modbud_fun6(); break; //6号功能码处理
case 7: break;
//....
}
}
else if(modbus.rcbuf[0] == 0) //广播地址
{
}
}
modbus.recount=0; //
modbus.reflag=0;
}
代码下载别人的,第一次写博客,为了更好的理解,有什么问题欢迎讨论