AVR单片机教程——按键动作
本文隶属于AVR单片机教程系列。
上一篇教程中我们学习了如何读取按键状态。而按键的动作,比如单击,至少需要两个状态才能判定,长按、双击的判定更加复杂。今天我们来学习如何使用库函数判断按键单击,以及其实现原理。
我们要实现的是:当一个按键被单击时,一个LED的状态改变(即亮变暗,暗变亮);4个按键对应4个LED。利用库提供的 button_pressed 函数,很容易就能实现这个功能。
#include <ee1/button.h>
#include <ee1/led.h>
#include <ee1/delay.h> int main()
{
led_init();
button_init(PIN_0, PIN_1);
while ()
{
for (uint8_t i = ; i != BUTTON_COUNT; ++i)
if (button_pressed(i))
led_flip(i);
delay();
}
}
在主循环中,程序对每个按键调用 button_pressed ,若返回真,则用 led_flip 将LED状态反转。
按键动作需要两个状态来判断,而函数在当下是无法从按键读取到以前的信息的,只能在本次调用时保存状态以供下次使用。自动变量保存的内容无法保留到下一次调用,可选的有全局变量与静态变量。由于此状态只被这一个函数使用,可以把它定义成静态变量。
button_pressed 函数可以判断4个按键的动作,每个按键需要一个 bool 变量,即一个bit的存储空间。为了节省空间,我使用了位操作,这里先不讲,把重心放在按键动作判断逻辑上。以下是判断一个按键动作的函数。
bool pressed()
{
static bool status = true;
bool pre = status;
status = button_down(BUTTON_0);
return !pre && status;
}
静态变量 status 用于保存按键在上一次调用时的状态。函数体中,先用自动变量 pre 临时保存了 status ,然后将 status 更新为当前的状态。return 语句返回的是 !pre && status ,即仅当 pre 为假且 status 为真时返回 true 。其逻辑为,如果上一次按键没有被按下而这一次被按下,则按键被单击了。
想一想,为什么 status 的初值要设置成 true ?
另外,上面的代码开头处的蓝色 bool 特别醒目,因为博客园代码着色是按照C#的规则,bool 是其中一个关键字。但是应当注意,C语言中没有 bool 这个关键字,而是 _Bool ;bool 与 true 和 false 都在 <stdbool.h> 中定义。
我们还没有解释过第一段代码中的 delay() 。如果你把它去掉,你会发现判定经常出错,往往在抬起的时候被多判定了一次,在按得不是很用力时很不稳定。这是按键内部的机械结构决定的,当处于连通和不连通位置的交界处时,单片机检测到的电平会迅速跳变(按键的原理,以及单片机如何检测按键状态,将在几篇后介绍),而一段延时就可以让这些跳变的电平被 button_down 函数忽略。这里的40是根据经验选取的。其实把40换成10到100之间的数,手感基本没有差别。
然而,即使有这句延时,单击判定还是有出错的时候。如果不能允许这样的错误,就需要“消抖”上场了,我们以后再讲。
作业:给其中一个按键加上一个功能,让它控制其余按键是否启用。
AVR单片机教程——按键动作的更多相关文章
- AVR单片机教程——按键状态
好久没更新了,今天开始继续,争取日更. 今天我们来讲按键.开发板的右下角有4个按键,按下会有明显的“咔嗒”声.如何检测按键是否被按下呢?首先要把按键或直接或间接地连接到单片机上.与之前使用的4个LED ...
- AVR单片机教程——数字输入
我们已经学习了如何使用按键和拨动开关,不知你有没有好奇 button_down 和 switch_status 等函数是如何实现的.本篇教程带你一探究竟,让我们从按键的原理开始. 在原理图中,按键的符 ...
- AVR单片机教程——拨动开关
在按键的上方有4个拨动开关.开关与按键,在原理和使用方法上都是很类似的,但有不同的用途——按键按下后松开就会弹起,而开关可以保存其状态. <switch.h> 定义了与开关相关的函数.sw ...
- AVR单片机教程——ADC
ADC 计算机的世界是0和1的.单片机可以通过读取0和1来确定按键状态,也可以输出0和1来控制LED.即使是看起来不太0和1的PWM,好像可以输出0到5V之间的电压一样,达到0和1之间的效果,但本质上 ...
- AVR单片机教程——串口发送
本文隶属于AVR单片机教程系列. 到目前为止,我们的开发板只能处理很小量的数据:读取几个引脚电平,输出几个LED,顶多用数码管显示一个两位数字.至于输入一个指令.输出一条调试信息,甚至用scanf ...
- AVR单片机教程——PWM调光
本文隶属于AVR单片机教程系列. PWM 两位数码管的驱动方式是动态扫描,每一位都只有50%的时间是亮的,我们称这个数值为其占空比.让引脚输出高电平点亮LED,占空比就是100%. 在驱动数码管时 ...
- AVR单片机教程——走向高层
本文隶属于AVR单片机教程系列. 在系列教程的最后一篇中,我将向你推荐3个可以深造的方向:RTOS.C++.事件驱动.掌握这些技术可以帮助你更快.更好地开发更大的项目. 本文涉及到许多概念性的内容 ...
- AVR单片机教程——旋转编码器
好久没写这个系列了.今天讲讲旋转编码器. 旋转编码器好像不是单片机玩家很常用的器件,但是我们的开发板上有,原因如下: 旋转编码器挺好用的.电位器能旋转的角度有限,旋转编码器可以无限圈旋转:旋转时不连续 ...
- AVR单片机教程——数码管
先解答之前一个思考题:如果不把引脚配置为输出而写高电平,连接LED会怎样? 实验结果是,LED会亮,但相比于输出高电平的情况,亮度很低.这是为什么呢? 通过上一篇教程我们知道,引脚输入输出模式是由寄存 ...
随机推荐
- 洛谷 P2850 [USACO06DEC]虫洞Wormholes 题解
P2850 [USACO06DEC]虫洞Wormholes 题目描述 While exploring his many farms, Farmer John has discovered a numb ...
- shell脚本编程之变量的小用法
变量赋值 ${parameter:-word}:如果parameter为空或未定义,则变量展开为"word":否则,展开为parameter的值: ${parameter:+wor ...
- Python之NumPy(axis=0/1/2...)的透彻理解
https://blog.csdn.net/sky_kkk/article/details/79725646 numpy中axis取值的说明首先对numpy中axis取值进行说明:一维数组时axis= ...
- mysql 通配符%以及_
%匹配任意长度 _ 匹配单个字符 mysql> select * from table1; +----------+------------+-----+-------------------- ...
- 获取当前服务的IP和端口号
package com.movitech.product.datahub.util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; ...
- 微信小程序之使用checkbox
效果图如下: 实例代码如下:type_add.js // pages/detail_add/detail_add.js Page({ /** * 页面的初始数据 */ data: { selectDa ...
- ‘Skimming-Perusal’ Tracking: A Framework for Real-Time and Robust Long-term Tracking
‘Skimming-Perusal’ Tracking: A Framework for Real-Time and Robust Long-term Tracking 2019-09-05 21:1 ...
- Selenium自动化对非输入框的日历或日期控件的处理
4.这个时候我们可以移除readonly的属性,问题就轻轻松松解决了,代码如下: String js = "document.getElementById('createTime').rem ...
- spring @Autowired注入map
注入map,平常一般不会这么做,今天看一段老代码时发现有这么个用法.补习一下. @Autowired 标注作用于 Map 类型时,如果 Map 的 key 为 String 类型,则 Spring 会 ...
- Android - Button(按钮)的响应点击事件的4种写法
Button控件setOnclickListener(View.OnClickListener listener)来接收一个点击事件的监听器 自定义一个点击事件监听器类让其实现View.OnClick ...