搜索
bottom↓
回复: 8

我的MODBUS程序在调试的时候有的时候接收数据正常有的时候不正常怎么回事啊

[复制链接]

出0入0汤圆

发表于 2007-8-20 10:17:05 | 显示全部楼层 |阅读模式
我的单片机是从机,用MODBUS协议与上位机通信,完成的功能很简单,只要上位机向下位机要数据,下位机能返回要的数据就行。

     我用MODBUS-RTU调试的。不知道为什么有的时候下位机返回来的数据对,有的时候不对,到底是为什么呢?哪位能指点一下,谢谢。附程序

#include <avr/io.h>

#include<avr/interrupt.h>

#include<math.h>

#include <avr/iom128.h>

#include "avr/delay.h"

#include <avr/SIGNAL.h>

//#include <macros.h>

//#include <Io_define.h>

//#include <serial.h>



//***********************

//变量定义

//***************************************

int fawan=0;

int num_recieve=0;

int D3=0;

int D7=0;

int recieve_data[20];

int send_data[100];

int  time=0;                         //定时器到0.5字节溢出,time加1

int  cuowu=0;                   //中断中用到的错误标志位

int  send_sp=0 ;          //发送数组的下标

int address=11;          //机号为11

int num_send;      //发送数组的长度

int variable_data[50]={1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9};

//*************************

//接收中断子程序

//**************************************************

//#pragma interrupt_handler usrt_resieve:19

//void usrt_resieve(void)

SIGNAL(SIG_USART0_RECV)

{if(D3==0)

{recieve_data[num_recieve]=UDR0;            //接收一个数据

num_recieve+=1;                       //接收数组下标加一

D3=0;                                  //计时标志清零

D7=0;

TCCR0=0x00;          //先停止定时计数器0

TCNT0=0xE5;         //初值0.5个字节,溢出TOV0=1

TCCR0=0x06;         //256分频,计时方式  重新启动定时器0

sei();

time=0;}

if(D3==1&&D7==0)

{D3=0;                                  //计时标志清零

D7=0;

TCCR0=0x00;          //停止定时计数器0

time=0;

cuowu=1;              //告诉主程序现在是1号错误,超时,进行相应的处理

num_recieve=0;

}

if(D3==1&&D7==1)

{time=0;

num_recieve=0;

fawan=1;

D3=0;

D7=0;}

}//接收usrt_resieve(void)中断程序到此结束



//*************************

//定时器0中断子程序

//**************************************************

//#pragma interrupt_handler t0:17

//void to(void)

SIGNAL(SIG_OVERFLOW0)

{TCCR0=0x00;          //先停止定时计数器0

TCNT0=0xE5;         //初值0.5个字节,溢出TOV0=1

TCCR0=0x06;         //256分频,计时方式  重新启动定时器0

time+=1;

if(time<5)

{D3=0;                                 

D7=0;}

else if(time>5&&time<9)

{D3=1;                                 

D7=0;}

else  

{D3=1;                                 

D7=1;

TCCR0=0x00;          //停止定时计数器0

}

}     //定时器0中断子程序to()到此结束







//***********************************************

//CRC校验子函数子函数

//************************************************8

unsigned int cal_crc(unsigned char *ptr, unsigned int len)  

             {   

              unsigned int crc=0xffff;   

              unsigned char i;   

              while(len!=0)

  {   

   crc^=*ptr;

               for(i=0;i<8;i++)

   {   

                if((crc&0x0001)==0) crc=crc>>1;

    else  

{

  crc=crc>>1;

  crc^=0xa001;  

}                     

               }  

   len-=1;

   ptr++;  

              }   

              return crc;

             }   







//********************************************

//分离

//********************************************

void fenli(unsigned int data,unsigned int data1)

     {

  send_data[data1]=(unsigned char)(data);

  send_data[data1+1]=(unsigned char)(data>>8);

}





//************************************

//组合

//******************************************8

unsigned int zhuhe(unsigned char data1,unsigned char data)

    {

unsigned int t;

t=data1;

t=(t<<8)+data;

return t;

}





//**************888

//发送字节

//**************************************

void send_run(void)

{

while( !(UCSR0A & (1<<UDRE0)) )

;

UDR0=send_data[send_sp];

send_sp++; }



//*********************************

//出错函数

//**************************************************8

void error(unsigned char data)

     {

  unsigned char add;

  num_send=5;

  send_data[1]=0x11;

  send_data[2]=data;

  add=cal_crc(send_data,3);

  fenli(add,3);

}



//*******************************8

//装数组函数

//*****************************************

