当前位置:首页 > 工业控制 > 工业控制
[导读]老产线改智能化,常遇到传感器MCU要直连只带RS485的老PLC。走完整Modbus当然稳,但若只有温度、振动、IO状态几类数据,自写轻量帧更省资源:MCU做采集和组包,PLC用自由口收帧、回应答,不依赖第三方协议栈,换波特率和点位只改配置。


老产线改智能化,常遇到传感器MCU要直连只带RS485的老PLC。走完整Modbus当然稳,但若只有温度、振动、IO状态几类数据,自写轻量帧更省资源:MCU做采集和组包,PLC用自由口收帧、回应答,不依赖第三方协议栈,换波特率和点位只改配置。

一、帧结构与分工

用二进制主从帧,避免ASCII解析开销:

AA 55帧头、addr从站、cmd命令、len数据长度、data[N]、crc16低、crc16高、0D 0A尾。cmd约定0x01MCU主动上报、0x02PLC读指定测点、0x03PLC下写参数、0x81/0x82为应答。长度域让接收方知道还要等几字节,CRC覆盖从addr到data末尾,帧尾或空闲线判定一帧结束均可。

MCU不处理控制逻辑,只负责“采准、发对、重发、看门狗”;PLC做量程限幅、联锁、写保持寄存器供上位机读。

二、C端采集与组包

以STM32裸机为例,定时器采ADC,串口DMA+空闲中断收帧,主循环组包:

uint16_t crc16(uint8_t *p, uint16_t n){

   uint16_t c=0xFFFF;

   for(uint16_t i=0;i<n;i++){c^=p[i];

       for(uint8_t j=0;j<8;j++)

           c=(c&1)?(c>>1)^0xA001:(c>>1);}

   return c;

}

int build_frame(uint8_t *f,uint8_t addr,uint8_t cmd,

              uint8_t *d,uint8_t len){

   f[0]=0xAA;f[1]=0x55;f[2]=addr;f[3]=cmd;

   f[4]=len;for(uint8_t i=0;i<len;i++)f[5+i]=d[i];

   uint16_t c=crc16(&f[2],3+len);          // addr+cmd+len+data

   f[5+len]=c&0xFF;f[6+len]=(c>>8)&0xFF;

   f[7+len]=0x0D;f[8+len]=0x0A;

   return 9+len;

}

void report_temp(uint8_t addr,float t){

   int16_t v=(int16_t)(t*10);              // 0.1℃定点

   uint8_t d[2]={v>>8,v&0xFF};

   uint8_t f[16];int n=build_frame(f,addr,0x01,d,2);

   rs485_de(1);uart_send(f,n);rs485_de(0); // 半双工切发送方向

}

RS485用GPIO控制DE/RE,发送前拉高、发完DMA TC中断拉低;115200在短线段比9600更省占空比,长线电机环境保守用19200/9600并加终端电阻。

三、接收状态机与重发

PLC轮询或MCU主动上报都可能有丢帧,C端用状态机收,不依赖整包到达:

enum{S_HEAD1,S_HEAD2,S_ADDR,S_CMD,S_LEN,S_DATA,S_CRC1,S_CRC2,S_TAIL}cst=S_HEAD1;

uint8_t rb[64],ridx,raddr,rcmd,rlen,rc1,rc2;

void on_byte(uint8_t b){

   switch(cst){

   case S_HEAD1: if(b==0xAA)cst=S_HEAD2; break;

   case S_HEAD2: if(b==0x55)cst=S_ADDR; else cst=S_HEAD1; break;

   case S_ADDR: raddr=b;cst=S_CMD; break;

   case S_CMD: rcmd=b;cst=S_LEN; break;

   case S_LEN: rlen=b;ridx=0;cst=rlen?S_DATA:S_CRC1; break;

   case S_DATA: rb[ridx++]=b; if(ridx>=rlen)cst=S_CRC1; break;

   case S_CRC1: rc1=b;cst=S_CRC2; break;

   case S_CRC2: rc2=b;cst=S_TAIL; break;

   case S_TAIL: if(b==0x0A)frame_done(raddr,rcmd,rb,rlen,rc1,rc2);

                cst=S_HEAD1; break;

   }

}

frame_done先按addr+cmd+len+data重算CRC,与rc1/rc2不符直接丢弃;PLC读命令则回0x81并带数据,写参数回0x82状态码。主机侧未收到应答,按指数退避重发,最多3次后置传感器质量位为坏,避免PLC用到陈旧值。

四、PLC自由口对接

S7-200类PLC把端口配自由口,设波特率、8N1,RCV用起始符或空闲线起帧、用最大长度/结束符收尾,接收完成中断里做地址过滤、命令分支、写VD/DB;XMT回包前确认半双工方向。 老三菱/欧姆龙可用无协议口按相同帧格式收ASCII或二进制;若PLC不支持自由口,MCU端改发标准Modbus RTU从站帧即可,应用层点位不变。

工程注意:RS485双绞、屏蔽单端接地、A/B不反;MCU与PLC共地但不能把强电地直接并接;ADC采样值做滑动平均和死区,突变超阈值才主动上报;长期通信可加热启动帧,PLC下发采样周期、滤波系数、报警上下限。按“轻帧+CRC+状态机+自由口回包+重发质量位”做,传感器直连传统PLC可省网关,改点只动配置,适合小产线、老设备加装采集。



本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除( 邮箱:macysun@21ic.com )。
关闭