需要用户交互的嵌入式系统必须与接受用户输入的设备(如键盘、条形码阅读器或智能卡接受器)以及向用户显示信息的设备(如 led 或 lcd 显示屏)接口。本应用笔记使用maxq2000微控制器,介绍两种典型器件的使用:4x4开关键盘和lcd显示器。
概述
需要用户交互的嵌入式系统必须与接受用户输入的设备(如键盘、条形码阅读器或智能卡接受器)以及向用户显示信息的设备(如 led 或 lcd 显示器)进行交互。本应用笔记介绍了两种典型器件(4 x 4开关键盘和lcd显示器)与maxq2000微控制器的使用。
本应用笔记的所有示例代码均使用max-ide开发环境,用maxq汇编语言编写。该代码针对maxq2000评估板(ev kit)板,使用以下附加硬件。
lcd—精电静态3v液晶显示器,部件号vi-502(包含在maxq2000评估板中)
键盘 - grayhill 16 按钮(4 行 x 4 列)键盘,部件号 96bb2-006-f
设计目标
我们的示例应用程序将通过接受来自键盘的输入并显示在lcd上输入的字符来演示键盘和lcd显示屏的基本用法。该应用程序将正确处理开关去抖动,以避免从单个按键注册多个字符,并且它还允许在输入后删除字符。作为最后一项任务,键盘将支持lcd显示屏的对比度调整。
与任何嵌入式设计一样,应用应尝试有效地利用maxq2000的资源。
中断例程应使用尽可能少的堆栈空间。
工作寄存器的使用应保持在最低限度。
与 4x4 键盘接口
用于此示例应用程序的键盘由 16 个开关组成,这些开关组织在一个 4 x 4 网格中。(图 1。
图1.键盘开关布局。
这些开关以行和列矩阵连接在一起,如图 2 所示。按下键盘开关将一行连接到一列线。例如,按下“3”键将第 1 行和第 3 列连接在一起。
图2.键盘行/列矩阵。
键盘提供八个接口引脚,键盘矩阵的每一行和每列一个引脚。为了允许使用一根八连接器电缆从键盘连接到maxq2000评估板,通过评估板上的ju6接头引脚连接器将键盘连接到端口引脚p5[0:7]和p1[0:2],如下表1所示。对于定制设计,键盘可以以最有效的方法连接到微控制器。
针 1 2 3 4 5 6 7 8
连接 第 1 行 第 2 行 第 3 行 第 4 行 科尔 1 科尔 2 科尔 3 科尔 4
端口销 p6.0 p6.1 p6.2 p6.3 p6.4 p6.5 p7.0 p7.1
ju2 引脚 54 52 50 48 46 44 42 40
在本例中,将键盘连接到评估板时,应按如下方式配置电路板:
这些 dip 开关必须关闭 — 所有 sw1 交换机、sw3.1、sw3.7、sw3.8、sw6.1、sw6.4、sw6.5、sw6.6、sw6.7 和 sw6.8。
打开跳线 ju5、ju6、ju8 和 ju9。
或者,在不进行修改的情况下运行示例应用程序时,可以关闭所有 dip 开关以简化设置;只有跳线 ju1、ju2、ju3 和 ju11 需要连接。
按列扫描
通过键盘的行和列排列,可以随时读取四个开关的状态。这可以按每行或每列完成。
要在一列中读取四个开关,必须将该列的行拉低,并将所有其他列三元组。接下来,必须在每行线上建立弱上拉。最后,将四行线连接到端口引脚输入。默认为 high 状态时,当按下该行的开关时,行输入将变为低电平。(图 3。
图3.键盘设置以读取第 1 列开关。
类似地,可以通过将该行线拉低并在所有四列上设置输入和弱上拉来读取连续四个开关的状态。行和列是可以互换的。
在我们的设置(表 2)中,四行线(键盘引脚 1 到 4)都连接到同一个输入端口 (p6[3:0]),这使得一次读取它们更容易。因此,示例应用程序将按列而不是按行扫描键盘。
连接到键盘的八个端口引脚线有四种设置状态,每种状态都允许读取四个开关。当正在读取的开关闭合时,所有输入线都读为低电平,当开关断开时,所有输入线都读为高电平。
州 p6.0 p6.1 p6.2 p6.3 p6.4 p6.5 p7.0 p7.1
1 输入 - 1 输入 - 4 输入 - 7 输入-* 低 三州 三州 三州
2 输入 - 2 输入 - 5 输入 - 8 输入 - 0 三州 低 三州 三州
3 输入 - 3 输入 - 6 输入 - 9 输入-# 三州 三州 低 三州
4 输入 - a 输入 - b 输入 - c 输入 - d 三州 三州 三州 低
中断驱动的状态机
为了确保不会错过按键,必须快速发送四列。此外,为了防止开关的弹跳触点注册多次按下,应用程序要求在注册之前按住某个键一定时间。这两个问题都可以同时解决,方法是将定时器驱动的中断例程作为应用程序的核心。
reload equ 0ff00hstarttimer: move iir.3, #1 ; enable interrupts for module 3 move imr.3, #1 move t2v0, #reload move t2r0, #0h move t2c0, #0h move acc, t2cfg0 ; set timer 0 to run from hfclk/128 and #08fh or #070h move t2cfg0, acc move t2cna0.3, #1 ; start timer 0 move t2cna0.7, #1 ; enable timer 0 interrupts ret 计时器的重新加载值(控制中断触发的频率)应足够短,以便捕获所有按键,并且按键响应不会明显缓慢。重新加载值也应该足够长,以免占用过多的处理时间。上面显示的值 0ff00h(大约每 2.4 毫秒一次)是通过实验得出的。
一旦一组四个开关的柱线被驱动为低电平,则可能需要一定的时间才能通过按下的开关进行连接,以将其输入线拉低。这个时间将受到开关的导通电阻以及一次按下柱上多少个开关的影响。为了避免在将柱线拉低和读取四个开关之间延迟中断服务例程,给定状态的柱线将在前一种状态下被驱动为低电平,如图4所示。
图4.键盘读取状态机。
由于maxq2000的中断向量(iv)可以即时设置,因此可以将每个状态的处理程序例程设置为下一个状态的处理程序例程,从而将下一个状态值保存在中断向量寄存器中。
org 0000hmain: call initializelcd move pd6, #010h ; for state 1 move po6, #00fh ; for all states move pd7, #000h ; for state 1 move po7, #000h ; for all states move iv, #state1 call starttimer move ic, #1 ; enable global interrupts jump $state1: push psf push acc move acc, pi6 and #000fh ; grab lowest four bits only sla4 move a[13], acc move pd6, #020h ; for state 2 move pd7, #000h move t2v0, #reload ; set reload value move t2cnb0.1, #0 ; clear interrupt flags move t2cnb0.3, #0 move iv, #state2 pop acc pop psf reti 其他四种状态的处理程序例程类似,只是在 a[13] 保持寄存器中先前收集的开关位中略微调整为 or。状态例程使用三个工作累加器。
a[13] 保存通过键盘的电流传递上读取的所有开关状态的位数组。状态 4 读取完成后,此寄存器将包含以下位,其中 1 位表示打开(释放)键开关,0 位表示关闭(按下)键开关。
位 15 位 14 位 13 位 12 位 11 位 10 位 9 位 8 位 7 位 6 位 5 位 4 位 3 位 2 位 1 位 0
* 7 4 1 2 5 8 0 3 6 9 # d c b 一个
<
a[14] 保存上一次通过状态机的位数组。这由去抖代码使用。
a[15] 保存最后一个位模式,该模式保持的时间足够长,可以注册为按键。这用于防止重复按键。
去抖动开关
达到状态 4 并扫描所有键后,必须决定是否接受按下的任何键。
处理去抖动的一种简单方法是为 4 个开关中的每一个保持一个计数器值。每次达到状态 并按下该键时,计数器都会递增。如果未按下该键,计数器将递减。当计数器达到某个值时,将注册按键。为了防止按住键重复(通常在计算机键盘上允许,但在小键盘上不允许),必须允许计数器递减到零(通过释放键),然后才能再次注册该键。
因为我们在单个寄存器中拥有所有 16 个键的状态,所以有一个更简单、内存占用更少的解决方案。应用程序将维护单个计数器值(保存在 lc[0] 中),该值最初将设置为去抖动常数。每次位模式与前一次传递中读取的模式匹配时,此计数器都会递减(在 a[14] 中)。
state4: push psf push acc move acc, pi6 and #000fh ; grab low four bits only or a[13] cmp a[15] jump e, state4_end ; ignore the last debounced pattern cmp a[14] jump e, state4_match ; match against pattern from last keypad read move lc[0], #debounce move a[14], acc ; reset current bit array 为了防止键重复,一旦位模式静态足够长,就可以接受,必须先接受不同的位模式(包括未按下任何键的空闲状态),然后才能再次接受第一个位模式。
处理同时按键
可以同时按下多个键。去抖动代码将确保如果在第一个键之后立即按下第二个键,则去抖动间隔将重新开始,但间隔在实践中会足够短,这不会成为问题。
一旦接受了位模式,就可以将所有 16 位旋转到进位中,一次使用累加器一个并依次检查每个位,从而对每个按下键位执行操作。下面的代码仅响应第一个按下的键,但这可以很容易地更改。
state4_match: djnz lc[0], state4_end move a[15], acc ; reset last debounced pattern rrc jump nc, state4_keya rrc jump nc, state4_keyb rrc jump nc, state4_keyc rrc jump nc, state4_keyd rrc jump nc, state4_key3 rrc jump nc, state4_key6 rrc jump nc, state4_key9 rrc jump nc, state4_keypound rrc jump nc, state4_key2 rrc jump nc, state4_key5 rrc jump nc, state4_key8 rrc jump nc, state4_key0 rrc jump nc, state4_key1 rrc jump nc, state4_key4 rrc jump nc, state4_key7 rrc jump nc, state4_keystar jump state4_end 与液晶显示器接口
maxq2000评估板附带的lcd显示器具有如图5所示的段定义。
图5.液晶屏段内存映射。
要使用 lcd 显示屏,必须首先将 lcd 控制器初始化为静态驱动模式并启用。
initializelcd: move lcra, #03e0h ; xxx0001111100000 ; 00 - duty : static ; 0111 - frm : frame freq ; 1 - lccs : hfclk / 128 ; 1 - lrig : ground vadj ; 00000 - lra : radj = max move lcfg, #0f3h ; 1111xx11 ; 1111 - pcf : all segments enabled ; 1 - opm : normal operation ; 1 - dpe : display enabled move lcd0, #00h ; clear all segments move lcd1, #00h move lcd2, #00h move lcd3, #00h move lcd4, #00h ret 完成此操作后,可以通过适当设置段将字符写入显示器。显示器连接到maxq2000的lcd段线,使得7个5段字符的段映射到存储器中。如上面的映射图(图0)所示,通过设置lcd1、lcd2、lcd3和lcd显示存储器寄存器来写入字符(从右到左)。
; dgfedcbalcd_char_0 equ 00111111blcd_char_1 equ 00000110blcd_char_2 equ 01011011blcd_char_3 equ 01001111blcd_char_4 equ 01100110blcd_char_5 equ 01101101blcd_char_6 equ 01111101blcd_char_7 equ 00000111blcd_char_8 equ 01111111blcd_char_9 equ 01101111blcd_char_a equ 01110111blcd_char_b equ 01111100blcd_char_c equ 00111001blcd_char_d equ 01011110bstate4_key0: move acc, #lcd_char_0 jump state4_shiftstate4_key1: move acc, #lcd_char_1 jump state4_shiftstate4_key2: move acc, #lcd_char_2 jump state4_shiftstate4_key3: move acc, #lcd_char_3 jump state4_shiftstate4_key4: move acc, #lcd_char_4 jump state4_shiftstate4_key5: move acc, #lcd_char_5 jump state4_shiftstate4_key6: move acc, #lcd_char_6 jump state4_shiftstate4_key7: move acc, #lcd_char_7 jump state4_shiftstate4_key8: move acc, #lcd_char_8 jump state4_shiftstate4_key9: move acc, #lcd_char_9 jump state4_shiftstate4_keya: move acc, #lcd_char_a jump state4_shiftstate4_keyb: move acc, #lcd_char_b jump state4_shiftstate4_keyc: move acc, #lcd_char_c jump state4_shiftstate4_keyd: move acc, #lcd_char_d jump state4_shift 编辑密码
当按下任何字母数字键时,相应的字符将加载到lcd显示屏最右侧的字符中。所有现有字符都向左移动一个位置。
state4_keystar: move lcd0, lcd1 move lcd1, lcd2 move lcd2, lcd3 move lcd3, #0 jump state4_endstate4_shift: move lcd3, lcd2 move lcd2, lcd1 move lcd1, lcd0 move lcd0, accstate4_end: move pd6, #010h ; set up values for next state move pd7, #000h move t2v0, #reload ; set reload value move t2cnb0.1, #0 ; clear interrupt flags move t2cnb0.3, #0 move iv, #state1 pop acc pop psf reti 在此应用程序中,“star”键连接到删除/退格功能。按星号键会将所有字符向右移动一个位置,并从显示屏上擦除最左侧的字符。
对比度调整
井号键执行一项附加功能以用于演示目的。按下它可以调整lcd显示屏的对比度,这是一项通过增加lcra寄存器中的radj位来执行的简单功能。
state4_keypound: move acc, lcra or #0ffe0h ; clear low five bits move a[13], acc ; save version with bits cleared move acc, lcra and #0001fh ; get low five bits only add #1 ; increment and #0001fh ; mask out any carry to sixth bit or a[13] ; or in the rest of the bits move lcra, acc ; change contrast jump state4_end 结论
maxq2000通过专用的lcd控制器外设轻松直接地与lcd显示器接口。使用maxq2000提供的灵活端口引脚配置,可以直接读取多路复用键盘。中断驱动的状态机允许在主应用程序的后台扫描和去抖动矩阵中的所有键,而对处理器开销的影响最小。
如何进一步优化可实现显示屏的 LED 驱动器
如何搭建BIFACES+HighTec开发环境
气体检测仪的使用方法及注意事项
中电金信获软件测试成熟度模型集成(TMMi)三级水平认证
分布式节点的技术特点
使用键盘和LCD显示屏与MAXQ2000
上半年面板淡季时量产,供过于求导致电视面板价格急跌
5G竞争正演变成场光纤基础设施的竞争
应用于广播视频监控系统中MPEG-4解码卡的设计
介绍机械领域的运动控制系统全自动化应用
本周六,上海站!RISC-V应用创新大赛开发者训练营一起上手RT-Thread Smart!
SpringBoot中MybatisX插件的简单使用教程
ISO 16750/7637抛负载测试保护选型TVS二极管型号推荐大全
【虹科】Myricom MVA释放高速相机的CPU占用
40个linux高效运维命令总结
做客户最强力后盾,涂鸦智慧商业开启客户服务“升级模式”
浅谈伺服电机编码器有哪些种类?
无线自组网的基本概念
什么是域控制器?域控制器市场概述
关于ESD管的叫法,你知道几个?-优恩半导体