/*********Modbus通信协议**********/
#include<pic.h>
#include <stdio.h>
#include<math.h>
#define uchar unsigned char
#define uint unsigned int
__CONFIG(0x3b31);
/**********全局变量的定义*********/
uint CRC16=0;
uint wdata,wdata2;//数据寄存器
uchar c[32]; // 命令寄存器
uchar counter=0; //帧前时间计数器
uchar counter2=0; //接受字节计数?
uchar cnt=0; //数据计数器
uchar mymeter=0; //本机标志位
uchar ADDR_H=0x01;//本机地址
bit flag=0;
/************************初始化*********************************/
void INIT()
{
T2CON=0x4d; //延时10ms
PR2=249;
TXSTA=0X04; //异步,高速波特率
SPBRG=0x19; //波特率为9600
RCSTA=0X90; //USART打开,连续接收串行数据
TRISC=0x80; //第七位接收,第六位发送
GIE=1;
PEIE=1;
TMR2IE=1;
RCIE=1;
mymeter=0; //本机标志位为0
counter2=0; //接受字节数为0
cnt=0; //数据计数为
}
//*******帧前延时时间**********
void delay(uint b) //延时函数,延时时间为bms
{
uchar i;
while(b--)
{
for(i=0;i<125;i++) //延时1ms
{;}
}
}
//**********CRC校验函数*********
unsigned int cal_crc( unsigned char *puchMsg, uchar usDataLen) //需要校验的数据地址和字节数
{
uint crc=0xffff;
uchar i;
while(usDataLen--!=0)
{
crc=crc^(*puchMsg);
for(i=0;i<8;i++)
{
if((crc&0x0001)==1)
{
crc=crc>>1;
crc^=0xA001;
}
else
{crc=crc>>1;}
}
puchMsg++;
}
return(crc);
}
/***********读数据功能函数**********/
void read_dat()
{
uchar i;
delay(10);
c[0]=1;
c[1]=3;
c[2]=6;
c[3]=wdata/256;
c[4]=wdata%256;
c[5]=wdata2/256;
c[6]=wdata2%256;
c[7]=wdata2/256;
c[8]=wdata2%256;
CRC16=cal_crc(c,9);
c[9]=CRC16%256;
c[10]=CRC16/256;
for(i=0;i<11;i++)
{
TXREG=c;
TXEN=1;
while(TXIF==0||TRMT==0);
TXEN=0;
}
}
/***********写数据功能函数**********/
void write_dat()
{
uchar i;
delay(10);
wdata=c[4]*256+c[5];
for(i=0;i<8;i++)
{
TXREG=c;
TXEN=1;
while(TXIF==0||TRMT==0);
TXEN=0;
}
}
//*********主函数******************
main()
{
uchar i;
INIT();//初始化程序
flag=0;
wdata=0x44;
wdata2=0x55;
while(1)
{
if(flag==1)
{
flag=0;
CRC16=c[7]*256+c[6]; //crc校验函数//如果校验正确 或不正确而后分析功能
if(CRC16==cal_crc(c,6)) //
{
switch(c[1])
{
case 0x01:
{ ;
break;}//取得一组逻辑线圈的当前状态(ON/OFF)
case 0x02:
{ ;
break;}//取得一组开关输入的当前状态(ON/OFF)
case 0x03:
{ read_dat() ;
break;}//在一个或多个保持寄存器中取得当前的二进制值
case 0x04:
{ ;
break;}//在一个或多个输入寄存器中取得当前的二进制值
case 0x05:
{ ;
break;}//强置一个逻辑线圈的通断状态
case 0x06:
{write_dat() ;
break;}//把具体二进值装入一个保持寄存器
//……?#############
default: break;
}
}
else //错误报告
{
c[1]=c[1]|0x80;
delay(10);
CRC16=cal_crc(c,6);
c[6]=CRC16%256;
c[7]=CRC16/256;
for(i=0;i<8;i++)
{
TXREG=c;
TXEN=1;
while(TXIF==0||TRMT==0);
TXEN=0;
}
//read_dat();
}
cnt=0;
}
else
asm("NOP");
}
}
//*******中断函数**********************
void interrupt pic()
{
if(RCIF==1)
{
uchar temp;
//GIE=0;
if(counter>=5) //是帧首
{
TMR2ON=0;
cnt=0;
temp=RCREG; //取出地址码
counter=0; //帧前时间清零
counter2=0;
if(temp==ADDR_H)//判断地址码是否正确
{
c[0]=ADDR_H;
mymeter=1; //如果正确就使标志位置1
}
else
{
mymeter=0;
}
}
else
{
if(mymeter==1) //若是本机
{
counter2++;
c[counter2]=RCREG;
if(counter2>=7)
{
mymeter=0;
counter2=0;
//counter=0;
flag=1;
TMR2ON=1;
}
}
}
//GIE=1;
}
if(TMR2IE==1&&TMR2IF==1) //定时10ms,帧前延时
{
TMR2IF=0;
if(counter>=5)
{
counter=5;
}
else
{
counter++;
}
}
}
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
一周热门 更多>