jihongyuan 发表于 2015-3-31 09:43:14

关于avr输入捕捉的问题

现在想用AVR的输入捕捉功能区捕捉一个16ms周期2ms高电平时间的方波
但是一直捕捉不到,求大神解释,急啊,急啊,不知道问题出在哪儿了,在线等啊,不胜感激
unsigned char up;
unsigned char down;

void port_init(void)
{
    PORTD = 0xFF;//输入上拉电阻使能,输出引脚为高电平
    DDRD = 0xBF;//PD4,PD5为输出,PD6为输入
}
void ICEInit(void)
{
    TCCR1A=0X00;//时钟与系统相同
    TCCR1B=0XC2;//使能噪声抑制,上升降沿触发,八分频,周期为1us
    TIMSK=0X20;//使能捕获中断
}
void main(void)
{
    DDRA=0xFF;    //PD口设成输出口
    PORTA=0xFF;
    port_init();//端口的初始化
    ICEInit();//输入捕获的初始化
    SEI();//打开总中断
    while(1)
    {
         if((down>9)&&(down<11))
      {
            Set_Bit(PORTA,0);
            Clr_Bit(PORTA,0);//PD0 置低
      }
      else if((down>19)&&(down<21))
      {
            Clr_Bit(PORTA,0);
            Set_Bit(PORTA,0);//PD0 置高
      }
    }
}
#pragma interrupt_handler CAPT_ISP:0X0A

void CAPT_ISP(void)
{
    unsigned char sreg;
    unsigned char ssreg;
    if(TCCR1B&(1<<ICES1))//假如是上升沿中断
    {
      ssreg = SREG;
      _CLI();
      up = TCNT1L;
      up |= ((unsigned int)TCNT1H << 8);//读取TCNT1的值
      SREG = ssreg;
      TCCR1B^=(1<<ICES1);
    }
    else//假如是下降沿中断
    {
      sreg = SREG;
      _CLI();
      down = TCNT1L;//读取TCNT1的值
      down |= ((unsigned int)TCNT1H << 8);
       if(up<down)
            down = (down - up)/10;
      SREG = sreg;
      TCCR1B |= (1<<ICES1);
    }
    TIFR&=(1<<ICF1);//清除中断标志位
}

xsh2005105326 发表于 2015-3-31 11:15:21

看看有没有中断产生。如果没有要么是输入信号问题,要么是ICP初始化问题,看看应用手册吧

jihongyuan 发表于 2015-3-31 11:20:28

xsh2005105326 发表于 2015-3-31 11:15
看看有没有中断产生。如果没有要么是输入信号问题,要么是ICP初始化问题,看看应用手册吧 ...

对着手册一位一位的确认了 没有问题啊 以前也调通过 现在中断都进不去 输入信号也有啊 很不解

zhanan 发表于 2015-3-31 12:00:55

本帖最后由 zhanan 于 2015-3-31 12:02 编辑

什么型号?

捕捉中断里面应该读ICR1寄存器吧,这个才是捕捉到的数据,用不着关中断读TCNT1
中断进不去,是不是和TIMSK1有关,这个是对应TC1的。

另外,AVR响应中断后捕捉标志会自动清0

alias 发表于 2015-3-31 12:07:25

jihongyuan 发表于 2015-3-31 11:20
对着手册一位一位的确认了 没有问题啊 以前也调通过 现在中断都进不去 输入信号也有啊 很不解 ...

使用大字体,小心ID不保。

jihongyuan 发表于 2015-3-31 12:51:26

zhanan 发表于 2015-3-31 12:00
什么型号?

捕捉中断里面应该读ICR1寄存器吧,这个才是捕捉到的数据,用不着关中断读TCNT1


mega16A ICR1不也是拷贝的TCNT1的值么,这两个寄存器都可以读取的啊,自动清零的状态只是在测频率的时候,要是测量占空比的话要手动清零,TIMSK的寄存器
• Bit 5 – TICIE1: T/C1输入捕捉中断使能
当该位被设为"1”,且状态寄存器中的I位被设为"1”时,T/C1的输入捕捉中断使能。一
旦TIFR的ICF1置位,CPU即开始执行T/C1输入捕捉中断服务程序 ( 见P43 “中断” )。
• Bit 4 – OCIE1A: 输出比较A匹配中断使能
当该位被设为"1”,且状态寄存器中的I位被设为"1”时,T/C1的输出比较A匹配中断使
能。一旦TIFR上的OCF1A置位,CPU即开始执行T/C1输出比较A匹配中断服务程序
(见P43 “中断” )。
• Bit 3 – OCIE1B: T/C1输出比较B匹配中断使能
当该位被设为"1”,且状态寄存器中的I位被设为"1”时,使能T/C1的输出比较B匹配中
断使能。一旦TIFR上的OCF1B置位,CPU即开始执行T/C1输出比较B匹配中断服务
程序 ( 见P43 “中断” )。
• Bit 2 – TOIE1: T/C1溢出中断使能
当该位被设为"1”,且状态寄存器中的I 位被设为”1” 时,T/C1的溢出中断使能。一旦
TIFR上的TOV1置位,CPU即开始执行T/C1溢出中断服务程序 ( 见P43 “中断” )。
我用的是0X20第五位置1上升沿中断,其他的都置零了,没问题啊

