打印
[AVR单片机]

ATmega16编码旋扭外部中断问题,为何总是响应其中一种,求大神指点

[复制链接]
1947|11
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
yarnn|  楼主 | 2015-10-29 23:03 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
电路很简单,旋转编码器,两个脚接PD3和PD2,开启PD3的外部中断允许。中断响应试过下降沿,上升沿,任意变动,能响应。(PB0~PB4是发光二极管,没有仿真器,只有用点亮标志位来判断程序走到哪)

中断响应如下:   问题是无论哪种触发方式,左右旋转,一直响应PB3,也就是最后一个判断。(改过触发方式,改过  if (PIND3==0),结果都一样)

void int1_isr(void)

{

   CLI();    //禁止外部中断
    DDRB=0XFF;
   PORTB=0XFF;
    if (PIND3==0)           //先判断是高电平产生的中断还是低点平的中断
{
if (PIND2==0)      
   {PORTB&=~BIT(0);kon-=1;if(kon>4096)kon=0;}
else
   {PORTB&=~BIT(1);kon+=1;if(kon>4096)kon=4095;}
}

else
     {  if (PIND2==1)
       {PORTB&=~BIT(2); kon+=1;if(kon>4096)kon=4095;}
else
   {PORTB&=~BIT(3);kon-=1;if(kon>4096)kon=0;}
}
   
SEI();
}



求哪位大神,帮我看看,问题出在哪里

相关帖子

沙发
yarnn|  楼主 | 2015-10-29 23:18 | 只看该作者
刚才再仔细试了一下,下降沿触发,
把if 语句简单化,变成单层了


if (PIND2==1)      
   {PORTB&=~BIT(0);kon-=1;if(kon>4096)kon=0;}
else
   {PORTB&=~BIT(1);kon+=1;if(kon>4096)kon=4095;}


仅有这层判断了,还是一样,进入else判断,点亮PD1,改成
if (PIND2==0)   
   {PORTB&=~BIT(0);kon-=1;if(kon>4096)kon=0;}
else
   {PORTB&=~BIT(1);kon+=1;if(kon>4096)kon=4095;}
效果一样,没有改变,
也就是说,在中断处理里面,if失效了,直接执行esle,如果有多层就是直接执行esle里面的esle.不应该啊!想的头都痛了,也不知道原因在哪里。​ ​

使用特权

评论回复
板凳
yarnn|  楼主 | 2015-10-30 11:29 | 只看该作者
人气太低了吧,还是我的问题太简单,大侠们都不肖看一眼?

使用特权

评论回复
地板
yarnn|  楼主 | 2015-10-30 12:38 | 只看该作者
刚才试了下,把中断服务里面的处理程序全删了,只留一条,取PD口的值,输出到显示,结果一直是0XFF,
有两个问题,第一,PD为0XFF,那个PD3应该为高,我在之前改过if (PIND3==1)的判断语句为什么响应的也是if 的else处理。
第二个,明明设置低电平或是下降沿中断,PD3为什么取值时是高电平?难道哪里能设置,PIND存储器与PD口断开?看了两遍手册,也没找到这样的设置,想不通!~

使用特权

评论回复
5
SD10A| | 2015-10-30 20:11 | 只看该作者
你用的哪个编译器?
   你要判断PD2的电平 首先在初始化中高把它设置成输入

使用特权

评论回复
6
SD10A| | 2015-10-30 20:15 | 只看该作者
其次PD3最好设置成输入带上拉   以下降沿 或 上升沿  触发中断。

使用特权

评论回复
7
cdwess| | 2015-10-31 01:00 | 只看该作者
三个中断口都接了编码器,很好用,带加速,自己看看吧,你程序没贴完,估计你端口没设置好

//端口初始化
void port_init(void)
{
        PORTA = 0x00;        DDRA  = 0xFF;
        PORTB = 0x04;        DDRB  = 0xF9;
        PORTC = 0xFF;        DDRC  = 0x00;
        PORTD = 0x7D;        DDRD  = 0x82;
}
//外中断初始化
void int_init(void)
{
        MCUCR |= 0x0A;
        MCUCSR|= 0x00;
        GICR  |= 0xE0;
}

//外中断1服务程序
//#pragma interrupt_handler int1_isr:3
//void int1_isr(void)
ISR(INT0_vect)
{
        sei();
        if(Bl_Flag) Adj_data =10;
          else      Adj_data =1;
        if(Int_0)Adj_data +=0x80;
        Bl_Flag=20;
        Adj_data |=0x40;
        //delay_us(500);
}

