打印
[AVR单片机]

ATmega16 红外遥控输入捕捉的程序问题

[复制链接]
4467|11
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tianyu4552|  楼主 | 2012-10-24 20:03 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
用的是NEC那个协议。1838的红外接收的数据口接PD6。利用定时器1输入捕获中断方式解码红外遥控。程序里有2个小地方有点看不懂。1、 初始化的时候是 用的是下降沿触发,为什么进入中断要改成上升沿触发了,而且复位还要改成下降沿?
2、 stamp是怎么在TCNT1里计数的,原理有点不懂。
我是新手,可能问的比较菜。大家帮我看看啊。程序如下:
volatile uint16_t stamp=0; //暂存时间印记
volatile uint8_t  count=0; //32位数据计数
volatile uint8_t  state=0; //状态机
volatile uint8_t  data[4]; //保存接收到的遥控数据

#define ir_state_machine_0 0 //无遥控信号
#define ir_state_machine_1 1 //引导码前段
#define ir_state_machine_2 2 //引导码后段
#define ir_state_machine_3 3 //数据码前段
#define ir_state_machine_4 4 //数据码后段

void init_ir(void)
{
//使用8MHz晶振,计数一次为1uS
// CLK/8 对系统时钟8分频并启动计时,下降沿触发中断
TCCR1B |= _BV(CS11);
//TCCR1B &=~( _BV(ICES1)); // 设置为下降沿
TIMSK |= _BV(TICIE1); //允许T/C1输入捕捉中断
state = ir_state_machine_0;
DDRB &=~(_BV(DDB0));
PORTB |=_BV(PORTB0); //启用PB0内部上拉电阻
}


/**************************************
*
* 复位状态设置
*
**************************************/
void reset_ir (void)
{
TCCR1B &=~( _BV(ICES1)); // 设置为下降沿触发
state = ir_state_machine_0; //复位为状态0
count=0;
}

/**************************************
*
* 定时器1输入捕获中断
*
**************************************/
ISR(TIMER1_CAPT_vect)
{
stamp= ICR1; //保存时间印记
TCNT1 = 0;   //清零计数器
TCCR1B ^= _BV(ICES1);   //切换捕获的触发方式
switch(state)
{
    case ir_state_machine_0: //第一次中断,数据丢弃(下降沿中断)
   state = ir_state_machine_1;//设置为状态1
    break;
      
    case ir_state_machine_1: //接收引导码前半段(9ms)(上升沿中断)
    if (stamp >8500&&stamp<9500)
    {
    state = ir_state_machine_2; //设置为状态2
      }
      else
      {
      reset_ir();//干扰信号,复位接收状态
      }
      break;
      
    case ir_state_machine_2: //接收引导码后半段(4.5ms)(下降沿中断)
      if (stamp >4000&&stamp<5000)
      {
       state = ir_state_machine_3; //设置为状态3
      }
      else if (stamp >2000&&stamp<2500)//连发码(2.25ms)
      { //可以加一个计数标志对连发计数.
       reset_ir();
      }
      else
      {
       reset_ir();//干扰信号,复位接收状态
      }
      break;

    case ir_state_machine_3://过滤掉数据码前半部分(560us)(上升沿中断)
      state = ir_state_machine_4; //设置为状态4
   break;

    case ir_state_machine_4://接收数据后半段(0=565us,1=1690us)(下降沿中断)
   count++;
   if(count<=32)//接收32位数据(低位在前)
   {
    state = ir_state_machine_3;//回到状态3
    data[(count-1)/8]>>=1;//依次将数据存到数组中
       if(stamp >1600&&stamp<1800) //保存数据"1"
       {
        data[(count-1)/8]|=0x80;//
       }
   }
      else
    {
       reset_ir();//完成接收,复位接收状态
    }
      break;
}
}

相关帖子

沙发
joyme| | 2012-10-25 15:40 | 只看该作者
1、无IR信号时为高电平,所以初始化为下降沿中断,表示有IR信号,程序开始解码
2、测量高电平脉宽,就是相邻上升沿和下降沿之间的时间,同样测试低电平脉宽就是相邻的下降沿和上升沿之间的时间。所以中断触发方式是间隔变化的
3、其实只测量相邻下降沿脉宽,也可以实现解码,那么引导码就是9ms+4.5ms =13.5ms, "1"的脉宽约2250us,"0" 脉宽约1120us,还有重复码等,看协议就知道了
4、计数的不是stamp(它只是个临时变量),ICR1是timer1作为输入捕捉寄存器,它记录了捕捉期间timer1的计数值

“当引脚ICP1 上的逻辑电平( 事件) 发生了变化,或模拟比较器输出ACO 电平发生了变
化,并且这个电平变化为边沿检测器所证实,输入捕捉即被激发:16 位的TCNT1 数据被
拷贝到输入捕捉寄存器ICR1,同时输入捕捉标志位ICF1 置位。如果此时ICIE1 = 1,输
入捕捉标志将产生输入捕捉中断。中断执行时ICF1 自动清零,或者也可通过软件在其对
应的I/O 位置写入逻辑"1” 清零。”

使用特权

评论回复
板凳
tianyu4552|  楼主 | 2012-10-26 14:05 | 只看该作者
2# joyme 谢谢!

使用特权

评论回复
地板
gxbltao| | 2014-12-4 08:31 | 只看该作者
谢谢  分享 学习了

使用特权

评论回复
5
implse| | 2014-12-4 22:03 | 只看该作者
不错

使用特权

评论回复
6
何勇茂| | 2014-12-7 15:11 | 只看该作者
长见识

使用特权

评论回复
7
ak64| | 2014-12-9 22:03 | 只看该作者
相当不错

使用特权

评论回复
8
自由自在2013| | 2015-2-9 16:10 | 只看该作者
学习了

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

0

主题

9

帖子

0

粉丝