详解ametal_键盘扫描接口和pwm接口技术

ZLG致远电子 2017-12-07 08:16 次阅读

第五章为深入浅出AMetal,本文内容为5.3 键盘扫描接口和5.4 PWM 接口。

5.3 键盘扫描接口

>>>  5.3.1 单个独立按键

1. 按键行为

如图5.1 所示,从按键的操作行为来看,共有3 种确定的方式,即无键按下、有键按下和按键释放。并用ret_flag 标志来区分这3 种按键的操作行为,其分别为0xFF、0 和1(通常用0xFF表示无效值)。当然还有可能发生的错误触发,ret_flag 也为0xFF。

图5.1 独立按键电路图

由于一次按键的时间通常为上百毫秒,相对于MCU 来说是很长的,因此不需要时时刻刻地检测按键,只需要每隔一定的时间(如10ms)检测GPIO 的电平即可。其检测方法如下(1 表示高电平、0 表示低电平):

(1)无键按下时,由于PIO0_1 内部自带弱上拉电阻,因此PIO0_1 为1;

(2)当KEY 按下时,则PIO0_1 为0。在下一次扫描(延时10ms 去抖动)后,如果PIO0_1 为1,说明错误触发;如果PIO0_1 还是0,说明确实有键按下,则将ret_flag 标志置0,执行相应的操作;

( 3)当KEY 释放时,则PIO0_1 由0 回到1,在下一次扫描(延时10ms 去抖动)后,如果PIO0_1 为0,说明错误触发;如果PIO0_1 还是1,说明按键已经释放,则将ret_flag标志置1,执行相应的操作。

由此可见,无论是否有键按下,都要每隔10ms 去扫描GPIO 的状态,那不妨将每次扫描获得的值称为当前键值(key_current_value)。由于按键存在抖动,因此需要将当前键值与下一次扫描得到的键值比较,以排除错误触发。由于下一次扫描的键值还是未知的,因此必须将本次的键值保存起来,等到下次扫描获取键值后,再与保存的键值比较。所以在每次扫描结束时,将key_current_value 的值转存到key_last_value 变量中。那么,对于每一次新的扫描来讲,key_last_value 始终保存了上次键值,如果新扫描获得key_current_value 键值与key_last_value 上次扫描的键值相等,说明该键值为有效值,然后将该键值保存到最终键值key_final_value 变量中,否则是错误触发。

2. GPIO 状态

从GPIO 的状态来看,分别为1/1、1/0、0/0、0/1 四种状态,初始化时:

key_last_value = 1,key_final_value = 1,ret_flag = 0xFF

其中,1/0 的“1”与“0”分别表示扫描前后获得的当前键值,每次扫描时都将ret_flag初始化为0xFF。

(1)1/1:如果GPIO 始终为高电平,说明状态没有发生转移(无键按下)

key_last_value = 1,key_current_value = 1,key_final_value = 1,ret_flag = 0xff

(2)1/0:如果GPIO 的状态从1 转移到0(有键按下),延时10ms 去抖动key_last_value = 1,key_current_value = 0,key_final_value = 1,ret_flag = 0xff0/0:如果GPIO 的状态还是0(确实有键按下),执行相应的操作

key_last_value = 0,key_current_value = 0

因为两次扫描获得key_current_value 键值都为0,所以将键值保存到key_final_value 中,同时置ret_flag 为0,即key_final_value = 0,ret_flag = 0,说明确实有键按下,否则视为错误触发。

(3)0/1:如果GPIO 的状态从0 转移到1(按键释放),延时10ms 去抖动

key_last_value = 0,key_current_value = 1,key_final_value = 0,ret_flag = 0xff

1/1:如果GPIO 还是1(按键确实释放),执行相应的操作

key_last_value = 1,key_current_value = 1

因为两次扫描获得key_current_value 键值都为1,所以将键值保存到key_final_value 中,同时置ret_flag 为1,即key_final_value = 1,ret_flag = 1,说明按键已经释放,否则视为错误触发。

3. 相关函数与示例

板级初始化和独立按键扫描函数详见程序清单5.42。

程序清单5.42 独立按键扫描程序(key1.c)

用于判断连续扫描的当前键值是否相等的检测过程,没有使用一个循环语句,且在扫描程序中避免了延时10ms 所带来的影响,从而极大地提高MCU 的运行效率。为了便于后续使用,不妨将key1.c 封装为key1.h 接口,详见程序清单5.43。