ISR(INT1_vect)
{
        sei();
    if(Bl_Flag) Adj_data =10;
      else      Adj_data =1;
    if(Int_1==0)Adj_data +=0x80;     
    Bl_Flag=20;
        Adj_data |=0x20;
        //delay_us(500);
}

ISR(INT2_vect)
{
        sei();
        if(Bl_Flag) Adj_data =10;
          else      Adj_data =1;
        if(Int_2==0)Adj_data +=0x80;       
        Bl_Flag=20;
        Adj_data |=0x10;
        //delay_us(500);
}
/*****************************************************
函数名称:void Data_Adj(void)
函数功能: 编码数处理
******************************************************/
void Data_Adj(uchar adj_data)
{
        Time[8]=10000;
        /**********电流调节**********/
        if(adj_data & 0x10)
         {
            if(adj_data & 0x80)
                 {
                        adj_data &=0x0F;  //清标志位
                    if((Tea+adj_data)<=Max_A)Tea+=adj_data;                          
                   }
                   else
                    {
                          adj_data &=0x0F;  //清标志位
                          if((Tea-adj_data)>=200)Tea-=adj_data;
                           }          
           }
/**********电压调节**********/
if(adj_data & 0x20)
{
   if(Key_flag&0x1C)
     {
                 if(Key_flag&0x14)
                  {
                         if(adj_data & 0x80)
                          {
                                  adj_data &=0x0F;  //清标志位
                                  if(Down_wire<100)Down_wire++;
                           }
                           else
                            {
                                  adj_data &=0x0F;  //清标志位
                                  if(Down_wire>0)Down_wire--;
                             }                          
                     }
                         else
                         {
                           if(Key_flag&0x08)
                            {
                                 if(adj_data & 0x80)
                                 {
                                         if(Up_wire<100)Up_wire++;
                                   }
                                   else
                                        {
                                         if(Up_wire>0)Up_wire--;
                                          }               
                                  }                          
                           }         
           }
     else
          {

                  if(adj_data & 0x80)
                        {
                                adj_data &=0x0F;  //清标志位
                                if((Teb+adj_data)<=460)Teb+=adj_data;
                          }
                        else
                        {
                                adj_data &=0x0F;  //清标志位
                                if((Teb-adj_data)>=200)Teb-=adj_data;
                          }
                     
           }
}
        /**********行走调节**********/
        if(adj_data & 0x40)
        {
                if(adj_data & 0x80)
                {
                        adj_data &=0x0F;  //清标志位
                        if((Tec+adj_data)<=1000)Tec+=adj_data;      
                  }
                else
                {
                        adj_data &=0x0F;  //清标志位
                         if(Tec<20)
                          {
                                 if(Tec>0)Tec--;
                            }
                           else Tec-=adj_data;
                  }
          }
                    
          Adj_data=0;
}

//主函数
int main(void)
{
        init_devices();
               
        Max_A=e2prom_read(1)*256+e2prom_read(2);
        if(Max_A>2000)
         {
                Max_A=1250;
                e2prom_write(1,Max_A/256);             //存电流高位
                e2prom_write(2,Max_A%256);
           }
                     
        if((e2prom_read(3)<21) && (e2prom_read(3)>0))Memory=e2prom_read(3);
          else Memory=1,e2prom_write(3,Memory);
               
        if(e2prom_read(4)!=0xFF)Led0=e2prom_read(4)+1;
          else Led0=0x89,e2prom_write(4,Led0);
        if((e2prom_read(5)==1) || (e2prom_read(5)==2))Led1=e2prom_read(5);
          else Led1=1,e2prom_write(5,Led1);
          
        if(e2prom_read(500)<101)Down_wire=e2prom_read(500);
          else Down_wire=30,e2prom_write(500,Down_wire);
        if(e2prom_read(501)<101)Up_wire=e2prom_read(501);
          else Up_wire=60,e2prom_write(501,Up_wire);
          
        Read_memory(Memory);//读取通道参数
    if((Tea>2000) || (Teb>2000) || (Tec>2000))
         {
           Tea=600;           Teb=300;           Tec=400;
           Write_memory(Memory);          
        //Memory=1;
        //Led0=0x89;
        //Led1=0x01;                  
            }
                On_line=2000;
while(1)
  {
        WDR();//喂狗   
       
/********外设任务***********/
        if(Adj_data)Data_Adj(Adj_data);   //编码器数据调整
    //   function_MODBUS();//串口接收
//        if(!On_line)Fault_code =1; //通讯连线故障
//        if(Fault_code)Fault();
        //if(Show_falg)Show_falg=0,Segment_Result();//实际值处理

        }
}