void data_act(void)

     {

  unsigned int add,i,n;

  send_data[0]=address;

  add=zhuhe(recieve_data[2],recieve_data[3]);

  add=add*2-2;



   if(recieve_data[1]==3)

   {

   n=zhuhe(recieve_data[4],recieve_data[5]);

   num_send=6+n;

   send_data[1]=recieve_data[1];  

   send_data[2]=recieve_data[4];

   send_data[3]=recieve_data[5];  

   for(i=0;i<n;i++)

   send_data[i+4]=variable_data[i+add];

   n=4+n;

   i=cal_crc(send_data,n);

   fenli(i,n);

  }

   else if(recieve_data[1]==6)

  {     

   num_send=num_recieve;

   for(i=1;i<num_recieve;i++)

   send_data=recieve_data;

  }

  else

error(2);

  }



//********************************************

//比较传来的CRC值与计算的是否相等

//**************************************

unsigned char crc_recieve(unsigned char data)

       {

    unsigned int crc0,crc1;

crc0=cal_crc(recieve_data,num_recieve-2);

crc1=zhuhe(recieve_data[data-1],recieve_data[data-2]);

if(crc0=crc1) return 1;

else return 0;  

}      

  //*************************

//通信主程序

//**************************************************

main()

{

int flag;//CRC校验是否正确标志位

  int i;

//DDRE |= (1 << PE2);//将方向设为输出

// PORTE |= (1 << PE2);//输出1

//_delay_ms(10);

//****************************************8

cli();                      // 中断?

TIMSK|=(1<<0);                      //定时器0溢出使能

//串口初始化

//*************************************************

UCSR0B=0x00;

UBRR0H=0x00;

UBRR0L=0x47;              //9600bps 11.0592MHz

UCSR0C=0x26;             //偶校验,停止位一位,数据位数8位

UCSR0A=0x00;

//UCSR0B=0x98;             //允许发送接收数据,响应接收完成中断

UCSR0B = (1<<RXCIE0)|(1<<RXEN0)|(1<<TXEN0);//允许发送接收数据,响应接收完成中断

//485先设为接收状态

//********************************

DDRE|=(1<<PE2);

PORTE &= ~(1<<2);   //输出0

//  _delay_ms(10);

//SREG|=(1<<7);                     //全局中断开

sei();

while(1)

{



if(fawan==1)                        //说明已经接受完一帧数据

{fawan=0;

if (recieve_data[0]==address)    //机号判断正确

{flag=crc_recieve(num_recieve);

if(flag==1)

  {

data_act();

DDRE|=(1<<PE2);

PORTE |= (1 << PE2);   //输出1

//_delay_ms(10);

send_sp=0;

cli();

for(i=0;i<(num_send+2);i++)

{UCSR0B|=(1<<TXEN0);

send_run();}

sei();

DDRE|=(1<<PE2);

PORTE &= ~(1<<2)      ;//输出0

//_delay_ms(6);

}

}

}

if(cuowu==1)

{error(0);

cuowu=0;

send_data[0]=address;

DDRE|=(1<<PE2);

PORTE |= (1 << PE2);//输出1

//_delay_ms(10);

send_sp=0;

cli();     

for(i=0;i<(num_send+2);i++)

{UCSR0B|=(1<<TXEN0);

send_run();}

sei();

DDRE|=(1<<PE2);

PORTE &= ~(1<<2)      ;//输出0

//_delay_ms(6);

}





}

}

阿莫论坛20周年了!感谢大家的支持与爱护!!

你熬了10碗粥,别人一桶水倒进去,淘走90碗,剩下10碗给你,你看似没亏,其实你那10碗已经没有之前的裹腹了,人家的一桶水换90碗,继续卖。说白了,通货膨胀就是,你的钱是挣来的,他的钱是印来的,掺和在一起,你的钱就贬值了。

出0入0汤圆

发表于 2007-8-20 21:13:56 | 显示全部楼层
你的程序好长。。。

根据经验,一般这种情况原因可能是两个;其一,你的数据缓冲区和索引可能有错误,导致接收的数据排列顺序出错,误认为错误的指令,从而导致返回的数据错误。其二有可能是硬件原因,数据传送错误。

仅供参考。

出0入0汤圆

发表于 2007-8-20 21:44:14 | 显示全部楼层
建议先别设置时间

出0入0汤圆

发表于 2007-8-20 21:57:36 | 显示全部楼层
索引?程序中没有索引啊?

出0入0汤圆

发表于 2007-8-20 21:57:44 | 显示全部楼层
索引?程序中没有索引啊?

出0入0汤圆

发表于 2007-8-20 21:58:31 | 显示全部楼层
索引?程序中没有索引啊?

出0入0汤圆

发表于 2007-8-20 22:12:41 | 显示全部楼层
没有索引怎么判断一条指令的啊?你是modbus协议吗?

出0入0汤圆

发表于 2007-8-21 10:03:42 | 显示全部楼层
可是程序中哪一部分是索引啊?

出0入0汤圆

发表于 2013-3-23 20:04:07 | 显示全部楼层
D7变量干什么的?
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-10-3 17:19

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表