51单片机与力控modbus通信

合集下载

51单片机与力控modbus通信

51单片机与力控modbus通信

网上关于单片机和力控modbus通信的实例很少,关键并不是modbus协议而是力控与单片机连接的设置,下面的程序是基于51单片机做的。

在正个调试过程中由于我们不清楚力控发送给单片机的请求数据格式,我们可以用串口调试工具进行串口调试,将力控发送请求显示在串口调试工具中,其中单片机的程序如下#include<reg52.h>#include<string.h>#define uchar unsigned char //一个字节#define uint unsigned int // 两个字节void send_char(unsigned char txd);uint rece_count=0;uint send_flag=0;uchar rece_buf[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};uint i;/*串行口初始化*/void chushi(){SCON=0x50; //串口工作方式1,即10位异步PCON=0x00;//波特率不倍增TMOD=0x20;TH1=TL1=0xfa;TR1=1;}/*主程序*/main(){chushi();rece_count=0;while(1){if(RI){RI=0;if(rece_count<8){rece_buf[rece_count]=SBUF;rece_count++;}}if(rece_count==8){send_flag=1;}while(send_flag==1){ for(i=0;i<8;i++){SBUF=rece_buf[i];while(TI==0) ;TI=0;}}}}打开力控运行,将发送的数据保存到单片机中,然后打开串口调试工具,显示如下:我们看力控发送请求的格式:01 03 ff ff 00 01 84 2e,最后的两位crc是高位在前,低位在后。

51单片机新手入门之Modbus通讯

51单片机新手入门之Modbus通讯

51单片机新手入门之Modbus通讯本文和另一篇----C# WPF新手入门之Modbus通讯为一个系列,所用模块均是气体分析模块,之前用C3做的上位机(主要是方便调试,单片机不好搞),既然电脑上串口通讯代码没问题,那么放到单片机稍加修改也就理所当然肯定可行O(∩_∩)O~。

本文包括单片机的电路设计和软件设计两部分(单片机采用STC12C5A60S2双串口),至此单片机和上位机的串口通讯均成功实现,供需要的同学参考。

1.电路设计Altium Designer原理图如下:电源部分:24V转5V及6VAD及滤波Modbus通讯电脑串口通讯lcd屏显示预留接口,可以另接MAX232用来调试发送给模块数据正确性实际效果如下:电脑串口接收到的数据,和LCD 屏显示的是一样的下载步骤1. 选择芯片下载步骤2. 打开串口 下载步骤3. 打开hex 文件 下载步骤4. MCU 先断电,点击下载,看到提示后上电2.软件设计这里最麻烦的在于模块的Modbus通讯需要偶校验,我是手动添加的校验位,例如字符‘0’换成ASCII码0X30,添加偶校验后就是0X3A,把所有需要发送的数据一个个手动添加了再发送^_^;另外lcd12864屏也搞半天,主要照着时序图写必须sid先发送,然后sclk,不然不行 ̄□ ̄。

气体模块详细的通讯协议参考和上位机通讯那篇,此处不再介绍。

图中电路板没有焊AD芯片和温度芯片,引脚备用,相关代码注释掉了。

