电子说
第六章为重用外设驱动代码,本文内容为6.5 键盘与数码管接口。
6.5 键盘与数码管接口
>>> 6.5.1 ZLG72128 接口
当矩阵扩大到一定数目时,逐行扫描的方法会显得费时,如果需要对2 个以上的按键“同时”操作时,则处理起来更是麻烦。ZLG72128 是ZLG 自行设计的数码管显示驱动与键盘扫描管理芯片,能够直接驱动12 位共阴式数码管(或96 只独立的LED),同时还可以扫描管理多达32 个按键,其中的8 个按键如同电脑键盘上的Ctrl、Shift 和Alt 键一样可以作为功能键使用。
另外,ZLG72128 内部还设置有连击计数器,能够使某键按下后不松手而连续有效。该芯片为工业级芯片,抗干扰能力强,在工业测控中已有大量应用。
1. 特点
直接驱动12 位1 英寸以下的共阴式数码管或96 只独立的LED;
能够管理多达32 个按键,其中的8 个按键可以用作功能键,自动消除抖动;
利用功率电路可以方便地驱动1 英寸以上的大型数码管;
具有位闪烁、位消隐、段点亮、段熄灭、功能键、连击键计数等强大功能;
具有10 种数字和21 种字母的译码显示功能,亦可直接向显示缓存写入显示数据;
软件配置支持0~12 个数码管显示模式;
与MCU 之间采用I2C 串行总线接口;
工作电压范围:3.0~5.5V;
工作温度范围:-40~+85℃;
封装:TSSOP28。
2. 典型应用电路
如图6.12 所示为ZLG72128 的管脚排列图,其相应的管脚功能说明详见表6.34。
表6.34 引脚功能表
图6.12 ZLG72128 管脚排列图
如图6.13 所示为按键电路,ZLG72128 能够管理多达32 个按键(4 行8 列),行线分别连接COM8 ~ COM11 引脚,列线分别连接COM0 ~ COM7。特别地,前3 行按键(共计24个按键)是普通按键,按键按下时会通过INT 引脚通知用户,按键释放时不做任何通知。最后一行按键(共计8 个按键)是功能键,其以一个8 位数据表示8 个键值的状态,F0 ~ F7分别对应bit0 ~ bit 7。按下时相应位为0,释放时相应位为1,只要表示这8 个按键的8 位数据值发生变化,则会通过INT 引脚通知用户,因此对于功能按键,按键按下或释放用户均能够得到通知。
注意,需要在键盘电路与ZLG72128 芯片引脚之间连接一个电阻,其典型值为1KΩ。在多数应用中可能不需要这么多的键,这时既可以按行也可以按列裁减键盘。需要注意的是,该按键电路对于3 个或3 个以上键按下的情况是不适用的。
图6.13 按键电路
如图6.14 所示是针对2 个或2 个以上功能键与普通键搭配使用的情况下的按键电路,在功能键与普通键之间加了一个二极管,注意:二极管应该尽量选择导通压降较小的。
图6.14 多个功能键复用按键电路
如图6.15 所示为ZLG72128 的典型应用电路原理图,用户在使用芯片驱动数码管与管理按键时,可参考该电路进行电路设计。ZLG72128 只能直接驱动12 位共阴式数码管驱动,在数码管的段与ZLG72128 芯片引脚之间需要接一个限流电阻,其典型值为270Ω。如果需要增大数码管的亮度,则可以适当减小电阻值。ZLG72128 的驱动能力毕竟有限,当使用大型数码管时,则可能显示亮度不够,这时可以适当减小数码管的限流电阻值以增加亮度,阻值最小为200Ω,如果亮度依旧不够,就必须加入功率驱动电路,详见ZLG72128 用户手册(http://www.zlgmcu.com)。
为了使ZLG72128 芯片电源稳定,一般在VCC 和GND 之间接入一个47~470μF 的电解电容。按照I2C 总线协议的要求,信号线SCL 和SDA 上必须分别接上拉电阻,其典型值是4.7KΩ。当通信速率大于100kbps 时,建议减小上拉电阻的值。芯片复位引脚RST 是低电平有效,可以将其接入到MCU 的I/O 来控制其复位。KEY_INT 引脚可输出按键中断请求信号(低电平有效),可以连接到MCU 的I/O 来获取按键按下或释放事件。
图6.15 ZLG72128 典型应用电路
3. 寄存器详解
ZLG72128 内部有12 个显示缓冲寄存器DispBuf0~DispBuf11,它们直接决定数码管显示的内容。ZLG72128 提供有2 种显示控制方式,一种是直接向显存写入字型数据,另一种是通过向命令缓冲寄存器写入控制指令实现自动译码显示。访问这些寄存器需要通过I2C 总线接口来实现,ZLG72128 的I2C 总线器件地址是60H(写操作)和61H(读操作),访问
内部寄存器要通过“子地址”实现。
(1)系统寄存器SystemReg(地址:00H)
系统寄存器的第0 位(LSB)称作KeyAvi,标志着按键是否有效,0-没有按键被按下,1-有某个按键被按下。SystemReg 寄存器的其它位暂时没有定义。当按下某个键时,ZLG72128 的KEY_INT 引脚会产生一个低电平的中断请求信号。当读取键值后,中断信号就会自动撤销(变为高电平),而KeyAvi 也同时予以反映。正常情况下MCU 只需要判断KEY_INT 引脚即可。通过不断查询KeyAvi 位也能判断是否有键按下,这样就可以节省微控制器的一根I/O 口线,但是I2C 总线处于频繁的活动状态,多消耗电流且不利于抗干扰。
(2)键值寄存器Key(地址:01H)
如果K1~K24 的某个普通键被按下,则微控制器可以从键值寄存器Key 中读取相应的键值1~24。如果微控制器发现ZLG72128 的KEY_INT 引脚产生了中断请求,而从Key 中读到的键值是0,则表示按下的可能是功能键。键值寄存器Key 的值在被读走后自动变成0。
(3)连击计数器RepeatCnt(地址:02H)
ZLG72128 为K1~K24 提供了连击计数功能。所谓连击是指按住某个普通键不松手,经过两秒钟的延迟后,开始连续有效,连续有效间隔时间约两百毫秒。这一特性跟电脑上的键盘很类似。在微控制器能够及时响应按键中断并及时读取键值的前提下,当按住某个普通键一直不松手时:首先会产生一次中断信号,这时连击计数器RepeatCnt 的值仍然是0;经过两秒延迟后,会连续产生中断信号,每中断一次RepeatCnt 就自动加1;当RepeatCnt 计数到255 时就不再增加,而中断信号继续有效。在此期间,键值寄存器的值每次都会产生。
(4)功能键寄存器FunctionKey(地址:03H)
ZLG72128 提供的8 个功能键F0~F7。功能键常常是配合普通键一起使用的,就像电脑键盘上的Shift、Ctrl 和Alt 键。当然功能键也可以单独去使用,就像电脑键盘上的F1~F12。当按下某个功能键时,在KEY_INT 引脚也会像按普通键那样产生中断信号。功能键的键值是被保存在FunctionKey 寄存器中的。功能键寄存器FunctionKey 的初始值是FFH,每一个位对应一个功能键,第0 位(LSB)对应F0,第1 位对应F1,依此类推,第7 位(MSB)对应F7。某一功能键被按下时,相应的FunctionKey 位就清零。功能键还有一个特性就是“二次中断”,按下时产生一次中断信号,抬起时又会产生一次中断信号;而普通键只会在被按下时产生一次中断。
(5)命令缓冲区CmdBuf0 和CmdBuf1(地址:07H 和08H)
通过向命令缓冲区写入相关的控制命令可以实现段寻址、下载显示数据功能。
(6)闪烁控制寄存器FlashOnOff(地址:0BH)
FlashOnOff 寄存器决定闪烁频率和占空比。复位值为0111 0111B。高4 位表示闪烁时亮的持续时间,低4 位表示闪烁时灭的持续时间。改变FlashOnOff 的值,可以同时改变闪烁频率和占空比。FlashOnOff 取值00H 时可获得最快的闪烁速度,亮灭时间计算公式如下:
T = N × 50 + 150mS
T 为闪烁时亮或灭的持续时间,N 为寄存器的高4 位或低4 位的值,取值0~15.最快闪烁频率为3.33Hz(周期为300mS),最慢闪烁频率为0.55Hz(周期为1.8S)。特别说明:单独设置FlashOnOff 寄存器的值,不会看到显示闪烁,而应该配合闪烁控制命令一起使用。
(7)消隐寄存器DispCtrl0(地址:0CH)和DispCtrl1(地址:0DH)
如表6.35 所示为消隐寄存器,DispCtrl0、DispCtrl1 寄存器决定哪些位是否显示,对应数码管的1~12 位。寄存器位为1 时,对应数码管位不显示。复位值都是0x00,即数码管的12 个位都扫描显示。
表6.35 消隐寄存器
在实际应用中可能需要显示的位数不足12 位,例如只显示8 位,这时可以把DispCtrl0的值设置为0x0F,把DispCtrl1 的值设置为0x00,则数码管的第0~7 位被扫描显示,而第8~12 位不会显示。
(8)闪烁寄存器Flash0(地址:0EH)和Flash1(地址:0FH)
如表6.36 所示为闪烁寄存器,Flash0、Flash 1 寄存器决定哪些位是否闪烁,对应数码管的1~12 位。寄存器位为1 时,对应数码管位闪烁。复位值都是0x00,即数码管的12 个位都不闪烁。
表6.36 闪烁寄存器
在实际应用中可能需要某些位闪烁,例如最后2 位闪烁,这时可以把Flash0 的值设置为0x00,把Flash1 的值设置为0x03,则数码管的第1、2 位闪烁,而第3~12 位不会闪烁。
(9)显示缓冲区DispBuf0~DispBuf11(地址:10H~1BH)
DispBuf0~DispBuf11 这12 个寄存器的取值直接决定了数码管的显示内容。每个寄存器的8 个位分别对应数码管的a、b、c、d、e、f、g、dp 段,MSB 对应a,LSB 对应dp。例如大写字母H 的字型数据为6EH(不带小数点)或6FH(带小数点)。
4. 控制命令详解
寄存器CmdBuf0(地址:07H)和CmdBuf1(地址:08H)共同组成命令缓冲区。通过向命令缓冲区写入相关的控制命令可以实现段寻址、下载显示数据、控制闪烁等功能。
(1)段寻址(SegOnOff)
如表6.37 所示为段寻址寄存器,在段寻址命令中12 位数码管被看成是96 个段,每一个段实际上就是一个独立的LED。
双字节命令在指令格式中,CmdBuff0 的高4 位“0001”是命令码,CmdBuff0 的最低位on 位表示该段是否点亮,0—熄灭,1—点亮。CmdBuff0 的B3B2B1B0 是位地址,取值0~11。S3S2S1S0 是4 位段地址,取值0~7,对应数码管的a、b、c、d、e、f、g、dp。
表6.37 段寻址寄存器
(2)下载数据并译码(Download)
如表6.38 所示为下载数据及译码寄存器,双字节命令在指令格式中,CmdBuff0 的高4位“0010”是命令码A3A2A1A0 是数码管显示数据的位地址,位地址编号按从左到右的顺序依次为11、10、9、8、……、0,dp 控制小数点是否点亮,0-熄灭,1-点亮。Flash 表示是否要闪烁,0-正常显示,1-闪烁。d4d3d2d1d0 是要显示的数据,包括10 种数字和21种字母,显示数据按照表6.39 中的规则进行译码。
表6.38 下载数据、译码寄存器
表6.39 下载数据并译码命令的数据表
(3)复位命令(Reset)
单字节命令,在指令格式中,CmdBuf0 的高4 位的“0011”是命令码,其功能是将所有LED 熄灭,详见表6.40。
表6.40 复位命令寄存器
(4)测试命令(Test)
单字节命令,在指令格式中,CmdBuf0 的高4 位的“0100”是命令码,其功能是将所有LED 按照0.5S 的速率闪烁,详见表6.41。
表6.41 测试命令寄存器
(5)左移命令(ShiftLeft)
单字节命令,在指令格式中,CmdBuf0 的高4 位的“0101”是命令码,详见表6.42。功能是以数码管的位为单位的,左移n 位。左移后右边空出的位不显示任何内容,即全部LED熄灭状态。n 的取值范围1~11,大于11 的值无效,n 的值由CmdBuf0 的低4 位决定,按下列公式计算:
n = (b3×8)+( b2×4)+ (b1×2)+ b0
表6.42 左移命令寄存器
(6)循环左移命令(CyclicShiftLeft)
单字节命令,在指令格式中,CmdBuf0 的高4 位的“0110”是命令码,详见表6.43。功能是以数码管的位为单位的,循环左移n 位。
左移后右边显示从最左边移出的内容。n 的取值范围1~11,大于11 的值无效,n 的值由CmdBuf0 的低4 位决定,按下列公式计算:
n = (b3×8)+( b2×4)+ (b1×2)+ b0
表6.43 循环左移命令寄存器
(7)右移命令(ShiftRight)
单字节命令,在指令格式中,CmdBuf0 的高4 位的“0111”是命令码,详见表6.44。功能是以数码管的位为单位的,右移n 位。
右移后左边空出的位不显示任何内容,即全部LED 熄灭状态。n 的取值范围1~11,大于11 的值无效,n 的值由CmdBuf0 的低4 位决定,按下列公式计算:
n = (b3×8)+( b2×4)+ (b1×2)+ b0
表6.44 右移命令寄存器
(8)循环右移命令(CyclicShiftRight)
单字节命令,在指令格式中,CmdBuf0 的高4 位的“1000”是命令码,详见表6.45。功能是以数码管的位为单位的,循环右移n 位。右移后左边显示从最右边移出的内容,n 的取值范围1~11,大于11 的值无效,n 的值由CmdBuf0 的低4 位决定,按下列公式计算:
n = (b3×8)+( b2×4)+ (b1×2)+ b0
表6.45 循环右移命令寄存器
(9)数码管扫描位数设置指令 (Scanning)
单字节命令,在指令格式中CmdBuf0 的高4 位的“1001”是命令码,设置数码管扫描位数n,详见表6.46。n 的取值为0~12,大于12 按12 位进行扫描。扫描位数n 以位选端第1位开始到位选端第n 位扫描有效。n 的值由CmdBuf0 的低四位决定,按下列公式计算。
n = (b3×8)+( b2×4)+ (b1×2)+ b0
表6.46 扫描位数设置寄存器
在使用过程中,如果不需要12 位数码管显示,从最高位开始裁剪,同时将数码扫描位数设置成相应的数码管位数。数码管的扫描位数减少后,有用的显示位由于分配的扫描时间更多,因而显示亮度得以提高。
>>> 6.5.2 ZLG72128 初始化
AMetal 已经提供了ZLG72128 的驱动函数,使用其它各功能函数管理数码管和按键前,必须先完成ZLG72128 的初始化。其初始化函数(am_zlg72128.h)的原型为:
该函数意在获取ZLG72128 的实例句柄。其中,p_dev 是指向am_zlg72128_dev_t 类型实例的指针,p_devinfo 是指向am_zlg72128_devinfo_t 类型实例信息的指针。
实例
定义am_zlg72128_dev_t 类型(am_zlg72128.h)实例如下:
其中,g_zlg72128_dev 为用户自定义的实例,其地址作为p_dev 的实参传递。
实例信息
实例信息描述了中断引脚相关的信息, 其类型am_zlg72128_devinfo_t 的定义(am_zlg72128.h)如下:
其中,use_int_pin 表示是否使用ZLG72128 的中断输出引脚(KEY_INT)。若该值为TRUE,表明需要使用中断引脚,此时int_pin 指定与主控制器(如LPC824)连接的引脚号,按键键值将在引脚中断中获取;若该值为FALSE,表明不使用中断引脚,此时interval_ms 指定查询键值的时间间隔。
一般地,只要主控器的I/O 资源不是非常紧缺,均会使用中断引脚。若为节省一个I/O中断资源,可将use_int_pin 设置为FALSE,此时将不占用IO 中断资源,而系统将会以查询的方式从ZLG72128 中获取键值,这就会耗费一定的CPU 资源,因为每隔一段时间就要主动查询一次键值。假设使用ZLG72128 的中断引脚,主控制器使用LPC824,ZLG72128 的KEY_INT 引脚与LPC824 的PIO0_17 连接。其实例信息定义如下:
I2C 句柄i2c_handle
若使用LPC824 的I2C1 与ZLG72128 通信,则I2C 句柄可以通过LPC82x 的I2C1 实例初始化函数am_lpc82x_i2c1_inst_init()获得。即:
获得的I2C 句柄即可直接作为i2c_handle 的实参传递。
实例句柄
am_zlg72128_init()函数的返回值为ZLG72128 实例的句柄,该句柄将作为其它功能接口(数码管显示、按键管理等)的第一个参数(handle)的实参。
其类型am_zlg72128_handle_t(am_zlg72128.h)定义如下:
若返回值为NULL,说明初始化失败;若返回值不为NULL,说明返回一个有效的handle。
基于模块化编程思想,将初始化相关的实例、实例信息等的定义存放到对应的配置文件中,通过头文件引出实例初始化函数接口,源文件和头文件的程序范例分别详见程序清单6.111 和程序清单6.112。
程序清单6.111 ZLG72128 实例初始化函数实现(am_hwconf_zlg72128.c)
程序清单6.112 ZLG72128 实例初始化函数声明(am_hwconf_zlg72128.h)
后续只需要使用无参数的实例初始化函数即可获取到ZLG72128 的实例句柄。即:
>>> 6.5.3 按键管理接口函数
ZLG72128 支持32 个键(4 行8 列矩阵键盘),其中,前3 行为普通键,同一时刻只能有一个普通键按下。最后一行为功能键,多个功能键可以同时按下。按键管理仅一个注册按键回调接口函数。
为了在检测到按键事件(有键按下)时,及时将按键事件通知用户,需要用户注册一个回调函数,当有按键事件发生时,将自动调用用户注册的回调函数。其函数原型为:
其中,pfn_key_cb 为注册的按键回调函数,p_arg 为回调函数的第一个参数的值,即当检测到按键事件自动调用回调函数时,将p_arg 的值作为回调函数的第一个参数的值。
回调函数的类型am_zlg72128_key_cb_t(am_zlg72128.h)定义如下:
由此可见,回调函数有4 个参数,用户可以通过这些参数获取按键相关的信息。特别地,第一个参数p_arg 为用户自定义的参数,其值即为注册回调函数时p_arg 参数设置的值。
key_val、repeat_cnt、funkey_val 表示按键事件的相关信息,ZLG72128 可能的按键事件有以下3 种:
有普通键按下(普通键释放不作为按键事件)
当有普通键按下时,key_val 表示按下键的键值,键值的有效范围为1 ~ 24,普通键的键值已在am_zlg72128.h 中定义为宏,宏名为AM_ZLG72128_KEY_X_Y,其中X 表示行号(1 ~ 3),Y 表示列号(1 ~ 8),如第2 行第5 个键的键值为:AM_ZLG72128_KEY_2_5。
普通键一直按下(处于连击状态)
普通键按下保持时间超过2s 后进入连击状态,处于连击状态时,每隔200ms 左右会产生一个按键事件,并使用一个连击计数器对产生的按键事件计数,每产生一个按键事件连击计数器的值加1,由于连击计数器的位宽为8 位,因此,当值达到255 后不再加1,但同样还会继续产生按键事件,直到键释放,连击计数器清0。处于连击状态时,key_val 表示按下键的键值,repeat_cnt 表示连击计数器的值。
功能键状态发生变化(功能键按下或释放都会造成状态改变)
funkey_val 的值表示所有功能键的状态。最后一行最多8 个键,从左至右分别为F0 ~ F7,与funkey_val 的bit0 ~ bit7 一一对应,位值为0 表示对应功能键按下,位值为1 表示对应功能键未按下。当无任何功能键按下时,funkey_val 的值为0xFF。只要funkey_val 的值发生改变,就会产生一个按键事件,功能键不提供连击功能。可以使用am_zlg72128.h 中的宏
AM_ZLG72128_FUNKEY_CHECK(funkey_val, funkey_num)来简单判断某一功能键是否按下。funkey_num 用于表示需要检测的功能键, 值已经定义为宏, F0 ~ F7 分别为AM_ZLG72128_FUNKEY_0 ~ AM_ZLG72128_FUNKEY_7。若对应键按下,则宏值为TURE;反之,则宏值FALSE。例如,通过funkey_val 判断F0 是否按下可以使用如下语句:
功能键类似PC 机上的Ctrl、Alt、Shift 等按键,使用普通键和功能键很容易实现组合键应用,注册按键回调函数的范例程序详见程序清单6.113。
程序清单6.113 ZLG72128 注册按键回调函数使用范例
若只按下第一行第一个键,则LED0 状态翻转,若按下第一行第一个键的同时,也按下了功能键F0,则LED1 状态翻转,该示例简单的展示了组合键的使用方法。
>>> 6.5.4 数码管显示接口函数
ZLG72128 支持12 位共阴式数码管,以及闪烁、位移等功能,虽然接口函数种类繁多,但各个接口函数的功能较为简单,下面将一一介绍各个接口函数的使用方法。
1. 闪烁持续时间
当数码管闪烁时,设置其点亮和熄灭持续时间的函数原型为:
上电时,数码管点亮和熄灭的持续时间默认值为500ms。on_ms 和off_ms 有效的时间值为150、200、250、……、800、850、900,即150ms ~ 900ms,且时间间隔为50ms。若时间间隔不是这些值,应该选择一个最接近的值。比如,设置数码管以最快的频率闪烁,即亮、灭时间最短为150ms,其使用方法如下:
注:仅设置闪烁时间还不能立即看到闪烁现象,必须打开某位的闪烁开关后才能看到闪烁现象,详见am_zlg72128_digitron_flash_ctrl()函数介绍。
2. 闪烁控制
控制数码管是否闪烁的函数原型为:
其中,ctrl_val 为控制值,bit0 ~ bit11 为有效位,分别对应数码管0 ~ 11,位值为0 时不闪烁,位值为1 时闪烁。上电默认值为0x0000,即所有数码管均不闪烁。比如,控制所有数码管闪烁,其使用方法如下:
注:由于初始时可能数码管未显示任何内容,这段代码可能看不到闪烁现象,因此可以在设置前,使用后续相关API 使数码管显示一些实际有效的内容。
3. 显示属性(开或关)
显示属性是指控制哪些数码管显示,哪些数码管不显示。在默认情况下,所有数码管均处于打开显示状态,扫描12 位数码管。而实际上,可能需要显示的位数并不足12 位,此时可以使用该函数关闭某些位的显示。其函数原型为:
其中,ctrl_val 为控制值,bit0 ~ bit11 为有效位,分别对应数码管0 ~ 11,位值为0 时打开显示,位值为1 时关闭显示。上电的默认值为0x0000,即所有位均正常显示。比如,只使用了数码管0 ~ 7,基于此,可以关闭数码管8 ~ 11,其使用方法如下:
注:使用该函数控制显示属性时,对应数码管的段码内容并不会改变。
4. 显示字符
在指定位置显示字符,ZLG72128 已经提供了0 ~ 9 这10 个数字和常见的21 种字母的自动译码显示,无需应用再自行译码。其函数原型为:
显示的字符必须是ZLG72128 已经支持的可以自动完成译码的字符,包括字符'0'~'9'与AbCdEFGHiJLopqrtUychT(区分大小写)。注意,若要显示数字1,则ch 参数应为字符'1',而不是数字1。
若指定的字符不支持,则返回-AM_ENOTSUP。只要成功显示,则返回AM_OK。若需要显示一些自定义的图形,使用 am_zlg72128_digitron_dispbuf_set() 直接设置显示的段码。
比如,在数码管0 显示字符F,不显示小数点,不闪烁,其使用方法如下:
5. 显示字符串
指定字符串显示的起始位置,开始显示一个字符串。其函数原型为:
字符串显示遇到字符结束标志'