程序清单5.43 key1.h 文件内容

如果key_scan()的返回值为0,说明确实有键按下;如果key_scan()的返回值为1,说明按键已经释放;如果返回值为0xFF,说明无键按下。其相应的测试程序详见程序清单5.44,如果有键按下,则蜂鸣器“嘀”一声;当按键释放后,则LED0 翻转。

程序清单5.44 独立按键范例程序

>>>  5.3.2 多个独立按键

多个独立按键与单个独立按键的扫描原理是一样的,在单个独立按键中,每个变量仅使用了一位。由于变量的一位的0 或1 值就可以表示按键的2 种状态,所以,当需要多个按键时,则可以充分利用多个位,每位对应一个独立按键。同时,由于独立按键的按下状态对应的电平并不一定全是低电平,因此将按键对应的管脚和按下键对应的电平保存到一个结构体数组中。比如:

上述代码段定义的4 个按键对应的管脚分别为PIO0_1、PIO0_2、PIO0_3、PIO0_5,并假设其对应键按下的电平分别为1、0、1、0。而在这里仅有一个独立按键,因此结构体数组中只包含一个按键的信息:

按照一位对应一个按键的思想,在key1.c 的基础上,修改支持多个独立按键的程序keyn.c,详见程序清单5.45。

程序清单5.45 支持多个独立按键的扫描程序(keyn.c)

同时,将函数接口的声明和相关类型的定义存放在keyn.h 中,详见程序清单5.46。

程序清单5.46 keyn.h 文件内容

显然,多个独立按键的程序设计思想与独立按键还是一样的,绝大部分程序都保持一样。所不同的是多个独立按键的操作是通过多个位操作来实现的。如果只有一个独立按键,则检测到键值变化时,就一定是该键状态变化。而对于多个独立按键来说,如果仅检测到键值的变化,还无法区分是哪个按键发生了变化。在这里巧妙地使用了一个change 变量,用于标志位的变化情况。由于存在多个按键,因此扫描函数的返回值不能简单地使用0、1 来表示按下和释放,还必须包含区分是哪一个按键的信息。其规则如下:

返回值的类型为8 位无符号数,使用最高位来表示按下(0)或释放(1),低7 位用于区分具体的按键,值为 0 ~ N-1,N 为按键的个数,0~N-1 具体表示的按键与数组g_key_info[]中元素的一一对应。因此,当第i 个按键按下时,其返回值为i“ret_flag = i;”。第i 个按键按下时,返回值应该在i 值的基础上,将最高位置1,即“ret_flag = (1 << 7) | i;”。

为了方便后续使用,先不考虑软件定时器,将上述程序添加到key.h 接口。使用多个按键的范例程序,同样按照键按下蜂鸣器发出“嘀”的一声,等按键释放后,LED0 灯翻转的要求编程,详见程序清单5.47。

程序清单5.47 支持多个独立按键范例程序

如果使用软件定时器,那么还需要新增一个软件定时器初始化函数。比如:

由于使用软件定时器后,会自动调用keyn_scan()函数,当发现按键事件时,则调用按键处理程序。现在的问题是,在封装模块时,并不知道按键处理程序的作用,所以必须使用回调机制。即通过应用程序注册一个函数,当事件发生时,然后自动调用已经注册的函数。即:

则重新定义带软件定时器的初始化函数,比如:

将上述函数声明和回调函数的定义添加到keyn.h 文件(程序清单5.48),同时将该函数的实现代码添加到keyn.c 文件(程序清单5.49)。

程序清单5.48 keyn.h 文件内容

显然,当按键事件发生时,即自动调用初始化函数时注册的回调函数。

程序清单5.49 新增带软件定时器的初始化接口

>>>  5.3.3 矩阵键盘

虽然矩阵连接法可以提高I/O 的使用效率,但要区分和判断按键动作的方法却比较复杂,所以这种接法一般多用在计算机中。下面仍然以图4.15 所示的2×2 的矩阵键盘电路为例,详细介绍逐行逐列键盘扫描发的程序设计方法,其相应的接口详见程序清单5.50 所示的matrixkey.h 和与接口相应的实现详见程序清单5.51 所示的matrixkey.c。

程序清单5.50 matrixkey.h 文件内容

程序清单5.51 matrixkey.c 文件内容

