C51应用 Modbs Rtu协议实现与KEPServerEx 通信
最近一客户要求使用STC12C5A60S2实现Modbus Rtu协议与KEPServerEx V4.0软件通信,采集单片机P2口每位的状态,设置P0口每位的状态,实现三路AD转换其中一路采集的是C02的浓度,以及使用SHT10获取温度和湿度。KEPServerEx V4.0使用TCP通信,而单片机使用的是串口RS232通信,所以增加了TCP转RS232的模块。
本程序相对比较简单,STH10有现成的代码,AD转换直接官方提供的程序,主要需要实现的就是Modbus RTU通信协议的实现。根据对方的要求,P0,P2口的设置需要一位一位的读取或设置,如果按Modbus的内容,可以使用设置线圈状态和读取线圈状态,而AD和温度湿度获取需要读取寄存器,这样一来就需要实现3个功能即对线圈设置线圈就读取寄存器。为了减少功能的实现数量,读取线圈和读取AD等数据都使用读取寄存器的03功能,为了方便能够位下位机传数据所以设置线圈使用06写单个寄存器。这样就只需要实现2个功能即可。在我的前一篇博客中已经介绍了使用单片机与PC进行通信,当时实现了03功能,本次只需要实现06功能即可。
06功能码的通信格式:
上位机发送数据格式 地址,功能码,数据地址高位,数据地址低位,数据高位,数据低位,CRC低位,CRC 高位,
下位机回应数据格式 地址,功能码,数据地址高位,数据地址低位,数据高位,数据低位,CRC低位,CRC 高位,
所以接收到上位机的命令后,只需要判断地址是否为本机地址,功能码是否为相应的06即可,如果是则对后面的数据进行解析,将相应的数据写入对应的寄存器即可。由于上位机每次发来的是对应P0口某一位的状态,所以需要有8个字节来对应8个位。而返回的信息就比较简单了,如果没有错误就直接将接收到的命令返回即可。
unsigned char createRespond_M_6(unsigned char *respondMessage,unsigned char* _messageReceived ,unsigned int* _registerData)
{
unsigned char i;
unsigned char numberOfPoints = ;
unsigned char _slaveAddress = ;
unsigned char bytesToSend = ;
unsigned char startAddress=;
unsigned char crcCalculation[]={,,}; unsigned int Address = _messageReceived[]; //将其转换为int型,由于使用的寄存器地址最多1,20个,所以只取低位即可,高位永远为0,丢弃 _registerData[Address ] = _messageReceived[]<<;
_registerData[Address ] |= _messageReceived[]; for(i = ; i < ; i ++)
{
respondMessage[i] = _messageReceived[i];
} return ;
}
由于在通信中要么是读取寄存器的值,要么是读取寄存器的做(其实就是开辟的一个整型数组),那么我们要实现设置P0口的状态和获取P2口的状态就需要在程序中根据需要,不停地更新寄存器的值或者从寄存器中读取数据写入到相应的端口即可,当然AD和温度湿度也是一样的道理。
在主函数的整个while大循环中加入以下代码:
P2 = 0XFF;
//八路输入由P2口决定,随时更新其寄存器的值,若主机要返回,则直接返回相应寄存器的值 registerData[] = P2&0x01; registerData[] = (P2&0x02)>>;
registerData[] = (P2&0x04)>>;
registerData[] = (P2&0x08)>>;
registerData[] = (P2&0x10)>>;
registerData[] = (P2&0x20)>>;
registerData[] = (P2&0x40)>>;
registerData[] = (P2&0x80)>>; //八路输出由P0输出,只需要由主机设置寄存器值即可更新寄存器的值 。
P0_0 = registerData[]&0x01 ; P0_1 = registerData[]&0x01 ;
P0_2 = registerData[]&0x01 ;
P0_3 = registerData[]&0x01 ;
P0_4 = registerData[]&0x01 ;
P0_5 = registerData[]&0x01 ;
P0_6 = registerData[]&0x01 ;
P0_7 = registerData[]&0x01 ; GetTempAndHumi(); //检查串口数据并使用ModBus协议进行检验,正确则返回数据,返回的数据在registerData,可以在其他的函数中改变相应的值。
CheckModBusAndRespondToHost();
对于AD的数据,由于AD的结果是使用的中断方式而不是查询所以在主循环中就看不到了,在中断函数中直接设置寄存器的值,在需要时直接返回。这部分使用了10的AD转换, 所以需要做相应的转换:代码如下:
void adc_isr() interrupt using
{
ADC_CONTR &= !ADC_FLAG; //Clear ADC interrupt flag registerData[ch+] = ADC_RES<<;
registerData[ch+] |= ADC_LOW2<<;
registerData[ch+] = registerData[ch+] >>; //if you want show 10-bit result, uncomment next line
// SendData(ADC_LOW2); //Show ADC low 2-bit result if (++ch > ) ch = ; //switch to next channel
ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ADC_START | ch;
}
在这里只使用了3路AD转换。
在使用Modbus RTU数据进行寄存器的读写时需要注意的是在上位机比如组态王、KEPServerEx等,在设置寄存器地址时是从1开始,而发送的命令是从0开始,
读写寄存器都位于4区,所以我们 设置的地址一般都为40001.....40002等,对应寄存器0 1。
以下是在KEPServerEx设置的每个端口即AD等所对应的寄存器地址,
测试结果:
在这里AD全为1023是因为开发板全部接了上拉所以都为1023。
在这次开发完成后,客户反应AD测量结果不准确,由于我并没有在客户的现场,无法得知道具体如何,所以我的第一反应是STC12C5A60S2的AD基准电源使用的是VCC,可能是VCC电源与5V差距比较远而引起的,建议客户增加电池做为基准或者提高电源的精度,但对方说比较困难。后来我问他如何发现不准确的,他说是和别的系统测量的结果进行比较的,并且给我发来了他们的传感器资料,我看了一下资料,突然发现传感器输出是0-2v,而STC的AD是0-5V,一下就明白了这中间的问题,让客户将结果X2.5后就正常了。
C51应用 Modbs Rtu协议实现与KEPServerEx 通信的更多相关文章
- ModBus通信协议的【Modbus RTU 协议使用汇总】
1.RTU模式 当控制器设为在Modbus网络上以RTU(远程终端单元)模式通信,在消息中的每个8Bit字节包含两个4Bit的十六进制字符.这种方式的主要优点是:在同样的波特率下,可比ASCII方式传 ...
- Modbus RTU 协议使用汇总
原创地址:https://blog.csdn.net/u012166958/article/details/64920144 标准的Modbus 口是使用RS-232C 兼容串行接口,它定义了连接口的 ...
- Modbus TCP和Modbus Rtu协议的区别 转
http://blog.csdn.net/educast/article/details/9177679 Modbus rtu和Modbus tcp两个协议的本质都是MODBUS协议,都是靠MOD ...
- 调试备忘录-RS485 MODBUS RTU协议简述
目录--点击可快速直达 目录 写在前面 先简单说下什么是MODBUS? 参考文章 写在前面 最近在做和物联网有关的小项目,有一个传感器通讯用到了RS485 MODBUS RTU协议,所以就写个随笔记录 ...
- SSL、TLS协议格式、HTTPS通信过程、RDP SSL通信过程(缺heartbeat)
SSL.TLS协议格式.HTTPS通信过程.RDP SSL通信过程 相关学习资料 http://www.360doc.com/content/10/0602/08/1466362_30787868 ...
- winform 客户端采用HTTP协议与服务端通信
本来从来没有仔细研究过Http协议,今天因为公司业务需求,调试了半天,终于现在会Winform用Http协议与服务端通信了,其中常用的有POST和Get方式: 仔细看了人人网和新浪等大部分都是采用GE ...
- winform 客户端 HTTP协议与服务端通信以及解决中文乱码
本来从来没有仔细研究过Http协议,今天因为公司业务需求,调试了半天,终于现在会Winform用Http协议与服务端通信了,其中常用的有POST和Get方式: 仔细看了人人网和新浪等大部分都是采用GE ...
- c#基于TCP/IP、CIP协议的欧姆龙PLC通信
一.关于CIP协议 CIP通信是Common Industrial Protocl(CIP)的简称,它是一个点到点的面向对象协议,能够实现工业器件(传感器,执行器)之间的连接,和高等级的控制器之间的连 ...
- modbus rtu 协议转DLT645-2007和DLT645-1997电表协议转换器定制,
现场会碰到现场数据为Modbus协议,但是后台系统为DLT645协议系统,本模块支持将工业ModbusRtu协议转换为电表国标协议DLT645协议,支持1997和2007俩种标准,只需要进行简单的配置 ...
随机推荐
- telnet的使用
1.要打开 telnet 不是内部或外部 命令 解决方案: 程序添加删除功能,添加即可 或法二 C:\WINDOWS\system32\telnet.exe (或用C:\WINDOWS\system3 ...
- 【转】Java中equals和==的区别
[转]Java中equals和==的区别 java中的数据类型,可分为两类: 1.基本数据类型,也称原始数据类型.byte,short,char,int,long,float,double,boole ...
- WisDom.Net 框架设计(六) license
WisDom.Net-license 1.为啥要用license license (许可证) 顾名思义就是说我的软件只能给在指定的机器上使用.毕竟很多项目都不是免费的,(说句题外话,其实我用的也 ...
- [上传下载] C#修改DownLoadHelper上传下载帮助类 (转载)
点击下载 DownLoadHelper.rar 主要功能如下 /// <summary> /// 输出硬盘文件,提供下载 支持大文件.续传.速度限制.资源占用小 /// </summ ...
- .NET平台下几种SOCKET模型的简要性能供参考
转载自:http://www.cnblogs.com/asilas/archive/2006/01/05/311309.html .NET平台下几种SOCKET模型的简要性能供参考 这个内容在cnbl ...
- Android EditText的输入监听,输入字符的动态获取
http://itindex.net/detail/38974-android-edittext-%E7%9B%91%E5%90%AC 有时候我们可能会用到时时的监听EditText输入字符的时时监听 ...
- T-SQL切割字符串方法小结 2
有表tb, 如下: id value ----------- ----------- 1 aa,bb 2 aaa,bbb,ccc 欲按id,分拆value列, 分拆后结果如下: id value -- ...
- linux du 显示目录下的各个子目录的大小
use command du display estimate file space usage size of subdirectories [oracle@ahjcyl-db backup]$ ...
- Java-jfree报表(学习整理)----饼状图、柱状图、折线统计图
1.使用的报表工具: jfree报表 2.下载网址: http://www.jfree.org/ 下载之后先解压:如下图 下载后:需要的jar包!如下图: 打开:找到以下的两个jar包 再导入开发项目 ...
- Visual EmbedLinux Tools:让vs支持嵌入式Linux开发(转)
转自:http://blog.csdn.net/lights_joy/article/details/49499743 1 什么是Visual EmbedLinux Tools Visual Embe ...