ATmega 8 ICP 解码NEC
利用ATmega8的ICP解码遥控器,精准快速,希望对初学者有帮助。以下是部分代码:
#define IR_state_0 0 //无遥控信号
#define IR_state_1 1 //引导码前段
#define IR_state_2 2 //引导码后段
#define IR_state_3 3 //数据码前段
#define IR_state_4 4 //数据码后段
volatile uInt stamp=0; //暂存时间印记
volatile uCharcount=0; //32位数据计数
volatile uChar state=0; //状态机
volatile uChar times=0;
volatile uChar IRCOM; //保存接收的遥控数据
volatile uLongNec_ircom=0;
volatile uCharADDRESS=0;
volatile uCharIRCODE=0;
volatile uChar err_flag=0;
//************************端口初始化*********************************
void STF_INIT(void)
{
PORTB=0X00;
PORTB|=(1<<Freq_ICP);
DDRB|=(1<<MOSI )|(1<<SCK)|(1<<DISPPL);
DDRB&=~(1<<Freq_ICP);
PORTD=0x00;
DDRD|=(1<<LcdRs)|(1<<LcdEn)|(1<<RXD)|(1<<TXD);
DDRD &= ~((1<<KEY_sta)|(1<<IRIN));
PORTC=0x00;
DDRC=0xff;
}
//******************test*************************
void Test (void)
{
STF_INIT();
Timer1_INIT();
Reset_IR();
sei();
while(1);
}
/**************************************
*
* NEC红外协议解码
*
**************************************/
void NEC_Decode(void)
{
switch(state)
{
case IR_state_0: //第一次中断,数据丢弃(下降沿中断)
state = IR_state_1;//设置为状态1
break;
case IR_state_1: //接收引导码前半段(9ms)(上升沿中断)
if ((stamp >8500)&&(stamp<9500))
state = IR_state_2; //设置为状态2
else
Reset_IR();//干扰信号,复位接收状态
break;
case IR_state_2: //接收引导码后半段(4.5ms)(下降沿中断)
if ((stamp >4000)&&(stamp<5000))
state = IR_state_3; //设置为状态3
else
Reset_IR();//干扰信号,复位接收状态
break;
case IR_state_3://过滤掉数据码前半部分(560us)(上升沿中断)
state = IR_state_4; //设置为状态4
break;
case IR_state_4://接收数据后半段(0=565us,1=1690us)(下降沿中断)
count++;
if(count<=32)//接收32位数据(低位在前)
{
state = IR_state_3; //回到状态3
Nec_ircom=Nec_ircom>>1;
if(stamp >1600&&stamp<1800) //保存数据"1"
{
Nec_ircom|=0x80000000;
}
}
else
{
IRCOM =( Nec_ircom&0xff);//地址
IRCOM = ((Nec_ircom>>8)&0xff); //地址反
IRCOM = (Nec_ircom>>16)&0xff;//数据
IRCOM = (Nec_ircom>>24)&0xff;//数据反
IRCOM = ~IRCOM;
if(IRCOM==IRCOM)
{
LcdClear(1);
LcdClear(2);
LcdWcom(0x80);
printf("addr:%2X code:%2X",IRCOM,IRCOM);
}
else
{
LcdWcom(0xc0);
printf("Decoding error !");
}
ADDRESS = IRCOM;
IRCODE = IRCOM;
Reset_IR(); //完成接收,复位接收状态
}
break;
}
}
/**************************************
*
* 复位状态设置
*
**************************************/
void Reset_IR (void)
{
TCCR1B &=~( _BV(ICES1)); // 设置为下降沿触发
state = IR_state_0; //复位为状态0
count=0;
err_flag=0;
}
/**************************************
*
* 初始化定时器1
*
**************************************/
void Timer1_INIT(void)
{
TCCR1B=0x00;
TCCR1A = 0x00; //普通模式
TCNT1H = 0x00; //8MHz
TCNT1L = 0x00;
TIMSK |=_BV(TICIE1); //输入捕捉中断标志
TIFR |= (1<<TOV1); //清中断标志
TCCR1B|= (1<<ICNC1)|((1<<CS11)); //开启输入捕捉口的噪声抑制器,8分频
TCCR1B&=~(1<<ICES1); //下降沿触发
}
/**************************************
*
* 定时器1 输入捕捉信号中断
*
**************************************/
ISR(TIMER1_CAPT_vect)
{
stamp= ICR1L; //保存时间印记
stamp+=(uInt)(ICR1H<<8);
TCNT1H = 0x00; //8MHz
TCNT1L = 0x00; //清零计数器
TCCR1B ^= _BV(ICES1); //切换捕获的触发方式
NEC_Decode();
}
好像是AVR GCC的,时间可以直接读取的,也可以不用分的, stamp=ICR1,虽然说要先读低位先,看看反汇编 askme 发表于 2014-9-13 09:33
好像是AVR GCC的,时间可以直接读取的,也可以不用分的, stamp=ICR1,虽然说要先读低位先,看看反汇编 ...
是的,可以直接读取
tjiang 发表于 2014-9-13 09:41
是的,可以直接读取
还有捕捉到时间不用清零,加上溢出修正就可以了,这样定时器又可以当定时器用,而不是单单的为了解码一个功能 askme 发表于 2014-9-13 09:53
还有捕捉到时间不用清零,加上溢出修正就可以了,这样定时器又可以当定时器用,而不是单单的为了解码一个 ...
溢出修正怎么设置? 学习一下下 用捕获这么奢侈,整个定时器都给您霸占了。其实用定时中断查询就好了,噪声容限更高,定时器还能作其它用途。 amigenius 发表于 2014-9-13 12:30
用捕获这么奢侈,整个定时器都给您霸占了。其实用定时中断查询就好了,噪声容限更高,定时器还能作其它用途 ...
也可以用定时器,在资源足够的情况下,用ICP捕捉更容易编写 tjiang 发表于 2014-9-13 15:53
也可以用定时器,在资源足够的情况下,用ICP捕捉更容易编写
本姑娘,其实定时器查询更简单,连捕获寄存器设置都不用折腾了 用定时器查询,十多行代码就能解决了,孰简单?
amigenius 发表于 2014-9-15 12:45
用定时器查询,十多行代码就能解决了,孰简单?
那麻烦仁兄慷慨解囊,分享一下你写的代码。 对啊,对啊,分享一下啊 tjiang 发表于 2014-9-15 17:00
那麻烦仁兄慷慨解囊,分享一下你写的代码。
#define LeadCodeMin 70
#define LeadCodeMax 130
#define OneCodeMin 12
#define OneCodeMax 25
#define ZeroCodeMin 4
#define ZeroCodeMax 12
uint8 IR_RecvCt=0; // 捕捉数据暂存
uint8 IR_Recv_Step=0; //接收状态
uint8 IR_Recv_int=0; //接收到一次有效的遥控指令就置1
uint8 IR_RecvBuf; //接收到的数据
uint8PulseWidth; //捕捉到的脉冲宽度
#define IR_RecvCt_Srv(){IR_RecvCt++;if(IR_RecvCt>=250){IR_RecvCt=0;IR_Recv_Step=0;}}
void IR_Recv_Srv(void){ //遥控解码,定时中断
uint8 i;
static uint8BitCt=0; // //接收位计数器
static uint8tmpByte=0; //正在接收的字节
static uint8 preIRin=1;
uint8 IRin;
uint8 IRin_falling=0;
IR_RecvCt_Srv();
IRin=IR_INPUT(); //定义您的输入
if(IRin==0 && preIRin) IRin_falling=1;
preIRin=IRin;
if(IRin_falling){
PulseWidth=IR_RecvCt;IR_RecvCt=0;
if (IR_Recv_Step==0){BitCt=0;IR_Recv_Step=1;return;}
if(IR_Recv_Step==1){
BitCt=0;
if ((PulseWidth<=LeadCodeMax)&&(PulseWidth>=LeadCodeMin)){IR_Recv_Step=2;}
return;
}
if (IR_Recv_int!=0){IR_Recv_Step=0;return;} //如果主循环还未响应遥控信号,则不接收新的遥控信号
if(IR_Recv_Step!=2){IR_Recv_Step=0;}
if (PulseWidth<ZeroCodeMin){IR_Recv_Step=0;return;}
if (PulseWidth>=OneCodeMax){IR_Recv_Step=0;return;}
tmpByte>>=1;
if (PulseWidth>=OneCodeMin){tmpByte|=0x80;}
BitCt++;i=BitCt>>3;
if (((BitCt&0x07)==0)&&(i>0)){IR_RecvBuf=tmpByte;}
if (BitCt>=(IR_BUF_LEN*8)){BitCt=0;IR_Recv_int=1;IR_Recv_Step=0;}
}
}
amigenius 发表于 2014-9-15 19:38
#define LeadCodeMin 70
#define LeadCodeMax 130
#define OneCodeMin 12
定时器中断未设定,代码说明不规范,仁兄,还需请您再调整一下代码,可否? 不错 收藏了 mark!!!!!!
页:
[1]