想要实现规约转换必须先得理解modbus rtu/ascii/tcp 规约. 我吃了这个亏,一开始就专注于小组的代码, 导致看了半天云里雾里, 随开始找资料, modbus规约那份pdf可以看看, 理解三点:(1) 上下行报文的概念 (2) 正常报文和异常报文 (3) RTU/ASCII报文帧之间的差别. 前面一点那份文档一点没提, 对我这种刚入行的人来说看起来不知所云. 关于理解ASCII模式, 有两份资料值得一看:Modbus读线圈命令详解还有ModBus通信规约, 电力行业的几个参数:遥信,遥测,遥控,定值,电度几个概念还有和功能码的关系需要理顺.
在公司平台上,实现上行报文发送到平台上, 然后编写dll加载到平台程序中, dll程序的主要逻辑就是读取本地数据库sqlite3的表数据作为平台配置, 然后通过各种开发工具,例如sscom, modsim等发送上行报文到平台上, 平台实现接收数据并转发下行报文到工具上.而平台的主要逻辑是接收上行报文,并分析之, 分析方法主要是以下几个:(1)判断报文长度是否合乎规格 (正常报文和错误报文) , 不正确则返回 (2) 判断功能码是否正确(FunctionCode & 0x80 ), 不正确则按照错误报文的方式处理 ,正确按照正常报文分析各数据段 (3) 判断校验码是否正确, CRC/LRC等 (4) 各种错误信息或者功能码打印出来, 能在平台上直观看到.
最重要的还是调试了, 还不是很熟练. 慢慢来....
下行报文中需要将平台上配置信息组装成ASCII帧发下去就需要函数将一个字节的十六进制数转换成两个字节的ascii值, 实现代码如下:
//将hex转换成ascii报文
HT_UCHAR AsciitoHex(HT_UCHAR iFrame)
{
HT_CHAR iDecFrameH[2];
HT_CHAR iDecFrameL[2];
//HT_CHAR cDecFrameH,cDecFrameL;
HT_UCHAR iDecT,iDecH,iDecL;
//hex>>ascii
HT_CHAR iFrameH = (iFrame>>4)&0xF;
HT_CHAR iFrameL = iFrame&0xF;
if(iFrameH > 9) iFrameH = iFrameH -10 +65;
else iFrameH = iFrameH + 48;
if(iFrameL > 9) iFrameL = iFrameL -10 + 65;
else iFrameL = iFrameL +48;
sprintf(iDecFrameH,"%x",iFrameH);
sscanf(iDecFrameH,"%d",&iDecH);
sprintf(iDecFrameL,"%x",iFrameL);
sscanf(iDecFrameL,"%d",&iDecL);
iDecT = ( iDecH << 8 ) | iDecL;
return iDecT;
}
一个月的总结就这么点, 确实有点丢人啊.