文章目录

  • 01 - PCB原理图例程
  • 02 - 分时复用的注意项和设计
    • 2.1 - 注意项
    • 2.2 - 设计
  • 03 - 代码实现

只要我跑的速度够快,寂寞就追不上我
只要Key和Led切换速度够快,人眼就看不出来

————小白


  如果你存在按键Key和显示Led共用同一个IO时,需要分时复用的需求,则可以移植代码进行使用:

  • 代码所占code少于0.5K
  • 线程安全,中断安全
  • 可移植性高,配置容易
  • 注意:系统需要存在一个至少为1ms的时钟中断

01 - PCB原理图例程

  举2个Key和Led共用IO口的例子,当MCU的IO口资源不足时,通常会让一些可以用速度欺骗人眼的做法进行资源的节省,比如Key扫描、Led扫描等,例如Led的扫描只要高于25Hz的速度,人眼就基本看不出闪烁,例如Key扫描只要大于100Hz,人的触感就难以察觉。

例程1

例程2

02 - 分时复用的注意项和设计

2.1 - 注意项

  Led和Key的分时复用需要考虑几个情况:
  1、Led扫描的频率,必须高于肉眼能看见闪烁的频率25HZ。一般为了效果较好,都会大于50HZ,也就是Led扫描时间<=20ms
  2、保证分时复用,扫描一定要有先后顺序。要确保Led扫描期间不能进行Key扫描,同时确保Key扫描期间不能进行Led扫描
  3、Led需要备份当前状态。因为扫描Key时Led是不起作用的,Key扫描完成后需要恢复Led的状态
  4、注意Led切换为Key时的准备动作。Led切换为Key时根据原理图要做哪些准备工作以防止切换后Key误触发,而Key切换为Led时按照电路决定是否需要做准备动作
  5、Led扫描时间比Key扫描时间长。考虑到肉眼的观察是最容易受影响的,时刻都能看见,而按键的使用次数则较低

2.2 - 设计

  根据注意项,总体设计如下:
  1、系统需要有一个至少为1ms的时钟中断,里面调用扫描ISR函数LedKeyStatusSwitchService_1ms,用于保证高频扫描
  2、理清状态机,存在2种状态的切换,分别为KeyState和LedState,值得注意的是,Led和Key的数量暂时未知,如果数量较多则实际的扫描动作不宜在中断内进行,此时中断则只做状态切换,所以2个状态分别需要一个记录器
  3、决定取舍,Led为人眼可见,最为敏感,Led的扫描动作直接放在中断进行,舍弃Key的中断扫描,让Key在前台进行扫描

03 - 代码实现

  以例程1的PCB为例,整个分时复用时间为6ms(167Hz),其中Led扫描占据4ms,Key扫描占据2ms,下面为参考代码:

