单片机按键处理技巧及C语言编程方式
51单片机及C语言入门教程

51单片机及C语言入门教程本教程将介绍51单片机及C语言的入门知识,帮助初学者快速掌握这两个方面的基本内容。
以下是本教程的详细内容:一、51单片机概述(200字)51单片机是由Intel公司推出的一种常见的单片机芯片,具有广泛应用的特点。
它采用了Harvard结构,具有8位数据总线和16位地址总线。
其主要特点是结构简单、易于学习、应用广泛,适用于各种嵌入式系统。
二、C语言基础(300字)C语言是一种高级编程语言,具有跨平台、可移植性强等特点,被广泛应用于各种软件开发和嵌入式系统中。
学习C语言的基础知识是学习51单片机编程的必要前提。
C语言基础知识主要包括数据类型、变量、常量、运算符、表达式、流程控制语句等内容。
这些知识是学习C语言和51单片机编程的基础,需要仔细理解和掌握。
三、51单片机编程入门(400字)1. 搭建开发环境:首先需要安装51单片机的开发工具,如KeilC51等。
然后,连接单片机开发板和电脑,确保硬件连接正确。
2.了解开发板:学习使用51单片机的开发板是学习51单片机编程的第一步。
具体包括开发板上各个接口的功能和使用方法。
3.编写第一个程序:根据教材或教程,编写第一个简单的程序,如让LED灯闪烁等。
学习如何通过C语言编写程序,将其烧录到单片机中,并运行和调试。
四、C语言与51单片机的应用(300字)在学习了C语言和51单片机的基础知识之后,可以进一步学习它们的应用。
1.输入输出操作:学习如何通过51单片机与外部设备进行输入输出操作,如控制LED灯的亮灭、读取按键输入等。
2.定时器和中断:学习如何使用51单片机的定时器和中断功能来实现定时任务和外部事件处理。
3.串口通信:学习如何通过51单片机的串口通信功能与其他设备进行数据交换和通信。
五、实例项目及拓展应用(200字)完成了基础学习后,可以尝试一些实例项目,如温度测量系统、遥控器、电子钟等。
同时,可以进一步学习其他相关知识,如LCD显示、SPI 通信等,以扩展自己的应用能力。
单片机控制按键实训报告

一、实训目的1. 掌握单片机的基本工作原理和硬件结构;2. 熟悉单片机编程环境及编程方法;3. 学习按键控制的基本原理和编程技巧;4. 提高动手能力和解决问题的能力。
二、实训内容1. 单片机简介2. 单片机编程环境及编程方法3. 按键控制原理及编程4. 实验设计与实现三、实训步骤1. 单片机简介(1)单片机定义:单片机是一种集成度高、功能强大的微处理器,具有运算、存储、输入输出、定时计数等功能。
(2)单片机硬件结构:主要包括中央处理单元(CPU)、存储器(RAM、ROM)、输入输出接口(I/O)、定时器/计数器、串行通信接口等。
2. 单片机编程环境及编程方法(1)编程环境:Keil uVision、IAR EWARM等。
(2)编程语言:C语言、汇编语言等。
3. 按键控制原理及编程(1)按键控制原理:按键作为一种输入设备,其作用是将物理信号转换为电信号,通过单片机对电信号进行处理,实现相应的功能。
(2)按键编程技巧:① 按键消抖:由于按键存在机械特性,按下和释放时会产生抖动,导致单片机检测到多个按键动作。
为了消除抖动,通常采用软件消抖方法,如延时消抖、计数消抖等。
② 按键扫描:按键扫描是检测按键状态的一种方法,通过单片机的I/O口循环检测每个按键的状态,实现按键的识别。
③ 按键去抖:在按键扫描过程中,若检测到按键动作,则需要进行去抖处理,以消除抖动对按键识别的影响。
4. 实验设计与实现(1)实验目的:通过按键控制LED灯的亮灭。
(2)实验原理:当按下按键时,单片机检测到按键动作,通过编程控制LED灯亮起;当按键释放时,单片机检测到按键释放,控制LED灯熄灭。
(3)实验步骤:① 准备实验器材:单片机、按键、LED灯、电阻、面包板等。
② 连接电路:将按键、LED灯、电阻等元器件连接到单片机的相应引脚上。
③ 编写程序:根据实验原理,编写控制LED灯的亮灭程序。
④ 烧录程序:将编写的程序烧录到单片机中。
⑤ 测试程序:观察LED灯的亮灭状态,验证程序的正确性。
单片机按键程序设计