为了使其它代码尽可能复用之前多个独立按键的程序,因此将扫描到的按键状态与键值的位一一对应,KEY0 对应bit0 ,KEY1 对应bit1……当有键按下时,其对应位为0;当按键释放时,其对应位为1。同时为了获取键值,还必须在初始化函数中,将行线配置为输出,列线配置为输入。由此可见,矩阵键盘和独立按键的主要区别在于键值的获取方式,为了使代码尽可能地复用,也将矩阵键盘的各个按键分别与键值的位对应起来。即:当有键按下时,其对应位为0;当按键释放时,其对应位为1。

如图5.2 所示的数码管的2 个com 端与矩阵键盘的列是复用的,PIO0_17 与PIO0_23 既是数码管的com0、com1,又是矩阵键盘的列线KL0、KL1 这样设计反而节省了引脚。作为键盘扫描时需将列线配置为输入,作为数码管扫描时需将com 端设置为输出。显然,在矩阵键盘与数码管联合使用时都要进行上述操作,则完全有必要将其封装为一个接口,即将matrixkey_scan_with_digtron()添加到程序清单5.52 所示的matrixkey.c 中,并将新的接口函数添加到程序清单5.53 所示的matrixkey.h 中。

图5.2 LED 显示器电路图

程序清单5.52 matrixkey_scan_with_digtron()函数实现

在这里,新增了一个保存开始扫描前键盘状态的g_col_level[]数组。在矩阵键盘扫描结束后,不仅会将列引脚恢复为输出状态,而且还会将其引脚电平恢复为扫描前的状态,从而使得整个键盘扫描程序结束后不影响与数码管公共引脚的状态。

程序清单5.53 matrixkey.h 文件内容

5.4 PWM 接口

大小和方向随时间发生周期性变化的电流称为交流,交流中最基本的波形称为正弦波,除此之外的波形称为非正弦波。计算机、电视机、雷达等装置中使用的信号称为脉冲波、锯齿波等,其电压和电流波形都是非正弦交流的一种。

PWM(Pulse Width Modulation)就是脉冲宽度调制的意思,一种脉冲编码技术,即可以按照信号电平改变脉冲宽度。而脉冲宽度调制波的周期也是固定的,用占空比(高电平/周期,有效电平在整个信号周期中的时间比率,范围为0~100%)来表示编码数值。PWM可以用于对模拟信号电平进行数字编码,也可以通过高电平(或低电平)在整个周期中的时间来控制输出的能量,从而控制电机转速或LED 亮度。

PWM 信号是由计数器和比较器产生的,比较器中设定了一个阈值,计数器以一定的频率自加。当计数器的值小于阈值时,则输出一种电平状态,比如,高电平。当计数器的值大于阈值,则输出另一种电平状态,比如,低电平。当计数器溢出清0 时,又回到最初的电平状态,即I/O 引脚发生了周期性的翻转而形成PWM 波形,详见图5.3。

图5.3 PWM 波形图

当计数器的值小于阈值时,则输出高电平;当计数器的值大于阈值时,则输出低电平。阈值为45,计数器的值最大为100。PWM 波形有三个关键点:起始点①,此时计数器的值为0;计数器值达到阈值②,I/O 状态发生翻转;计数器达到最大值③,I/O 状态发生翻转,计数器的值回到0 重新开始计数。

>>>  5.4.1 初始化

在使用PWM 通用接口前,必须先完成PWM 的初始化,以获取到标准的PWM 实例句柄。在LPC82x 中,能够提供PWM 输出功能的外设有SCT(State Configurable Timer),其实质是一个状态可编程定时器,可以用作普通定时器、输入捕获、PWM 输出等,功能非常强大。在这里,仅仅将其作为PWM 功能使用,AMetal 提供了将SCT 用作PWM 功能的实例初始化函数。其函数原型为:

函数的返回值为am_pwm_handle_t 类型的PWM 实例句柄,该句柄将作为PWM 通用接口中handle 参数的实参。类型am_pwm_handle_t(am_pwm.h)定义如下:

由于函数返回的PWM 实例句柄仅作为参数传递给PWM 通用接口,不需要对该句柄作其它任何操作,因此,完全不需要对该类型作任何了解。需要特别注意的是,若函数返回的实例句柄的值为NULL,则表明初始化失败,该实例句柄不能被使用。

直接调用该实例初始化函即可完成SCT 的初始化,并获取对应的实例句柄:

SCT 用作PWM 功能时,支持6 个通道,即可同时输出6 路PWM,各通道对应的I/O口详见表5.8。

