1. 引子

在进行mcu驱动和应用开发时,经常会遇到独立按键驱动的开发,独立按键似乎是每一个嵌入式工程师的入门必修课。笔者翻阅了许多书籍(包括上大学时候用的书籍)同时查阅了网上许多网友的博客,无一例外,清一色采用检测、延时、再检测,千篇一律,似乎是按键过于简单,因此没有人愿意推陈出新。

本文介绍一种独立按键驱动,消除抖动不采用软件延时(让CPU死等,mcu无休止的运行_nop_()函数,在稍微复杂应用场景,cpu时间捉襟见肘的场合,一个独立按键便让CPU如此耗力,是非常不明智的)。本驱动短小精悍,可以是适用于裸机应用,也可方便移植到rtos。

2. 思路

分析独立按键按下的过程,分为稳定状态非稳定状态

根据经验值,抖动消除时间为10ms左右;

累计检测到超过10ms按下状态,视为按键按下;

累计检测到超过10ms弹起状态,视为按键弹起;

2.1 按键驱动key.c

/**
* @file: key.c
* @brief: 按键驱动实现
*/
#include <reg52.h>
#define STAT_RELEASED (1)
#define STAT_PRESSED (0)
unsigned char (*keyfn)(void);// 应用提供本函数实现,返回1表示读到高电平,返回0表示读到低电平
unsigned char flg_down;
unsigned char flg_up;
unsigned char stat; // 默认是弹起状态
unsigned char timer; void key_init(unsigned char (*fn)(void))
{
stat = STAT_RELEASED;
keyfn = fn;
} void key_scan(void)
{
if(keyfn && !keyfn()) // 有按键按下
{
if(timer < 1) // 非稳态
{
timer++;
return;
}
if(stat == STAT_RELEASED)
{
stat = STAT_PRESSED;
// post down event
flg_down = 1;
}
}
else
{
if(timer > 0) // 非稳态
{
timer--;
return;
}
if(stat == STAT_PRESSED)
{
stat = STAT_RELEASED;
// post up event
flg_up = 1;
}
}
}

2.2 按键对外接口key.h

/**
* @file:key.h
* @brief:按键驱动对外接口
*/
/**
* @function: key_init
* @param fn: 函数指针,有返回值,读到高电平返回1,读到低电平返回0
* @brief: 按键模块初始化函数,传递io电平读取函数到按键模块
*/
extern void key_init(unsigned char (*fn)(void));
extern unsigned char flg_down;
extern unsigned char flg_up;
extern void key_scan(void); // 10ms周期调用

3 实验

假设单片机P2.1口为按键;

按下和弹起时,串口打印输出

为了方便实验,添加串口驱动、定时器驱动程序。

3.1 串口驱动

/**
* @file: uart.c
* @brief: 串口驱动,波特率9600bps,10bit模式
*
*/
#include <reg52.h> void uart_init(void)
{
SCON = 0X50; // 10bit 可变波特率模式 //T1: SM1SM0=10,8bit auto reload,波特率9600bps
TMOD = (TMOD & 0X0F) | (1 << 5);
TH1 = TL1 = 0XFD;
TR1 = 1; ES = 1;
EA = 1;
TI = 1; // start transmit if using putchar provided by c51 lib
} void uart_isr(void) interrupt 4
{
if(RI)
{
RI = 0;
}
if(TI)
{
}
}
/**
* @file: uart.h
*/
// 串口模块
extern void uart_init(void);

3.2 定时器驱动

/**
* @file: timer0.c
* @brief: 产生10ms事件
*/
#include <reg52.h>
int systick;
unsigned char flg_10ms;
unsigned char flg_50ms;
unsigned char flg_sec;
void timer_init(unsigned char ms)
{
TMOD = (TMOD & 0XF0); // 模式0:13bit 定时器模式,最大计数值8192
TH0 = (8192 - ms * 1000) / 32; // TH0的8位保存13bit初值的高8bit
TL0 = (8192 - ms * 1000) % 32; // TL0的低5位用来存储13bit初值得低5bit TR0 = 1; ET0 = 1;
EA = 1;
} void timer_isr(void) interrupt 1
{
TR0 = 0;
timer_init(1); systick++;
if(systick % 10 == 0)
{
flg_10ms = 1;
if(systick % 50 == 0)
{
flg_50ms = 1;
if(systick % 1000 == 0)
{
flg_sec = 1;
}
}
}
}
/**
* @file:timer0.h
*/
// 定时器模块
extern unsigned char flg_10ms;
extern unsigned char flg_50ms;
extern unsigned char flg_sec;
extern void timer_init(unsigned char ms);

3.3 编写应用

  1. 初始化串口、定时器、按键模块
  2. 10ms为周期扫描按键
  3. 监测按键事件并处理
#include <reg52.h>
#include <timer0.h>
#include <uart.h>
#include <key.h>
#include <stdio.h> sbit button = P2^1; unsigned char kfn(void)
{
return button? 1: 0;
} void main(void)
{
uart_init();
timer_init(1);
key_init(kfn);
while(1)
{
if(flg_10ms)
{
flg_10ms = 0;
key_scan(); // 10ms扫描1次
}
if(flg_down)
{
flg_down = 0;
printf("key pressed\r\n");
}
if(flg_up)
{
flg_up = 0;
printf("key released\r\n");
}
}
}

