组态王51单片机ASCII协议编程
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
单片机源程序如下:
- #define uchar unsigned char
- #define uint unsigned int
- #define tim0 -50000
- #define BPS57600 -1 //11.0592
- #define BPS28800 -2 //11.0592
- #define BPS19200 -3 //11.0592
- #define BPS9600 -6 //11.0592
- #define BPS4800 -12 //11.0592
- //////////////////////////////////////////////////////////////
- //支持字节和字类型,由于他的浮点怪异所以不支持
- idata uchar DatB[4]; //组态字节
- idata uint DatW[4]; //组态整数
- idata float DatF[4]; //组态浮点
- uchar Addr;
- bit RECV=0;
- idata uchar Rbuf[40],Rptr,Rnum;
- idata uchar Tbuf[40],Tptr,Tnum;
- code uchar asc[]="0123456789ABCDEF";
- uchar AscHex(uchar m)
- {
- if(m>='0' && m<='9') return m-'0';
- else if(m>='A' && m<='F') return m-'A'+10;
- else if(m>='a' && m<='f') return m-'a'+10;
- return 0;
- }
- uchar AscByte(uchar p) //ASC变BYTE
- {
- uchar x1,x2;
- x1=AscHex(Rbuf[p]);
- x2=AscHex(Rbuf[p+1]);
- return x2+x1*16;
- }
- void ByteAsc(uchar p) //BUYE变ASC
- {
- Tbuf[Tnum++]=asc[p>>4];
- Tbuf[Tnum++]=asc[p&15];
- }
- bit ChkLRC() //接收数据包效验
- {
- uchar i,d,s=0;
- for(i=0;i<Rnum-2;i++) s^=Rbuf[i];
- d=AscByte(Rnum-2);
- return s==d;
- }
- void SetLRC() //发送数据包效验并发送
- {
- uchar i,s=0;
- for(i=0;i<Tnum;i++) s^=Tbuf[i];
- ByteAsc(s);
- Tbuf[Tnum++]=0x0d; //添加包结束符
- SBUF=0x40; //发送包起始并启动串口发送
- }
- void serial() interrupt 4 using 2 //串口数据收发
- {
- uchar m;
- if(RI) //接收部分
- {
- RI=0; m=SBUF;
- if(m==0x40) //帧开始
- {
- Rptr=0; Rnum=0;
- }
- else if(m==0x0D) //帧结束
- {
- RECV=1;
- }
- else if(Rnum<40) //包长限制
- {
- Rbuf[Rptr++]=m;
- Rnum++;
- }
- }
- if(TI) //发送部分
- {
- TI=0;
- if(Tnum>0)
- {
- SBUF=Tbuf[Tptr++];
- Tnum--;
- }
- }
- }
- //////////////////////////////////////////////////////
- void KingASC() //通信协议的处理程序
- {
- uint p,x0,x1,x2;
- uchar n,cmd,i;
- uchar *s;
- cmd=AscByte(2)&0xf;
- p=AscByte(4)*256+AscByte(6);
- n=AscByte(8);
- if((cmd&1)==0) //组态王从单片机读数据
- {
- Tnum=0; Tptr=0;
- ByteAsc(Addr);
- ByteAsc(n);
- switch(cmd&0x0c)
- {
- case 0x00: //字节变量处理
- s=(uchar*)DatB+p;
- for(i=0;i<n;i++)
- ByteAsc(s[i]);
- break;
- case 0x04: //字变量处理
- s=(uchar*)DatW+2*p;
- for(i=0;i<n/2;i++)
- {
- ByteAsc(s[2*i]);
- ByteAsc(s[2*i+1]);
- }
- break;
- case 0x08: //浮点变量处理
- case 0x0c: //浮点变量处理
- s=(uchar*)DatF+4*p;
- for(i=0;i<n/4;i++)
- {
- x1=s[4*i]&0x80;
- x2=s[4*i]<<1;
- x2+=(s[4*i+1])>>7;
- ByteAsc(x1+x2-126);
- ByteAsc((s[4*i+1])|0x80);
- ByteAsc(s[4*i+2]);
- ByteAsc(s[4*i+3]);
- }
- break;
- }
- SetLRC();
- }
- else //组态王向单片机写数据
- {
- switch(cmd&0x0c)
- {
- case 0x00: ////字节变量处理
- s=(uchar*)DatB+p;
- for(i=0;i<n;i++)
- s[i]=AscByte(10+2*i);
- break;
- case 0x04: //字变量处理
- s=(uchar*)DatW+2*p;
- for(i=0;i<n/2;i++)
- {
- s[2*i]=AscByte(10+4*i);
- s[2*i+1]=AscByte(12+4*i);
- }
- break;
- case 0x08: //浮点变量处理
- case 0x0c: //浮点变量处理
- s=(uchar*)DatF+4*p;
- for(i=0;i<n/4;i++)
- {
- x0=AscByte(10+8*i);
- x1=x0&0x80;
- x2=x0&0x7f;
- x2=x2+126;
- x0=x1|(x2>>1);
- s[4*i]=x0;
- x0=AscByte(12+8*i)&0x7f;
- if(x2&1) x0=x0|0x80;
- s[4*i+1]=x0;
- s[4*i+2]=AscByte(14+8*i);
- s[4*i+3]=AscByte(16+8*i);
- }
- break;
- }
- Tnum=0; Tptr=0;
- ByteAsc(Addr);
- Tbuf[Tnum++]='#';
- Tbuf[Tnum++]='#';
- SetLRC();
- }
- Rnum=0; Rptr=0;
- }
- void timer0() interrupt 1 //定时对串口收到的数据包进行处理
- {
- TH0=tim0>>8; TL0=tim0;
- if(RECV)
- {
- RECV=0;
- if(ChkLRC()) //先进行数据效验
- {
- if(AscByte(0)==Addr) KingASC(); //地址是本机则进行协议的处理
- }
- }
- }
- void Init() //对定时器及串口进行初始化
- {
- EA=1; ES=1; ET0=1;
- TMOD=0X21; IP=0x10;
- SCON=0X50; PCON=0X80;
- TH1=BPS19200; TR1=1; //串口波特率的设置
- TH0=tim0>>8; TL0=tim0; TR0=1;
- }
- 主函数:
- #include <reg52.h>
- #include <glzxj.h> //对协议的引用
- ///////////////////////////////////////////////////////
- main()
- {
- Init(); //资源的初始化
- DatB[0]=0xff; DatB[1]=0xff;
- DatW[0]=123; DatW[1]=234;
- DatW[2]=345; DatW[3]=456;
- DatF[0]=-1.123; DatF[1]=-1.145;
- DatF[2]=10.123; DatF[3]=100.145;
- Addr=1; //单片机地址设置
- while(1)
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有资料51hei提供下载:
组态王单片机ASCII协议编程.rar
(25.66 KB, 下载次数: 102)
|