单片机按键程序设计单片机按键的基本原理其实并不复杂。
通常,按键就是一个简单的开关,当按键按下时,电路接通,对应的引脚电平发生变化;当按键松开时,电路断开,引脚电平恢复到初始状态。
在程序设计中,我们需要不断检测引脚的电平变化,从而判断按键是否被按下。
在实际的按键程序设计中,有多种方式可以实现按键检测。
其中一种常见的方法是查询法。
这种方法是通过不断地读取按键对应的引脚状态来判断按键是否被按下。
以下是一个简单的查询法示例代码:```cinclude <reg51h> //包含 51 单片机的头文件sbit key = P1^0; //定义按键连接的引脚void main(){while(1) //无限循环{if(key == 0) //如果按键按下,引脚为低电平{//执行按键按下的操作//比如点亮一个 LED 灯P2 = 0xfe;while(key == 0);//等待按键松开}}}```上述代码中,我们首先定义了按键连接的引脚`key`,然后在主函数的无限循环中不断检测按键引脚的状态。
当检测到按键按下时,执行相应的操作,并通过`while(key == 0)`等待按键松开。
除了查询法,还有中断法可以用于按键检测。
中断法的优点是能够及时响应按键动作,不会因为程序的其他操作而导致按键响应延迟。
```cinclude <reg51h> //包含 51 单片机的头文件sbit key = P1^0; //定义按键连接的引脚void int0_init()//中断初始化函数{IT0 = 1; //下降沿触发中断EX0 = 1; //使能外部中断 0EA = 1; //开总中断}void int0() interrupt 0 //外部中断 0 服务函数{//执行按键按下的操作//比如点亮一个 LED 灯P2 = 0xfe;}void main(){int0_init();//初始化中断while(1);//无限循环,保持程序运行}```在上述代码中,我们首先在`int0_init` 函数中对中断进行了初始化设置,然后在`int0` 函数中编写了按键按下时的处理代码。
按键处理程序C语言单片机