使用特权

评论回复
8
yarnn|  楼主 | 2015-10-31 15:24 | 只看该作者
cdwess 发表于 2015-10-31 01:00
三个中断口都接了编码器,很好用,带加速,自己看看吧,你程序没贴完,估计你端口没设置好

//端口初始化

感谢回复,你的程序有点长看了一遍,没看太明白。
回复
你用的哪个编译器?
   你要判断PD2的电平 首先在初始化中高把它设置成输入

ICCavr7,设置成输入了,还是一样

回复,CDWESS

先说我的问题吧,我调试了很多遍,端口设置、触发方式,都有试着各种方法(包括输入,输出,上拉,高阻),效果一样,只要是直接与PIND相比较或是处理的数据就不行,比如if(PIND3==1),直接测试PD3口,为高或低电平,语句是没有效果的,只有把它读出来,比如,M=PIND,再对M进行判断,才有效果。
是不是意味着,PIND口,不能直接参与运算和判断?在单片机里面,他是仅读存储器,难道不能参与比较判断吗?

另外,你贴的程序里面,  我没理解错的话, if(Int_0)Adj_data +=0x80;    这句应该是判断INT0脚位高低,然后赋值吧,不知道你的头文件是什么,(Int_0)是直接的PIND2存储器还是取值后有过处理的值?
还有,你的程序这句是旋扭在增量,没有看如何判断减量。

我在网上也找到一个前辈的程序,很类似,他是判断ifD((PIND&0X04)==0),他是一个开源的数控电源,按说应该是验证过的,也就是说PIND口可以直接比较判断,和我的推断不一样,想不通,我的问题出在哪里

使用特权

评论回复
9
cdwess| | 2015-11-1 14:45 | 只看该作者
忘记给你贴宏定义了,#define Int_0     (PIND&(1<<PD4)),变量Adj_data数据是1或者10, Bl_Flag是倍率标志,最高位0x80是主程序用来判断旋转方向的位,来决定调节量是加或者减
  if(adj_data & 0x80)
                        {
                                adj_data &=0x0F;  //清标志位
                                if((Teb+adj_data)<=460)Teb+=adj_data;
                          }
                        else
                        {
                                adj_data &=0x0F;  //清标志位
                                if((Teb-adj_data)>=200)Teb-=adj_data;
                          }

使用特权

评论回复
10
yarnn|  楼主 | 2015-11-2 11:57 | 只看该作者
cdwess 发表于 2015-11-1 14:45
忘记给你贴宏定义了,#define Int_0     (PIND&(1

你的意思,你的程序是由按健或是主程序标志0X80,作为增量或是减量的标志,而不是在中断里面判断旋扭方向,对吧?这样确实可以减少干扰。

我的程序,是在中断里面判断pd3,和PD2的先后低电平来判断,旋扭转动方向。
现在问题算是初步解决,确实是个低级错误。if (PIND3==0)这样的使用方法是有错误的,AVR不能单独操作某个引脚,只能是if ((PIND&0X04)==1)才能成立,而前面由于个人习惯,缺了里面那对扩号,所以语句也没有生效。

为什么说初步解决呢,我在判断处理中加了有PB口作指示,在转动旋扭时,PB口四个灯都亮了,意味着四个处理子程序都生效了,但是增量减量都还正常,暂时不管了,现在又卡在19264液晶上了。电子单片机有五六年没碰了,看样子得重新学一遍了!~

使用特权

评论回复
11
cdwess| | 2015-11-3 20:09 | 只看该作者
中断里直接处理数据,如果这个编码器旋钮是多功能的,中断里的程序就很大,中断里处理尽量快捷,所以只置标志,主程序里来处理数据。

使用特权

评论回复
12
yarnn|  楼主 | 2015-11-5 11:09 | 只看该作者
看样子你的程序是多任务的了,谢谢你的回复了!

使用特权

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

本版积分规则

5

主题

29

帖子

0

粉丝