在IAP15f261S单片机中,独立按键属于矩阵键盘中的一部分,如下图:
可以看到,当跳线帽接在J5的2,3口上时只有S4~S7起作用,此时为独立按键状态,由P33~P30低四位控制。
我们可以通过这个函数来判断按键的IO情况:
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清零,屏蔽不关心的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;
}
接着我们来实现一个效果:
Description:
统计S4按下的次数:每按下一次S4,数码管的数字+1 (默认数字是0)
Attention:
一个好的按键程序,必须有:
(1)消抖;
(2)按键状态的判断,包括判断按键按下,判断按键弹起;
(3)不阻塞程序,不用delay消抖
源代码:
/*************************************************
File name: 【独立按键】状态机法
Description:
统计S4按下的次数:每按下一次S4,数码管的数字+1 (默认数字是0)
Attention:
一个好的按键程序,必须有:
(1)消抖;
(2)按键状态的判断,包括判断按键按下,判断按键弹起;
(3)不阻塞程序,不用delay消抖
Copyright (c) 电子设计工坊 dianshe.taobao.com
All rights reserved
*************************************************/
#include "system.h"
#include <intrins.h>
#include "Delay.h"
#include "Device.h"
u8 code smg_code[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x76,0x79,0x38}; //共阴数码管码表
// H , E , L
HexToBin led_ctrl,uln_ctrl;
/**
* @brief 系统初始化函数:关闭继电器、蜂鸣器
* @param None
* @retval None
* @author dianshe.taobao.com
*/
void vSystem_Init(void)
{
vDevice_Ctrl(0xa0,0); /* 关闭蜂鸣器、继电器*/
led_ctrl.hex=0xff;
vDevice_Ctrl(0x80,led_ctrl.hex); /* 关闭LED*/
}
void vTimer2_Init(void) //1毫秒@12.000MHz
{
AUXR &= 0xFB; //定时器时钟12T模式
T2L = 0x18; //设置定时初值
T2H = 0xFC; //设置定时初值
AUXR |= 0x10; //定时器2开始计时
IE2 |= 0x04; //开定时器2中断
EA = 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清零,屏蔽不关心的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;
}
//按键处理函数
u8 cnt_key;
u8 s4_number;
void vBTN_Process(void)
{
u8 key_val;
if(cnt_key>=10)
{
cnt_key=0;
key_val = vBTN_Read();
if(key_val==4)
{
s4_number++;
}
}
}
//数码管操作函数
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 main(void)
{
vSystem_Init();
vTimer2_Init();
while(1)
{
vBTN_Process();
vSMG_Process();
}
}
//数码管显示函数
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;
}
//中断服务程序
void vTimer2_ISR() interrupt 12 //中断入口
{
cnt_key++;
vSMG_Display();
}
头文件:
#ifndef __SYSTEM_H_
#define __SYSTEM_H_
#include <STC15F2K60S2.H>
typedef char s8;
typedef unsigned char u8;
typedef int s16;
typedef unsigned int u16;
typedef unsigned long u32;
/* 用typedef定义一个叫bits的结构体“数据类型”, 从而可以用 bits b; 定义b为结构体的“变量”*/
typedef struct
{
u8 b0 : 1;
unsigned char b1 : 1;
unsigned char b2 : 1;
unsigned char b3 : 1;
unsigned char b4 : 1;
unsigned char b5 : 1;
unsigned char b6 : 1;
unsigned char b7 : 1;
}bits;
/* 用typedef定义一个叫HexToBin的共用体“数据类型”, 从而可以用 HexToBin led_ctrl; 定义led_ctrl为共用体的“变量”*/
typedef union
{
unsigned char hex;
bits b;
}HexToBin;
#endif