按键处理程序C语言单片机分享一种按键处理程序(用C)//头文件定义:Ustruct KEY{Uchar Val;#define Key_Model_C 0 //按键1值#define Key_AddVal_C 1 //按键2值Uint ScanOnTime;Uchar LongKeyState;Uchar LongKeyRestState;Uchar SetInRn;Uchar Model; //按键状态(模式)#define Off_C 0 //之前未按下#define On_C 1 //现按下#define Delay_C 2 //按键处理后标志}Key;//----------------定义两个IO输入口为按键入口--------------------//#define KeyMo_Bin (GPIOB->IDR.Bit.B5)#define KeyAdd_Bin (GPIOB->IDR.Bit.B6)/*===================================== ==========================*/GPIO_Init(GPIO_Pin_5|GPIO_Pin_6,GPIO_Mode_In_PU_No_IT); //初始化为上拉输入无中断/*===================================== ==========================*///主程序大循环中每1毫秒扫描1次void KeyScan(void){if(Key.LongKeyRestState == 1) //长按键标志(复位处理长按键){if((KeyMo_Bin == 1) && (KeyAdd_Bin == 1)) //当两按键均抬起{if(++Key.ScanOnTime >= 130) //延时后复位{Key.LongKeyRestState=0;Key.Model=Delay_C;}}elseKey.ScanOnTime=0;return;}if(Key.Model == Off_C) //如果当前按键状态为未按下“Off_C”{if((KeyMo_Bin == 0) || (KeyAdd_Bin == 0))//按键1或按键2已按下(低有效){if(++Key.ScanOnTime >= 10) //当按下后自加1,加够10次即1ms*10=10ms去抖动{Key.ScanOnTime=0;if(KeyMo_Bin == 0) //如果按键1为0即按下{Key.Val=Key_Model_C; //付当键1值(看头文件定义)Key.Model=On_C; //置按键已按下标志}else if(KeyAdd_Bin == 0) //如果按键2为0即按下{Key.Val=Key_AddVal_C; //付当键2值(看头文件定义)Key.Model=On_C; //置按键已按下标志}BellOn(200); //蜂鸣器响}}elseKey.ScanOnTime=0; //清去抖延时计数值}else if(Key.Model == Delay_C) //如果当前按键状态为已按下且已处理“Delay_C”{if((KeyMo_Bin == 1) && (KeyAdd_Bin == 1))//如果两按键均抬起{if(++Key.ScanOnTime >= 100) //延时100ms后复位按键状态为“Off_C”{Key.SetInRn=0;Key.ScanOnTime=0;Key.Model=Off_C;}}else //如果按键没有被抬起,对应上面if{if(++Key.ScanOnTime >= 1000) //延时1000ms后再复位按键状态为“Off_C”(为长按处理){Key.ScanOnTime=0;Key.Model=Off_C;}}}}//===================================== ========================================= ========void LoadCheckKeyRest(void){Key.LongKeyRestState=1;Key.ScanOnTime=0;}//===================================== ========================================= ========//处理相应按键(可250ms才调用一次)长按if(Key.Model == On_C) //按键状态为已按下{if(Key.Val == Key_Model_C) //是键1按下(看头文件定义){if(++Key.SetInRn >= 3) //连计3次数3秒后为长按键(对应上面,如果按下未抬起的话会延时1000ms){Key.SetInRn=0;LoadCheckKeyRest(); //调清长按处理BellOn(600); //蜂鸣器响//-----------长按需处理的内容-----下-----------//WorkStateBit.Bit.SettingMo=1;SetOverTime=0;SetMoRn=0;SetBak[0]=Rtc_InitDate.RTC_Year;SetBak[1]=Rtc_InitDate.RTC_Month;SetBak[2]=Rtc_InitDate.RTC_Date;SetBak[3]=Rtc_InitDate.RTC_WeekDay;SetBak[4]=Rtc_InitTime.RTC_Hours;SetBak[5]=Rtc_InitTime.RTC_Minutes;//-----------长按需处理的内容------上----------//Key.Model=Delay_C; //置按键模式为:已处理按键(看头文件定义)return;}}elseKey.SetInRn=0;Key.Model=Delay_C;}。
STC单片机C语言程序设计STC单片机C语言编程入门