表5.8 各通道对应的I/O 口

>>>  5.4.2 PWM 接口函数

AMetal 提供了3 个PWM 标准输出接口函数,详见表5.9。

表5.9 PWM 标准接口函数

1. 配置PWM 通道

配置一个PWM 通道的周期时间和高电平时间,其函数原型为:

如果返回AM_OK,说明配置成功;如果返回-AM_EINVAL,说明配置失败,范例程序详见程序清单5.54。

程序清单5.54 am_pwm_config()范例程序

2. 使能通道输出

使能通道输出,使相应通道开始输出波形,其函数原型为:

若返回AM_OK,说明使能成功,开始输出波形;若返回-AM_EINVAL,说明使能失败,范例程序详见程序清单5.55。

程序清单5.55 am_pwm_enable()范例程序

3. 禁能通道输出

禁能通道输出,关闭相应通道的波形输出,其函数原型为:

若返回AM_OK,说明禁能成功;若返回-AM_EINVAL,说明禁能失败,范例程序详见程序清单5.56。

程序清单5.56 am_pwm_disable()范例程序

>>>  5.4.3 蜂鸣器接口函数

在蜂鸣器的发声程序中,虽然延时时间只有500us,但对于MCU 来说非常耗费资源,因为延时期间无法做其它任何想做的事情。我们不妨用MCU 的PWM 输出功能来实现,即通过PWM 直接输出一个脉冲宽度调制波形来驱动蜂鸣器发声。假定波形的周期为1ms,且高低电平占用的时间相等,即占空比为50%,范例程序详见程序清单5.57。

程序清单5.57 蜂鸣器发声范例程序

为了方便控制蜂鸣器,基于PWM 接口函数编写蜂鸣器通用接口,将接口函数的声明和实现分别放到buzzer.h 和buzzer.c 文件中。当需要使用蜂鸣器时,直接调用蜂鸣器相关接口即可,buzzer.h 详见程序清单5.58。

程序清单5.58 蜂鸣器通用接口

当接口定义好后,则将实现全部放到buzzer.c 文件,详见程序清单5.59。

程序清单5.59 蜂鸣器通用接口实现

ZLG致远电子技术专区

原文标题:周立功:深入浅出AMetal——键盘扫描接口和 PWM 接口

文章出处:【微信号:ZLG_zhiyuan,微信公众号:ZLG致远电子】欢迎添加关注!文章转载请注明出处。

关注电子发烧友微信

有趣有料的资讯及技术干货

下载发烧友APP

打造属于您的人脉电子圈

关注发烧友课堂

锁定最新课程活动及技术直播
收藏 人收藏
分享:

评论

相关推荐

开关电源电路基础知识详解

开关电源的主要电路是由输入电磁干扰滤波器(EMI)、整流滤波电路、功率变换电路、PWM控制器电路、输....

的头像 工控资料窝 发表于 12-11 10:09 次阅读 0条评论
开关电源电路基础知识详解

基于MOSFET控制的PWM型直流可调电源的设计与实现

由于仪器所用电源的体积和重量通常受到限制,为此提出一种由MOSFET控制,并且由高频变压器隔离的开关....

发表于 12-06 16:31 次阅读 0条评论
基于MOSFET控制的PWM型直流可调电源的设计与实现

LT3743能完成大电流脉冲功率驱动器苛刻的准确度和速度要求

从 DLP 投影机中的大电流 LED 到大功率激光二极管,在很多照明应用中,都采用了能产生稳定的大....

发表于 12-06 06:37 次阅读 0条评论
LT3743能完成大电流脉冲功率驱动器苛刻的准确度和速度要求

开关电源功耗分析和提高待机效率的方法

随着能源效率和环保的日益重要,人们对开关电源待机效率期望越来越高,客户要求电源制造商提供的电源产品能....

发表于 12-06 05:22 次阅读 0条评论
 开关电源功耗分析和提高待机效率的方法

静止同步补偿器技术的简介和工作原理及其控制方式和应用现状

静止同步补偿器(StaticSynchronousCompensator,STATCOM)是柔性交流....

发表于 12-06 04:20 次阅读 0条评论
 静止同步补偿器技术的简介和工作原理及其控制方式和应用现状

TL494检测方法和TL494各脚电压值介绍

随着信息化的不断普及,微机已进入普通家庭和中小学校,随之而来的维修工作也越来越重。而微机中硬件故障率....

