|
我的单片机是从机,用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碗,继续卖。说白了,通货膨胀就是,你的钱是挣来的,他的钱是印来的,掺和在一起,你的钱就贬值了。
|