在基于微控制器(MCU)的项目中,矩阵式键盘常被用作输入设备。将矩阵键盘连接至微控制器的常规做法需使用微控制器的多个I/O引脚。然后MCU运用扫描算法来确认按住了哪些键。这种办法的一个弊端就是需要大量MCU的I/O引脚来连接键盘。例如,连接一个4×3键盘需7个数字I/O引脚。而当项目采用的是低引脚数MCU,或使用的MCU不具备足够的可用I/O引脚数时,就出现了问题。
对于这一问题,有两个解决办法:使用现成的I/O扩展器,或用一只电阻排,为每个键设定一个唯一的电压,然后使用模拟引脚来读取电压值,判断按住了哪个键。每个方案都有其不足之处。
由于在大多数情况下,I/O扩展器需通过特殊的通信协议(如I2C协议或SPI协议)来读写数据,MCU需要具备内置通信模块,或用户需实现相关的通信协议软件,而这明显增加了MCU的负担。另一方面,当按键数量增加时,通过电阻排给各按键分配独特电压会变得很繁琐,而这最终将导致电压裕度较小。此外,由于电阻值会随温度而变化,使用较小的电压裕度可能导致读取错误,甚至连开关弹跳都可能成为导致电压出错的重要原因。这种方法的另一个弊端是要求MCU中有模拟输入引脚。这里描述的实例显示出能够高效解决上述所有问题的办法,及其具备的几个优势:它只需要两只I/O引脚,而不论连接的开关数量有多少;不需要特别的通信协议;不需要模拟引脚。本实例基于两个CD4017约翰逊计数器,这种计数器很常见而且不贵。
图1显示出4×3键盘采用的电路。R1、R4、R5和R6用于限流,D7、D4、D5和D6构成一个“或”门。
这里描述的例子显示出如何采用这种方法来读取4×3键盘。其中一个CD4017被用来控制键盘行,另一个控制键盘列。
MCU生成时钟信号,然后将其供给控制列的计数器IC。起初,列计数器和行计数器的第0个输出处于逻辑高位。在收到时钟脉冲后,列计数器将增加。在收到第四个时钟脉冲时,列计数器将重置,并同时将行计数器增加1。在列控制器重置后,行控制器增加,并在收到第五个来自列控制器的时钟脉冲后重置。在生成时钟脉冲的同时,应增加MCU的计数变量,并且在第五个时钟脉冲到达行控制器时,将计数变量重置为1。键盘的两个输出做“或”运算,并连接到MCU的一个外部中断引脚。
只有当行和列的相关按钮均处于逻辑高位,一个按钮被按下时才会发生中断。如果按钮的行或列处于逻辑零值,则不会发生中断。
中断发生时,MCU读取当时的计数值,所读取的值即对应于刚按下的按钮。
当MCU每隔一段时间产生时钟脉冲时,MCU内的时钟计数增加;这一计数等于键盘上的开关数目,按下这些开关时可造成中断。图2中的流程图描述了这一情况。
注意:虽然本例仅展示了4×3键盘的读取方法,但可以用两个4017计数器的剩余输出来读取10×10键盘。另外,必要时,还可以级联更多的4017IC来扩展键盘。