MCU软件最佳实践——独立按键的更多相关文章

  1. MCU软件最佳实践——矩阵键盘驱动

    1.矩阵键盘vs独立按键 在mcu应用开发过程中,独立按键比较常见,但是在需要的按键数比较多时,使用矩阵键盘则可以减少io占用,提高系统资源利用率.例如,某mcu项目要求有16个按钮,如果采用独立按键 ...

  2. MCU软件最佳实践——使用printf打印数据

    在mcu上开发应用时,使用串口打印调试信息是最常用的调试手段之一.printf是c标准库提供的函数,可以方便输出格式化的信息.但针对不同的mcu芯片,printf函数要能正常工作,需要做一些移植和适配 ...

  3. 敏捷遇上UML-需求分析及软件设计最佳实践(郑州站 2014-6-7)

      邀请函: 尊敬的阁下:我们将在郑州为您奉献高端知识大餐,当敏捷遇上UML,会发生怎样的化学作用呢?首席专家张老师将会为您分享需求分析及软件设计方面的最佳实践,帮助您掌握敏捷.UML及两者相结合的实 ...

  4. Atitit. 软件设计 模式 变量 方法 命名最佳实践 vp820 attilax总结命名表大全

    Atitit. 软件设计 模式 变量 方法 命名最佳实践 vp820 attilax总结命名表大全 1. #====提升抽象层次1 2. #----使用通用单词1 3. #===使用术语..1 4.  ...

  5. 基于开源软件在Azure平台建立大规模系统的最佳实践

    作者 王枫 发布于2014年5月28日 前言 Microsoft Azure 是微软公有云的唯一解决方案.借助这一平台,用户可以以多种方式部署和发布自己的应用. 这是一个开放的平台,除了对于Windo ...

  6. 移动App測试实战:顶级互联网企业软件測试和质量提升最佳实践

    这篇是计算机类的优质预售推荐>>>><移动App測试实战:顶级互联网企业软件測试和质量提升最佳实践> 国内顶级互联网公司測试实战经验总结.阿里.腾讯.京东.携程.百 ...

  7. Atitit.软件开发概念说明--io系统区--特殊文件名称保存最佳实践文件名称编码...filenameEncode

    Atitit.软件开发概念说明--io系统区--特殊文件名称保存最佳实践文件名称编码...filenameEncode 不个网页title保存成个个文件的时候儿有无效字符的问题... 通常两个处理方式 ...

  8. 读《软件需求最佳实践》YOUGAN

    这几天在看<软件需求最佳实践>作者徐锋老师的软件需求培训,三天的课程,虽然原来对需求也关注了很多,自己也做过需求分析和开发的工作,但是这次培训感觉收获还是很多.三天的培训先做个记录,后续多 ...

  9. MCU 51-4 独立按键&编码按键

    独立按键: 按键的按下与释放是通过机械触点的闭合与断开来实现的,因机械触点的弹性作用,在闭合与断开的瞬间均有一个抖动的过程,抖动必须清除. 按键按下一次,数码管数值加1: #include<re ...

随机推荐

  1. HSPICE与非门仿真

    一.HSPICE的基本操作过程 打开HSPICE程序,通过OPEN打开编写好的网表文件. 按下SIMULATE进行网表文件的仿真. 按下AVANWAVES查看波形图(仿真结果). 二. 网表文件结构总 ...

  2. CF1144A Diverse Strings 题解

    Content 我们定义一个字符串是合法的,当且仅当这个字符串是"连续排列"(按照字母表顺序排序).现在给出 \(n\) 个字符串 \(s_1,s_2,s_3,...,s_n\), ...

  3. JAVA结合 JSON Web Token(JWT) 工具类

    引入java-jwt-3.3.0.jar .  jjwt-0.9.0.jar .jackson-all-1.7.6.jar 或者maven <!-- https://mvnrepository. ...

  4. VS2015常用的字体 和 插件

    Inconsolata 字体 自己常使用 Inconsolata 作为代码字体, 阅读代码非常舒适. 其他插件 GoToDef.vsix , 查看 声明非常方便. (ctrl+鼠标左键) Viasfo ...

  5. leetcode 761. Special Binary String

    761. Special Binary String 题意: 一个符合以下两个要求的二进制串: \(1.串中包含的1和0的个数是相等的.\) \(2.二进制串的所有前缀中1的个数不少于0的个数\) 被 ...

  6. hdu-3833 YY's new problem(数组标记)

    http://acm.hdu.edu.cn/showproblem.php?pid=3833 做这题时是因为我在网上找杭电的数论题然后看到说这道题是数论题就点开看了以下. 然后去杭电上做,暴力,超时了 ...

  7. P1753HackSon的趣味题

    1 #include<stdio.h> 2 #include<algorithm> 3 #include<iostream> 4 #include<stdli ...

  8. Glossary Collection

    目录 直接修饰用 间接强调用 (多为副词) 过渡用 特别的名词 动词 词组 各种介词 句子 摘要 引言 总结 正文 实验 直接修饰用 Word 含义 例句 近义词 nuanced adj. 微妙的:具 ...

  9. 对比显示每条线路的价格和该类型线路的平均价格,分别使用子查询和 exists 获取线路数量

    查看本章节 查看作业目录 需求说明: 对比显示每条线路的价格和该类型线路的平均价格 分别使用子查询和 exists 获取线路数量超过"出境游"线路数的线路类型信息,要求按照线路数升 ...

  10. Java的发展简史

    Java是由Sun Microsystems公司(简称Sun公司)于1995 年 5 月推出的 Java程序设计语言和Java平台的总称.Java语言是一种可以撰写跨平台应用软件的面向对象的程序设计语 ...