STC15F2K60S2学习笔记3——独立按键
目录
2.独立按键原理
3.编程实现:统计S4按下次数
3.1.判断按键是否按下函数
3.2.按键处理函数
3.3.数码管函数
3.4.外设控制函数
3.5主函数
1.独立按键原理图
STC15F2K60S2中的按键有独立按键和矩阵按键两个模式,J5跳冒控制按键模式。当J5跳冒接在23口时该按键处于独立按键模式(BTN模式),当J5跳冒接在12口时该按键处于矩阵按键模式(KBD模式)。这里,我们需要将J5跳冒接在23口实现独立按键模式。
2.独立按键原理
以S7按下为例。当S7按下时,按键两端导通。由于S7左端接的GND,导通后P30口即为低电平。于是,当单片机判断一个按键是否按下时,只需检测连接该按键的端口是否为低电平即可。但是,在实际操作中,会伴随这按键的抖动。于是我们要对按键进行消抖处理,才可精确判断按键是否按下。
3.编程实现:统计S4按下次数
思路:在while(1)内循环换:
①读取P33状态
②如果是0,则等待10ms,再读取P33状态
③如果还是0,确定有按键按下;则执行number++;让数码管数字+1
如果不是0,则说明是抖动;则不执行任何程序
④等待按键弹起后,再等待10ms,从①再开始执行
3.1.判断按键是否按下函数
这里我们使用的是状态机法,程序代码如下:
//独立按键状态机法
#define KEY_NO 0 //无按键状态,用于判断是否按下
#define KEY_DOWN 1 //有按键按下状态,判断是否为抖动
#define KEY_UP 2 //等待松手状态,判断是否弹起
u8 vBTN_Read(void) //10ms执行一次
{
static u8 key_state=0; //定义key_state为静态变量,用于保存每次按键状态
u8 key_io=0,key_val=0; //key_io:读取IO口的状态;key_val:返回键值;
key_io=P3&0x0f; //对P3读回来的高4位IO口清0,屏蔽不关心的IO口状态
switch(key_state)
{
case KEY_NO: //无按键状态,用于判断是否按下
if(key_io!=0x0f) key_state=KEY_DOWN;
break;
case KEY_DOWN: //有按键按下状态,判断是否为抖动
if(key_io!=0x0f)
{
if(key_io==0x0e) key_val=7; //S7
if(key_io==0x0d) key_val=6; //S6
if(key_io==0x0b) key_val=5; //S5
if(key_io==0x07) key_val=4; //S4
key_state=KEY_UP;
}
else
key_state=KEY_NO;
break;
case KEY_UP: //等待松手状态,判断弹起
if(key_io==0x0f) key_state=KEY_NO;
break;
}
return key_val;
}
3.2.按键处理函数
u8 cnt_key; //定义按键计时变量,在定时器中计时
u8 s4_number;//定义用来保存S4按下的次数变量
void vBTN_Process(void)
{
u8 key_val;
if(cnt_key>=10) //10MS进行一次读取
{
cnt_key=0;
key_val=vBTN_Read(); //读取按键的键值
if(key_val==4)
{
s4_number++;
}
}
}
3.3.数码管函数
//共阴数码管码表
u8 smg_code[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
//数码管操作函数
u8 smg_buf[8];
void vSMG_Process()
{
smg_buf[0]=smg_code[s4_number/100];
smg_buf[1]=smg_code[s4_number/10%10];
smg_buf[2]=smg_code[s4_number%10];
smg_buf[3]=0x00;
smg_buf[4]=0x00;
smg_buf[5]=0x00;
smg_buf[6]=0x00;
smg_buf[7]=0x00;
}
//数码管显示函数
void vSMG_Display()
{
static u8 i=0;
vDevice_Ctrl(0xc0,0); //位选(消除鬼影)
vDevice_Ctrl(0xe0,~smg_buf[i]); //段选
vDevice_Ctrl(0xc0,0x01<<i); //位选
i=(i+1)%8;
}
3.4.外设控制函数
#include "Device.h"
/**
* @brief 外设控制函数
* @param None
* @retval None
*/
void vDevice_Ctrl(unsigned char P2data,unsigned char P0data)
{
P0=P0data;
P2=P2data;
P2=0;
}
3.5主函数
#include "system.h"
#include <intrins.h>
#include "Device.h"
HexToBin led_ctrl,uln_ctrl;
/**
* @brief 系统初始化函数:关闭继电器、蜂鸣器
* @param None
* @retval None
*/
void vSystem_Init(void)
{
vDevice_Ctrl(0xa0,0); /*关闭蜂鸣器、继电器*/
led_ctrl.hex=0xff;
vDevice_Ctrl(0x80,led_ctrl.hex); /*关闭LED*/
}
void Timer2Init(void) //1毫秒@12.000MHz
{
AUXR |= 0x04; //定时器时钟12T模式
T2L = 0x20; //设置定时初值
T2H = 0xD1; //设置定时初值
AUXR |= 0x10; //定时器2开始计时
IE2|=0x04; //开定时器2中断
EA=1;
}
void main(void)
{
vSystem_Init();
Timer2Init();
while(1)
{
vSMG_Process();
vBTN_Process();
}
}
//中断服务程序
void vTimer2_ISR() interrupt 12 //中断入口
{
cnt_key++;
vSMG_Display();
}
注意事项:1.每次按键按下需要单次触发
2.需要有松手检测
3.不用delay延时堵塞程序
2301_80294874: 为啥没有定时器就显示不了呢?
CSDN-Ada助手: 非常感谢你分享了这么有价值的博客!关于8086寻址方式的学习笔记非常实用,我相信会对很多读者有所帮助。同时,我也想鼓励你继续创作相关的技术博文,因为这是一个需要不断学习和更新的领域。如果你感兴趣的话,我建议你可以写一篇关于微机原理中常见的数据传输方式的博客,例如DMA、中断和IO口等。期待你的作品! 2023年博客之星「城市赛道」年中评选已开启(https://activity.csdn.net/creatActivity?id=10470&utm_source=blog_comment_city ), 博主的原力值在所在城市已经名列前茅,持续创作就有机会成为所在城市的 TOP1 博主(https://bbs.csdn.net/forums/blogstar2023?typeId=3152981&utm_source=blog_comment_city),更有丰厚奖品等你来拿~。
SudoReboot: 我改好了,因为前面作用域设置的是全局,前面加个{}就好了
芷汀琯: 你的代码是啥样呀 我看看我会么
SudoReboot: 为什么我设置中文的粗体与斜体的时候,整行中文都变成了粗体且没有斜体