STC单片机C语言程序设计STC单片机C语言编程入门STC单片机是一种广泛应用于嵌入式系统和物联网设备中的微控制器。
它具有体积小、功耗低、运算能力强等特点,被广泛应用于各种控制系统中。
本文将介绍STC单片机C语言程序设计的入门知识,以帮助初学者快速上手。
首先,我们需要了解一些基本的概念和术语。
1.单片机:单片机是一种集成电路芯片,其中包含了中央处理器、存储器、输入输出接口等功能模块。
它可以独立完成特定的任务,不需要额外的硬件设备与之配合。
2.C语言:C语言是一种高级编程语言,被广泛应用于嵌入式系统开发中。
它具有简洁、高效的特点,易于理解和学习。
了解了上述基本概念后,接下来我们将介绍一些STC单片机C语言程序设计的入门知识。
2. 程序结构:一个C语言程序通常由多个函数组成,其中一个函数名为main(。
程序从main(函数开始执行,执行完main(函数后程序结束。
3.数据类型:C语言中有多种数据类型,包括整型、浮点型、字符型等。
在使用数据类型时,需要根据需要选择合适的数据类型。
4.变量和常量:在C语言中,可以使用变量和常量来存储数据。
变量是可以改变值的,而常量是固定不变的值。
5. 输入和输出:C语言中使用标准库函数scanf(和printf(来实现输入和输出操作。
通过这两个函数可以从键盘获取输入数据,并将结果输出到屏幕上。
6. 控制语句:在C语言中,可以使用if语句、for循环和while循环等控制语句来控制程序的执行流程。
通过控制语句,可以实现条件判断、循环执行等功能。
7.函数:函数是C语言中的重要概念,它可以将一段代码封装成一个独立的模块,方便重复使用。
在编写程序时,可以自定义函数来实现特定的功能。
8.数组:数组是一种存储相同类型数据的连续内存区域。
在C语言中,可以使用数组来存储一组数据,并对数据进行操作。
9.文件操作:C语言提供了文件操作函数,可以对文件进行读写操作。
通过文件操作,可以实现数据的持久化存储。
单片机C语言编程课件

连接电机驱动器和单片机的GPIO接口;
3
配置单片机的GPIO口为输出模式;
案例三:基于单片机的电机控制程序
使用C语言编写电机控制的程序代码;
输标02入题
将程序代码烧录到单片机中,并观察电机的运行状态 。
01
03
案例总结:该案例通过编写更为复杂的C语言程序, 实现了单片机对电机的控制,展示了单片机C语言编
运行错误
逻辑错误
逻辑错误通常是由于代码中的逻辑问题引起的,如条件语句的判断条件不正确、循环语句的终止条件不正确等。解 决这类问题需要仔细检查代码的逻辑,确保其正确性。
数组越界
如果在访问数组时超出了其索引范围,就会发生数组越界错误。解决这类问题需要确保数组的索引在有效范围内, 并避免使用负数索引。
内存泄漏
案例总结:该案例通过编 写较为复杂的C语言程序 ,实现了单片机对温度的 检测和显示,展示了单片 机C语言编程在实际应用 中的重要性和实用性。
案例三:基于单片机的电机控制程序
• 电机控制程序介绍:该程序通过单片机控制电机的启动、 停止、正转和反转等操作。
案例三:基于单片机的电机控制程序
编程步骤
1
2
如果在程序中动态分配了内存但未释放,就会发生内存泄漏错误。解决这类问题需要使用适当的内存管 理函数(如malloc、free等)来分配和释放内存,并确保在程序结束时释放所有已分配的内存。
06 单片机C语言编程案例分 析
案例一:基于单片机的LED闪烁程序
• LED闪烁程序介绍:该程序通过单片机控制LED灯的亮灭,实 现LED灯的闪烁效果。
使用break、continue等关键字实现 跳转控制。
循环语句
使用for、while等关键字实现循环控 制。
编写单片机C语言代码的技巧和经验

编写单片机C语言代码的技巧和经验编写单片机C语言代码的技巧和经验C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。
那么编写单片机C语言代码的技巧和经验都有哪些呢。
以下仅供参考!具体如下:1、如果可以的话少用库函数,便于不同的mcu和编译器间的移植2、选择合适的算法和数据结构应该熟悉算法语言,知道各种算法的优缺点,具体资料请参见相应的参考资料,有很多计算机书籍上都有介绍。
将比较慢的顺序查找法用较快的二分查找或乱序查找法代替,插入排序或冒泡排序法用快速排序、合并排序或根排序代替,都可以大大提高程序执行的效率。
选择一种合适的数据结构也很重要,比如你在一堆随机存放的数中使用了大量的插入和删除指令,那使用链表要快得多。
数组与指针语句具有十分密码的关系,一般来说,指针比较灵活简洁,而数组则比较直观,容易理解。
对于大部分的编译器,使用指针比使用数组生成的代码更短,执行效率更高。
但是在Keil中则相反,使用数组比使用的指针生成的代码更短。
3、使用尽量小的数据类型能够使用字符型(char)定义的变量,就不要使用整型(int)变量来定义;能够使用整型变量定义的变量就不要用长整型(long int),能不使用浮点型(float)变量就不要使用浮点型变量。
当然,在定义变量后不要超过变量的作用范围,如果超过变量的范围赋值,C编译器并不报错,但程序运行结果却错了,而且这样的错误很难发现。
在ICCAVR中,可以在Options中设定使用printf参数,尽量使用基本型参数(%c、%d、%x、%X、%u和%s格式说明符),少用长整型参数(%ld、%lu、%lx和%lX格式说明符),至于浮点型的参数(%f)则尽量不要使用,其它C编译器也一样。
在其它条件不变的情况下,使用%f 参数,会使生成的代码的数量增加很多,执行速度降低。
4、使用自加、自减指令通常使用自加、自减指令和复合赋值表达式(如a-=1及a+=1等)都能够生成高质量的程序代码,编译器通常都能够生成inc和dec之类的指令,而使用a=a+1或a=a-1之类的指令,有很多C编译器都会生成二到三个字节的指令。
单片机按键单击双击长按功能实现

单片机按键单击双击长按功能实现在很多嵌入式系统中,都需要对按键进行检测和处理,以实现不同的功能。
常见的按键功能包括单击、双击和长按。
在这篇文章中,我们将介绍如何使用单片机实现这些按键功能。
首先,我们需要连接一个按键到单片机的I/O口。
按键通常是一个开关,有两个接触点。
当按键按下时,两个接触点会闭合,导致I/O口的电平发生变化。
我们可以利用这个变化来检测按键的状态。
为了实现按键功能,我们需要编写一段程序来监测按键的状态。
以下是一个简单的流程:1.初始化I/O口:将按键连接到I/O口上,并将I/O口设置为输入模式。
2.监测按键状态:定时读取I/O口的电平状态,以检测按键是否按下。
如果I/O口电平发生变化,则按键被按下或松开。
3.单击功能:当按键被按下时,记录当前时间,并等待一段时间,如果超过这段时间,说明按键已松开,则触发单击功能。
4.双击功能:如果在两次按键之间的时间间隔内再次检测到按键按下,则触发双击功能。
5.长按功能:当按键被按下一段较长的时间后,触发长按功能。
下面我们来具体介绍如何实现这些功能。
首先,我们需要初始化单片机的I/O口。
这个过程可以通过配置相应的寄存器实现。
具体的方法和步骤依赖于你使用的单片机型号和开发环境。
在这里,我们不具体展开,而是假设我们已经成功初始化了I/O口。
接下来,我们需要设置一个计时器用于定时检测按键的状态。
计时器的定时周期决定了我们可以检测的最短按键时间间隔。
通常,我们使用一个定时器来实现单击和双击功能,使用另一个定时器来检测长按功能。
一旦我们完成了计时器的配置,我们就可以开启定时器中断,并启动计时器。
每当定时器溢出时,中断函数会被触发,我们可以在这个函数中检测按键的状态。
在中断函数中,我们读取I/O口的电平状态,并根据当前的按键状态做出相应的处理。
首先,我们需要检测按键是否按下。
为了防止按键的抖动和误触发,我们使用一个状态机来确定按键的状态。
状态机的状态可以分为按下和松开两种。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
2
#define KEY_STATE_LONG
3
#define KEY_STATE_CONTINUE
4
#define KEY_STATE_RELEASE
5
接着我们开始编写完整的上层按键扫描函数,按键的短按,长按,连按,释放等等状态的判断均是在此函数中完成。
对照状态流程转移图,然后再看下面的函数代码,可以更容易的去理解函数的执行流程。完整的函数代码如下:
void GetKey(uint8 *pKeyValue)
{
static uint8 s_u8KeyState = KEY_STATE_INIT ;
static uint8 s_u8KeyTimeCount = 0 ;
static uint8 s_u8LastKey = KEY_NULL ; //保存按键释放时候的键值
#define KEY_DOWN
0x80
#define KEY_LONG
0x40
#define KEY_CONTINUE
0x20
#define KEY_UP
0x10
//定义按键状态
#define KEY_STATE_INIT
0
#define KEY_STATE_WOBBLE
1
#define KEY_STATE_PRESS
//先延时 20ms 避开抖动时期
If(0 == io_KeyEnter)
//然后再检测,如果还是检测到有键按下
{
return KeyValue ;
//是真的按下了,返回键值
}
else
{
return KEY_NULL
//是抖动,返回空的键值
}
while(0 == io_KeyEnter) ;
//等待按键释放
动程序吧。 下面是我使用的硬件的连接图。
硬件连接很简单,四个独立按键分别接在 P3^0------P3^3 四个 I/O 上面。
因为 51 单片机 I/O 口内部结构的限制,在读取外部引脚状态的时候,需要向端口写 1.在 51 单片机复位后,不需要进
行此操作也可以进行读取外部引脚的操作。因此,在按键的端口没有复用的情况下,可以省略此步骤。而对于其它一
这样便存在这样一个问题。假设我们的系统有这样功能需求:在检测到按键按下的时候,将某个 I/O 的状态取反。由
于这种抖动的存在,使得我们的微控制器误以为是多次按键的按下,从而将某个 I/O 的状态不断取反,这并不是我们
想要的效果,假如该 I/O 控制着系统中某个重要的执行的部件,那结果更不是我们所期待的。于是乎有人便提出了软
数级别的代码重用已经足够了。
在编写我们的上层按键扫描函数之前,需要先完成一些宏定义。
//定义长按键的 TICK 数,以及连_发间隔的 TICK 数
#define KEY_LONG_PERIOD
100
#define KEY_CONTINUE_PERIOD
25
//定义按键返回值状态(按下,长按,连_发,释放)
口电平的变化与否,即可以知道按键是否被按下,从而做出相应的响应。一切看起来很美好,是这样的吗? 在我们通过上面的按键检测原理得出上述的结论的时候,那就是现实中按键按下时候的电平变化状态。我们的结 论是基于理想的情况得出来的,而实际中,由于按键的弹片接触的时候,并不是一接触就紧紧的闭合,它还存在一定
的抖动,尽管这个时间非常的短暂,但是对于我们执行时间以 us 为计算单位的微控制器来说, 它太漫长了。因而,实际的波形图应该如下面这幅示意图一样。
取到如下的信息:按键按下(短按),按键长按,按键连_发,按键释放。这样的功能到底是如何实现的呢,今天就让我
们来剖析它的原理吧。下面让我们来简单的描绘一下它的状态流程转移图。
下面对上面的流程图进行简要的分析。
首先按键程序进入初始状态 S1,在这个状态下,检测按键是否按下,如果有按下,则进入按键消抖状态 2,在下一次 执行按键程序时候,直接由按键消抖状态进入按键按下状态 3,在此状态下检测按键是否按下,如果没有按键按下,则 返回初始状态 S1,如果有则可以返回键值,同时进入长按状态 S4,在长按状态下每次进入按键程序时候对按键时间计 数,当计数值超过设定阈值时候,则表明长按事件发生,同时进入按键连_发状态 S5。如果按键键值为空键,则返回按 键释放状态 S6,否则继续停留在本状态。在按键连_发状态下,如果按键键值为空键则返回按键释放状态 S6,如果按 键时间计数超过连_发阈值,则返回连_发按键值,清零时间计数后继续停留在本状态。 下面让我们一起来编写按键驱
}
其中 io_key_1 等是我们按键端口的定义,如下所示:
sbit io_key_1 = P3^0 ;
sbit io_key_2 = P3^1 ;
sbit io_key_3 = P3^2 ;
sbit io_key_4 = P3^3 ;
KeyScan()作为底层按键的驱动程序,为上层按键扫描提供一个接口,这样我们编写的上层按键扫描函数可以几乎不用 修改就可以拿到我们的其它程序中去使用,使得程序复用性大大提高。同时,通过有意识的将与底层硬件连接紧密的 程序和与硬件无关的代码分开写,使得程序结构层次清晰,可移植性也更好。对于单片机类的程序而言,能够做到函
结果 CPU 就一直死死的盯住该按键,其它事情都不管了,那其它事情不干了吗?
消除抖动有必要吗?
的确,软件上的消抖确实可以保证按键的有效检测。但是,这种消抖确实有必要吗?抖动的出现即意味着按键已
经按下,尽管这个电平还没有稳定。所以只要我们检测到按键按下,即可以返回键值,问题的关键是,在你执行完其
它任务的时候,再次执行我们的按键任务的时候,抖动过程还没有结束,这样便有可能造成重复检测。所以,如何在
{ s_u8KeyTimeCount = 0 ; KeyTemp |= KEY_CONTINUE ;
} } else { s_u8KeyState = KEY_STATE_RELEASE ; } } break ; case KEY_STATE_RELEASE : { s_u8LastKey |= KEY_UP ; KeyTemp = s_u8LastKey ; s_u8KeyState = KEY_STATE_INIT ; } break ; default : break ; } *pKeyValue = KeyTemp ; //返回键值 } 关于这个函数内部的细节我并不打算花过多笔墨去讲解。对照着按键状态流程转移图,然后去看程序代码,你会发现 其实思路非常清晰。最能让人理解透彻的,莫非就是将整个程序自己看懂,然后想象为什么这个地方要这样写,抱着 思考的态度去阅读程序,你会发现自己的程序水平会慢慢的提高。不管怎么样,这样的一个程序已经完成了本章开始 时候要求的功能:按下,长按,连按,释放。事实上,如果掌握了这种基于状态转移的思想,你会发现要求实现其它 按键功能,譬如,多键按下,功能键等等,亦相当简单,在下一章,我们就去实现它。 在主程序中我编写了这样的一段代码,来演示我实现的按键功能。 void main(void)
uint8 KeyTemp = KEY_NULL ;
KeyTemp = KeyScan() ;
//获取键值
switch(s_u8KeyState)
{
case KEY_STATE_INIT :
{
if(KEY_NULL != (KeyTemp))
{
s_u8KeyState = KEY_STATE_WOBBLE ;
返回键值后,避免重复检测,或者在按键一按下就执行功能函数,当功能函数的执行时间小于抖动时间时候,如何避
免再次执行功能函数,就成为我们要考虑的问题了。所以消除抖动的目的是:防止按键一次按下,多次响应。
基于状态转移的独立按键程序设计
本章所描述的按键程序要达到的目的:检测按键按下,短按,长按,释放。即通过按键的返回值我们可以获
0x0e
#define KEY_VALUE_2
0x0d
#define KEY_VALUE_3
0x0b
#define KEY_VALUE_4
0x07
#define KEY_NULL
0x0f
下面我们来编写按键的硬件驱动程序。
根据第一章所描述的按键检测原理,我们可以很容易的得出如下的代码:
static uint8 KeyScan(void)
}
}
break ;
case KEY_STATE_WOBBLE :
//消抖
{
s_u8KeyState = KEY_STATE_PRESS ;
}
break ;
case KEY_STATE_PRESS :
{
if(KEY_NULL != (KeyTemp))
{
s_u8LastKey = KeyTemp ; //保存键值,以便在释放按键状态
返回键值
KeyTemp |= KEY_DOWN ; //按键按下
s_u8KeyState = KEY_STATE_LONG ;
}
else
{
s_u8KeyState = KEY_STATE_INIT ;
}
} break ; case KEY_STATE_LONG :
{ if(KEY_NULL != (KeyTemp))
{ if(++s_u8KeyTimeCount > KEY_LONG_PERIOD)
{ s_u8KeyTimeCount = 0 ; KeyTemp |= KEY_LONG ; //长按键事件发生 s_u8KeyState = KEY_STATE_CONTINUE ;
} } else { s_u8KeyState = KEY_STATE_RELEASE ; } } break ; case KEY_STATE_CONTINUE : { if(KEY_NULL != (KeyTemp)) { if(++s_u8KeyTimeCount > KEY_CONTINUE_PERIOD)