代码如下:#include "STC12C5A60S2.H"#include <intrins.H>.//头文件#define uchar unsigned char#define uint unsigned intuchar sendbuffer[17];//发送数据uchar flag=0;uchar re_buffer[32];uchar count=0;uint ad_data=0;double ad_vol=0;uint con_mid=0;uint gascon=0;long sum_o2=0;uint average_counter=20;uint idata oldtemp[21];uchar idata Send_Buff[20]; //moduleuint pre_contemp=0;uint O2_con=0;uchar idata test[21]; //moduleuint temperature=0;uint dat;uint testlcd=0;uchar c[]={0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9};//MAX1241 模数芯片引脚设置,此电路板我没焊^_^//sbit ADC_CS=P0^1;//sbit ADC_CLK=P0^0;//sbit ADC_DOUT=P0^2;sbit ADC_CS=P3^6;sbit ADC_CLK=P3^5;sbit ADC_DOUT=P3^7;//LCD12864 LCD屏幕引脚设置sbit cs=P2^2;sbit sid=P2^1;sbit sclk=P2^0;sbit DQ=P0^1; //DS18B20 温度引脚设置,依然没有…#define N 11#define N2 20void delayms(unsigned char t){unsigned char i;unsigned char j;for(j=t;j;j--)for(i=192;i;i--);/*1ms延时*/}void delayus(uint t){uint i;for(i=0;i<t;i++){_nop_();}}void delay(float sec){unsigned int i;unsigned int j;j=sec*100;while(j--){i=1561;while(--i);}}void UART1_init() //串口1初始化,此串口和电脑通讯{TMOD=0x20;/设置定时器工作方式2TH1=0xfd; //波特率9600TL1=0xfd;TR1=1;REN=1;SM0=0;SM1=1;//ES=1;}void UART2_init()//串口2初始化,和模块通讯 Modbus{S2CON= 0x50; //方式1,允许接收BRT = 0xf4; //波特率2400AUXR = AUXR |0X10; //允许独立波特率允许AUXR1 = AUXR1&0xef; //将uart2切换到P1口IE2 = IE2|0X01; //允许串口2中断}void UART1_Send (unsigned char UART_data)//{//ES=0;SBUF = UART_data; //将接收的数据发送回去while(TI!=1); //检查发送中断标志位TI = 0; //另发送中断标志位为0//ES=1;}void UART2_Send(unsigned char UART_data)//串口2发送{//ES = 0 ;S2BUF = UART_data;while((S2CON&0x02)!=0x02);S2CON &= ~0x02;//ES = 1 ;}void UART1_Send_String (char *str, char len)//串口1发送字符串{unsigned char i;for(i=0;i<=len;i++){UART1_Send(str[i]);}}void UART2_Send_String (char *str, char len) //串口2发送字符串{unsigned char i;for(i=0;i<=len;i++){UART2_Send(str[i]);}}unsigned char Creat_Addr(unsigned char adr, unsigned char position)//计算模块地址{unsigned char hich;unsigned char loch;hich = adr/16;loch = adr%16;if(hich>9)hich+=7;if(loch>9)loch+=7;if(position == 1){return hich+0x30;}else if(position == 0){return loch+0x30;}}unsigned char CheckSum(unsigned char *str, unsigned char position, uchar len)/计算校验码{uchar i;unsigned int sum=0;uchar hi, lo;//uchar len = 12;for(i = 1; i <= len; i ++){*str ++;sum += *str;}sum = 256-(sum%256);hi = sum/16;lo = sum%16;if(hi > 9)hi += 7;if(lo > 9)lo += 7;hi += 0x30;lo += 0x30;if(sum == 256)hi = lo = 0x30;if(position == 1){return hi;}else if(position == 0){return lo;}}void data_init(){sendbuffer[0]=0x5B;sendbuffer[1]=0x30;sendbuffer[2]=0x30;sendbuffer[3]=0x30;sendbuffer[4]=0x30;sendbuffer[5]=0x30;sendbuffer[6]=0x7C;sendbuffer[7]=0x30;sendbuffer[8]=0x30;sendbuffer[9]=0x30;sendbuffer[10]=0x30;sendbuffer[11]=0x30;//TEMsendbuffer[12]=0x30;sendbuffer[13]=0x30;sendbuffer[14]=0x5D;sendbuffer[15]=0x0D;sendbuffer[16]=0x0A;}void calculate_module(unsigned char str[])//lcd屏显示{unsigned int concen;uchar wan,qian,bai,shi,ge;/*uchar d4 = str[7]-48;uchar d3 = str[8]-48;uchar d2 = str[9]-48;uchar d1 = str[10]-48;*/ //浓度只需要后面部分 uchar d4 = str[24]-48;uchar d3 = str[25]-48;uchar d2 = str[26]-48;uchar d1 = str[27]-48;if(d4>9)d4-=7;if(d3>9)d3-=7;if(d2>9)d2-=7;if(d1>9)d1-=7;concen = d4*4096+d3*256+d2*16+d1;gascon=concen;wan=concen/10000;qian=concen%10000/1000;bai=concen%1000/100;shi=concen%100/10;ge=concen%10;//sendbuffer[6]=wan+0x30; //最终显示XXX.X%sendbuffer[7]=qian+0x30;sendbuffer[8]=bai+0x30;sendbuffer[9]=shi+0x30;sendbuffer[10]=ge+0x30;}void module_init()//气体模块初始化{Send_Buff[0] = ':';Send_Buff[3] = '0';Send_Buff[4] = '3';Send_Buff[5] = '0';Send_Buff[6] = '0';Send_Buff[7] = '0';Send_Buff[8] = 'A';Send_Buff[9] = '0';Send_Buff[10] = '0';Send_Buff[11] = '0';Send_Buff[12] = '1';Send_Buff[1] = Creat_Addr(31, 1);Send_Buff[2] = Creat_Addr(31, 0);Send_Buff[13] = CheckSum(Send_Buff, 1, 12);Send_Buff[14] = CheckSum(Send_Buff, 0, 12);Send_Buff[15] = 0x0D;Send_Buff[16] = 0x0A;//手动添加校验,例如字符‘0’换成ASCII码0X30,添加偶校验后就是0X3A,最终发送给模块的以下数据,地址被写死,这个不像C#做的一目了然O(∩_∩)Otest[0]=0X3A;test[1]=0XB1;test[2]=0XC6;test[3]=0X30;test[4]=0X33;test[5]=0X30;test[6]=0X30;test[7]=0X30;test[8]=0X41;test[9]=0X30;test[10]=0X30;test[11]=0X30;test[12]=0XB1;test[13]=0X39;test[14]=0XB4;test[15]=0X8D;test[16]=0X0A;}/*uint read_max1241() AD芯片处理{uint ADC_Data;uchar i;ADC_CLK=0;ADC_CS=0;ADC_Data=0;while(!ADC_DOUT);ADC_CLK=1;ADC_CLK=0;for(i=0;i<12;i++){ADC_CLK=1;ADC_Data<<=1;ADC_Data |= ADC_DOUT;ADC_CLK=0;}ADC_CS=1;ADC_CLK=0;return ADC_Data;}unsigned int ad_filter()//滤波{unsigned int count1,i,j;unsigned int value_buf[N];unsigned int temp;unsigned int sum=0;for (count1=0;count1<N;count1++){value_buf[count1] =read_max1241(); delayms(20);}for (j=0;j<(N-1);j++){for (i=0;i<(N-j);i++){if ( value_buf[i]>value_buf[i+1] ) {temp = value_buf[i];value_buf[i] = value_buf[i+1]; value_buf[i+1] = temp;}}}for(count1=3;count1<(N-3);count1++){sum += value_buf[count1];}return (unsigned int)(sum/(N-6));}void calculate_o2()//测试用{uchar wan,qian,bai,shi,ge;uint con_fin=0;uchar i;ad_data=ad_filter();ad_vol=(ad_data/4096.0)*2500.0;//Voltage ad_data=(uint)ad_vol; //concentrationdelayms(2);if(average_counter>0){sum_o2+= ad_data;oldtemp[average_counter-1]=ad_data;average_counter--;}else{sum_o2 -=oldtemp[19];for(i=20;i>0;i--){oldtemp[i]=oldtemp[i-1];}oldtemp[0]=ad_data;sum_o2+=oldtemp[0];con_fin=(uint)(sum_o2/N2);//O2_con=0.8*con_fin+0.2*pre_contemp;//pre_contemp=O2_con;wan=con_fin/10000;qian=con_fin%10000/1000;bai=con_fin%1000/100;shi=con_fin%100/10;ge=con_fin%10;sendbuffer[1]=wan+0x30;sendbuffer[2]=qian+0x30;sendbuffer[3]=bai+0x30;sendbuffer[4]=shi+0x30;sendbuffer[5]=ge+0x30;delayms(5);}}//-------------18B20 温度显示复位函数--------------- void ow_reset(void){char presence=1;while(presence){while(presence){DQ=1;delayus(2);DQ=0; //delayus(550); // 550usDQ=1; //delayus(66); // 66uspresence=DQ;}delayus(500); //延时500uspresence = ~DQ;}DQ=1;}//-----------18B20写命令函数------------void write_byte(uchar val){uchar i;for (i=8; i>0; i--) //{DQ=1;delayus(2);DQ = 0;delayus(5);//5usDQ = val&0x01;delayus(66); //66usval=val/2;}DQ = 1;delayus(11);}//--------------18B20读一个字节函数---------uchar read_byte(void){uchar i;uchar value = 0;for (i=8;i>0;i--){DQ=1;delayus(2);value>>=1;DQ = 0;delayus(4); //4usDQ = 1;delayus(4); //4usif(DQ)value|=0x80;delayus(66); //66us}DQ=1;return(value);}void Read_Temperature(void){unsigned int Temp1,Temp2;uchar bai,shi,ge;ow_reset(); //DS18B20write_byte(0xCC);write_byte(0x44);ow_reset(); //DS1302复位write_byte(0xCC);write_byte(0xbe);Temp1=read_byte();Temp2=read_byte();ow_reset();temperature=(((Temp2<<8)|Temp1)*0.625); //0.0625=xx, 0.625=xx.x, 6.25=xx.xxbai=temperature/100;shi=temperature%100/10;ge=temperature%10;sendbuffer[11]=bai+0x30;sendbuffer[12]=shi+0x30;sendbuffer[13]=ge+0x30;delayms(5);}* //图中电路板此部分没焊,此部分代码不使用^_^void writecmd_lcd(uchar cmd) //lcd屏写指令{uchar i;uchar cmd1;cmd1=cmd;//----------先写控制,选择写指令,还是写数据11111000 for(i=0;i<5;i++) //必须sid先发送,然后sclk,不然不行 {sid=1;sclk=1;sclk=0;}for(i=0;i<3;i++){sid=0;sclk=1;sclk=0;}//delayms(10);cmd=cmd&0xf0; //先高4位for(i=0;i<8;i++){if(cmd&0x80){sid=1;}else sid=0;sclk=1;sclk=0;cmd=cmd<<1;}//delayms(10);cmd1=((cmd1<<4)&0xf0); //低4位 for(i=0;i<8;i++){if(cmd1&0x80){sid=1;}else sid=0;sclk=1;sclk=0;cmd1=cmd1<<1;}}void writedata_lcd(uchar dat) {uchar i;uchar dat1;dat1=dat;//11111010for(i=0;i<5;i++){sid=1;sclk=1;sclk=0;}sid=0;sclk=1;sclk=0;sid=1;sclk=1;sclk=0;sid=0;sclk=1;sclk=0;//delayms(10);dat=dat&0xf0;for(i=0;i<8;i++)if(dat&0x80){sid=1;}else sid=0;sclk=1;sclk=0;dat=dat<<1;}//delayms(10);dat1=((dat1<<4)&0xf0);for(i=0;i<8;i++){if(dat1&0x80){sid=1;}else sid=0;sclk=1;sclk=0;dat1=dat1<<1;}}void init_lcd()//初始化lcd屏{cs=1;writecmd_lcd(0x30);//设定为8位控制writecmd_lcd(0x0c);//显示打开writecmd_lcd(0x01);//清屏}void gotoxy(uint row, uint col){switch(row){case 1: writecmd_lcd(0x80+col);break; case 2: writecmd_lcd(0x90+col);break; case 3: writecmd_lcd(0x88+col);break; case 4: writecmd_lcd(0x98+col);break;}void clear(){writecmd_lcd(0x01);delayms(10);}void SendStr(uchar *str){uchar i;for(i=0;str[i]!='\0';i++){writedata_lcd(str[i]);}}void lcd_display(uint lcddata)//lcd屏显示浓度{uchar wan,qian,bai,shi,ge;wan=lcddata/10000;qian=lcddata%10000/1000;bai=lcddata%1000/100;shi=lcddata%100/10;ge=lcddata%10;gotoxy(2,1);writedata_lcd(0xa3);writedata_lcd(c[qian]);gotoxy(2,2);writedata_lcd(0xa3);writedata_lcd(c[bai]);gotoxy(2,3);writedata_lcd(0xa3);writedata_lcd(c[shi]);gotoxy(2,4);SendStr(".");gotoxy(2,5);writedata_lcd(0xa3);writedata_lcd(c[ge]);gotoxy(2,6);SendStr("%");}void main()//主函数{delay(2.1);UART1_init();UART2_init();data_init();module_init();init_lcd();EA=1;delay(2.1);while(1){/*calculate_o2();//测试用Read_Temperature();*/ //温度芯片没焊UART2_Send_String(test,16);//串口2:和模块通讯delay(0.8);if(flag==1){calculate_module(re_buffer);delayms(5);UART1_Send_String(sendbuffer,16);//串口1:电脑上可以接收发送的数据 flag=0;delay(0.8);}lcd_display(gascon);//lcd显示浓度delay(0.8);}}/*void uart1_in() interrupt 4/串口1中断,不使用,因为只是发送{RI=0;re_buffer[count]=SBUF;if(re_buffer[0]!=':'){count=0;}else{count++;if(count==10){flag=1;count=0;}}}*/void uart2_in() interrupt 8//串口2中断,需要接受模块返回的数据{if(S2CON&0X01){re_buffer[count]=S2BUF;re_buffer[count]&=0x7f;count++;S2CON&=0XFE;}if(count==32){count=0;flag=1;}}。