jihongyuan 发表于 2015-3-31 12:52:06

alias 发表于 2015-3-31 12:07
使用大字体,小心ID不保。

啊?这个有限制么?不知道啊,下次注意

gdjsfy_86 发表于 2015-3-31 15:37:25

1.先确认中断进去了没有,可以把Set_Bit(PORTA,0);Clr_Bit(PORTA,0);//PD0 置低   直接放中断里调用一下
2.unsigned char up;
unsigned char down;应该为unsigned int吧

jihongyuan 发表于 2015-3-31 15:48:57

gdjsfy_86 发表于 2015-3-31 15:37
1.先确认中断进去了没有,可以把Set_Bit(PORTA,0);Clr_Bit(PORTA,0);//PD0 置低   直接放中断里调用一下
...

int 是八位的最后的数据是16位的 所以我用的是char类型,中断没有进去,现在在找原因,但是输入捕捉中断是系统自动进入的,配置好了就行了,我把手册上看了几遍也没看出我哪儿配置错了啊

zhanan 发表于 2015-3-31 22:17:44

到底是进不去中断,还是数据处理有问题?

什么编译?#pragma interrupt_handler CAPT_ISP:0X0A这里是写中断号还是中断地址?

       down |= ((unsigned int)TCNT1H << 8);   down是8位的变量,怎么能装16位呢?

在中断里面点一个灯,不就能看到进没进中断了。

捕捉有ICR为什么不用,偏偏去读TCNT。读TCNT的时候,已经不是捕捉时刻的值了。

alias 发表于 2015-3-31 22:38:21

中断内会被改变的变量要加上 Volatile 描述,否则…{:shocked:}

jihongyuan 发表于 2015-4-1 09:30:11

zhanan 发表于 2015-3-31 22:17
到底是进不去中断,还是数据处理有问题?

什么编译?#pragma interrupt_handler CAPT_ISP:0X0A这里是写 ...

down 是char类型的已经改过为读取ICR1了,向量号是6,也改过来了,中断能进去了,但是数据处理好像还是不合适
unsigned char up;       //定义一个char类型的变量
unsigned char down;
#pragma interrupt_handler timer1_CAPT:6
void timer1_CAPT(void) //输入捕捉端口有下降沿电平,则触发中断
{
      unsigned char sreg;
        if(TCCR1B&(1<<ICES1))//假如是上升沿中断
        {
               TCNT1=0;//TCNT1清零
               TCCR1B^=(1<<ICES1);//设置为下降沿中断
               TIFR|=(1<<ICF1);
               //PORTA =~PORTA; //LED状态翻转
      }
        else if(!(TCCR1B&(1<<ICES1)))//假如是下降沿中断
   {
         sreg = SREG;
         _CLI();
         up = ICR1L;
         up |= ((unsigned int)ICR1H<<8);
         down = (up/100);
         SREG = sreg;
         TCCR1B|=(1<<ICES1);
       TIFR|=(1<<ICF1);
       //PORTA =~PORTA; //LED状态翻转
   }   
}
具体程序是这个样子的,但是down数据一直不对劲啊

jihongyuan 发表于 2015-4-1 09:31:15

alias 发表于 2015-3-31 22:38
中断内会被改变的变量要加上 Volatile 描述,否则…

啊?不是太明白,什么描述?

zhanan 发表于 2015-4-1 10:53:24

把up、down改为u16吧。 不然这句 up=((unsigned int)ICR1H<<8); 是无效的,也可能你故意丢的吧,8位就够了。
TCNT1=0;//TCNT1清零这句也是有问题的,16位的寄存器必须先写高字节,后写低字节。

正确的捕捉应该是这样的:按照捕捉的分辨率设置好定时器频率,启动定时器,捕捉一次,up记录下上升沿捕捉到的值ICR,再下降沿捕捉一次down记录一下,这两个捕捉在中断里面做,主程序中判断差值down-up就行了。不用改TCNT1的值,也不用关中断。

jihongyuan 发表于 2015-4-1 14:37:28

zhanan 发表于 2015-4-1 10:53
把up、down改为u16吧。 不然这句 up=((unsigned int)ICR1H

好的,我试试
页: [1]
查看完整版本: 关于avr输入捕捉的问题