MCU软件最佳实践——独立按键

短小精悍,适用于有rtos和无rtos场合的按键驱动程序

  1. 引子

在进行mcu驱动和应用开发时,经常会遇到独立按键驱动的开发,独立按键似乎是每一个嵌入式工程师的入门必修课。笔者翻阅了许多书籍(包括上大学时候用的书籍)同时查阅了网上许多网友的博客,无一例外,清一色采用检测、延时、再检测,千篇一律,似乎是按键过于简单,因此没有人愿意推陈出新。
本文介绍一种独立按键驱动,消除抖动不采用软件延时(让CPU死等,mcu无休止的运行_nop_()函数,在稍微复杂应用场景,cpu时间捉襟见肘的场合,一个独立按键便让CPU如此耗力,是非常不明智的)。本驱动短小精悍,可以是适用于裸机应用,也可方便移植到rtos。

  1. 思路

分析独立按键按下的过程,分为 稳定状态非稳定状态
根据经验值,抖动消除时间为10ms左右;
累计检测到超过10ms按下状态,视为按键按下;
累计检测到超过10ms弹起状态,视为按键弹起;

2.1 按键驱动key.c

/**
 * @file: key.c
 * @brief: 按键驱动实现
 */
#include
#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

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
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
#include
#include
#include
#include

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软件最佳实践——独立按键

Original: https://www.cnblogs.com/arminker/p/14699669.html
Author: 流云的博客
Title: MCU软件最佳实践——独立按键

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/684480/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 如何使用 Python 实现彩票自由(大乐透)

    前言 有没有小伙伴喜欢买股票的,我自己是不会玩的,不是不想玩,是真的挽不回,只能玩比较简单一点的刮刮乐。虽然我不会买股 票,但是用python分析股票还是简简单单的… …

    技术杂谈 2023年6月21日
    087
  • 20. 有序数组、BST、l累加树的转换

    title: 有序数组、BST、l累加树的转换 📃 题目一描述 题目链接:108. 将有序数组转换为二叉搜索树 🔔 解题思路 解法一:递归法 符合高度平衡,那么每次取中间值作为节点…

    技术杂谈 2023年7月24日
    078
  • Bean Validation(数据校验注解大全 @Valid和@Validated的区别。

    原文地址: https://www.cnblogs.com/nxzblogs/articles/13995569.html@AssertFalse | bool | 元素必须是fa…

    技术杂谈 2023年5月30日
    083
  • systemd系列文章

    骏马金龙 (博客已搬家:www.junmajinlong.com) 网名骏马金龙,钟情于IT世界里的各种原理和实现机制,强迫症重症患者。爱研究、爱翻译、爱分享。特借此一亩三分田记录…

    技术杂谈 2023年5月31日
    0104
  • 日本开放Wi-Fi 6E认证

    2022年9月2日,日本MIC(総務省)发布了”電波法施行規則等の一部を改正する省令(令和4年総務省令第59号)”省令,更新了Wi-Fi 6E Band 5…

    技术杂谈 2023年6月21日
    0101
  • 54.等我回家

    dsfds posted @2022-09-28 08:30 随遇而安== 阅读(3 ) 评论() 编辑 Original: https://www.cnblogs.com/55z…

    技术杂谈 2023年6月21日
    0118
  • 一张动图,让你明白时域和频域的关系

    看明白了这张图,就可以了解为什么既要做时域分析也要做频域分析了吧。 简单总结下,时域和频域的关系如下: 时域是信号在时间轴随时间变化的总体概括。 频域是把时域波形的表达式做傅立叶等…

    技术杂谈 2023年5月31日
    087
  • java.sql.SQLSyntaxErrorException: Unknown database报错

    一般是jdbc链接的数据库名字写错了,检查数据库的名字。 Original: https://www.cnblogs.com/333czh/p/15622694.htmlAutho…

    技术杂谈 2023年6月21日
    073
  • Kaldi 语音识别基础教程

    Kaldi 介绍 Kaldi 是由 C++ 编写的语音识别工具,其目的在于为语音识别研究者提供一个研究和使用的平台。 Kaldi 环境搭建 本文主要通过使用 Docker 和 Nv…

    技术杂谈 2023年5月30日
    086
  • MVCC简介

    一、MVCC简介 MVCC (Multiversion Concurrency Control),即多版本并发控制技术,它使得大部分支持行锁的事务引擎,不再单纯的使用行锁来进行数据…

    技术杂谈 2023年6月1日
    096
  • 算法练习(20)-平滑加权轮询算法

    一个很自然的想法:A-A-A-A-B ,按权重顺序依次分配,同时计数,每分配1次,计数减1,减到0后,再分配『次权重』的服务器。 看上去好象也凑合能用,但如果A:B的权重是100:…

    技术杂谈 2023年5月31日
    080
  • Java-泛型

    泛型出现的原因 Java的泛型是在JDK1.5开始才加上的。在此之前的Java是没有泛型的。没有泛型的Java使用起来给人感觉非常的笨重,为了体会泛型带来的好处,来看看如果没有泛型…

    技术杂谈 2023年7月11日
    063
  • python练习题:将列表中的大写字母转换成小写

    将列表中的大写字母转换成小写如果list中既包含字符串,又包含整数,由于非字符串类型没有lower()方法,L1 = [‘Hello’, ‘World’, 18, ‘Apple’,…

    技术杂谈 2023年7月24日
    072
  • dotenv 加载本地环境变量

    https://www.npmjs.com/package/dotenv Original: https://www.cnblogs.com/mengfangui/p/157928…

    技术杂谈 2023年5月31日
    068
  • 快速上手Mybatis项目

    1、搭建实验数据库 CREATE DATABASE mybatis; USE mybatis; DROP TABLE IF EXISTS user; CREATE TABLE us…

    技术杂谈 2023年7月11日
    074
  • 【转】iOS中的md5,crc32校验

    在使用URLSession下载一个文件过程中,如何校验呢? md5算法在ios中实现 我们在下载后会拿到一个NSData. const char str = (const char…

    技术杂谈 2023年6月1日
    0109
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球