最近做的一个项目,大概是通过定时器定时20ms读取部分外部IO状态,当状态发生改变时,把数据发送到串口,同时串口按协议接收上位命令对其它IO做出输出或关闭输出。在长期工作后,某些机器会不停地往串口发同一串数据,有时候数据长度不对,有时候数据有乱码。用的是WINavr+avr studio.出问题时还能正常进入定时器中断,在主程序大循坏加看门狗没作用,加了很多冗余标志位也没用。
代码如下,希望大神帮忙下,很着急。弄了两个月没找到原因。
#include<avr/io.h>
#include<avr/iom128.h>
#include<avr/interrupt.h>
#include <avr/wdt.h>
#define CLI() do { __asm__ __volatile__ ("cli"); } while (0)
#define SEI() do { __asm__ __volatile__ ("sei"); } while (0)
#define NOP() do { __asm__ __volatile__ ("nop"); } while (0)
#define uchar unsigned char
#define uint unsigned int
volatile uchar wdt1=1;
volatile uchar RE_rcorrect[128]; //正确接收到的新码;
volatile uchar wdt2=1;
//------------------------
volatile uchar RD_count;
volatile uchar Rdata;
volatile uchar usart0_Rbuff[128]; //接收缓冲器
volatile uchar usart0_REflag=0;
volatile uchar usart0_RSflag=0;
volatile uchar wdt3=1;
volatile uchar send_flag=0;
volatile uchar send_Tflag=0;
volatile uchar Send_buff[128]; //发送缓冲器
volatile uchar REtime=0;
volatile uchar RecDataBCC=0;
volatile uchar IN_BCC=0;
volatile uchar OUT_BCC=0;
volatile uchar Send_buff[128]; //发送缓冲器
volatile uchar wdt4=1;
volatile uchar temA=0;
volatile uchar temB=0;
volatile uchar temA1=0;
volatile uchar temB1=0;
volatile uchar Send_buff[128]; //发送缓冲器
volatile uchar PasttemA=0;
volatile uchar PasttemB=0;
volatile uchar passmark=0;
volatile uchar passcount=0;
volatile uchar wdt5=1;
volatile uchar Send_tem[128]; //T发送缓冲器
void usart0_send(uchar sdata);
void String_send(uchar *p,uchar Lenth);
volatile uchar wdt6=1;
volatile uchar t1=0;
volatile uchar t2=0;
volatile uchar t3=0;
volatile uchar t4=0;
volatile uchar usart0_ST1buff[128]; //T发送缓冲器
volatile uchar send_INmark=0;
volatile uchar send_OUTmark=0;
void timer1_init(void)
{
TCCR1A=0x00; //普通模式,不与OCnA相连。
TCCR1B=0x03; //Clk/64
TCCR1C=0x00; //不设置强制输出通道
TCNT1H=0xEC; //定时20ms=次数/每秒次数=(FFFF-初值)/(F_CU/分频)
TCNT1L=0x77;
// TCNT1H=0xF6; //定时10ms=次数/每秒次数=(FFFF-初值)/(F_CU/分频)
// TCNT1L=0x3B;
TIMSK|=_BV(TOIE1);//使能定时器1;
}
ISR(SIG_OVERFLOW1)//定时器1中断
{
uchar i=0;
NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();
wdt1=0;
TCNT1H=0xEC; //定时20ms=次数/每秒次数=(FFFF-初值)/(F_CU/分频)
TCNT1L=0x77;
//--------------------------------------
if(REtime<=0) //串口接收超时丢弃。
{
usart0_RSflag=0;
}
else
{
REtime--;
}
temA=PINA;
temB=PINB&0x0f;
NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();
temA1=PINA;
temB1=PINB&0x0f;
if((temA==temA1)&&(temB==temB1))
{
IN_BCC=0;
Send_tem[0]=0x02;
IN_BCC=0x42;
Send_tem[1]=0x42;
for(i=0;i<8;i++)
{
if(((temA>>i)&0x01)==0x01)
{
Send_tem[2+i]=0x30;
}
else
{
Send_tem[2+i]=0x31;
}
IN_BCC=IN_BCC^Send_tem[2+i];
}
for(i=0;i<4;i++)
{
if(((temB>>i)&0x01)==0x01)
{
Send_tem[10+i]=0x30;
}
else
{
Send_tem[10+i]=0x31;
}
IN_BCC=IN_BCC^Send_tem[10+i];
}
Send_tem[14]=IN_BCC;
Send_tem[15]=0x03;
if((PasttemA!=temA)||(PasttemB!=temB))
{
PasttemA=temA;
PasttemB=temB;
send_Tflag=1; //注销这一行即可取消主动反馈
send_INmark=1;//注销这一行即可取消主动反馈
}
}
wdt1=1;
}
void usart0_init()
{
UCSR0B=0x00; //close USART
UCSR0A=0x00;
UCSR0C=0x06;
UBRR0H=0x00;
UBRR0L=0x67;
UCSR0B=0xd8; //open USARTd8
}
ISR(USART0_TX_vect)
{
NOP();
UCSR0A |= (1<<6); //发送结束清零
}
void usart0_send(uchar sdata)
{
NOP();NOP();NOP();NOP();
if((sdata!=0x02)&&(sdata!=0x30)&&(sdata!=0x31)&&(sdata!=0x42)&&(sdata!=0x43)&&(sdata!=0x44)&&(sdata!=0x45)&&(sdata!=0x03))
{
wdt6=0;
}
else
{
//wdt6=1;
while(!(UCSR0A&(1<<UDRE0)));
UDR0=sdata;
}
NOP();NOP();NOP();NOP();
// while(!(UCSR0A&(1<<TXC0)));
// UCSR0A |= _BV(TXC0);
}
ISR(USART0_RX_vect) //按协议存储除了命令头02和结束03之外的所有数据
{
NOP();NOP();NOP();NOP();
wdt2=0;
if(RXC0) //接收到数据
{
REtime=50;//1没接收完命令将丢弃,定时器中1s后usart0_RSflag=0;
Rdata=UDR0; //提取数据
if(Rdata==0x02) //命令头
{
usart0_RSflag=1;//符合协议开始接收
RD_count=0; //接收个数计数
RecDataBCC=0; //初始化BCC校验值
}
else if(usart0_RSflag)
{
if((Rdata==0x03)&&(RecDataBCC==0)) //如果收到03并且BCC校验正确
{
usart0_RSflag=0; //结束接收
if(usart0_Rbuff[0]==0x43) //输出命令
{
for(uchar i=0;i<14;i++)
RE_rcorrect[i]=usart0_Rbuff[i];
usart0_REflag=1;
send_OUTmark=1;
}
else if(usart0_Rbuff[0]==0x41) //输入命令
{
send_Tflag=1;
send_INmark=1;
}
}
else if((Rdata==0x03)&&(RecDataBCC!=0))//校验不正确
{
usart0_RSflag=0;
RD_count=0;
RecDataBCC=0;
}
else
{
usart0_Rbuff[RD_count++]=Rdata; //存储数据
RecDataBCC=RecDataBCC^Rdata; // BCC校验
}
}
if(RD_count>14) //定长,收到命令头后只存14个数据,超出长度也不符合协议
{
usart0_RSflag=0; //重新开始接收
}
}
wdt2=1;
}
void usart0_handle(void)
{
uchar i;
wdt3=0;
switch(RE_rcorrect[0])
{
//-----------------------设置码 12路状态设置-------------------------------
case 0x43:
switch(RE_rcorrect[1])
{
case 0x30: PORTB&=~(1<<PB4);
break;
case 0x31: PORTB|=(1<<PB4);
break;
default: break;
}
switch(RE_rcorrect[2])
{
case 0x30: PORTB&=~(1<<PB5);
break;
case 0x31: PORTB|=(1<<PB5);
break;
default: break;
}
switch(RE_rcorrect[3])
{
case 0x30: PORTB&=~(1<<PB6);
break;
case 0x31: PORTB|=(1<<PB6);
break;
default: break;
}
switch(RE_rcorrect[4])
{
case 0x30: PORTB&=~(1<<PB7);
break;
case 0x31: PORTB|=(1<<PB7);
break;
default: break;
}
switch(RE_rcorrect[5])
{
case 0x30: PORTC&=~(1<<PC2);
break;
case 0x31: PORTC|=(1<<PC2);
break;
default: break;
}
switch(RE_rcorrect[6])
{
case 0x30: PORTC&=~(1<<PC3);
break;
case 0x31: PORTC|=(1<<PC3);
break;
default: break;
}
switch(RE_rcorrect[7])
{
case 0x30: PORTC&=~(1<<PC4);
break;
case 0x31: PORTC|=(1<<PC4);
break;
default: break;
}
switch(RE_rcorrect[8])
{
case 0x30: PORTC&=~(1<<PC5);
break;
case 0x31: PORTC|=(1<<PC5);
break;
default: break;
}
switch(RE_rcorrect[9])
{
case 0x30: PORTC&=~(1<<PC6);
break;
case 0x31: PORTC|=(1<<PC6);
break;
default: break;
}
switch(RE_rcorrect[10])
{
case 0x30: PORTC&=~(1<<PC7);
break;
case 0x31: PORTC|=(1<<PC7);
break;
default: break;
}
switch(RE_rcorrect[11])
{
case 0x30: PORTC&=~(1<<PC0);
break;
case 0x31: PORTC|=(1<<PC0);
break;
default: break;
}
switch(RE_rcorrect[12])
{
case 0x30: PORTC&=~(1<<PC1);
break;
case 0x31: PORTC|=(1<<PC1);
break;
default: break;
}
//--------------------------------
OUT_BCC=0;
Send_buff[0]=0x02;
Send_buff[1]=0x44;
OUT_BCC=0x44;
for(i=0;i<12;i++)
{
Send_buff[i+2]=RE_rcorrect[i+1];
OUT_BCC=OUT_BCC^RE_rcorrect[i+1];
}
Send_buff[14]=OUT_BCC;
Send_buff[15]=0x03;
// send_flag=1;
//-------------------------------
break;
default: break;
}
wdt3=1;
}
//------------------------------
//IO
//------------------------------
void IO_iniaitil(void)
{
DDRE=0xfe; //E口设成输出 11111110
PORTE=0xff;
DDRA=0x00; //A口设成输入
PORTA=0xff; //
DDRB=0xF0; //B口低四位设成输入,高四位为输出
PORTB=0x0f; //
DDRC=0xff; //C口设成输出
PORTC=0x00; //00000000
wdt1=1;
wdt2=1;
wdt3=1;
wdt4=1;
wdt5=1;
wdt6=1;
}
int main(void)
{
CLI();
IO_iniaitil();
timer1_init();
usart0_init();
SEI(); //开总中断
wdt_enable(WDTO_250MS); //启动开门狗250ms
wdt_reset();//开始喂看门狗
while(1)
{
if((send_Tflag==1)&&(send_INmark==1))//输入
{
wdt4=0;
send_Tflag=0;
TIMSK&=~_BV(TOIE1);//关闭定时器中断
for(t1=0;t1<16;t1++)
{
usart0_ST1buff[t1]=Send_tem[t1];
}
TIMSK|=_BV(TOIE1);//使能定时器1中断;
for(t2=0;t2<16;t2++)
{
usart0_send(usart0_ST1buff[t2]);
}
send_INmark=0;
wdt4=1;
}
if((usart0_REflag==1)&&(send_OUTmark==1))//输出
{
wdt5=0;
usart0_REflag=0;
usart0_handle();
for(t3=0;t3<16;t3++)
{
usart0_send(Send_buff[t3]);
}
send_OUTmark=0;
wdt5=1;
}
if((wdt1==1)&&(wdt2==1)&&(wdt3==1)&&(wdt4==1)&&(wdt5==1)&&(wdt6==1))
{
wdt_reset();//喂看门狗
}
}
}
故障现象为串口不停发送Send_buff[0]到Send_buff[15]的数据,有时候是不是0-15的数据,只有其中一段或者夹着乱码,此时定时器还能进中断更新Send_buff[]的数据。搞了很多天没找到原因,压力很大,求解救。 |