有域名后续怎么做网站,规划建网站步骤,关于网站建设的调查报告,济南突然宣布前言#xff1a;
本文是根据哔哩哔哩网站上“正点原子[第二期]Linux之ARM#xff08;MX6U#xff09;裸机篇”视频的学习笔记#xff0c;在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。…前言
本文是根据哔哩哔哩网站上“正点原子[第二期]Linux之ARMMX6U裸机篇”视频的学习笔记在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。
引用
正点原子IMX6U仓库 (GuangzhouXingyi) - Gitee.com
《【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.5.2.pdf》
正点原子资料下载中心 — 正点原子资料下载中心 1.0.0 文档 正文
本文是 “正点原子[第二期]Linux之ARMMX6U裸机篇--第17 讲” 的读书笔记。第17讲主要是介绍I.MX6U处理器的EPIT定时器的按键消抖。本节将参考正点原子的视频教程第17讲和配套的正点原子开发指南文档进行学习。
0. 概述
在第15章和第17章实验都使用到了按键用到按键就要处理因为机械结构带来的抖动问题也就是按键消抖。前面的时延中都是直接使用了延时函数来实现消抖因为简单但是直接使用延时函数来实现消抖会浪费CPU的性能因为在延时函数里面CPU什么都做不了。如果按键使用中断的话更不能再中断里面使用延时函数因为中断服务函数要快进快出本章我们学习如何使用定时器来实现按键消抖使用定时器既可以实现按键消抖而且也不会浪费CPU性能这个也是Linux驱动里面按键消抖的做法。
1. 定时器按键消抖简介
按键消抖的原理已经在第十五章详细的讲解过了起始就是在按键按下以后延时一段时间再去读取按键值如果此时按键值还有效那就表示这是一次有效的按键中间的延时就是消抖的。
但是这有一个缺点就是已按时函数会浪费CPU性能应为延时函数就是空跑。如果按键是用中断方式实现的那就更不应该在中断服务函数里使用延时函数因为中断服务函数最基本的要求就是快进快出上一章我们学习了EPIT定时器定时器设置好定时时间然后CPU就可以做其他事情去了定时时间到了以后就会触发中断然后在中断中做相应的处理即可。 因此我们可以借助定时器来实现消抖 按键采用中断驱动的方式当按下按键触发按键中断在按键中断中开启一个定时器定时周期为10ms当定时时间到了以后就会触发定时器中断最后在定时器中断处理函数中读取按键的值如果按键还是按下的状态那就表示这是一次有效的按键。 定时器按键消抖如下图所示 在图19.1.1中的t1~t3这一段时间就是按键抖动是需要消除的。设置按键为下降沿触发因此会在t1,t2,和t3这三个时刻触发那件中断每次进入中断处理函数都会重开定时器中断所以会在t1,t2,和t3这三个时刻开定时器中断。但是t1~t2和t2~t3这两段时间是小于我们设置的定时器中断周期也就是消抖时间比如10ms所以虽然t1开启了定时器但是定时器时间没有到呢t2时刻就重置了定时器最终之后t3时刻开启的定时器能完整的完成整个定时周期并触发中断我们就可以在中断处理函数里面做按键处理了这就是定时器完成按键消抖的原理Linux里面的按键驱动用的就是这个原理
关于定时器消毒的原理就介绍到这里接下来讲解如何使用EPIT1来配置按键KEY来实现具体的消抖步骤如下 配置按键IO中断 配置按键所使用的IO因为要使用到中断驱动按键所以要配置IO的中断模式。初始化消抖用的定时器 上面已经讲的很清楚了消抖要用定时器来完成所以需要初始化一个定时器这是使用上一章讲解的EPIT1定时器也算是对EPIT1定时器的一次巩固。定时器的定时周期为10ms也可以根据实际情况调整定时周期。编写中断处理函数 需要编写两个中断处理器函数按键对应的GPIO中断处理函数和EPIT1定时器的中断处理函数。在按键的中断处理函数中主要用于开启EPIT1定时器EPIT1定时器处理函数才是重点按键要做的具体任务都是在定时器EPIT1的中断处理函数中完成的比如控制蜂鸣器打开或关闭。 2. 定时器按键消抖程序编写
更具上面分析的定时器按键消抖的原理和定时器按键消抖实验的步骤编写定时器按键消抖程序源码如下
bsp/keyfilter/bsp_keyfilter.h
#ifndef __BSP_KEYFILTER_H__
#define __BSP_KEYFILTER_H__#include imx6u.hvoid keyfilter_init(void);
void keyfilter_timer_init(int value);
void keyfilter_timer_stop(void);
void keyfilter_timer_restart(int value);
void keyfilter_timer_irqhandler(IRQn_Type irq, void *userparam);
void gpio1_16_31_irqhandler(IRQn_Type irq, void *userparam);#endif
bsp/keyfilter/bsp_keyfilter.c
#include bsp_keyfilter.h
#include bsp_beep.h
#include bsp_led.h
#include bsp_int.h
#include bsp_gpio.h
#include bsp_epittimer.hvoid keyfilter_init(void)
{/* GPIO1_IO18 */gpio_pin_config_t config;/* 1. 初始化IO复用复用为GPIO1_IO18 */IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18, 0);/* 2. 设置 UART1_CTS_B IO 的电气特性 */IOMUXC_SetPinConfig(IOMUXC_UART1_CTS_B_GPIO1_IO18, 0xf080);/* 3. 初始化 GPIO1_IO18 设置为输入 */config.directioin kGPIO_DigitalInput;config.intMode kGPIO_FalllingEdgeInt;gpio_init(GPIO1, 18, config);/* 启用GIC IRQ */GIC_EnableIRQ(GPIO1_Combined_16_31_IRQn);/* 注册IRQ处理函数 */system_irqhandler_register(GPIO1_Combined_16_31_IRQn, gpio1_16_31_irqhandler, NULL);/* EPIT1定时器初始化 */keyfilter_timer_init(66000000/100);/* 启用gpio中断 */gpio_int_enable(GPIO1, 18);
}void keyfilter_timer_init(int value){EPIT1-CR 0;EPIT1-CR (1 24 )| (1 3) | (1 2) | (1 1);EPIT1-LR value;EPIT1-CMPR 0;/* 使能GIC EPIT1_IRQn 中断 */GIC_EnableIRQ(EPIT1_IRQn);/* 注册中断处理函数 */system_irqhandler_register(EPIT1_IRQn, keyfilter_timer_irqhandler, NULL);
}void keyfilter_timer_stop(void)
{EPIT1-CR ~(1 0);
}void keyfilter_timer_restart(int value){EPIT1-CR ~(1 0); /* 关闭EPIT1 */EPIT1-LR value; /* EPIT1加载值寄存器 */EPIT1-CR | (1 0); /* 打开EPIT1 */
}void keyfilter_timer_irqhandler(IRQn_Type irq, void *userparam){static int beep_state 0;if(EPIT1-SR (1 0)){ /* 检查EPIT1中断标志 */keyfilter_timer_stop(); /* 关闭EPIT1定时器 */if(gpio_pinread(GPIO1, 18) 0) /* 检查gpio引脚电平值 */{beep_state !beep_state; /* 翻转蜂鸣器 */beep_switch(beep_state);}}/* 清除中断标志位 */EPIT1-SR | (10);
}void gpio1_16_31_irqhandler(IRQn_Type irq, void *userparam){if(GPIO1-ISR (1 18)){keyfilter_timer_restart(66000000/100); /* 重启EPIT1定时器定时器周期10ms */}/* 清除中断标志位 */gpio_int_cleanFlag(GPIO1, 18);
}
在如上的源码中初始化按键KEY0 对应GPIO1_IO18的 IO 复用IO特性启用IO中断并注册GPIO1_IO18的中断处理函数在按键中断处理函数中重启 EPIT1定时器设置定时周期为10ms当定时周期完成时触发EPIT1定时器比较事件中断在EPIT1定时器中断里再次检查gpio引脚的输入电平如果还是有效说明此次按键按下是有效的此时在EPIT1定时器中断里翻转蜂鸣器的鸣叫。
3. 编译烧写SD卡验证实验结果
译修改主频后源码烧录SD卡验证本节的EPIT定时器消抖实验是否生效。预期烧录SD卡后正点原子I.MX6ULL ALPHA/Mini 开发板后按下按键蜂鸣器鸣叫再次按下按键蜂鸣器停止鸣叫多次测试按键按下都能翻转蜂鸣器开关。
我本地验证的结果是EPIT定时器按键消抖实验结果正常多次按下按键都能正确的翻转蜂鸣器鸣叫开关。 4. 总结和实验遇到的问题记录
4.1 问题1EPIT定时器消抖实验程序烧录SD发现有时按下并松开按键后蜂鸣器只鸣叫一声就停止预期应该一直鸣叫。
原因分析如下 由于按键的机械结构不仅仅在按键按下的瞬间有电平的多次抖动从而在按键按下的瞬间多次在按键gpio电平的下降沿触发GPIO中断进而重置EPIT1定时器最终出发EPIT1定时器中断。按键的机械结构决定了在按键松开的瞬间也有多次的gpio引脚电平抖动也会在按键松开的瞬间由于抖动在电平的下降沿触发GPIO中断进而重置EPIT1定时器最终出发EPIT1定时器中断。由上分析可知由于按键的机械结构在按键按下的时会有电平抖动从而触发GPIO中断在按键松开的时同样也会有电平抖动从而触发GPIO中断 所以必须在EPIT1定时器中断里再次检查 GPIO 引脚的电平是否有效对于本实验在按键按下的时候EPIT1中断处理函数读取到的gpio引脚为低电平证明按键按下有效。 (EPIT1定时中断处理函数里读取到gpio引脚为高电平说明是按键松开。) 5. 结束
本文至此结束