组态王及modbus通信课程设计.docx
《组态王及modbus通信课程设计.docx》由会员分享,可在线阅读,更多相关《组态王及modbus通信课程设计.docx(39页珍藏版)》请在冰豆网上搜索。
组态王及modbus通信课程设计
测控网络课程设计
一、实践要求
本次实践以开发DCS测控系统为最终目的,要求掌握DCS测控系统的工作原理,学习组态王工控组态软件的使用方法,根据要求完成工程组态;掌握MODBUS通信协议的原理,开发具有MODBUS通讯功能的智能仪表,最终完成和组态工程之间的通讯。
二、实践内容
分为两大部分:
1、组态王基本操作2、MODBUS通讯
具体内容:
(1)熟悉组态王软件安装,基本开发环境,采用构建简单的工程(采用仿真数据和设备,工程应包含PID功能),计划时间1天;
(2)根据罐区工艺的要求,完成相应的组态工程,实现对原油储罐的监控,计划时间2天;
(3)掌握MODBUS通讯协议的工作原理,在MSP430F5438单片机上编程实现MODBUS客户端服务程序,要求通过串行口将现场的温度、泵状态、流量等参数上传到上位机上,计划时间3天。
(4)在单片机上编程实现流量、温度上下限及仪表地址和波特率等参数设置功能,同时能从上位机对仪表参数进行设置,计划时间2天。
(5)优化设计,要求当出现通讯错误时在上位机和单片机上都要做出相应的反应,计划时间0.5天。
(6)
上位机采用高级语言编程,实现对现场智能仪表的控制。
熟悉现场总线测控网络系统,搭建PROFIBUS网络,实现对ET200S和S7-200的控制。
组态王部分
一、设计要求
根据罐区工艺的要求,完成相应的组态工程,实现对原油储罐的监控。
1、罐区工艺流程图
2-储油罐进口电动阀;3-储油罐排污电动阀;4-储油罐出口电动阀;5-泵
图1:
罐区工艺流程图
2、具体要求
(1)监测各罐的液位(0-20m)/(0-1m)/温度(0-100度)(现场仪表4-20mA输出)。
(2)根据各罐液位控制各罐出口电动阀(H>16m,关进口阀,选择最低液位的罐进油;H<2m,关出口阀,选择最高液位的罐出油),手动遥控排污阀。
液位H>15.5m高报警,H>17m高高报警;
液位H<2m低报警,H<1.5m低低报警。
界位>1m高报警,界位>1.5m高高报警;
界位<0.5m低报警,H<0.2m低低报警;
(3)启动泵组设置出入口流量(100M3/h,200M3/h,250M3/h)
二、设计内容
(一)组态数据库:
数据库-----数据词典
(二)组态画面
画面1:
工艺流程总画面
对画面的基本说明:
主要功能:
对油罐液位的监测。
泵总开关控制进口的3个泵的总开和总关;
泵总关闭控制出口的3个泵的总关和总开;
当同时按下泵提示和某一个泵的按钮,显示该泵的详细信息;
液位报警和界位报警时记录相应的报警事件;
液位实时和历史曲线记录油罐液位的变化情况。
画面2:
各泵弹出式放大画面(包括参状态/型号等),点击总画面上的泵弹出此画面
1、编写事件命令语言:
当同时按下泵提示和某一个泵的按钮,显示该泵的参数信息。
2、弹出画面
画面3:
液位/界位报警画面
报警设置:
低低、低、高、高高报警值设置:
液位报警画面:
画面4:
液位/温度/界位各一个实时趋势图和历史趋势图
实时趋势图:
选择工具箱中的
工具,在画面上绘制一实时趋势曲线窗口。
在曲线定义选项卡中选择要实时反映的变量。
历史趋势图:
对于要以历史趋势曲线形式显示的变量,必须设置变量的记录属性。
在“定义变量”对话框中单击“记录和安全区”属性页,将不记录改为数据变化记录,变化灵敏为:
0。
在工程浏览器窗口左侧的“工程目录显示区”中双击“系统配置”中的“历史数据记录”选项,弹出“历史记录配置”对话框。
实时和历史趋势图:
报表画面(液位,温度,界位)
报表分为实时数据报表和历史数据报表。
(3)优化设置
1、组态操作权限
优先级分1~999级,1级最低999级最高。
每个操作者的优先级别只有一个。
系统安全区共有64个,用户在进行配置时。
每个用户可选择除“无”以外的多个安全区,即一个用户可有多个安全区权限。
设置油罐用户组,将管理员、操作员看成用户,并设置管理员优先级最高,并设置相应的密码。
配置运行现象登陆界面
2、通过链接切换画面
增加报警画面、趋势图、报表画面,通过右侧链接
(4)画面命令语言
变量说明:
g1、g2、g3、g4代表每个油罐的液位,in代表泵总开,out代表泵总关,in1、in2、in3、in4代表每个油罐的入口阀门,out1、out2、out3、out4代表每个油罐的出口阀门,clear1、clear2、clear3、clear4代表手动排污阀。
bengin1,2,3和bengout1,2,3代表进口泵和出口泵。
num代表泵输入总流量的比
num=bengin1*1+bengin2*2+bengin3*2.5;
num1代表泵输出总流量的比
num1=bengout1*1+bengout2*2+bengout3*2.5;
设置每个油罐跟液位相关的系数值
xishu1=0.25;
xishu2=0.2;
xishu3=0.15;
xishu4=0.3;
if(in==1&&num>0)
{
如果油罐1液位最低,增加油罐1的液位
if(g1<=g2&&g1<=g3&&g1<=g4&&g1<16)
in1=1;
in2=0;
in3=0;
in4=0;
g1=g1+num*xishu1;
}
else
如果油罐2液位最低,增加油罐2的液位
if(g2{in1=0;in2=1;in3=0;in4=0;g2=g2+xishu2*num;}else{如果油罐3液位最低,增加油罐3的液位if(g3{in1=0;in2=0;in3=1;in4=0;g3=g3+xishu3*num;}else{如果油罐4液位最低,增加油罐4的液位if(g4{in1=0;in2=0;in3=0;in4=1;g4=g4+xishu4*num;}}}}}if(out==1&&num1>0){如果油罐1液位最高,降低油罐1的液位if(g1>=g2&&g1>=g3&&g1>=g4&&g1>2){out1=1;out2=0;out3=0;out4=0;g1=g1-xishu1*num1;}else{如果油罐2液位最高,降低油罐2的液位if(g2>=g1&&g2>=g3&&g2>=g4&&g2>2){out1=0;out2=1;out3=0;out4=0;g2=g2-xishu2*num1;}else{如果油罐3液位最高,降低油罐3的液位if(g3>=g1&&g3>=g2&&g3>=g4&&g3>2){out1=0;out2=0;out3=1;out4=0;g3=g3-xishu3*num1;}else{如果油罐4液位最高,降低油罐4的液位if(g4>=g1&&g4>=g2&&g4>=g3&&g4>2){out1=0;out2=0;out3=0;out4=1;g4=g4-xishu4*num1;}}}}}if(clear1==1||clear2==1||clear3==1||clear4==1)手动排污{g1=g1-clear1*0.1;g2=g2-clear2*0.1;g3=g3-clear3*0.1;g4=g4-clear4*0.1;//jiewei1=jiewei1-0.1*clear1;//jiewei2=jiewei2-0.1*clear2;//jiewei3=jiewei3-0.1*clear3;//jiewei4=jiewei4-0.1*clear4;}如果液位大于16,关闭相应的进口阀if(g1>=16){in1=0;}if(g2>=16){in2=0;}if(g3>=16){in3=0;}if(g4>=16){in4=0;}如果液位小于2,关闭相应出口阀if(g1<=2){out1=0;}if(g2<=2){out2=0;}if(g3<=2){out3=0;}if(g4<=2){out4=0;}if(num==0){in1=0;in2=0;in3=0;in4=0;}if(num1==0){out1=0;out2=0;out3=0;out4=0;}(5)运行总画面(6)与PLC通信设置在工程浏览器中选择设备—com1—新建,如下图,配置com口跟PLC连接。设置bengin1,2,3和bengout1,2,3分别与Q0.0等相联系,可观察到PLC输出指示灯会随着这些变量的改变和改变。三、组态王部分总结组态王是组态王软件是一种通用的工业监控软件,它融过程控制设计、现场操作以及工厂资源管理于一体,将一个企业内部的各种生产系统和应用以及信息交流汇集在一起,实现最优化管理,操作方便,界面美观。组态王软件结构由工程管理器、工程浏览器及运行系统三部分构成。通过这次课程设计,我们学会了如何建立一个组态王工程,如何设计界面,编写命令语言、以及报警事件、趋势曲线和报表的相关制作,权限的设置,以及与实际设备的简单通信,通过本次实习,我想在以后工作中,我们会更好的应用此例软件,完成工业监控。智能仪表部分一、MODBUSASCII和MODBUSRTU通讯协议简介Modbus协议是应用于电子控制器上的一种通用语言。通过此协议,控制器相互之间、控制器经由网络(例如以太网)和其它设备之间可以通信。此协议定义了一个控制器能认识使用的消息结构,而不管它们是经过何种网络进行通信的。它描述了控制器请求访问其它设备的过程,如果回应来自其它设备的请求,以及怎样侦测错误并记录。它制定了消息域格局和内容的公共格式。两种串行传输模式:RTU模式和ASCII模式。RTU传输模式:当设备使用RTU(RemoteTerminalUnit)模式在Modbus串行链路通信,报文中每个8位字节含有两个4位十六进制字符。这种模式的主要优点是较高的数据密度,在相同的波特率下比ASCII模式有更高的吞吐率。每个报文必须以连续的字符流传送。RTU模式每个字节(11位)的格式为:编码系统:8位二进制,报文中每个8位字节含有两个4位十六进制字符(0–9,A–F。)BitsperByte:1起始位,8数据位,首先发送最低有效位,1位作为奇偶校验,1停止位。ASCII传输模式当Modbus串行链路的设备被配置为使用ASCII(AmericanStandardCodeforInformationInterchange)模式通信时,报文中的每个8位子节以两个ASCII字符发送。ASCII模式每个字节(10位)的格式为:编码系统:十六进制,ASCII字符0-9,A-F。报文中每个ASCII字符含有1十六进制字符。BitsperByte:1起始位,7数据位,首先发送最低有效位,1位奇偶校验,1停止位。03读保持寄存器上位机发送数据格式:“:”ADDRESS03ADDRHADDRLNUMHNUMLLRC0X0D0X0A正确时变频器返回数据格式:“:“ADDRESS03BYTECOUNTDATA1DATA2DATA3DATANLRC0D0A06写单个保持寄存器值上位机发送数据格式:“:“ADDRESS06ADDRHADDRLDATAHDATALLRC0X0D0X0A正确时变频器返回数据格式:“:“ADDRESS06ADDRHADDRLDATAHDATALLRC0X0D0X0A二、MODBUSASCII编程以及与组态王通信1、变量定义unsignedcharERR[21]="InputLRCERROR!";//出错时显示字符unsignedcharRX[32];//单片机接受数据数组unsignedcharTX[32];//03功能时单片机发送数据数组unsignedcharTX6[32];//06功能时单片机发送数据数组unsignedcharBuf[10];//存储数据的数组unsignedintflag;//上位机发送数据标志位unsignedintflag1;//单片机应答数据标志位unsignedintflow;//流量值unsignedinttemperature;//温度值unsignedcharLRC;//上位机发送数据校验码unsignedcharLRCt;//单片机应答数据校验码2、通过UART中断完成上位机给单片机发送编程思路:通过UART中断,实现上位机给单片机发送数据,当单片机接受到:,表示上位机要向单片机发送指令,相应标志位置1,当再次发生中断时,就开始接受数据,同时存入RX[32]的数组里,直到接收到回车换行符,则发送命令结束。此时发送标志位置1,进入应答程序。#pragmavector=USCI_A1_VECTOR__interruptvoidUSCI_A1_ISR(void){while(!(UCA1IFG&UCTXIFG));//判断是否发送完毕if(UCA1RXBUF==':')//:为起始标志,如果开始,标志位flag置位{flag=1;}if(flag==1)//当标志位flag置位说明发送命令开始,开始接受命令数据{RX[0]=':';if(UCA1RXBUF!=0x0D&&UCA1RXBUF!=0x0A)//只要不是回车换行符,就依次将数据存入接受数组RX中,同时计数变量tempnumb加1{tempnumb++;RX[tempnumb]=UCA1RXBUF;}if(UCA1RXBUF==0x0D)//若是回车{tempnumb++;RX[tempnumb]='D';}if(UCA1RXBUF==0x0A)//若是换行{tempnumb++;RX[tempnumb]='A';flag=0;//接受标志位清零flag1=1;//发送标志位置1TTXX();//调用发送数据函数}}}3、单片机通过UART中断向上位机发送应答指令编程思路:先计算上位机发送数据的校验码,如果和发送的校验码相同,单片机再应答。设置寄存器地址0001,存储流量数据;设置寄存器0002,存储温度数据。然后判断是03号功能还是06号功能,若是03号功能,按照相应的格式发送数据,若是06号功能,按照命令更改数据,并返回应答命令。voidTTXX(){inti;intj;unsignedintb;unsignedintc;unsignedintd;In_LRC();//计数上位机发送命令校验码if(RX[8]=='1')//如果地址为寄存器0001,发送流量数据shitohex(flow);if(RX[8]=='2')//如果地址位寄存器0002,发送温度数据shitohex(temperature);if(RX[3]=='0'&&RX[4]=='3')//如果是03号功能{if((LRCHi==RX[tempnumb-3])&&(LRCLo==RX[tempnumb-2]))//如果上位机发送校验码正确{for(b=0;b<=4;b++){TX[b]=RX[b];}temp=asciitohex(RX[tempnumb-4]);//计算单片机要发送数据的字节数TX[5]=hextoascii(((temp*2)>>4)&0x0F);TX[6]=hextoascii((temp*2)&0x0F);for(i=0;i{TX[7+i]=hextoascii(Buf[i]);//要发送的数据TX[8+i]=hextoascii(Buf[i+1]);}tempnumt=7+i;//统计数据长度,用于计算校验码Out_LRC();//计算单片机发送数据校验码TX[7+i]=LRCtHi;TX[8+i]=LRCtLo;TX[9+i]=0x0D;TX[10+i]=0x0A;for(j=0;j<=(10+i);j++)//单片机发送数据{while(!(UCA1IFG&UCTXIFG));//判断是否发送完毕UCA1TXBUF=TX[j];}}else//如果校验码不正确,返回错误代码InputLRCERROR!只能通过串口调试看到{ERR[19]='8';ERR[20]=TX[4];for(d=0;d<=20;d++){while(!(UCA1IFG&UCTXIFG));//判断是否发送完毕UCA1TXBUF=ERR[d];}}}elseif(RX[3]=='0'&&RX[4]=='6')//如果是06号功能{for(c=0;c<=tempnumb;c++){TX6[c]=RX[c];while(!(UCA1IFG&UCTXIFG));//判断是否发送完毕UCA1TXBUF=TX6[c];}selflow(TX6[10]);//设置流量值seltemp(TX6[11]);//设置温度值}flag1=0;//单片机发送标志位清零tempnumb=0;//上位机发送数据计算值清零}4、辅助模块部分(1)、LRC校验模块编程思路:LRC的计算,对报文中的所有的连续8位字节相加,忽略任何进位,然后求出其二进制补码。unsignedchar*auchMsg;指向含有用于生成LRC的二进制数据报文缓冲区的指针,unsignedshortusDataLen;报文缓冲区的字节数.unsignedcharMODBUS_LRC(unsignedchar*auchMsg,unsignedshortusDataLen){unsignedcharuchLRC=0;//LRC初始化while(usDataLen--)//完成整个报文缓冲区uchLRC+=*auchMsg++;//缓冲区字节相加,无进位return((unsignedchar)(-((char)uchLRC)));//返回二进制补码}(2)发送和应答校验码计数程序voidIn_LRC(){unsignedinta;for(a=1;a<(tempnumb-3);a+=2){tempRX[(a-1)/2]=(asciitohex(RX[a])<<4)|asciitohex(RX[a+1]);}LRC=MODBUS_LRC(&tempRX[0],(tempnumb-4)/2);//进行LRC效验计算LRCHi=hextoascii((LRC>>4)&0x0F);LRCLo=hextoascii(LRC&0x0F);}voidOut_LRC(){unsignedintc;for(c=1;c{tempTX[(c-1)/2]=(asciitohex(TX[c])<<4);tempTX[(c-1)/2]=(asciitohex(TX[c])<<4)|asciitohex(TX[c+1]);}LRCt=MODBUS_LRC(&tempTX[0],(tempnumt-1)/2);//进行LRC效验计算LRCtHi=hextoascii((LRCt>>4)&0x0F);LRCtLo=hextoascii(LRCt&0x0F);}(3)进制之间转换程序由于发送和读取的数据是字符,而寄存器中数据多按照十六进制存储,故需要各种进制间的相互转换。//十六进制数转换为ASCII码unsignedcharhextoascii(unsignedcharhex){if(hex<=0x09)returnhex+0x30;elsereturnhex+0x37;}//ASCII码转换为十六进制的数unsignedcharasciitohex(unsignedcharascii){if(ascii<=0x39)returnascii-0x30;elsereturnascii-0x37;}//十进制转十六进制,由于组态王通信时会自动将十六进制数转换位十进制数,因此需要在单片机内将十进制数转换位十六进制数,这样组态王读到的就是十进制的数据。unsignedcharshitohex(unsignedintshi){inti,b,d,c;inta=0;d=4;charshiliu[10];while(shi)//shi代表相应的十进制数{c=shi%16;//每次除以16取余求得相应的十六进制数shi=shi/16;shiliu[a]=c;a++;}for(i=a;i<=4;i++)//得到的数据首位倒置,才是要求的十六进制数{shiliu[i]=0;}for(b=0;b<4;b++){d--;Buf[b]=shiliu[d];}return0;}(4)波特率,流量、温度的设置//选定流量voidselflow(unsignedcharselflow){switch(selflow){case'0':flow=100;break;case'1':flow=1799;break
in1=0;
in2=1;
g2=g2+xishu2*num;
如果油罐3液位最低,增加油罐3的液位
if(g3{in1=0;in2=0;in3=1;in4=0;g3=g3+xishu3*num;}else{如果油罐4液位最低,增加油罐4的液位if(g4{in1=0;in2=0;in3=0;in4=1;g4=g4+xishu4*num;}}}}}if(out==1&&num1>0){如果油罐1液位最高,降低油罐1的液位if(g1>=g2&&g1>=g3&&g1>=g4&&g1>2){out1=1;out2=0;out3=0;out4=0;g1=g1-xishu1*num1;}else{如果油罐2液位最高,降低油罐2的液位if(g2>=g1&&g2>=g3&&g2>=g4&&g2>2){out1=0;out2=1;out3=0;out4=0;g2=g2-xishu2*num1;}else{如果油罐3液位最高,降低油罐3的液位if(g3>=g1&&g3>=g2&&g3>=g4&&g3>2){out1=0;out2=0;out3=1;out4=0;g3=g3-xishu3*num1;}else{如果油罐4液位最高,降低油罐4的液位if(g4>=g1&&g4>=g2&&g4>=g3&&g4>2){out1=0;out2=0;out3=0;out4=1;g4=g4-xishu4*num1;}}}}}if(clear1==1||clear2==1||clear3==1||clear4==1)手动排污{g1=g1-clear1*0.1;g2=g2-clear2*0.1;g3=g3-clear3*0.1;g4=g4-clear4*0.1;//jiewei1=jiewei1-0.1*clear1;//jiewei2=jiewei2-0.1*clear2;//jiewei3=jiewei3-0.1*clear3;//jiewei4=jiewei4-0.1*clear4;}如果液位大于16,关闭相应的进口阀if(g1>=16){in1=0;}if(g2>=16){in2=0;}if(g3>=16){in3=0;}if(g4>=16){in4=0;}如果液位小于2,关闭相应出口阀if(g1<=2){out1=0;}if(g2<=2){out2=0;}if(g3<=2){out3=0;}if(g4<=2){out4=0;}if(num==0){in1=0;in2=0;in3=0;in4=0;}if(num1==0){out1=0;out2=0;out3=0;out4=0;}(5)运行总画面(6)与PLC通信设置在工程浏览器中选择设备—com1—新建,如下图,配置com口跟PLC连接。设置bengin1,2,3和bengout1,2,3分别与Q0.0等相联系,可观察到PLC输出指示灯会随着这些变量的改变和改变。三、组态王部分总结组态王是组态王软件是一种通用的工业监控软件,它融过程控制设计、现场操作以及工厂资源管理于一体,将一个企业内部的各种生产系统和应用以及信息交流汇集在一起,实现最优化管理,操作方便,界面美观。组态王软件结构由工程管理器、工程浏览器及运行系统三部分构成。通过这次课程设计,我们学会了如何建立一个组态王工程,如何设计界面,编写命令语言、以及报警事件、趋势曲线和报表的相关制作,权限的设置,以及与实际设备的简单通信,通过本次实习,我想在以后工作中,我们会更好的应用此例软件,完成工业监控。智能仪表部分一、MODBUSASCII和MODBUSRTU通讯协议简介Modbus协议是应用于电子控制器上的一种通用语言。通过此协议,控制器相互之间、控制器经由网络(例如以太网)和其它设备之间可以通信。此协议定义了一个控制器能认识使用的消息结构,而不管它们是经过何种网络进行通信的。它描述了控制器请求访问其它设备的过程,如果回应来自其它设备的请求,以及怎样侦测错误并记录。它制定了消息域格局和内容的公共格式。两种串行传输模式:RTU模式和ASCII模式。RTU传输模式:当设备使用RTU(RemoteTerminalUnit)模式在Modbus串行链路通信,报文中每个8位字节含有两个4位十六进制字符。这种模式的主要优点是较高的数据密度,在相同的波特率下比ASCII模式有更高的吞吐率。每个报文必须以连续的字符流传送。RTU模式每个字节(11位)的格式为:编码系统:8位二进制,报文中每个8位字节含有两个4位十六进制字符(0–9,A–F。)BitsperByte:1起始位,8数据位,首先发送最低有效位,1位作为奇偶校验,1停止位。ASCII传输模式当Modbus串行链路的设备被配置为使用ASCII(AmericanStandardCodeforInformationInterchange)模式通信时,报文中的每个8位子节以两个ASCII字符发送。ASCII模式每个字节(10位)的格式为:编码系统:十六进制,ASCII字符0-9,A-F。报文中每个ASCII字符含有1十六进制字符。BitsperByte:1起始位,7数据位,首先发送最低有效位,1位奇偶校验,1停止位。03读保持寄存器上位机发送数据格式:“:”ADDRESS03ADDRHADDRLNUMHNUMLLRC0X0D0X0A正确时变频器返回数据格式:“:“ADDRESS03BYTECOUNTDATA1DATA2DATA3DATANLRC0D0A06写单个保持寄存器值上位机发送数据格式:“:“ADDRESS06ADDRHADDRLDATAHDATALLRC0X0D0X0A正确时变频器返回数据格式:“:“ADDRESS06ADDRHADDRLDATAHDATALLRC0X0D0X0A二、MODBUSASCII编程以及与组态王通信1、变量定义unsignedcharERR[21]="InputLRCERROR!";//出错时显示字符unsignedcharRX[32];//单片机接受数据数组unsignedcharTX[32];//03功能时单片机发送数据数组unsignedcharTX6[32];//06功能时单片机发送数据数组unsignedcharBuf[10];//存储数据的数组unsignedintflag;//上位机发送数据标志位unsignedintflag1;//单片机应答数据标志位unsignedintflow;//流量值unsignedinttemperature;//温度值unsignedcharLRC;//上位机发送数据校验码unsignedcharLRCt;//单片机应答数据校验码2、通过UART中断完成上位机给单片机发送编程思路:通过UART中断,实现上位机给单片机发送数据,当单片机接受到:,表示上位机要向单片机发送指令,相应标志位置1,当再次发生中断时,就开始接受数据,同时存入RX[32]的数组里,直到接收到回车换行符,则发送命令结束。此时发送标志位置1,进入应答程序。#pragmavector=USCI_A1_VECTOR__interruptvoidUSCI_A1_ISR(void){while(!(UCA1IFG&UCTXIFG));//判断是否发送完毕if(UCA1RXBUF==':')//:为起始标志,如果开始,标志位flag置位{flag=1;}if(flag==1)//当标志位flag置位说明发送命令开始,开始接受命令数据{RX[0]=':';if(UCA1RXBUF!=0x0D&&UCA1RXBUF!=0x0A)//只要不是回车换行符,就依次将数据存入接受数组RX中,同时计数变量tempnumb加1{tempnumb++;RX[tempnumb]=UCA1RXBUF;}if(UCA1RXBUF==0x0D)//若是回车{tempnumb++;RX[tempnumb]='D';}if(UCA1RXBUF==0x0A)//若是换行{tempnumb++;RX[tempnumb]='A';flag=0;//接受标志位清零flag1=1;//发送标志位置1TTXX();//调用发送数据函数}}}3、单片机通过UART中断向上位机发送应答指令编程思路:先计算上位机发送数据的校验码,如果和发送的校验码相同,单片机再应答。设置寄存器地址0001,存储流量数据;设置寄存器0002,存储温度数据。然后判断是03号功能还是06号功能,若是03号功能,按照相应的格式发送数据,若是06号功能,按照命令更改数据,并返回应答命令。voidTTXX(){inti;intj;unsignedintb;unsignedintc;unsignedintd;In_LRC();//计数上位机发送命令校验码if(RX[8]=='1')//如果地址为寄存器0001,发送流量数据shitohex(flow);if(RX[8]=='2')//如果地址位寄存器0002,发送温度数据shitohex(temperature);if(RX[3]=='0'&&RX[4]=='3')//如果是03号功能{if((LRCHi==RX[tempnumb-3])&&(LRCLo==RX[tempnumb-2]))//如果上位机发送校验码正确{for(b=0;b<=4;b++){TX[b]=RX[b];}temp=asciitohex(RX[tempnumb-4]);//计算单片机要发送数据的字节数TX[5]=hextoascii(((temp*2)>>4)&0x0F);TX[6]=hextoascii((temp*2)&0x0F);for(i=0;i{TX[7+i]=hextoascii(Buf[i]);//要发送的数据TX[8+i]=hextoascii(Buf[i+1]);}tempnumt=7+i;//统计数据长度,用于计算校验码Out_LRC();//计算单片机发送数据校验码TX[7+i]=LRCtHi;TX[8+i]=LRCtLo;TX[9+i]=0x0D;TX[10+i]=0x0A;for(j=0;j<=(10+i);j++)//单片机发送数据{while(!(UCA1IFG&UCTXIFG));//判断是否发送完毕UCA1TXBUF=TX[j];}}else//如果校验码不正确,返回错误代码InputLRCERROR!只能通过串口调试看到{ERR[19]='8';ERR[20]=TX[4];for(d=0;d<=20;d++){while(!(UCA1IFG&UCTXIFG));//判断是否发送完毕UCA1TXBUF=ERR[d];}}}elseif(RX[3]=='0'&&RX[4]=='6')//如果是06号功能{for(c=0;c<=tempnumb;c++){TX6[c]=RX[c];while(!(UCA1IFG&UCTXIFG));//判断是否发送完毕UCA1TXBUF=TX6[c];}selflow(TX6[10]);//设置流量值seltemp(TX6[11]);//设置温度值}flag1=0;//单片机发送标志位清零tempnumb=0;//上位机发送数据计算值清零}4、辅助模块部分(1)、LRC校验模块编程思路:LRC的计算,对报文中的所有的连续8位字节相加,忽略任何进位,然后求出其二进制补码。unsignedchar*auchMsg;指向含有用于生成LRC的二进制数据报文缓冲区的指针,unsignedshortusDataLen;报文缓冲区的字节数.unsignedcharMODBUS_LRC(unsignedchar*auchMsg,unsignedshortusDataLen){unsignedcharuchLRC=0;//LRC初始化while(usDataLen--)//完成整个报文缓冲区uchLRC+=*auchMsg++;//缓冲区字节相加,无进位return((unsignedchar)(-((char)uchLRC)));//返回二进制补码}(2)发送和应答校验码计数程序voidIn_LRC(){unsignedinta;for(a=1;a<(tempnumb-3);a+=2){tempRX[(a-1)/2]=(asciitohex(RX[a])<<4)|asciitohex(RX[a+1]);}LRC=MODBUS_LRC(&tempRX[0],(tempnumb-4)/2);//进行LRC效验计算LRCHi=hextoascii((LRC>>4)&0x0F);LRCLo=hextoascii(LRC&0x0F);}voidOut_LRC(){unsignedintc;for(c=1;c{tempTX[(c-1)/2]=(asciitohex(TX[c])<<4);tempTX[(c-1)/2]=(asciitohex(TX[c])<<4)|asciitohex(TX[c+1]);}LRCt=MODBUS_LRC(&tempTX[0],(tempnumt-1)/2);//进行LRC效验计算LRCtHi=hextoascii((LRCt>>4)&0x0F);LRCtLo=hextoascii(LRCt&0x0F);}(3)进制之间转换程序由于发送和读取的数据是字符,而寄存器中数据多按照十六进制存储,故需要各种进制间的相互转换。//十六进制数转换为ASCII码unsignedcharhextoascii(unsignedcharhex){if(hex<=0x09)returnhex+0x30;elsereturnhex+0x37;}//ASCII码转换为十六进制的数unsignedcharasciitohex(unsignedcharascii){if(ascii<=0x39)returnascii-0x30;elsereturnascii-0x37;}//十进制转十六进制,由于组态王通信时会自动将十六进制数转换位十进制数,因此需要在单片机内将十进制数转换位十六进制数,这样组态王读到的就是十进制的数据。unsignedcharshitohex(unsignedintshi){inti,b,d,c;inta=0;d=4;charshiliu[10];while(shi)//shi代表相应的十进制数{c=shi%16;//每次除以16取余求得相应的十六进制数shi=shi/16;shiliu[a]=c;a++;}for(i=a;i<=4;i++)//得到的数据首位倒置,才是要求的十六进制数{shiliu[i]=0;}for(b=0;b<4;b++){d--;Buf[b]=shiliu[d];}return0;}(4)波特率,流量、温度的设置//选定流量voidselflow(unsignedcharselflow){switch(selflow){case'0':flow=100;break;case'1':flow=1799;break
in3=1;
g3=g3+xishu3*num;
如果油罐4液位最低,增加油罐4的液位
if(g4{in1=0;in2=0;in3=0;in4=1;g4=g4+xishu4*num;}}}}}if(out==1&&num1>0){如果油罐1液位最高,降低油罐1的液位if(g1>=g2&&g1>=g3&&g1>=g4&&g1>2){out1=1;out2=0;out3=0;out4=0;g1=g1-xishu1*num1;}else{如果油罐2液位最高,降低油罐2的液位if(g2>=g1&&g2>=g3&&g2>=g4&&g2>2){out1=0;out2=1;out3=0;out4=0;g2=g2-xishu2*num1;}else{如果油罐3液位最高,降低油罐3的液位if(g3>=g1&&g3>=g2&&g3>=g4&&g3>2){out1=0;out2=0;out3=1;out4=0;g3=g3-xishu3*num1;}else{如果油罐4液位最高,降低油罐4的液位if(g4>=g1&&g4>=g2&&g4>=g3&&g4>2){out1=0;out2=0;out3=0;out4=1;g4=g4-xishu4*num1;}}}}}if(clear1==1||clear2==1||clear3==1||clear4==1)手动排污{g1=g1-clear1*0.1;g2=g2-clear2*0.1;g3=g3-clear3*0.1;g4=g4-clear4*0.1;//jiewei1=jiewei1-0.1*clear1;//jiewei2=jiewei2-0.1*clear2;//jiewei3=jiewei3-0.1*clear3;//jiewei4=jiewei4-0.1*clear4;}如果液位大于16,关闭相应的进口阀if(g1>=16){in1=0;}if(g2>=16){in2=0;}if(g3>=16){in3=0;}if(g4>=16){in4=0;}如果液位小于2,关闭相应出口阀if(g1<=2){out1=0;}if(g2<=2){out2=0;}if(g3<=2){out3=0;}if(g4<=2){out4=0;}if(num==0){in1=0;in2=0;in3=0;in4=0;}if(num1==0){out1=0;out2=0;out3=0;out4=0;}(5)运行总画面(6)与PLC通信设置在工程浏览器中选择设备—com1—新建,如下图,配置com口跟PLC连接。设置bengin1,2,3和bengout1,2,3分别与Q0.0等相联系,可观察到PLC输出指示灯会随着这些变量的改变和改变。三、组态王部分总结组态王是组态王软件是一种通用的工业监控软件,它融过程控制设计、现场操作以及工厂资源管理于一体,将一个企业内部的各种生产系统和应用以及信息交流汇集在一起,实现最优化管理,操作方便,界面美观。组态王软件结构由工程管理器、工程浏览器及运行系统三部分构成。通过这次课程设计,我们学会了如何建立一个组态王工程,如何设计界面,编写命令语言、以及报警事件、趋势曲线和报表的相关制作,权限的设置,以及与实际设备的简单通信,通过本次实习,我想在以后工作中,我们会更好的应用此例软件,完成工业监控。智能仪表部分一、MODBUSASCII和MODBUSRTU通讯协议简介Modbus协议是应用于电子控制器上的一种通用语言。通过此协议,控制器相互之间、控制器经由网络(例如以太网)和其它设备之间可以通信。此协议定义了一个控制器能认识使用的消息结构,而不管它们是经过何种网络进行通信的。它描述了控制器请求访问其它设备的过程,如果回应来自其它设备的请求,以及怎样侦测错误并记录。它制定了消息域格局和内容的公共格式。两种串行传输模式:RTU模式和ASCII模式。RTU传输模式:当设备使用RTU(RemoteTerminalUnit)模式在Modbus串行链路通信,报文中每个8位字节含有两个4位十六进制字符。这种模式的主要优点是较高的数据密度,在相同的波特率下比ASCII模式有更高的吞吐率。每个报文必须以连续的字符流传送。RTU模式每个字节(11位)的格式为:编码系统:8位二进制,报文中每个8位字节含有两个4位十六进制字符(0–9,A–F。)BitsperByte:1起始位,8数据位,首先发送最低有效位,1位作为奇偶校验,1停止位。ASCII传输模式当Modbus串行链路的设备被配置为使用ASCII(AmericanStandardCodeforInformationInterchange)模式通信时,报文中的每个8位子节以两个ASCII字符发送。ASCII模式每个字节(10位)的格式为:编码系统:十六进制,ASCII字符0-9,A-F。报文中每个ASCII字符含有1十六进制字符。BitsperByte:1起始位,7数据位,首先发送最低有效位,1位奇偶校验,1停止位。03读保持寄存器上位机发送数据格式:“:”ADDRESS03ADDRHADDRLNUMHNUMLLRC0X0D0X0A正确时变频器返回数据格式:“:“ADDRESS03BYTECOUNTDATA1DATA2DATA3DATANLRC0D0A06写单个保持寄存器值上位机发送数据格式:“:“ADDRESS06ADDRHADDRLDATAHDATALLRC0X0D0X0A正确时变频器返回数据格式:“:“ADDRESS06ADDRHADDRLDATAHDATALLRC0X0D0X0A二、MODBUSASCII编程以及与组态王通信1、变量定义unsignedcharERR[21]="InputLRCERROR!";//出错时显示字符unsignedcharRX[32];//单片机接受数据数组unsignedcharTX[32];//03功能时单片机发送数据数组unsignedcharTX6[32];//06功能时单片机发送数据数组unsignedcharBuf[10];//存储数据的数组unsignedintflag;//上位机发送数据标志位unsignedintflag1;//单片机应答数据标志位unsignedintflow;//流量值unsignedinttemperature;//温度值unsignedcharLRC;//上位机发送数据校验码unsignedcharLRCt;//单片机应答数据校验码2、通过UART中断完成上位机给单片机发送编程思路:通过UART中断,实现上位机给单片机发送数据,当单片机接受到:,表示上位机要向单片机发送指令,相应标志位置1,当再次发生中断时,就开始接受数据,同时存入RX[32]的数组里,直到接收到回车换行符,则发送命令结束。此时发送标志位置1,进入应答程序。#pragmavector=USCI_A1_VECTOR__interruptvoidUSCI_A1_ISR(void){while(!(UCA1IFG&UCTXIFG));//判断是否发送完毕if(UCA1RXBUF==':')//:为起始标志,如果开始,标志位flag置位{flag=1;}if(flag==1)//当标志位flag置位说明发送命令开始,开始接受命令数据{RX[0]=':';if(UCA1RXBUF!=0x0D&&UCA1RXBUF!=0x0A)//只要不是回车换行符,就依次将数据存入接受数组RX中,同时计数变量tempnumb加1{tempnumb++;RX[tempnumb]=UCA1RXBUF;}if(UCA1RXBUF==0x0D)//若是回车{tempnumb++;RX[tempnumb]='D';}if(UCA1RXBUF==0x0A)//若是换行{tempnumb++;RX[tempnumb]='A';flag=0;//接受标志位清零flag1=1;//发送标志位置1TTXX();//调用发送数据函数}}}3、单片机通过UART中断向上位机发送应答指令编程思路:先计算上位机发送数据的校验码,如果和发送的校验码相同,单片机再应答。设置寄存器地址0001,存储流量数据;设置寄存器0002,存储温度数据。然后判断是03号功能还是06号功能,若是03号功能,按照相应的格式发送数据,若是06号功能,按照命令更改数据,并返回应答命令。voidTTXX(){inti;intj;unsignedintb;unsignedintc;unsignedintd;In_LRC();//计数上位机发送命令校验码if(RX[8]=='1')//如果地址为寄存器0001,发送流量数据shitohex(flow);if(RX[8]=='2')//如果地址位寄存器0002,发送温度数据shitohex(temperature);if(RX[3]=='0'&&RX[4]=='3')//如果是03号功能{if((LRCHi==RX[tempnumb-3])&&(LRCLo==RX[tempnumb-2]))//如果上位机发送校验码正确{for(b=0;b<=4;b++){TX[b]=RX[b];}temp=asciitohex(RX[tempnumb-4]);//计算单片机要发送数据的字节数TX[5]=hextoascii(((temp*2)>>4)&0x0F);TX[6]=hextoascii((temp*2)&0x0F);for(i=0;i{TX[7+i]=hextoascii(Buf[i]);//要发送的数据TX[8+i]=hextoascii(Buf[i+1]);}tempnumt=7+i;//统计数据长度,用于计算校验码Out_LRC();//计算单片机发送数据校验码TX[7+i]=LRCtHi;TX[8+i]=LRCtLo;TX[9+i]=0x0D;TX[10+i]=0x0A;for(j=0;j<=(10+i);j++)//单片机发送数据{while(!(UCA1IFG&UCTXIFG));//判断是否发送完毕UCA1TXBUF=TX[j];}}else//如果校验码不正确,返回错误代码InputLRCERROR!只能通过串口调试看到{ERR[19]='8';ERR[20]=TX[4];for(d=0;d<=20;d++){while(!(UCA1IFG&UCTXIFG));//判断是否发送完毕UCA1TXBUF=ERR[d];}}}elseif(RX[3]=='0'&&RX[4]=='6')//如果是06号功能{for(c=0;c<=tempnumb;c++){TX6[c]=RX[c];while(!(UCA1IFG&UCTXIFG));//判断是否发送完毕UCA1TXBUF=TX6[c];}selflow(TX6[10]);//设置流量值seltemp(TX6[11]);//设置温度值}flag1=0;//单片机发送标志位清零tempnumb=0;//上位机发送数据计算值清零}4、辅助模块部分(1)、LRC校验模块编程思路:LRC的计算,对报文中的所有的连续8位字节相加,忽略任何进位,然后求出其二进制补码。unsignedchar*auchMsg;指向含有用于生成LRC的二进制数据报文缓冲区的指针,unsignedshortusDataLen;报文缓冲区的字节数.unsignedcharMODBUS_LRC(unsignedchar*auchMsg,unsignedshortusDataLen){unsignedcharuchLRC=0;//LRC初始化while(usDataLen--)//完成整个报文缓冲区uchLRC+=*auchMsg++;//缓冲区字节相加,无进位return((unsignedchar)(-((char)uchLRC)));//返回二进制补码}(2)发送和应答校验码计数程序voidIn_LRC(){unsignedinta;for(a=1;a<(tempnumb-3);a+=2){tempRX[(a-1)/2]=(asciitohex(RX[a])<<4)|asciitohex(RX[a+1]);}LRC=MODBUS_LRC(&tempRX[0],(tempnumb-4)/2);//进行LRC效验计算LRCHi=hextoascii((LRC>>4)&0x0F);LRCLo=hextoascii(LRC&0x0F);}voidOut_LRC(){unsignedintc;for(c=1;c{tempTX[(c-1)/2]=(asciitohex(TX[c])<<4);tempTX[(c-1)/2]=(asciitohex(TX[c])<<4)|asciitohex(TX[c+1]);}LRCt=MODBUS_LRC(&tempTX[0],(tempnumt-1)/2);//进行LRC效验计算LRCtHi=hextoascii((LRCt>>4)&0x0F);LRCtLo=hextoascii(LRCt&0x0F);}(3)进制之间转换程序由于发送和读取的数据是字符,而寄存器中数据多按照十六进制存储,故需要各种进制间的相互转换。//十六进制数转换为ASCII码unsignedcharhextoascii(unsignedcharhex){if(hex<=0x09)returnhex+0x30;elsereturnhex+0x37;}//ASCII码转换为十六进制的数unsignedcharasciitohex(unsignedcharascii){if(ascii<=0x39)returnascii-0x30;elsereturnascii-0x37;}//十进制转十六进制,由于组态王通信时会自动将十六进制数转换位十进制数,因此需要在单片机内将十进制数转换位十六进制数,这样组态王读到的就是十进制的数据。unsignedcharshitohex(unsignedintshi){inti,b,d,c;inta=0;d=4;charshiliu[10];while(shi)//shi代表相应的十进制数{c=shi%16;//每次除以16取余求得相应的十六进制数shi=shi/16;shiliu[a]=c;a++;}for(i=a;i<=4;i++)//得到的数据首位倒置,才是要求的十六进制数{shiliu[i]=0;}for(b=0;b<4;b++){d--;Buf[b]=shiliu[d];}return0;}(4)波特率,流量、温度的设置//选定流量voidselflow(unsignedcharselflow){switch(selflow){case'0':flow=100;break;case'1':flow=1799;break
in4=1;
g4=g4+xishu4*num;
if(out==1&&num1>0)
如果油罐1液位最高,降低油罐1的液位
if(g1>=g2&&g1>=g3&&g1>=g4&&g1>2)
out1=1;
out2=0;
out3=0;
out4=0;
g1=g1-xishu1*num1;
如果油罐2液位最高,降低油罐2的液位
if(g2>=g1&&g2>=g3&&g2>=g4&&g2>2)
out1=0;
out2=1;
g2=g2-xishu2*num1;
如果油罐3液位最高,降低油罐3的液位
if(g3>=g1&&g3>=g2&&g3>=g4&&g3>2)
out3=1;
g3=g3-xishu3*num1;
如果油罐4液位最高,降低油罐4的液位
if(g4>=g1&&g4>=g2&&g4>=g3&&g4>2)
out4=1;
g4=g4-xishu4*num1;
}}}
if(clear1==1||clear2==1||clear3==1||clear4==1)
手动排污
g1=g1-clear1*0.1;
g2=g2-clear2*0.1;
g3=g3-clear3*0.1;
g4=g4-clear4*0.1;
//jiewei1=jiewei1-0.1*clear1;
//jiewei2=jiewei2-0.1*clear2;
//jiewei3=jiewei3-0.1*clear3;
//jiewei4=jiewei4-0.1*clear4;
如果液位大于16,关闭相应的进口阀
if(g1>=16)
{in1=0;}
if(g2>=16)
{in2=0;}
if(g3>=16)
{in3=0;}
if(g4>=16)
{in4=0;}
如果液位小于2,关闭相应出口阀
if(g1<=2)
{out1=0;}
if(g2<=2)
{out2=0;}
if(g3<=2)
{out3=0;}
if(g4<=2)
{out4=0;}
if(num==0)
if(num1==0)
(5)运行总画面
(6)与PLC通信设置
在工程浏览器中选择设备—com1—新建,如下图,配置com口跟PLC连接。
设置bengin1,2,3和bengout1,2,3分别与Q0.0等相联系,可观察到PLC输出指示灯会随着这些变量的改变和改变。
三、组态王部分总结
组态王是组态王软件是一种通用的工业监控软件,它融过程控制设计、现场操作以及工厂资源管理于一体,将一个企业内部的各种生产系统和应用以及信息交流汇集在一起,实现最优化管理,操作方便,界面美观。
组态王软件结构由工程管理器、工程浏览器及运行系统三部分构成。
通过这次课程设计,我们学会了如何建立一个组态王工程,如何设计界面,编写命令语言、以及报警事件、趋势曲线和报表的相关制作,权限的设置,以及与实际设备的简单通信,通过本次实习,我想在以后工作中,我们会更好的应用此例软件,完成工业监控。
智能仪表部分
一、MODBUSASCII和MODBUSRTU通讯协议简介
Modbus协议是应用于电子控制器上的一种通用语言。
通过此协议,控制器相互之间、控制器经由网络(例如以太网)和其它设备之间可以通信。
此协议定义了一个控制器能认识使用的消息结构,而不管它们是经过何种网络进行通信的。
它描述了控制器请求访问其它设备的过程,如果回应来自其它设备的请求,以及怎样侦测错误并记录。
它制定了消息域格局和内容的公共格式。
两种串行传输模式:
RTU模式和ASCII模式。
RTU传输模式:
当设备使用RTU(RemoteTerminalUnit)模式在Modbus串行链路通信,报文中每个8位字节含有两个4位十六进制字符。
这种模式的主要优点是较高的数据密度,在相同的波特率下比ASCII模式有更高的吞吐率。
每个报文必须以连续的字符流传送。
RTU模式每个字节(11位)的格式为:
编码系统:
8位二进制,报文中每个8位字节含有两个4位十六进制字符(0–9,A–F。
)
BitsperByte:
1起始位,8数据位,首先发送最低有效位,1位作为奇偶校验,1停止位。
ASCII传输模式
当Modbus串行链路的设备被配置为使用ASCII(AmericanStandardCodeforInformationInterchange)模式通信时,报文中的每个8位子节以两个ASCII字符发送。
ASCII模式每个字节(10位)的格式为:
十六进制,ASCII字符0-9,A-F。
报文中每个ASCII字符含有1十六进制字符。
1起始位,7数据位,首先发送最低有效位,1位奇偶校验,1停止位。
03读保持寄存器
上位机发送数据格式:
“:
”ADDRESS03ADDRHADDRLNUMHNUMLLRC0X0D0X0A
正确时变频器返回数据格式:
“ADDRESS03BYTECOUNTDATA1DATA2DATA3DATANLRC0D0A
06写单个保持寄存器值
“ADDRESS06ADDRHADDRLDATAHDATALLRC0X0D0X0A
二、MODBUSASCII编程以及与组态王通信
1、变量定义
unsignedcharERR[21]="InputLRCERROR!
";//出错时显示字符
unsignedcharRX[32];//单片机接受数据数组
unsignedcharTX[32];//03功能时单片机发送数据数组
unsignedcharTX6[32];//06功能时单片机发送数据数组
unsignedcharBuf[10];//存储数据的数组
unsignedintflag;//上位机发送数据标志位
unsignedintflag1;//单片机应答数据标志位
unsignedintflow;//流量值
unsignedinttemperature;//温度值
unsignedcharLRC;//上位机发送数据校验码
unsignedcharLRCt;//单片机应答数据校验码
2、通过UART中断完成上位机给单片机发送
编程思路:
通过UART中断,实现上位机给单片机发送数据,当单片机接受到:
,表示上位机要向单片机发送指令,相应标志位置1,当再次发生中断时,就开始接受数据,同时存入RX[32]的数组里,直到接收到回车换行符,则发送命令结束。
此时发送标志位置1,进入应答程序。
#pragmavector=USCI_A1_VECTOR
__interruptvoidUSCI_A1_ISR(void)
while(!
(UCA1IFG&UCTXIFG));//判断是否发送完毕
if(UCA1RXBUF==':
')//:
为起始标志,如果开始,标志位flag置位
flag=1;
if(flag==1)//当标志位flag置位说明发送命令开始,开始接受命令数据
RX[0]=':
';
if(UCA1RXBUF!
=0x0D&&UCA1RXBUF!
=0x0A)//只要不是回车换行符,就依次将数据存入接受数组RX中,同时计数变量tempnumb加1
tempnumb++;
RX[tempnumb]=UCA1RXBUF;
if(UCA1RXBUF==0x0D)//若是回车
RX[tempnumb]='D';
if(UCA1RXBUF==0x0A)//若是换行
RX[tempnumb]='A';
flag=0;//接受标志位清零
flag1=1;//发送标志位置1
TTXX();//调用发送数据函数
3、单片机通过UART中断向上位机发送应答指令
先计算上位机发送数据的校验码,如果和发送的校验码相同,单片机再应答。
设置寄存器地址0001,存储流量数据;设置寄存器0002,存储温度数据。
然后判断是03号功能还是06号功能,若是03号功能,按照相应的格式发送数据,若是06号功能,按照命令更改数据,并返回应答命令。
voidTTXX()
inti;
intj;
unsignedintb;
unsignedintc;
unsignedintd;
In_LRC();//计数上位机发送命令校验码
if(RX[8]=='1')//如果地址为寄存器0001,发送流量数据
shitohex(flow);
if(RX[8]=='2')//如果地址位寄存器0002,发送温度数据
shitohex(temperature);
if(RX[3]=='0'&&RX[4]=='3')//如果是03号功能
if((LRCHi==RX[tempnumb-3])&&(LRCLo==RX[tempnumb-2]))//如果上位机发送校验码正确
for(b=0;b<=4;b++)
TX[b]=RX[b];
temp=asciitohex(RX[tempnumb-4]);//计算单片机要发送数据的字节数
TX[5]=hextoascii(((temp*2)>>4)&0x0F);
TX[6]=hextoascii((temp*2)&0x0F);
for(i=0;i{TX[7+i]=hextoascii(Buf[i]);//要发送的数据TX[8+i]=hextoascii(Buf[i+1]);}tempnumt=7+i;//统计数据长度,用于计算校验码Out_LRC();//计算单片机发送数据校验码TX[7+i]=LRCtHi;TX[8+i]=LRCtLo;TX[9+i]=0x0D;TX[10+i]=0x0A;for(j=0;j<=(10+i);j++)//单片机发送数据{while(!(UCA1IFG&UCTXIFG));//判断是否发送完毕UCA1TXBUF=TX[j];}}else//如果校验码不正确,返回错误代码InputLRCERROR!只能通过串口调试看到{ERR[19]='8';ERR[20]=TX[4];for(d=0;d<=20;d++){while(!(UCA1IFG&UCTXIFG));//判断是否发送完毕UCA1TXBUF=ERR[d];}}}elseif(RX[3]=='0'&&RX[4]=='6')//如果是06号功能{for(c=0;c<=tempnumb;c++){TX6[c]=RX[c];while(!(UCA1IFG&UCTXIFG));//判断是否发送完毕UCA1TXBUF=TX6[c];}selflow(TX6[10]);//设置流量值seltemp(TX6[11]);//设置温度值}flag1=0;//单片机发送标志位清零tempnumb=0;//上位机发送数据计算值清零}4、辅助模块部分(1)、LRC校验模块编程思路:LRC的计算,对报文中的所有的连续8位字节相加,忽略任何进位,然后求出其二进制补码。unsignedchar*auchMsg;指向含有用于生成LRC的二进制数据报文缓冲区的指针,unsignedshortusDataLen;报文缓冲区的字节数.unsignedcharMODBUS_LRC(unsignedchar*auchMsg,unsignedshortusDataLen){unsignedcharuchLRC=0;//LRC初始化while(usDataLen--)//完成整个报文缓冲区uchLRC+=*auchMsg++;//缓冲区字节相加,无进位return((unsignedchar)(-((char)uchLRC)));//返回二进制补码}(2)发送和应答校验码计数程序voidIn_LRC(){unsignedinta;for(a=1;a<(tempnumb-3);a+=2){tempRX[(a-1)/2]=(asciitohex(RX[a])<<4)|asciitohex(RX[a+1]);}LRC=MODBUS_LRC(&tempRX[0],(tempnumb-4)/2);//进行LRC效验计算LRCHi=hextoascii((LRC>>4)&0x0F);LRCLo=hextoascii(LRC&0x0F);}voidOut_LRC(){unsignedintc;for(c=1;c{tempTX[(c-1)/2]=(asciitohex(TX[c])<<4);tempTX[(c-1)/2]=(asciitohex(TX[c])<<4)|asciitohex(TX[c+1]);}LRCt=MODBUS_LRC(&tempTX[0],(tempnumt-1)/2);//进行LRC效验计算LRCtHi=hextoascii((LRCt>>4)&0x0F);LRCtLo=hextoascii(LRCt&0x0F);}(3)进制之间转换程序由于发送和读取的数据是字符,而寄存器中数据多按照十六进制存储,故需要各种进制间的相互转换。//十六进制数转换为ASCII码unsignedcharhextoascii(unsignedcharhex){if(hex<=0x09)returnhex+0x30;elsereturnhex+0x37;}//ASCII码转换为十六进制的数unsignedcharasciitohex(unsignedcharascii){if(ascii<=0x39)returnascii-0x30;elsereturnascii-0x37;}//十进制转十六进制,由于组态王通信时会自动将十六进制数转换位十进制数,因此需要在单片机内将十进制数转换位十六进制数,这样组态王读到的就是十进制的数据。unsignedcharshitohex(unsignedintshi){inti,b,d,c;inta=0;d=4;charshiliu[10];while(shi)//shi代表相应的十进制数{c=shi%16;//每次除以16取余求得相应的十六进制数shi=shi/16;shiliu[a]=c;a++;}for(i=a;i<=4;i++)//得到的数据首位倒置,才是要求的十六进制数{shiliu[i]=0;}for(b=0;b<4;b++){d--;Buf[b]=shiliu[d];}return0;}(4)波特率,流量、温度的设置//选定流量voidselflow(unsignedcharselflow){switch(selflow){case'0':flow=100;break;case'1':flow=1799;break
TX[7+i]=hextoascii(Buf[i]);//要发送的数据
TX[8+i]=hextoascii(Buf[i+1]);
tempnumt=7+i;//统计数据长度,用于计算校验码
Out_LRC();//计算单片机发送数据校验码
TX[7+i]=LRCtHi;
TX[8+i]=LRCtLo;
TX[9+i]=0x0D;
TX[10+i]=0x0A;
for(j=0;j<=(10+i);j++)//单片机发送数据
UCA1TXBUF=TX[j];
else//如果校验码不正确,返回错误代码InputLRCERROR!
只能通过串口调试看到
ERR[19]='8';
ERR[20]=TX[4];
for(d=0;d<=20;d++)
UCA1TXBUF=ERR[d];
elseif(RX[3]=='0'&&RX[4]=='6')//如果是06号功能
for(c=0;c<=tempnumb;c++)
TX6[c]=RX[c];
UCA1TXBUF=TX6[c];
selflow(TX6[10]);//设置流量值
seltemp(TX6[11]);//设置温度值
flag1=0;//单片机发送标志位清零
tempnumb=0;//上位机发送数据计算值清零
4、辅助模块部分
(1)、LRC校验模块
LRC的计算,对报文中的所有的连续8位字节相加,忽略任何进位,然后求出其二进制补码。
unsignedchar*auchMsg;指向含有用于生成LRC的二进制数据报文缓冲区的指针,
unsignedshortusDataLen;报文缓冲区的字节数.
unsignedcharMODBUS_LRC(unsignedchar*auchMsg,unsignedshortusDataLen)
unsignedcharuchLRC=0;//LRC初始化
while(usDataLen--)//完成整个报文缓冲区
uchLRC+=*auchMsg++;//缓冲区字节相加,无进位
return((unsignedchar)(-((char)uchLRC)));//返回二进制补码
(2)发送和应答校验码计数程序
voidIn_LRC()
unsignedinta;
for(a=1;a<(tempnumb-3);a+=2)
tempRX[(a-1)/2]=(asciitohex(RX[a])<<4)|asciitohex(RX[a+1]);
LRC=MODBUS_LRC(&tempRX[0],(tempnumb-4)/2);//进行LRC效验计算
LRCHi=hextoascii((LRC>>4)&0x0F);
LRCLo=hextoascii(LRC&0x0F);
voidOut_LRC()
for(c=1;c{tempTX[(c-1)/2]=(asciitohex(TX[c])<<4);tempTX[(c-1)/2]=(asciitohex(TX[c])<<4)|asciitohex(TX[c+1]);}LRCt=MODBUS_LRC(&tempTX[0],(tempnumt-1)/2);//进行LRC效验计算LRCtHi=hextoascii((LRCt>>4)&0x0F);LRCtLo=hextoascii(LRCt&0x0F);}(3)进制之间转换程序由于发送和读取的数据是字符,而寄存器中数据多按照十六进制存储,故需要各种进制间的相互转换。//十六进制数转换为ASCII码unsignedcharhextoascii(unsignedcharhex){if(hex<=0x09)returnhex+0x30;elsereturnhex+0x37;}//ASCII码转换为十六进制的数unsignedcharasciitohex(unsignedcharascii){if(ascii<=0x39)returnascii-0x30;elsereturnascii-0x37;}//十进制转十六进制,由于组态王通信时会自动将十六进制数转换位十进制数,因此需要在单片机内将十进制数转换位十六进制数,这样组态王读到的就是十进制的数据。unsignedcharshitohex(unsignedintshi){inti,b,d,c;inta=0;d=4;charshiliu[10];while(shi)//shi代表相应的十进制数{c=shi%16;//每次除以16取余求得相应的十六进制数shi=shi/16;shiliu[a]=c;a++;}for(i=a;i<=4;i++)//得到的数据首位倒置,才是要求的十六进制数{shiliu[i]=0;}for(b=0;b<4;b++){d--;Buf[b]=shiliu[d];}return0;}(4)波特率,流量、温度的设置//选定流量voidselflow(unsignedcharselflow){switch(selflow){case'0':flow=100;break;case'1':flow=1799;break
tempTX[(c-1)/2]=(asciitohex(TX[c])<<4);
tempTX[(c-1)/2]=(asciitohex(TX[c])<<4)|asciitohex(TX[c+1]);
LRCt=MODBUS_LRC(&tempTX[0],(tempnumt-1)/2);//进行LRC效验计算
LRCtHi=hextoascii((LRCt>>4)&0x0F);
LRCtLo=hextoascii(LRCt&0x0F);
(3)进制之间转换程序
由于发送和读取的数据是字符,而寄存器中数据多按照十六进制存储,故需要各种进制间的相互转换。
//十六进制数转换为ASCII码
unsignedcharhextoascii(unsignedcharhex)
if(hex<=0x09)
returnhex+0x30;
returnhex+0x37;
//ASCII码转换为十六进制的数
unsignedcharasciitohex(unsignedcharascii)
if(ascii<=0x39)
returnascii-0x30;
returnascii-0x37;
//十进制转十六进制,由于组态王通信时会自动将十六进制数转换位十进制数,因此需要在单片机内将十进制数转换位十六进制数,这样组态王读到的就是十进制的数据。
unsignedcharshitohex(unsignedintshi)
inti,b,d,c;
inta=0;
d=4;
charshiliu[10];
while(shi)//shi代表相应的十进制数
c=shi%16;//每次除以16取余求得相应的十六进制数
shi=shi/16;
shiliu[a]=c;
a++;
for(i=a;i<=4;i++)//得到的数据首位倒置,才是要求的十六进制数
shiliu[i]=0;
for(b=0;b<4;b++)
d--;
Buf[b]=shiliu[d];
return0;
(4)波特率,流量、温度的设置
//选定流量
voidselflow(unsignedcharselflow)
switch(selflow)
case'0':
flow=100;break;
case'1':
flow=1799;break
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1