飞思卡尔16位单片机(四)——GPIO输入功能测试

一、介绍

        在这篇文章中,我们以按键作为输入器件对飞思卡尔XEP100单片机的GPIO的输入功能进行测试。对应的硬件电路如下图所示。

        当按键未按下时,由于有上拉电阻R39~R312的作用,单片机检测到的电平为高电平;当按键按下时,单片机引脚与地短接,单片机检测到引脚为低电平。

         当按键按下时,按键输出端的原始电平如下图所示:

        由图中可以看出,在按键按下和松开时,按键的电平信号存在波动,一般为10~15ms,这样有可能导致误判。为了消除抖动,可行的方法有:硬件去抖和软件去抖两种方法。本文的电路上使用的方法为硬件去抖,即在按键的两端加了一个去抖电容。软件去抖的方法是在检测到按键按下后,延时10~15ms,跳过抖动的这段信号,再进行检测,如果是低电平则判断按键按下。

        本文的硬件电路的按键与单片机引脚的连接关系如下:

PTH3——KEY1

PTH2——KEY2

PTH1——KEY3

PTH0——KEY4

单片机的PH口是有中断功能的I/O口,因此对按键状态的读入有查询和中断两种方式。

        所谓查询方式是指,单片机以一定的时间间隔按时对输入口的电平进行读取。中断是指计算机在执行程序的过程中,当出现异常情况或特殊请求时,计算机停止现在执行的程序,转向对这些异常情况或特殊请求的处理,处理结束后再返回之前的程序的间断处,继续执行原程序。中断时单片机实时处理内部事件或外部事件的一种机制,当某种内部事件或外部事件发生时,单片机的中断系统将迫使CPU暂停正在执行的程序转而去执行中断事件,中断事件处理完毕后,再返回被中断的程序处,继续执行下去。中断机制如下图所示。   

在程序中使用中断具有以下优点:

(1)提高了CPU的效率。CPU与外围设备的工作方式有查询和中断两种方式,查询方法是无论外围设备是否需要服务,CPU每隔一段时间都要依次查询一遍,这种方法CPU需要花费时间做查询工作。而中断则是在外围设备需要服务时主动告诉CPU,CPU则停下当前的工作去处理中断程序,从而可以提高CPU的效率。

(2)可以实现实时处理。外围设备任何时刻都可以发出请求中断信号,CPU接到请求后及时处理,以满足实时的需求。

(3)可以及时处理故障。单片机系统运行过程中难免会出现故障,有许多事情是无法预料到的。如:电源掉电、存储器出错、外围设备工作不正常等,这时可以通过中断系统向CPU发送中断请求,由CPU及时转到相应的出错处理程序,从而提高了系统的可靠性。

        产生中断时,中断服务程序执行完毕后恢复单片机状态,单片机从被中断打断的地方继续执行。当某一中断事件发生,与该事件相对应的标志将被置位。如果该中断未使能,那么单片机不会对该中断作出反应。CCR寄存器中的全局中断屏蔽位I在复位之后为1,屏蔽掉所有中断事件。在用户程序完成堆栈指针和其他设置之后,清除I,允许单片机响应中断事件,程序中的 “EnableInterrupts;”语句就是实现使能中断的功能。当单片机接收到一个有效的中断请求,在响应之前,它会执行完当前运行的指令,然后逐周期执行以下过程:

        保存CPU寄存器到堆栈中
        设置CCR寄存器中的I=1,禁止全局中断
        获取当前所有挂起的待处理中断事件中最高优先级中断向量
        预取中断向量的地址排列到指令队列中
当单片机响应中断后,I自动置为1,避免中断嵌套。通常,ISR执行完毕后,I恢复为0(CCR从堆栈弹出)。如果在ISR中,清除I(即设置I=0),那么MCU有可能在当前中断事件未完成之前响应其他中断事件,即中断嵌套。中断嵌套可能对用户程序调试带来麻烦。

        当ISR执行到RTI指令,CCR,A,X,PC从堆栈恢复。

        用户可在自己的中断服务程序一开始将I清零,从而使能全局中断。那么当前运行的中断服务程序可以被其他中断打断,MCU运行新的中断服务程序,从而形成中断嵌套。用户在使用中断嵌套时会对调试带来不便,故建议避免使用中断嵌套。在中断服务程序的开始,用户程序应清掉产生该中断的标志位,其目的是同一中断源产生另外一个中断事件能够被记录,并在完成当前中断服务程序之后能够得到MCU的响应。

       每一个中断对应一个中断向量。这个向量指向这个中断的服务程序。用CodeWarrior编程时,在工程的“Project Settings\Linker Files”文件夹下的“Project.prm”文件中设置相应中断的中断向量。

