按键扫描——74HC164驱动(一)

前言:在做MCU的外部按键扫描时,74HC164是一种不错的选择。笔者在使用它的过程中,遇到了一些问题,在这里整理记录下。

74HC164的特性

  • 如下图所示,74HC164是 8 位边沿触发式移位寄存器,串行输入数据,然后并行输出(即串入并出)。数据通过两个输入端(A 或 B)之一串行输入;任一输入端可以用作高电平使能端,控制另一输入端的数据输入。两个输入端或者连接在一起,或者把不用的输入端接高电平,一定不要悬空。
  • 时钟 (CLK) 每次由低变高时,数据右移一位,输入到 Q0, Q0 是两个数据输入端(A 和 B)的逻辑与,它将上升时钟沿之前保持一个建立时间的长度。
  • 主复位 (CLR) 输入端上的一个低电平将使其它所有输入端都无效,同时非同步地清除寄存器,强制所有的输出为低电平。

按键扫描——74HC164驱动(一)_第1张图片

74HC164按键扫描思想

  • 在使用74HC164用作按键扫描时,74HC164的8个输出端QA~QH可以连接8个按键,8个按键则可以同时串联在一个或者多个公共端上,公共端可以直接是MCU的输入引脚。这时就会出现两种情况:

  • 1)公共端接地,74HC164定时扫描出高电平

    这时,如果进行扫描时,公共端出现高电平,那么结合这时74HC164扫描到哪一位,就可以判断出是这个公共端上哪个按键被短路,即被按下。

  • 2)公共端上拉,74HC164定时扫描出低电平

    这时,如果进行扫描时,公共端出现低电平,那么结合这时74HC164扫描到哪一位,就可以判断出是这个公共端上哪个按键被短路,即被按下。

74HC164按键扫描实现

74HC164需要结合定时器来进行按键扫描,这里将定时器的定时时间定为2.5ms,即每2.5ms调用一次该函数,将i++。这里选择的接法是按键公共端上拉,74HC164定时扫描出低电平。

/*74HC164是传入并出的8位寄存器,想要定时扫描出低电平,可以将建立如下的扫描值表*/
const uint8_t Tab_74HC164[8] = {0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F};
/*
* keyBuff:传入按键值缓冲区的地址
* tab:传入扫描键值表,为上述的Tab_74HC164
* i:扫描一个字节中的哪一位,作为tab的索引使用
*/
void Key_74HC164(uint8_t *keyBuff,uint8_t const *tab,uint8_t i)
{
  uint8_t j = i - 1,temp = tab[i];
  if(!i) j = 7;
 
 /*进行公共端扫描*/
 if(!(Key_Com0_Port&Key_Com0_Pin))
   keyBuff[0] |= (1<<j);
  if(!(Key_Com1_Port&Key_Com1_Pin))
   keyBuff[1] |= (1<<j);
  if(!(Key_Com2_Port&Key_Com2_Pin))
   keyBuff[2] |= (1<<j);
  if(!(Key_Com3_Port&Key_Com3_Pin))
   keyBuff[3] |= (1<<j);
 
 /*进行74HC164扫描*/
  j = 8; 
 do{
      Clk164_Port &= ~Clk164_Pin;
      Ser164_Port &= ~Ser164_Pin;
   if(temp&0x80) Ser164_Port |= Ser164_Pin; //从最高位开始传输
   DelayTimes(10); //作延迟,等待信号稳定传输
   Clk164_Port |= Clk164_Pin;
   DelayTimes(10); //作延迟,等待信号稳定传输
   j--;
   temp <<= 1;
 }while(j);
}

/*延迟函数*/
void DelayTimes(uint16_t nLoop)
{
    while(nLoop--);
}

代码分析

  • 1.端口和引脚
  • 上面提到的一些端口和引脚都可以根据自己的需要进行更改和重命名。如:Key_Com0_Port,Key_Com0_Pin,Key_Com1_Port,Key_Com1_Pin,Key_Com2_Port,Key_Com2_Pin,Key_Com3_Port,Key_Com3_Pin,Clk164_Port,Clk164_Pin,Ser164_Port,Ser164_Pin。
  • 2.公共端扫描和164扫描谁先进行

按键扫描——74HC164驱动(一)_第2张图片

  • 上面是某型号74HC164手册中的图,可知想要让数据信号稳定的输出,在不同的电压下需要的时间不同。因此,对于定时扫描来说最好不要先扫描74HC164输出电平,紧接着扫描公共端。这样很可能因为数据没有稳定输出造成误差。比较稳妥的一种做法是,先扫秒74HC164输出目标电平,等待下次定时器中断到来时,再针对上一次的74HC164扫描数据进行公共端扫描,这样可以保证有足够的延迟时间。(注:这里只是建议先进行74HC164扫描,再进行公共端扫描,并不一定说反之不可行)。
    所以上面的j=i-1的做法是指对上一次74HC164扫面结果做出处理。
  • 3.延迟函数的使用
  • 通过上面的图可以知道,74HC164的电平信号干扰抖动时间是纳秒级别的,如果以系统时钟24MHz来计算,MCU的时钟周期约为41ns,对于上述图中某些低电压时的延迟时间来说,它并不能够完全保证74HC164的信号可以稳定输出,更不用说当系统时钟频率更高的情况。因此,在74HC164传入并出移位时,在时钟移位信号和数据信号前可以适当的加上延迟函数,保证信号能够稳定输出。

总结:74HC164是一个串入并出的8位寄存器,在使用它进行按键扫描时需要分清它和公共端谁负责高电平,谁负责低电平。最后需要注意信号电平的延迟时间的问题。

你可能感兴趣的:(MCU)