#define LED_SACND_TIME_MS    4
#define KEY_SACND_TIME_MS   2
volatile uint8_t configKeyFlag = 0;
volatile uint8_t configLedFlag = 0;
uint8_t ledKeyStatusSwitchCnt = 0;/* MCU的底层配置 */
void IOPorts_ConfigKey(void)
{}/* MCU的底层配置 */
void IOPorts_ConfigLed(void)
{}/* 恢复Led的状态 */
void revProcess_AfterConfigLed(void)
{}/* 在底层配置为Key之前的预处理,主要是Led电路对Key电路的影响 */
void preProcess_BeforeConfigKey(void)
{//COM1 & COM2必须拉高,否则数码管内会输出低电平导致Key误触发_IO_setDisplayCOM1(1);_IO_setDisplayCOM2(1);//把复用的IO拉高,防止寄存器内为0导致Key误触发_IO_setDisplayS5(1);_IO_setDisplayS6(1);_IO_setDisplayS7(1);_IO_setDisplayS8(1);
}/* 为保证频率,Service一般都在中断内执行 */
void ledKeyStatusSwitchService_1ms(void)
{ledKeyStatusSwitchCnt++;if(ledKeyStatusSwitchCnt <= LED_SACND_TIME_MS) {if ((configLedFlag == 0) && (configKeyFlag == 0)) {configLedFlag = 1;IOPorts_ConfigLed();revProcess_AfterConfigLed();}} else if(ledKeyStatusSwitchCnt <= (LED_SACND_TIME_MS + KEY_SACND_TIME_MS)) {if ((configKeyFlag == 0) && (configLedFlag == 1)) {preProcess_BeforeConfigKey();IOPorts_ConfigKey();configKeyFlag = 1;configLedFlag = 0;//当按键数较少而且扫描时间较短时,可以选择在中断内进行,但一般选择在main中进行/*keyScanHandler();configKeyFlag = 0;*/}} else if (ledKeyStatusSwitchCnt >= (LED_SACND_TIME_MS + KEY_SACND_TIME_MS + 1)) {ledKeyStatusSwitchCnt = 0;}
}/* 在main()前台执行 */
void KeyScandHandler(void)
{if (configKeyFlag) {keyScan();configKeyFlag = 0;}
}

【嵌入式底层知识修炼】按键和LED共用IO口的分时复用扫描方法相关推荐

  1. 【嵌入式底层知识修炼】基于通用消抖算法,拓展通用非阻塞Key按键识别算法

    文章目录 01 - 通用消抖算法 02 - Key按键识别需求 03 - 拓展通用非阻塞Key按键算法 04 - 实际使用方法 05 - 总结 首先学习别人的东西,然后吸收别人的东西,接着应用并改造别 ...

  2. 【软件开发底层知识修炼】十三 链接器-如何写出不依赖C库函数的代码

    本文将综合以下4篇文章,学习如何写出不依赖libc库的程序: [软件开发底层知识修炼]九 链接器-可重定位文件与可执行文件 [软件开发底层知识修炼]十 链接器-main函数不是第一个被执行的函数 [软 ...

  3. 【软件开发底层知识修炼】二十八 C/C++中volatile的作用

    上一篇文章学习了C/C++中的指针与数组的区别,点击链接进行查看:[软件开发底层知识修炼]二十七 C/C++中的指针与数组是不同的 本篇文章将学习volatile关键字在C/C++中的作用 文章目录 ...

  4. 【软件开发底层知识修炼】二十七 C/C++中的指针与数组是不同的

    上几篇文章学习了ABI-应用程序二进制接口:[软件开发底层知识修炼]二十六 ABI-应用程序二进制接口 学习总结文章目录 本篇文章就指针与数组的联系与区别来学习学习 文章目录 1 疑问 2 指针与数组 ...

  5. 【软件开发底层知识修炼】二十六 ABI-应用程序二进制接口 学习总结文章目录

    前面学习了ABI的知识,感觉受益良多.对底层与编译器有更加深刻的认识,为此这里将前面写过的关于ABI 的文章给列出来,方便学习与翻阅. [软件开发底层知识修炼]二十一 ABI-应用程序二进制接口一 [ ...

  6. 【软件开发底层知识修炼】二十五 ABI之函数调用约定二之函数返回值为结构体时的约定

    上一篇文章学习了几种函数调用约定的区别,点击链接查看上一篇文章:[软件开发底层知识修炼]二十四 ABI之函数调用约定 本篇文章继续学习函数调用约定中,关于函数返回值的问题.当函数返回值为结构体时,函数 ...

  7. 【软件开发底层知识修炼】二十四 ABI之函数调用约定

    上一篇文章学习了Linux环境下的函数栈帧的形成与摧毁.点击链接查看相关文章:软件开发底层知识修炼]二十三 ABI-应用程序二进制接口三之深入理解函数栈帧的形成与摧毁 本篇文章继续学习ABI接口相关的 ...

  8. 【软件开发底层知识修炼】二十三 ABI-应用程序二进制接口三之深入理解函数栈帧的形成与摧毁

    上两篇文章我们初步接触了ABI-应用程序二进制接口的概念,点击链接查看上一篇文章:[软件开发底层知识修炼]二十二 ABI-应用程序二进制接口 二.了解了为什么会有ABI的存在.本篇文章继续学习ABI ...

  9. 【软件开发底层知识修炼】二十二 ABI-应用程序二进制接口 二

    上一篇文章学习了ABI的相关内容,具体最后分析了不同ABI下结构体的对齐方式的不同.点击链接查看上一篇文章:[软件开发底层知识修炼]二十一 ABI-应用程序二进制接口一 本篇文章继续学习ABI相关内容 ...

最新文章

  1. Angular开发实践(一):环境准备及框架搭建
  2. Ubuntu中的默认shell
  3. .net core 使用 codegenerator 创建默认CRUD代码
  4. embedding 层的详细解释
  5. IDEA使用自带数据库连接工具连接Mysql,及报错解决
  6. 数据结构与算法之“之”字型打印矩阵和矩阵中找数
  7. cascade rcnn论文总结
  8. poj 1308 Is It A Tree?
  9. APUE 12.7 取消选项
  10. rhel5下的DNS服务器架设
  11. 《南溪的python灵隐笔记》——有趣的Munch字典库
  12. Windows Print Spooler 被曝未修复 0day,可导致恶意软件以管理员权限运行
  13. LeetCode 655. Print Binary Tree (C++)
  14. 文字处理(WORD/WP)中,布局与绘制必然分开
  15. 遭遇nat.exe,socks.exe,USP10.dll,BOSC.dll,kb080387.CNT,~ctwxw.txt等1
  16. Ubuntu16.04 微信网页版安装
  17. 叮,你有一份光线追踪技术合集待查收 | IMG2020
  18. shell脚本中执行ssh
  19. 使用 FFmpeg 删除导出视频字幕文件
  20. 自媒体推广应该怎么入手,如何去做

热门文章

  1. hive内置操作符与内置函数
  2. ebay注册流程_【eBay新手开店】2020年eBay注册开店流程图文详解
  3. unity轻松制作塔防游戏
  4. socket函数简介
  5. 31岁程序员的苦恼:妻子总让我想办法考体制,铁饭碗总比码农强
  6. matlab 人工势能法,人工势能场(APF)的原理
  7. 筋膜枪原理与筋膜枪MCU软硬件方案PCBA方案分享
  8. 完爆面试官!2021年我们程序员该如何进阶和规划?面经解析
  9. 小学数学计算机教案模板,小学数学万能教案模板
  10. Unity使用新输入系统InputSystem制作飞机大战Demo(实现能量技能)