文章目录
前言
一、硬件电路设计
1.开发板用户按键硬件电路
2.按键检测接法
3.按键检测电路考虑因素
二、软件设计
1.寄存器解析
1.1.端口数据寄存器
1.2.端口上拉电阻控制寄存器
2.GPIO输入按键检测实验(单个c文件)
2.1.头文件引用和路径设置
2.2.编写代码
3.流水灯实验(多个c文件)
3.1.工程需要用到的c文件
3.2.头文件引用和路径设置
3.3.编写代码
总结
前言
做完了GPIO点灯实验,成就感满满,不知道小白的我是不是入门了,哈哈!开始做下一个GPIO按键检测的实验。
一、硬件电路设计
1.开发板用户按键硬件电路
轻触按键又称轻触开关(下文简称按键),是电路中常用的一种开关元器件,也是一种常用的人机接口。广泛用于家电、数码产品、便携仪产品、电脑产品等电子设备中。STC8A8K64S4A12开发板上设计了4个用户按键KEY1、KEY2、KEY3、KEY4,当使用KEY1和KEY2时,可短接J26端子的P37
KEY1、P36
KEY2。程序中通过读取这些按键对应的GPIO的状态(高电平或低电平)可判断该按键是否按下,这种电路的形式称为高低电平接法,这种检测按键的方法称为按键高低电平检测。
图1:开发板按键检测电路及实物图
表1:用户按键引脚分配
轻触按键,顾名思义我们只需要施加很小的力量即可改变开关连接的状态。轻触按键在所需外力作用下(按下按键)触点导通,无外力作用时(释放按键)触点断开,如下图所示:
图2:轻触按键原理
2.按键检测接法
高低电平式接法是最常见的按键检测的接法,顾名思义,该接法就是需要单片机引脚具有高低电平的检测能力,也就是常见的GPIO引脚即可。高低电平式接法又可分为两种:独立式接法和行列式接法。行列式接法是利用单片机的GPIO口组成行与列,在行与列的每一个交点处连接按键。故也称为矩阵式按键,该接线方法最大的优势是可以使用较少的GPIO口实现较多按键的检测,这个在矩阵按键扫描实验中会详细介绍。独立式接法的含义就是使用单片机的一个GPIO引脚检测一个按键的状态,有多少按键需检测就需要多少个GPIO引脚,对每个按键的检测相互独立。独立式按键接法一般会用低电平有效的方式,即按键按下是GPIO输入为低电平,如下图所示。
图3:独立式接法
上图中的电阻R的作用是将GPIO输入端口不确定的信号通过该电阻钳位在高电平状态。我们知道数字电路有三种状态:高电平、低电平和高阻状态,有些应用场合并不希望出现高阻状态,这时加上拉电阻即可让GPIO输入端口保持确定的状态。按键释放时,因为上拉电阻R的关系,GPIO输入检测是高电平,按键闭合时,GPIO短接到GND,输入检测是低电平。这样,单片机根据GPIO的输入状态即可确定按键是否按下。
■按键检测知识扩展:ADC通过电阻分压检测多个按键按键检测除了高低电平检测的方法之外,还有一种方法是使用ADC通过电阻分压检测多个按键,这种按键检测的电路形式称为分压式接法。分压式接法,使用的单片机引脚必须具有ADC功能,根据检测口测得的不同的电压值来识别是哪个按键被按下。如下图所示,是分压式接法的原理示意图。这种方法最大的好处是节省IO资源,它只需一个具有ADC功能的IO即可实现多个按键的检测,它适用于IO资源紧张的场合,如一些电磁炉的按键使用的就是这种方法。相对于高低电平检测,这种方法在编程上要复杂一些,需要事先计算好分压的电压值,存储于“表”中,程序运行时,采样到电压值后查表即可获知是哪个按键按下。
图4:分压式接法原理
3.按键检测电路考虑因素
按键检测电路设计的时候,需要我们考虑两个方面:按键释放时GPIO口状态的确定和按键消抖。1)按键释放时GPIO口状态的确定按键检测电路中,当按键释放后要能保证GPIO口电平是确定的,即按键释放时GPIO口固定为高电平或低电平。开发板RN1排阻就是满足用户按键释放时,在单片机GPIO口上保持高电平。2)按键消抖对于按键硬件上的消抖,一般常用的方式是在按键上并接一个容值约0.1uF左右电容,利用电容两端的电压不能突变的特性,消除抖动时产生的毛刺电压。虽然电容可以起到消除抖动的作用,但是在考虑按键灵敏度的情况下,电容时无法完全消除抖动的,消除抖动还需要软件的配合。开发板上按键电路没有增加硬件消抖,开发板使用的是软件消抖,这对于一般的按键检测已经完全足够。
3)GPIO口保护开发板按键检测电路中还串有排阻RN12,该排阻阻值欧姆,串在单片机GPIO口和按键引脚中,起到保护GPIO口的目的。分析:如果GPIO口不小心误配置为输出模式,并且输出高电平,则分析下电路可知,此时如果没有排阻RN12,若按下用户按键,则单片机GPIO口(控制输出高电平)直接和GND相连,会损坏GPIO口。
二、软件设计
1.寄存器解析
1.1.端口数据寄存器
下图是对端口数据寄存器P0、P1、P2、P3、P4、P5、P6、P7的描述,端口数据寄存器各位代表对应端口的GPIO口,在完成对配置寄存器设置后,可直接读取端口引脚电平。
图5:端口数据寄存器
1.2.端口上拉电阻控制寄存器
下图是对端口上拉电阻控制寄存器P0PU、P1PU、P2PU、P3PU、P4PU、P5PU、P6PU、P7PU的描述,这些特殊功能寄存器不支持位寻址。端口上拉电阻控制寄存器各位代表对应端口的GPIO口是否使能其上拉电阻,在完成对该寄存器设置后,相应GPIO端口便在单片机内部有了上拉电阻。该功能使得GPIO口在硬件电路设计时具有了更多的灵活性。但务必知晓端口上拉电阻控制寄存器为扩展SFR,逻辑地址位于XDATA区域,访问前需先将P_SW2寄存器的最高位(EAXFR)置1。
图6:端口数据寄存器
2.GPIO输入按键检测实验(单个c文件)
2.1.头文件引用和路径设置
■需要宏定义部分及引用的头文件因为在“main.c”文件中使用了STC8的头文件“STC8.h”,所以需要引用下面的头文件。在头文件“STC8.h”中需要确定主时钟取值,所以宏定义主时钟值。
#defineMAIN_FoscL//定义主时钟#include"STC8.H"
在程序设计中会用到定义变量的类型,为了定义变量方便,将较为复杂的“unsignedint”和“unsignedchar”进行了宏定义。
#defineuint16unsignedint#defineuint8unsignedchar
这样,再定义变量时可直接使用“uint16”和“uint8”来取代“unsignedint”和“unsignedchar”即可。
■需要包含的头文件路径本例需要包含的头文件路径如下表:
表2:头文件包含路径
MDK中点击魔术棒,打开工程配置窗口,按照下图所示添加头文件包含路径。
图7:添加头文件包含路径
2.2.编写代码
首先根据开发板按键及指示灯GPIO分配,定义寄存器位变量,代码如下。
/**********************引脚别名定义***********************/sbitKEY=P0^7;//用户按键KEY3用IO口P07sbitLED_D3=P7^2;//用户指示灯D3用IO口P72
然后,在主函数中先对P7.2和P0.7口进行模式配置,后主循环中检测按键状态,确认按键按下控制蓝色指示灯D3亮。
intmain(void){P7M1=0xFB;P7M0=0xFB;//设置P7.2为准双向口P0M1=0x7F;P0M0=0x7F;//设置P0.7为准双向口//P0M1
=0x80;P0M0=0x7F;//设置P0.7为高阻输入while(1){if(KEY==0)//检测用户按键KEY3对应引脚P0.7是否是低电平(按键按下,引脚为低电平){delay_ms(10);//软件延时10ms,如果延时后按键KEY3的电平依然没有变化,说明按键确实被有效操作,简称按键消抖if(KEY==0)//检测用户按键KEY3对应引脚P0.7是否依然是低电平{LED_D3=0;//点亮用户指示灯D3while(KEY==0)//等待按键KEY3释放,即如果P0.7一直为低电平,会一直执行空命令{;//条件KEY==0成立,会执行这个空命令}LED_D3=1;//按键KEY3释放,熄灭用户指示灯D3}}}}
3.流水灯实验(多个c文件)
3.1.工程需要用到的c文件
本例需要用到的c文件如下表所示,工程需要添加下表中的c文件。
表3:实验需要用到的c文件
3.2.头文件引用和路径设置
■需要引用的头文件因为在“main.c”文件中使用了控制led的函数和延时函数(延时函数没有在main.c中定义),所以需要引用下面的头文件。
#include"led.h"#include"delay.h"#include"key.h"
■需要包含的头文件路径本例需要包含的头文件路径如下表:
表4:头文件包含路径
MDK中点击魔术棒,打开工程配置窗口,按照下图所示添加头文件包含路径。
图8:添加头文件包含路径
3.3.编写代码
首先在key.h中,宏定义4个用户按键,引用延时函数的头文件,声明按键检测函数供外部调用。代码如下。
#include"delay.h"#defineKEY_ON0#defineKEY_OFF1#defineKEYS_OFF0//没有按键按下#defineKEY1_ON1//按键KEY1按下#defineKEY2_ON2//按键KEY2按下#defineKEY3_ON3//按键KEY3按下#defineKEY4_ON4//按键KEY4按下/********************************************引脚别名定义*********************************************/sbitKEY_S1=P3^7;//用户按键KEY1用IO口P37sbitKEY_S2=P3^6;//用户按键KEY2用IO口P36sbitKEY_S3=P0^7;//用户按键KEY3用IO口P07sbitKEY_S4=P0^5;//用户按键KEY4用IO口P05externuint8Keys_Scan(uint8mode);
然后,在key.c文件中编写一个按键检测函数Keys_Scan,代码如下。
程序清单:延时函数
/**************************************************************************功能描述:检测开发板上的4个用户按键(KEY1、KEY2、KEY3、KEY4)入口参数:uint8mode是否支持连按返回值:按键编号*************************************************************************/uint8Keys_Scan(uint8mode){staticuint8Key_up=1;//标志变量if(mode==1)//支持连按{Key_up=1;//变量Key_up会被重新赋值为1}//检测按键KEY1、按键KEY2、按键KEY3、按键KEY4用IO口电平是否为低电平if(Key_up((KEY_S1==KEY_ON)
(KEY_S2==KEY_ON)
(KEY_S3==KEY_ON)
(KEY_S4==KEY_ON))){delay_ms(10);//软件延时10ms,去抖Key_up=0;//变量Key_up会被赋值为0if(KEY_S1==KEY_ON){returnKEY1_ON;}elseif(KEY_S2==KEY_ON){returnKEY2_ON;}elseif(KEY_S3==KEY_ON){returnKEY3_ON;}elseif(KEY_S4==KEY_ON){returnKEY4_ON;}}elseif((KEY_S1==KEY_OFF)(KEY_S2==KEY_OFF)(KEY_S3==KEY_OFF)(KEY_S4==KEY_OFF)){Key_up=1;//变量Key_up会被赋值为1}returnKEYS_OFF;}
因为按键检测函数Keys_Scan中使用了控制led的函数、有关KEY的宏定义和延时函数,所以需要在key.c文件中引用下面的头文件。
#include"led.h"#include"key.h"
最后,在主函数中先对4个用户指示灯和4个用户按键用到的GPIO口进行模式配置,后主循环中调用按键检测函数,可观察各用户按键按下后用户指示灯变化情况。
代码清单:主函数
intmain(void){uint8temp;P2M1=0x3F;P2M0=0x3F;//设置P2.6~P2.7为准双向口P7M1=0xF9;P7M0=0xF9;//设置P7.1~P7.2为准双向口P0M1=0x5F;P0M0=0x5F;//设置P0.5,P0.7为准双向口//P0M1
=0xA0;P0M0=0x5F;//设置P0.5,P0.7为高阻输入P3M1=0x3F;P3M0=0x3F;//设置P3.6~P3.7为准双向口//P3M1
=0xC0;P3M0=0x3F;//设置P3.6~P3.7为高阻输入//P_SW2
=0x80;//将EAXFR位置1,以访问在XDATA区域的扩展SFR//P0PU
=0xA0;//设置P0.5,P0.7口有上拉电阻//P3PU
=0xC0;//设置P3.6~P3.7口有上拉电阻//P_SW2=0x7F;//将EAXFR位置0,恢复访问XRAMwhile(1){temp=Keys_Scan(0);//获取开发板用户按键检测值,不支持连按if(temp==KEY1_ON)//如果按键KEY1被操作{led_toggle(LED_1);//控制用户指示灯D1翻转}elseif(temp==KEY2_ON)//如果按键KEY2被操作{led_toggle(LED_2);//控制用户指示灯D2翻转}elseif(temp==KEY3_ON)//如果按键KEY3被操作{led_toggle(LED_3);//控制用户指示灯D3翻转}elseif(temp==KEY4_ON)//如果按键KEY4被操作{led_toggle(LED_4);//控制用户指示灯D4翻转}}}
总结
以上就是今天要讲的内容,希望对你有所帮助!
转载请注明:http://www.0431gb208.com/sjszyzl/2693.html