各位达人,有个 AVR 单片机的问题,想求教一下,麻烦啦。
我最近在做一个案子,就是利用TCS3200 检测 LED 的颜色,TCS3200 检测到不同的颜色会输出不同的频率,也就利用单片的 做一个检测频率的程序,我已经利用51单片机初步实现频率检测的程序,但是51能检测的最大频率为:30~40 KHz,不能满足更高 频率的测量要求,所以我就选用 AVR 单片机(ATMEGA8L)来做,算法也是参照51写的,一个测量过程的算法是这样:配置 AVR 单 片的 INTO 的中断方式为上升沿触发,中断程序中有个计数器,第一次触发时,打开定时器1(定时器1用的是16位的计数方式)开 始 50ms 的定时, 中断每触发一次,计数器加1,直到50ms定时中断到了,关闭 INT0 和定时器1 ,然后调用数据处理函数,根据 计数器的值算出检测到的频率值。可是 AVR 单片机在运行的时候程序好像跑飞了一样,一个测量过程,定时器1好像中断了好几次 ,我分析了一下,应该是中断嵌套的时候出错了,我做了一些修正算法,但是程序还是不能正常的运行测量。我附上我写的程序,请各位达人,帮我看看,谢谢啦!
程序:
#include <iom8v.h>
#include <macros.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define uint unsigned int
#define ulint unsigned long int
#define uchar unsigned char
#define Led_ON PORTB &= ~BIT(PB1)
#define Led_OFF PORTB |= BIT(PB1)
#define Beep_ON PORTB |= BIT(PB2)
#define Beep_OFF PORTB &= ~BIT(PB2)
#define S0_ON PORTC |= BIT(PC0)
#define S0_OFF PORTC &= ~BIT(PC0)
#define S1_ON PORTC |= BIT(PC1)
#define S1_OFF PORTC &= ~BIT(PC1)
#define S2_ON PORTC |= BIT(PC2)
#define S2_OFF PORTC &= ~BIT(PC2)
#define S3_ON PORTC |= BIT(PC3)
#define S3_OFF PORTC &= ~BIT(PC3)
// low effectiv
#define OE_ON PORTD |= BIT(PD6)
#define OE_OFF PORTD &= ~BIT(PD6)
void Init();
void InitUART();
void InitTC1();
void InitINT0();
void delayms(uint z);
void Receive(uchar rbuf);
void SendChar(uchar TempBuf);
void SendString(const uchar *AddressPointer);
void AnalysisCommand();
void DisposeValue(ulint temp_data);
void ShowValue(uchar *p , signed char j);
void TestRed();
void TestBlue();
void TestGreen();
void TestClear();
void TestAll();
ulint count = 0 ;
uchar TimerONFlag ;
uchar ConvertFlag ;
uchar TestAllFlag ;
const uchar waittime=15;
const uchar CommandPrompt[]={"Command error , please check ! "};
struct
{
uchar index ;
uchar index_end;
uchar r_flag_end1;
uchar r_flag_end2;
uchar comm_infor[20];
} Receive_command={0,19,0,0,{0}};
void main()
{
Init();
delayms(2000);
SendString("Color Test ! \r");
SendString("Begin ...");
SendChar('\r');
while(1)
{
TestRed();
while(ConvertFlag==0);
delayms(2000);
}
}
void Init()
{
DDRD &= ~BIT(PD0) + ~BIT(PD2) ; // set PD0, PD2 as input RXD ,INT0
DDRD |=BIT(PD1)+ BIT(PD6); // set PD1, PD6(OE) as output TXD
DDRB |= BIT(PB1) + BIT(PB2) ; // set PB1 , PB2 as output
DDRC |= BIT(PC0) + BIT(PC1) + BIT(PC2) + BIT(PC3) + BIT(PC4) + BIT(PC5) ; // PC0--PC5,(S0--S3) as output
TimerONFlag=0 ; // not open Timer
CLI(); // clear global interrupt
InitUART();
InitTC1();
InitINT0();
S0_ON; // 100% output
S1_ON;
SEI(); // set global interrupt
}
void InitUART()
{
UCSRA = 0X00 ;
UCSRB = 0X00 ;
UCSRC = 0X00 ; // control register clear
UCSRA |= BIT(UDRE) ; // data buf empty , could receive data
UCSRB |= BIT(RXCIE) + BIT(RXEN) + BIT(TXEN); // enable RXB interrupt
UCSRC |= BIT(URSEL) + BIT(UCSZ1)+ BIT(UCSZ0); // SET 1
UBRR=0x2F; // baud=9600 7.3728 Mhz U2X = 0
}
void InitTC1()
{
TCCR1A &= ~BIT(WGM11) + ~BIT(WGM10);
TCCR1B &= ~BIT(WGM12) + ~BIT(WGM13) + ~BIT(CS10) + ~BIT(CS12) ;
TCCR1B |= BIT(CS11); // 8 divide frequency , usual mode
TCNT1 = 0X4BFF ; // 50ms
}
void InitINT0()
{
MCUCR |= BIT(ISC01) + BIT(ISC00) ; // INT0 rise edge trigger
}
void TestRed()
{
S2_OFF;
S3_OFF;
OE_OFF;
delayms(waittime);
ConvertFlag=0;
SendString("R :");
GICR |= BIT(INT0); // enable INT0
}
void TestBlue()
{
S2_OFF;
S3_ON;
OE_OFF;
delayms(waittime);
ConvertFlag=0;
SendString("B :");
GICR |= BIT(INT0); // enable INT0
}
void TestGreen()
{
S2_ON;
S3_ON;
OE_OFF;
delayms(waittime);
ConvertFlag=0;
SendString("G :");
GICR |= BIT(INT0); // enable INT0
}
void TestClear()
{
S2_ON;
S3_OFF;
OE_OFF;
delayms(waittime);
ConvertFlag=0;
SendString("I :");
GICR |= BIT(INT0); // enable INT0
}
void TestAll()
{
TestRed();
while(ConvertFlag==0);
TestGreen();
while(ConvertFlag==0);
TestBlue();
while(ConvertFlag==0);
TestClear();
while(ConvertFlag==0);
}
void SendChar(uchar TempBuf)
{
UCSRB &= ~BIT(RXCIE) ; // unable RXB interrupt?
UDR = TempBuf ;
while((UCSRA & BIT(TXC))==0);
UCSRA &= ~BIT(TXC) ; // clear flag bit
UCSRB |= BIT(RXCIE) ; // enable RXB interrupt
}
void SendString(const uchar *AddressPointer)
{
UCSRB &= ~BIT(RXCIE); // unable RXB interrupt
while('\0' != *AddressPointer )
{
UDR = *AddressPointer;
while((UCSRA & BIT(TXC))==0); // waiting send finish
UCSRA |= BIT(TXC); // send finish flag set 0
AddressPointer++;
}
UCSRB |= BIT(RXCIE); // enable RXB interrupt
}
void AnalysisCommand()
{
uchar i;
if((0==(strcmp( Receive_ ,"on"))) || (0==(strcmp( Receive_ ,"ON"))))
{
Led_ON;
Beep_ON;
SendString("Led ON");
SendChar('\r');
}
else if((0==(strcmp( Receive_ ,"off")))||(0==(strcmp( Receive_ ,"OFF"))))
{
Led_OFF;
Beep_OFF;
SendString("Led OFF");
SendChar('\r');
}
else
{
SendString(CommandPrompt);
for(i=0;i<Receive_command.index;i++)
Receive_[i]='\0';
Receive_command.index=0;
return ;
}
for(i=0;i<Receive_command.index;i++)
Receive_[i]='\0';
Receive_command.index=0;
}
void Receive(uchar rbuf )
{
uchar i;
uchar r_flag=0;
if((13==rbuf)||(10==rbuf))
{
if(13==rbuf)
Receive_command.r_flag_end1=1;
if(10==rbuf)
Receive_command.r_flag_end2=1;
r_flag= (1==Receive_command.r_flag_end1) && (1==Receive_command.r_flag_end2);
if(1==r_flag)
{
Receive_command.r_flag_end1=0;
Receive_command.r_flag_end2=0;
AnalysisCommand();
}
}
else
{
if((1==Receive_command.r_flag_end1)||(1==Receive_command.r_flag_end2))
{
Receive_command.r_flag_end1=0;
Receive_command.r_flag_end2=0;
for(i=0;i<Receive_command.index;i++)
Receive_[i]='\0';
Receive_command.index=0; // count set 0
}
Receive_[Receive_command.index]=rbuf;
Receive_command.index++ ;
if(Receive_command.index>=Receive_command.index_end) // avoid array overflow
{
for(i=0;i<Receive_command.index;i++)
Receive_[i]=0;
Receive_command.index=0;
}
}
}
void DisposeValue(ulint temp_data)
{
uchar value[20]={0};
signed char i=0;
if(temp_data==0)
{
if(TestAllFlag)
SendString("Light is Weak , Please check! ");
else
SendString("Light is Weak , Please check! \r ");
count=0;
ConvertFlag=1;
return ;
}
// temp_data=temp_data*100; // calculate frequency time 10ms
temp_data=temp_data*20; // time 50ms 100% output , Hz
while(temp_data!=0)
{
value[i]=temp_data % 10;
temp_data=temp_data / 10;
i++;
}
ShowValue(&value[0],i-1);
}
void ShowValue(uchar *p , signed char j)
{
while(j>=0)
{
SendChar(0x30+(*(p+j)));
if(j==3)
SendChar('.');
j=j-1;
}
if(TestAllFlag)
SendString(" KHz ");
else
SendString(" KHz \r");
count=0;
ConvertFlag=1;
}
/************************ delayms *****************************************/
void delayms(uint z)
{
uint i,j;
for(i=1;i<z;i++)
for(j=1;j<(uint)(7.3728*143-2);j++); // 7.3728 Mhz
}
/************************ interrupt *************************************/
#pragma interrupt_handler Int0: 2
void Int0(void)
{
TimerONFlag=1;
GIFR |= BIT(INTF0); // write "1" , clear interrupt flag bit
SEI(); // set global interrupt
count++; // counter rise edge
if(TimerONFlag)
TIMSK |= BIT(TOIE1); // open timer1
}
#pragma interrupt_handler TC1COMPA: 7
void TC1COMPA(void)
{
GICR &= ~BIT(INT0); // unable INT0
GIFR |= BIT(INTF0); // write "1" ,clear interrupt flag bit
TIMSK &= ~BIT(TOIE1); // unable TC1
TIFR |= BIT(TOV1); // write "1" ,clear interrupt flag bit
TCNT1 = 0X4BFF ; // 50 ms
TimerONFlag=0; // clear flag
DisposeValue(count-1);
}
#pragma interrupt_handler UARTReceive: 12
void UARTReceive(void)
{
Receive(UDR);
}