力控组态软件怎么和支持modbus协议的设备通信

力控组态软件怎么和支持modbus协议的设备通信

问题:力控组态软件怎么和支持modbus协议的设备通信回答:Modbus是应用于电子控制器上的一种通用协议。

通过此协议,控制器相互之间、控制器经由网络(例如以太网)或者串口和其它设备之间可以通信。

力控科技的开发平台,既可以作为modbus主站从设备采集数据,也可以作为modbus从站将数据转发给其他的modbus 主站,下面以力控作为modbus(rtu串行口)主站为例讲解1、力控作为modbus主站访问其他modbus从站的方法概括来讲可以分为两个步骤:(1)、进入io设备组态,找到modbus(rtu串行口),组设备结合现场情况填写以上参数,设备地址和实际连接设备的地址一致。

(2)、串口配置(3)、采集配置(1)写单个寄存器:HR保持寄存器单寄存的写入操作,一般设备支持这个命令。

一条命令只能写一个寄存器。

简单的数据类型可以用这条命令支持,如8位、16位的数据类型可以用此命令写入。

(2)写多个寄存器:HR保持寄存器多寄存器的写入操作,一条命令可以写多个寄存器的值。

复杂的数据类型用这条命令支持,如32位,64位的数据类型。

(3)屏蔽写寄存器:HR保持寄存器的模拟量按位操作命令(设备要支持屏蔽写命令22功能码)。