发表于 12-05 17:23 次阅读 0条评论
TL494检测方法和TL494各脚电压值介绍

TL494工作原理图解(引脚功能_内部结构_参数及开关电源电路)

 TL494是一种固定频率脉宽调制电路,它包含了开关电源控制所需的全部功能,广泛应用于单端正激双管式....

发表于 12-05 16:26 次阅读 0条评论
TL494工作原理图解(引脚功能_内部结构_参数及开关电源电路)

TL494推挽式输出的电路设计(基于TL494的H桥直流电机控制系统)

介绍了以TL494为核心,采用PWM技术的直流电机控制系统。基于TL494的H桥直流电机控制系统可简....

发表于 12-05 15:37 次阅读 0条评论
TL494推挽式输出的电路设计(基于TL494的H桥直流电机控制系统)

由TL494构成的恒流闭环控制电路的设计与实现

开发了一种用TL494构成的恒流恒压双闭环控制系统。系统通过两个闭环共用同一个脉宽调制实时处理方法,....

发表于 12-05 15:06 次阅读 0条评论
由TL494构成的恒流闭环控制电路的设计与实现

TL494控制BUCK型开关电源电路

文章介绍了开关电源的基本原理,DC/DC变换主电路分类,对开关电源的控制方式进行了比较,给出了专用集....

发表于 12-05 14:24 次阅读 0条评论
TL494控制BUCK型开关电源电路

基于TL494的PWM脉宽调制等速送丝电路

设计了一种基于TL494芯片的电压负反馈配合电流正反馈的CO2焊机送丝调速电路。该电路通过PWM脉宽....

发表于 12-05 11:55 次阅读 0条评论
基于TL494的PWM脉宽调制等速送丝电路

一款基于脉宽调制芯片TL494的微型车载逆变器设计电路

针对汽车内部直流电源不能用于交流用电器的问题,设计了一款基于脉宽调制芯片TL494的微型车载逆变器。....

发表于 12-05 11:32 次阅读 0条评论
一款基于脉宽调制芯片TL494的微型车载逆变器设计电路

TL494脉宽调制器集成电路的设计与实现

详细介绍了TL494脉宽调制器集成电路的内部结构和工作原理,并给出了TL494在脉冲激光电源中的应用....

发表于 12-05 11:18 次阅读 0条评论
TL494脉宽调制器集成电路的设计与实现

STC单片机实现可调PWM输出的C51程序

脉冲宽度调制(PWM),是英文“ Pulse Width Modulation” 的缩写,简称脉宽调....

发表于 12-05 10:13 次阅读 0条评论
STC单片机实现可调PWM输出的C51程序

用PWM控制集成电路TL494实现单回路控制器

 本文介绍了以电压驱动型脉宽调制控制集成电路TL494为核心元件并加上简单滤波电路及RC放电回路所构....

发表于 12-05 10:03 次阅读 0条评论
用PWM控制集成电路TL494实现单回路控制器

人因照明在植物、畜牧业及人类生活中的影响分析

情绪照明(mood lighting)通常被误解为人因照明(HCL)。但人因照明则包含更多,因为它包....

的头像 CNLED网 发表于 12-04 13:58 次阅读 0条评论
人因照明在植物、畜牧业及人类生活中的影响分析

PWM控制方法的详细分析

PWM控制的基本原理很早就已经提出,但是受电力电子器件发展水平的制约,在上世纪80年代以前一直未能实....

发表于 12-04 06:22 次阅读 0条评论
 PWM控制方法的详细分析

数字电源控制系统详细分析与应用

在数字电源的所有讨论中,必须区分两个关键的概念:功率控制和功率管理。Ericsson公司采用电源控制....

发表于 12-04 04:51 次阅读 0条评论
 数字电源控制系统详细分析与应用

电镀电源开关功率的因数校正和提高

传统电镀电解直流电源采用晶闸管相控整流模式,导致电网侧谐波大、功率因数低。现代电镀电解开关电源采用二....

发表于 12-03 20:17 次阅读 0条评论
电镀电源开关功率的因数校正和提高

PWM 实现DAC 电路设计

当MCU 需要产生不同的模拟信号时,通常采用集成或独立的D/A 转换器实现。但是在要求低成本的场合,....

的头像 周立功单片机 发表于 12-01 14:12 次阅读 0条评论
PWM 实现DAC 电路设计