pic16f877a写的modbus程序,可与组态王无法通讯,组态王设置正确。求高人给看看

2020-02-08 12:11发布

/*********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++;
   }
}
}
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。