(4)最大长度:是指MODBUS中一条数据所读取的字(两个字节)数,包的长度越长,一次读取的数据就越多,通讯效率就越快。

MODBUS协议中规定数据包最大长度不能超过255个字节。

另外有些PLC对包长还有限制,请根据具体设备进行填写。

(5)组包间隔:两个相邻采集点的字偏移地址如果大于等于“组包间隔”就重新打一个包。

他可以控制包中数据点的密度,如上图配置包中相邻数据的地址间距不会大于10。

(6)05功能码:选中后线圈下置命令用05功能码执行。

(7)15功能码:选中后线圈下置命令用15功能码执行。

2、数据连接打开数据库组态,选择数据库新建点:选择相应的点类型,点击继续填写点名,其他可以默认,点击数据连接点参数:常用的是PV(现场实时值)和DESC,当要读取字符串时要用DESC连接IO设备:选择要连接的的设备名称连接项:点击“增加”增加链接项根据实际的工程需要设置相对应的内存区以及偏移地址、数据格式、读写属性,就完成了数据连接的全过程。

Modbus ASCⅡ协议在51单片机上的实现

Modbus ASCⅡ协议在51单片机上的实现
二、 协议 简 介
生 反馈 消息 并用 Mo b s d u 协议 发 出 在其 它 网络 上包 含 息 中每个 字节
代 码系统 : 位二 进制 , 八 十六 进制 数 0 , …9 A…F 消 息 中每 个 8位域 都 由两个 十六 进制 字符组 成
结 位 束
ED N
消 息格式 : Mo b s 信分 为 两种 . du 通 一种 经 由 R 2 2兼 容 串行 起 位 S3 始 地 f 功 码 数 位 C校 码 址e 码 能代 据 R 验 c TR ADES DRs FNTO DT Uc I N AA CCC K R 腿C 接 口组成 Mob s d u 网络 进行通 信 . 另一 种 通过 以太 网结 SAT
( ) C I 式 1AS I 模
字 节 。起始 位 默认 设 置 O 3 (, 位 默认 设置 O O x A :结束 1 xD ( 回车)O O ( 行) ,x A 换 。用 户 通过 设 置地 址 位可 实 现多 机 机 设定 功能 代码 为 O O , l , 表单 片机 检 测, 能代 x0O O代 x 功
Mo b s d u 是全球 第 一个真 正用 于工业 现场 的 总线 协 中每个 A CI S I 字符 都是~ 个 十六进 制字符 。 议、 通过 此协 议 , 制 器相互 之 间 、 制器 经 由 网络 ( 控 控 例 消 息格式 : 如以太 网 ) 和其 它设 备之间 可 以通信 。 已经 成 为一种 起始 它 位 T R 通 用 的工业 标准 。 了它 , 有 不同厂 商生 产 的控 制设 备 之 S AT
包 含两个 4 i 的十六进 制 的字符 bt
制 器须 要 知道 它们 的设 备地 址 . 别按 地址 发 来 的 消 识 息, 决定 要产 生何 种行 动 。如果需 要 回应 . 制器 将产 控 了 Mo b s消息转 换为 在此 网络上使 用 的帧或 包 结构 . du 这种 转换 也 扩展 了根 据具体 的网络解 决节 地址 、路 由 路 径及错 误 检测 的方 法

51单片机程序(modbus通信)

51单片机程序(modbus通信)

modbus通信1、LCD.c#include <reg51.h>#include<LCD.h>unsigned char code number_X[]={ //宽x高=8x16,纵向字节倒序0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00, //00x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00,0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00, //10x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00, //20x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00,0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00, //30x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00,0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00, //40x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00,0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00, //50x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00,0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00, //60x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00,0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00, //70x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00, //80x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00,0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00, //90x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // .0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00, //-0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //nop 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00, //:0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00};void LCD_WriteCommandE1(unsigned char com) {while(CRADD1 & 0x80);CWADD1 = com;}void LCD_WriteDataE1(unsigned char dat)while(CRADD1 & 0x80);DWADD1 = dat;}void LCD_WriteCommandE2(unsigned char com) {while(CRADD2 & 0x80);CWADD2 = com;}void LCD_WriteDataE2(unsigned char dat){while(CRADD2 & 0x80);DWADD2 = dat;}void LCD_Init(){LCD_WriteCommandE1(0xe2);LCD_WriteCommandE2(0xe2);LCD_WriteCommandE1(0xa4);LCD_WriteCommandE2(0xa4);LCD_WriteCommandE1(0xa9);LCD_WriteCommandE2(0xa9);LCD_WriteCommandE1(0xa0);LCD_WriteCommandE2(0xa0);LCD_WriteCommandE1(0xc0);LCD_WriteCommandE2(0xc0);LCD_WriteCommandE1(0xaf);LCD_WriteCommandE2(0xaf);}void LCD_Clear(void){unsigned char i,j;for(i=0;i<4;i++){LCD_WriteCommandE1(i+0xb8);LCD_WriteCommandE2(i+0xb8);LCD_WriteCommandE1(0x00);LCD_WriteCommandE2(0x00);for(j=0;j<0x50;j++){LCD_WriteDataE1(0x00);LCD_WriteDataE2(0x00);}}void display_cn(unsigned char lin,unsigned int col,unsigned int len,unsigned char *p) {unsigned int seg,i,j;unsigned char a,L,n;switch(lin){case 0: n=0xba;break;case 1: n=0xb8;break;}for(i=0;i<len;i++){for(j=0;j<2;j++){L=col;LCD_WriteCommandE1(n+j);LCD_WriteCommandE2(n+j);for(seg=0;seg<16;seg++){if (L < 61){a = L;LCD_WriteCommandE1(a);LCD_WriteDataE1(*p++);}else{a = L-61;LCD_WriteCommandE2(a);LCD_WriteDataE2(*p++);}L++;}}col=col+16;}}void display_number(unsigned char lin,unsigned int col,unsigned char num){unsigned int seg,i,j;unsigned char a,L,n,k;switch(lin){case 0: n=0xba;break;case 1: n=0xb8;break;}k=num*16;for(j=0;j<2;j++){L=col;LCD_WriteCommandE1(n+j);LCD_WriteCommandE2(n+j);for(seg=0;seg<8;seg++){if (L < 61){a = L;LCD_WriteCommandE1(a);LCD_WriteDataE1(number_X[k++]);}else{a = L-61;LCD_WriteCommandE2(a);LCD_WriteDataE2(number_X[k++]);}L++;}}}void display_unsigned_int(unsigned char lin,unsigned int col,unsigned int dat) {unsigned int seg;unsigned char k[4];k[3]=dat%10;k[2]=((dat/10)%10);k[1]=((dat/100)%10);k[0]=((dat/1000)%10);if(k[0]==0) {k[0]=12;}if((k[0]==12)&&(k[1]==0)){ k[0]=12;k[1]=12;}if((k[0]==12)&&(k[1]==12)&&(k[2]==0)){k[0]=12;k[1]=12;k[2]=12;}for(seg=0;seg<4;seg++){display_number(lin,col,k[seg]);col=col+10;}}void display_signed_int(unsigned char lin,unsigned int col,signed int dat){unsigned int seg;unsigned char k[5],a;k[0]=12;if(dat<0){dat=(~dat)+1;k[0]=11;}k[4]=dat%10;k[3]=((dat/10)%10);k[2]=((dat/100)%10);k[1]=((dat/1000)%10);a=k[0];if(k[1]==0) {k[0]=12;k[1]=a;}if((k[1]==a)&&(k[2]==0)){ k[0]=12;k[1]=12;k[2]=a;}if((k[1]==12)&&(k[2]==a)&&(k[3]==0)){k[0]=12;k[1]=12;k[2]=12;k[3]=a;}for(seg=0;seg<5;seg++){display_number(lin,col,k[seg]);col=col+10;}}void display_unsigned_char(unsigned char lin,unsigned int col,unsigned char dat) {unsigned int seg;unsigned char k[3];k[1]=dat%10;k[0]=((dat/10)%10);for(seg=0;seg<2;seg++){display_number(lin,col,k[seg]);col=col+10;}}2、LCD.h#include <reg51.h>#include <absacc.h>#ifndef __LCD__#define __LCD__#define CWADD1 XBYTE[0x8000]#define DWADD1 XBYTE[0x8001]#define CRADD1 XBYTE[0x8002]#define DRADD1 XBYTE[0x8003]#define CWADD2 XBYTE[0x8004]#define DWADD2 XBYTE[0x8005]#define CRADD2 XBYTE[0x8006]#define DRADD2 XBYTE[0x8007]extern void LCD_Init();extern void display_cn(unsigned char lin,unsigned int col,unsigned int len,unsigned char *p);extern void display_signed_int(unsigned char lin,unsigned int col,signed int dat);extern void display_unsigned_int(unsigned char lin,unsigned int col,unsigned int dat);extern void display_unsigned_char(unsigned char lin,unsigned int col,unsigned char dat);extern void LCD_Clear(void);#endif1、MCU.c#include <reg51.h>#include "MCU.h"#define oscillator 12000000void timer0_init(void){TMOD|=0x01;//Timer0 is 16 bits timer, timer1 is Baud rate generatorTH0=0x97;TL0=0xd5;TR0=1;ET0=1;}void uart_init(unsigned int baud_rate){PCON=0x00;SCON=0x50;TMOD|=0x20;TL1=256-(oscillator/384)/baud_rate;TH1=256-(oscillator/384)/baud_rate;TR1=1;ES=1;}2、MCU.h#ifndef __MCU__#define __MCU__extern void timer0_init(void);extern void uart_init(unsigned int baud_rate);#endif3、MODBUSASC.c#include <reg51.h>unsigned char xdata TX_buf[200]_at_ 0x9100;unsigned char xdata Dat[200] _at_ 0x9200;void Data_ASCII(unsigned char num,unsigned char * buf ){unsigned char a;a=(num>>4)&0x0f;if(a>9) buf[0]=a+0x37;else buf[0]=a+0x30;a=num&0x0f;if(a>9) buf[1]=a+0x37;else buf[1]=a+0x30;}unsigned char ASCII_Data(unsigned char* buf ){unsigned char a,b;a=buf[0]-0x30;if(a>9) a=a-0x07;b=buf[1]-0x30;if(b>9) b=b-0x07;a=(a<<4)|b;return (a);}unsigned char LRC(unsigned char*Msg_buf,unsigned char MsgLen){unsigned char LRC_buf = 0,i ;for(i=0;i<MsgLen;i++){LRC_buf=Msg_buf[i]+LRC_buf;}i=~LRC_buf;LRC_buf=i+1;return LRC_buf ;}void Send_modbusASC_UART(unsigned char* SendData,unsigned char DataLen) {unsigned char buf[2];unsigned int i,j,k;j=1;TX_buf[0]=0x3a;for(i=0;i<DataLen;i++){Data_ASCII(SendData[i],buf );TX_buf[j]=buf[0];j++;TX_buf[j]=buf[1];j++;}TX_buf[j]=0x0d;j++;TX_buf[j]=0x0a;j++;for(i=0;i<j;i++){TI=0;SBUF=TX_buf[i];while(!TI);TI=0;for(k=0;k<30;k++);}}void Send_modbusASC_Err(unsigned char FunNum,unsigned char ErrNum,unsigned char ID) {unsigned char temp[4];temp[0]=ID;temp[1]=FunNum+0x80;temp[2]=ErrNum;temp[3]=LRC(temp,3);Send_modbusASC_UART(temp,4);}void FunctionASC_NO3(unsigned char* Msg_buf,unsigned int* AO_state,unsigned char ID) {unsigned char a,i,j,n,temp[2];unsigned int Fun_addr,Fun_num;j=1;for(i=0;i<7;i++){temp[0]=Msg_buf[j];j++;temp[1]=Msg_buf[j];j++;Dat[i]=ASCII_Data(temp );}a=LRC(Dat,6);if(a!=Dat[6]) return;Fun_addr=(Dat[2]<<8)|Dat[3];Fun_num=(Dat[4]<<8)|Dat[5];if((Fun_num==0)||(Fun_num>64)){Send_modbusASC_Err(1,3,ID);return;}if(Fun_addr>63){Send_modbusASC_Err(1,2,ID);return;}Dat[0]=ID;Dat[1]=3;Dat[2]=Fun_num*2;j=3;n=Fun_addr;for(i=0;i<Fun_num;i++){Dat[j]=(unsigned char)(AO_state[n]>>8);j++;Dat[j]=(unsigned char)AO_state[n];j++;n++;}Dat[j]=LRC(Dat,j);Send_modbusASC_UART(Dat,j+1);}void FunctionASC_NO6(unsigned char* Msg_buf,unsigned int* AO_state,unsigned char ID) {unsigned char a,i,j,temp[2];unsigned int Fun_addr,Fun_out;j=1;for(i=0;i<7;i++){temp[0]=Msg_buf[j];j++;temp[1]=Msg_buf[j];j++;Dat[i]=ASCII_Data(temp );}a=LRC(Dat,6);if(a!=Dat[6]) return;Fun_addr=(Dat[2]<<8)|Dat[3];Fun_out=(Dat[4]<<8)|Dat[5];if(Fun_out>0xff00){Send_modbusASC_Err(1,3,ID);return;}if(Fun_addr>64){Send_modbusASC_Err(1,2,ID);return;}AO_state[Fun_addr]=Fun_out;j=1;for(i=0;i<5;i++){Dat[j]=Msg_buf[j];j++;}Dat[j]=LRC(Dat,j);Send_modbusASC_UART(Msg_buf,j+1);}4、MODBUSASC.h#ifndef _MODBUSASC_#define _MODBUSASC_#ifdef __cplusplusextern "C"{#endifextern void Data_ASCII(unsigned char num,unsigned char * buf );extern unsigned char ASCII_Data(unsigned char* buf );extern void FunctionASC_NO3(unsigned char* Msg_buf,unsigned int* AO_state,unsigned char ID);extern void FunctionASC_NO4(unsigned char* Msg_buf,unsigned int* AI_state,unsigned char ID);extern void FunctionASC_NO6(unsigned char* Msg_buf,unsigned int* AO_state,unsigned char ID);#ifdef __cplusplus}#endif5、MAIN.c#include <reg51.h>#include<LCD.h>#include<main.h>#include "mcu.h"#include "modbusASC.h"void wait(unsigned int x){unsigned int i;i=0;for(i=0;i<x;i++);}void timer0_isr(void)interrupt 1{TH0=0x3c;TL0=0xb0;ms_count++;if(ms_count>=20){ms_count=0;LED=~LED;S_flag=1;}}void UART_isr(void)interrupt 4{unsigned char a;RI=0;a=SBUF;if(a==0x3a)UART_offset=0;if(a==0x0a)UART_message=1;RX_buf[UART_offset]=a;UART_offset++;}void display(void){unsigned char i,col;col=28;display_unsigned_int(0,col,modbus_buf[0]);display_unsigned_int(1,col,modbus_buf[1]); }void ModbusASC_Msg(unsigned char* modmus_buf){unsigned char temp[2];unsigned char a;temp[0]=modmus_buf[1];temp[1]=modmus_buf[2];a=ASCII_Data(temp );if(a!=Mode_ID) return;temp[0]=modmus_buf[3];temp[1]=modmus_buf[4];a=ASCII_Data(temp );switch(a){case 0x03:{FunctionASC_NO3(modmus_buf,modbus_buf,Mode_ID);break;}case 0x06:{FunctionASC_NO6(modmus_buf,modbus_buf,Mode_ID);break;}}}void main(void){unsigned char i;LCD_Init();LCD_Clear();display_cn(0,0,1,RD_dat);display_cn(1,0,1,TD_dat);modbus_buf[0]=18;modbus_buf[1]=28;timer0_init();uart_init(2400);EA=1;Mode_ID=1;while(1){display( );if(UART_message==1){ModbusASC_Msg(RX_buf);UART_message=0;}if(S_flag==1){modbus_buf[0]++;S_flag=0;}}}6、MAIN.h#include <reg51.h>#ifndef MAIN_H__#define MAIN_H__code unsigned char RD_dat[]={ //纵向字节倒序。

51单片机modbus协议程序

51单片机modbus协议程序

51单片机modbus协议程序#include ;#define uint8 unsigned char#define uint16 unsigned int#define FOSC 16000000uint16 BAUD=9600;uint16 TEMP_Alert=1000;//字地址 0 - 255 (只取低8位)//位地址 0 - 255 (只取低8位)uint16 TempRegister; //用于测试字址址16 uint8 localAddr = 0x01; //单片机控制板的地址uint8 sendCount; //发送字节个数uint8 receCount;//接收到的字节个数//uint8 sendPosi;//发送位置uint8 xdata receBuf[1];uint8 xdata sendBuf[1];void checkComm0Modbus(void);uint16 getRegisterVal(uint16 addr,uint16*tempData);uint16 setRegisterVal(uint16 addr,uint16 tempData); void switch_BAUD(uint16 value);/*****************************波特率调整函数********************************/////函数功能:调整串口通信波特率////串口工作在工作方式1,即8位波特率可变模式/************************************************ ****************************/void switch_BAUD(uint16 value){switch(value){case 0x0001: { BAUD=9600;break; }case 0x0002: { BAUD=14400;break; }case 0x0003: { BAUD=19200;break; }}TR1=0;//停止定时器1ES=0;//关闭串口中断TH1=TL1=-(FOSC/12/32/BAUD);//设置波特率TR1=1;//开启定时器1ES=1;//使能串口中断}/***************************CRC校验码生成函数********************************/////函数功能:生成CRC校验码////本代码中使用查表法,以提高运算速度/****************************************************************************/uint16 crc16(uint8 *puchMsg, uint16 usDataLen){uint8 uchCRCHi = 0xFF ; /* 高CRC字节初始化 */uint8 uchCRCLo = 0xFF ; /* 低CRC 字节初始化 */uint16 uIndex ; /* CRC循环中的索引 */while (usDataLen--) /* 传输消息缓冲区 */{uIndex = uchCRCHi ^ *puchMsg++ ; /* 计算CRC */ uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex] ;uchCRCLo = auchCRCLo[uIndex] ;}return (uchCRCLo ;>; 8;sendBuf[i+4] = tempData & 0xff;}sendBuf[0] = localAddr;sendBuf[1] = 3; //function code : 03sendBuf[2] = byteCount;byteCount += 3;//加上前面的地址,功能码,地址共3+byteCount 个字节crcData = crc16(sendBuf,byteCount);sendBuf[byteCount] = crcData & 0xff;// CRC代码低位在前byteCount++;sendBuf[byteCount] = crcData >;>; 8 ;//高位在后sendCount = byteCount + 1;//例如byteCount=49,则sendBuf[]中实际上有49+1个元素待发Begin_send();}//void readRegisters(void)/********从机响应主机问询函数,function code : 16,设置多个寄存器值 *********/////函数功能:丛机根据串口接收到的数据包receBuf[]里面的内容,根据被强制寄存器////的起始地址,去设置相应寄存器的值,响应数据包同询问数据包////的内容相同,经过串口发送到主机。

关于51单片机上实现modbus协议

关于51单片机上实现modbus协议

关于51单片机上实现modbus协议你找一个MODBUS的协议详细资料好好看看,就是一种通讯约定,你按照它规定的格式通讯就可以了协议发送给询问方。

Modbus协议包括ASCII、RTU、TCP等,并没有规定物理层。

此协议定义了控制器能够认识和使用的消息结构,而不管它们是经过何种网络进行通信的。

标准的Modicon控制器使用RS232C实现串行的Modbus。

Modbus的ASCII、RTU协议规定了消息、数据的结构、命令和就答的方式,数据通讯采用Maser/Slave方式,Master端发出数据请求消息,Slave端接收到正确消息后就可以发送数据到Master端以响应请求;Master端也可以直接发消息修改Slave端的数据,实现双向读写。

Modbus协议需要对数据进行校验,串行协议中除有奇偶校验外,ASCII模式采用LRC校验,RTU模式采用16位CRC校验,但TCP模式没有额外规定校验,因为TCP协议是一个面向连接的可靠协议。

另外,Modbus采用主从方式定时收发数据,在实际使用中如果某Slave站点断开后(如故障或关机),Master端可以诊断出来,而当故障修复后,网络又可自动接通。

因此,Modbus协议的可靠性较好。

下面我来简单的给大家介绍一下,对于Modbus的ASCII、RTU和TCP协议来说,其中TCP和RTU协议非常类似,我们只要把RTU协议的两个字节的校验码去掉,然后在RTU协议的开始加上5个0和一个6并通过TCP/IP网络协议发送出去即可。

所以在这里我仅介绍一下Modbus的ASCII和RTU协议。

下表是ASCII协议和RTU协议进行的比较:协议开始标记结束标记校验传输效率程序处理ASCII :(冒号)CR,LF LRC 低直观,简单,易调试RTU 无无CRC 高不直观,稍复杂通过比较可以看到,ASCII协议和RTU协议相比拥有开始和结束标记,因此在进行程序处理时能更加方便,而且由于传输的都是可见的ASCII字符,所以进行调试时就更加的直观,另外它的LRC校验也比较容易。

51单片机的modbus

51单片机的modbus
#include "REG51.h"
#include <intrins.h>
#define uchar unsigned char
#define length 8
unsigned char sum=0;
unsigned int crc;
unsigned char crc_tmp=0;
/* CRC 高位字节值表 */
const uint8 code auchCRCHi[] = {
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
TH1=0xFA;
TL1=0xFA;
TR1=1;
//PS=1;
}
unsigned char delay(unsigned char j)
{
unsigned char k,l;
for(l=0;l<=j;l++ )
for(k=0;k<=10;k++);
return 0;
typedef unsigned char uint8;
typedef unsigned int uint16;
typedef unsigned long uint32;
uint16 crc16(uint8 *puchMsg, uint16 usDataLen);
sbit Send_Rcv=P3^2;
sbit bdog = P3^4;
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

网上关于单片机和力控modbus通信的实例很少,关键并不是modbus协议而是力控与单片机连接的设置,下面的程序是基于51单片机做的。

在正个调试过程中由于我们不清楚力控发送给单片机的请求数据格式,我们可以用串口调试工具进行串口调试,将力控发送请求显示在串口调试工具中,其中单片机的程序如下#include<reg52.h>#include<string.h>#define uchar unsigned char //一个字节#define uint unsigned int // 两个字节void send_char(unsigned char txd);uint rece_count=0;uint send_flag=0;uchar rece_buf[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};uint i;/*串行口初始化*/void chushi(){SCON=0x50; //串口工作方式1,即10位异步PCON=0x00;//波特率不倍增TMOD=0x20;TH1=TL1=0xfa;TR1=1;}/*主程序*/main(){chushi();rece_count=0;while(1){if(RI){RI=0;if(rece_count<8){rece_buf[rece_count]=SBUF;rece_count++;}}if(rece_count==8){send_flag=1;}while(send_flag==1){ for(i=0;i<8;i++){SBUF=rece_buf[i];while(TI==0) ;TI=0;}}}}打开力控运行,将发送的数据保存到单片机中,然后打开串口调试工具,显示如下:我们看力控发送请求的格式:01 03 ff ff 00 01 84 2e,最后的两位crc是高位在前,低位在后。

Crc的高低位的前后顺序一定要注意,尤其在单片机编程中。

单片机程序:#include<reg52.h>#include<string.h>#define uchar unsigned char //一个字节#define uint unsigned int // 两个字节void send_char(unsigned char txd);uchar send_buf[7];uchar rece_buf[8];uint i;uint crc_data;uchar rece_count=0;uchar send_flag=0;/*串行口初始化*/void chushi(){SCON=0x50; //串口工作方式1,即10位异步PCON=0x00;//波特率不倍增TMOD=0x20;TH1=TL1=0xfa; //22.1184M晶振TR1=1;}/*CRC校验表*/const uchar code auchCRCHi[] = { //数组定义必须加code ,否则出现空间不够用的情况0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,0x40} ;const uchar code auchCRCLo[] = {0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD,0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7,0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB,0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91,0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80,0x40} ;/*CRC计算程序*/uint crc16 (uchar *puchMsg, uint usDatalen){uchar uchCRCHi=0xff;uchar uchCRCLo=0xff;uint uindex;uint crcdata;while(usDatalen--){uindex=uchCRCHi^*puchMsg++;uchCRCHi=uchCRCLo^auchCRCHi[uindex];uchCRCLo=auchCRCLo[uindex];;}crcdata=uchCRCLo; //低位在前高位在后crcdata=crcdata<<8;crcdata=crcdata+uchCRCHi;return(crcdata);}/*主程序*/main(){chushi();send_buf[0]=0x01;//站址send_buf[1]=0x03;//读操作send_buf[2]=0x02;//字节数send_buf[3]=0x00;//第一个寄存器数据高字节send_buf[4]=0x01;//第一个寄存器数据低字节/*计算crc*/crc_data=crc16(send_buf,5);send_buf[6]=crc_data>>8; //低位send_buf[5]=crc_data; //高位while(1){if(RI){RI=0;if(rece_count<8){rece_buf[rece_count]=SBUF;rece_count++;}}if(rece_count==8){ if(rece_buf[0]==0x01){send_flag=1;}}if(send_flag==1){ for(i=0;i<7;i++){SBUF=send_buf[i];while(TI==0) ;TI=0;}send_flag=0;rece_count=0;}}}力控设置如下:Com口可以在电脑设备管理器中查找到这里面必须是03号命令,这在modbus中代表读操作,对于偏置我不是很明白,数据格式按这样选择是正确的。

相关文档
最新文档