二、查询方式读取按键

        在这个实验中,我们采用查询方式对按键的状态进行读取,主要代码如下,(完整代码可以从本文的资源中下载)

void main(void) {
	DisableInterrupts;
  init_led_key();	
  EnableInterrupts;


  for(;;) 
  {
      delay();
      data=data<<1;         //左移一位
      if(data==0)
          data=0x01;
      if(KEY1==0&&KEY1_last==1)   //按键F1按下
          mode=1;
      if(KEY2==0&&KEY2_last==1)   //按键F2按下
          mode=2;          
      KEY1_last=KEY1;             //保存F1的状态
      KEY2_last=KEY2;             //保存F2的状态
      if(mode==1)
          LED = ~data;
      else
          LED = data;
  } 
}

在这段代码中,发光二极管以流水灯的方式进行闪烁,每个周期经过delay();函数延时之后,读取KEY1和KEY2的状态,并且与上个周期的转态进行比较,如果上个周期为1(没有按下),这个周期为0(按键按下),则改变灯闪的模式,如果按下按键“KEY2”,则8个灯中只有一个熄灭,并且熄灭的灯循环向右移动。按下按键“KEY1”,则8个灯中只有一个点亮,并且点亮的灯循环向右移动。

三、中断方式读取按键

        在这个实验中,我们通过中断来进行按键的读取,为了使能中断功能,首先要对按键进行初始化,代码如下所示。

void init_key(void) 
{
     KEY1_dir =0;       //设置为输入
     KEY2_dir=0;
     KEY3_dir=0;
     KEY4_dir=0;
     PPSH = 0x00;		      //极性选择寄存器,选择下降沿;
     PIFH = 0x0f;					//对PIFH的每一位写1来清除标志位;
     PIEH = 0x0f;		      //中断使能寄存器;
}

在这段代码中,首先将每个按键的方向寄存器设置为输入状态,然后通过PPSH寄存器设置PH0~PH3的输入极性为下降沿触发中断。PIFH = 0x0f; 将标志位清除,PIEH=0x0f; 将中断功能使能。

        这个程序的主函数代码如下所示。

void main(void) {
	DisableInterrupts;
  init_led();
  init_key();
	EnableInterrupts;


  for(;;) 
  {
      delay(time);
      if(direction==1)
      {
          data=data<<1;         //左移一位
          if(data==0)
              data=0x01;
      } 
      else 
      {
          data=data>>1;         //右移一位
          if(data==0)
              data=0x80;
      }
      
      LED = ~data;
  } 
}

这段代码中,初始化了按键和LED,然后主循环中控制LED闪烁,LED的状态根据time和direction进行变化,time决定了延时的长短,进而影响闪烁的快慢,direction影响灯闪烁的方向。

        中断的处理函数如下所示

interrupt void PTH_inter(void) 
{
   if(PIFH != 0)     //判断中断标志
   {
      PIFH = 0xff;     //清除中断标志
      if(KEY1 == 0)         //按键1按下
      {
          time-=1;
          if(time==0)
              time=1;
      }
      if(KEY2 == 0) 
      {
          time+=1;
          if(time>10)
              time=10;
      }
      if(KEY3 == 0)
          direction=0;
      if(KEY4 == 0)
          direction=1;
   }
}

由于中断设置的是下降沿触发中断,当有按键按下时,会进入中断函数,在中断函数中,首先确认标志位,判断是否确实有中断发生,然后判断是哪个按键按下,用KEY1和KEY2来改变time的值,用KEY3和KEY4来改变direction的值。

        需要注意的是,要设置中断向量,在工程的“Project Settings\Linker Files”文件夹下的“Project.prm”文件中设置,如下所示,

VECTOR ADDRESS 0xffcc PTH_inter

这个实验的现象是,8个LED灯中有一个点亮,并且点亮的灯循环向右移动。按下按键“KEY1”,灯移动的速度加快;按下按键“KEY2”,灯移动的速度减慢;按下按键“KEY3”,灯向左移动;按下按键“KEY4”,灯向右移动。

 
 

发布了78 篇原创文章 · 获赞 6 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/bhniunan/article/details/104213439