wam_master 发表于 2007-8-20 10:17:05

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

我的单片机是从机,用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;

int send_data;

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

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

intsend_sp=0 ;          //发送数组的下标

int address=11;          //机号为11

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

int variable_data={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=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=(unsigned char)(data);

send_data=(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++; }



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

//出错函数

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

void error(unsigned char data)

   {

unsigned char add;

num_send=5;

send_data=0x11;

send_data=data;

add=cal_crc(send_data,3);

fenli(add,3);

}



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

//装数组函数

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

void data_act(void)

   {

unsigned int add,i,n;

send_data=address;

add=zhuhe(recieve_data,recieve_data);

add=add*2-2;



   if(recieve_data==3)

   {

   n=zhuhe(recieve_data,recieve_data);

   num_send=6+n;

   send_data=recieve_data;

   send_data=recieve_data;

   send_data=recieve_data;

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

   send_data=variable_data;

   n=4+n;

   i=cal_crc(send_data,n);

   fenli(i,n);

}

   else if(recieve_data==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,recieve_data);

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==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=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);

}





}

}

MicroPLC 发表于 2007-8-20 21:13:56

你的程序好长。。。

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

仅供参考。

icecool 发表于 2007-8-20 21:44:14

建议先别设置时间

xiaojingzi001 发表于 2007-8-20 21:57:36

索引?程序中没有索引啊?

xiaojingzi001 发表于 2007-8-20 21:57:44

索引?程序中没有索引啊?

xiaojingzi001 发表于 2007-8-20 21:58:31

索引?程序中没有索引啊?

MicroPLC 发表于 2007-8-20 22:12:41

没有索引怎么判断一条指令的啊?你是modbus协议吗?

xiaojingzi001 发表于 2007-8-21 10:03:42

可是程序中哪一部分是索引啊?

jiangzhimin 发表于 2013-3-23 20:04:07

D7变量干什么的?
页: [1]
查看完整版本: 我的MODBUS程序在调试的时候有的时候接收数据正常有的时候不正常怎么回事啊