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俩种标准,只需要进行简单的配置 ...
随机推荐
- Oracle怎么更改用户名
http://blog.csdn.net/weiwenhp/article/details/8094575 目录(?)[-] 改用户名的用处 怎么改用户名 还要做的工作 想干坏事明文显示密码 很多 ...
- vim的全局替换
本文出自 http://blog.csdn.net/shuangde800 本文是在学习<使用vi编辑器, Lamb & Robbins编著>时在所记的笔记. 本文内容: 基本 ...
- 使用like时left outer join和inner join的区别
--select top 10000 * into #s from search set statistics time on set statistics io on select userId,c ...
- PCAP 抓包
PCAP是一个数据包抓取库, 很多软件都是用它来作为数据包抓取工具的. WireShark也是用PCAP库来抓取数据包的.PCAP抓取出来的数据包并不是原始的网络字节流,而是对其进行从新组装,形成一种 ...
- QuaZip实现多文件打包
项目需求: 在Goldenfarm客户端中当用户选择了本地场景文件,并进行本地场景文件分析后会产生分析结果,分析结果主要包括:贴图纹理.可渲染层等,其中贴图纹理指出了在场景文件中使用到的贴图或其它文件 ...
- android之AlertDialog 点击其他区域自动消失
遇到一个问题记录下来,在开发中使用了AlertDialog,想点击屏幕其他区域的时候让这个dialog消失,一开始不做任何设置,在小米手机可以正常显示,但是在三星中却有问题,后来发现少了一个属性: V ...
- PHP图片文件上传类型限制扩展名限制大小限制与自动检测目录创建。
程序测试网址:http://blog.z88j.com/fileuploadexample/index.html 代码分为两部分: 一部分form表单: <!doctype html> & ...
- chmod -R o+rX /data
When using chmod -R o+rx /data , you set the execute permission on all directories as well as files ...
- CentOS7系统下搭建Jenkins环境
1. 安装JDK yum -y install java 2.安装Ant 添加JPackage源 yum -y install wget wget http://www.jpackage.org/jp ...
- nginx同时监听本机ipv4/ipv6端口
修改nginx.conf配置文件 server { listen ; listen [::]:; } 0.0.0.0 表示本机所有ipv4地址,需要监听特定地址替换即可 [::] 表示本机所有ip ...