基于STC系列单片机实现单个按键的单击、双击、长按功能

Key.c

#include "Key.h"
#include "Timer0.h"
#define uchar unsigned char//自定义无符号字符型为uchar
#define uint unsigned int//自定义无符号整数型为uint
#define  KeyPressDelayTime  10//自定义按键按下延时时间
#define  KeyLongPressIntervalTime  25//自定义按键长按间隔时间
#define  KeyDoublePressTime  50//自定义按键双击时间 
#define  KeyLongPressTime  80//自定义按键长按时间
uchar  KeyPressLockFlag = 0;//定义按键按下自锁标志位
uchar  KeyPressDelay = 0;//定义按键按下延时   
uint   KeyPressCount = 0;//定义按键按下计数  
uint   KeyDoublePressIntervalTimeCount = 0;//定义按键双击间隔时长计数
uint   KeyLongPressIntervalTimeCount = 0;//定义按键长按间隔时长计数
uint   KeyType = 0;//定义按键类型变量
uint   KeyPressNumber = 0;//声明按键按下数值变量
  void KeyScan()//按键扫描函数
{
   if(Key)//判断按键是否被按下
 {
    KeyPressLockFlag = 0;//按键按下自锁标志位置0
    KeyPressDelay = 0;//按键按下延时清0
    if(KeyPressCount > 0)//判断按键按下计数是否大于0
  {
     KeyDoublePressIntervalTimeCount++;//按键双击间隔时长计数自加
     if(KeyDoublePressIntervalTimeCount > KeyDoublePressTime)//判断按键双击间隔时长计数是否大于按键双击时长
   {
      if(KeyPressCount == 1)//判断按键按下计数是否等于1
    {
       KeyType = 1;//按键单击
      }
      KeyDoublePressIntervalTimeCount = 0;//按键双击间隔时长计数清0 即清除按键双击时间间隔
      KeyPressCount = 0;//按键按下计数清0
    }
   }
  }
   else if(!KeyPressLockFlag)//判断按键被按下 
 {
    KeyPressDelay++;//按键按下延时自加
    if(KeyPressDelay > KeyPressDelayTime)//判断按键按下延时是否大于按键按下延时时间
  {
     KeyPressDelay = 0;//按键按下延时
     KeyDoublePressIntervalTimeCount = 0;//按键双击间隔时长计数清0
     KeyPressCount++;//按键按下时长计数自加
     KeyPressLockFlag = 1;//按键按下自锁标志位置1
//     if(KeyPressCount == 1)//判断按键按下计数是否为1
//   {
//      KeyType = 1;//按键单击
//     }           
     if(KeyPressCount == 2)判断按键按下计数是否为2
   {
      KeyType = 2;//按键双击
	  LED1=~LED1;//按键双击指示灯
     }
   }
  }
   else if(KeyPressDelay < KeyLongPressTime)//判断按键按下时长是否小于按键长按时长 key1_cnt
 {
    KeyPressDelay++;//按键按下延时
   }
   else//否则
 {	
	KeyLongPressIntervalTimeCount++;//按键长按间隔时长计数
	if(KeyLongPressIntervalTimeCount > KeyLongPressIntervalTime)//判断按键长按间隔时长计数是否大于按键长按间隔时间
  {
	 KeyLongPressIntervalTimeCount = 0;//按键长按间隔时长计数清0
	 KeyType = 3;//按键连击
	 LED2 = ~LED2;//按键长按指示灯
	}
  }
 }
  void KeyScanResult()//按键扫描结果函数
{
   switch(KeyType)//按键类型筛选位
 {
    case 1 ://单击触发位
           KeyPressNumber++;//按键按下数值自加
           if(KeyPressNumber > 9999)//如果按键按下数值大于9999
          {
            KeyPressNumber = 0;//按键按下数值清0
           }
           KeyType = 0;//按键类型清0
           break;//跳出
    case 2 ://双击触发位
           KeyPressNumber++;//按键按下数值自加
           if(KeyPressNumber > 9999)//如果按键按下数值大于9999
          {
            KeyPressNumber = 0;//按键按下数值清0
           }
           KeyType = 0;//按键类型清0
           break;//跳出
    case 3 ://长按触发位
           KeyPressNumber++;//脉冲宽度值自减
           if(KeyPressNumber > 9999)//如果按键按下数值大于9999
          {
            KeyPressNumber = 0;//按键按下数值清0
           }
           KeyType = 0;//按键类型清0
           break;//跳出
    default:break;//跳出
   }
  }

Key.h

#ifndef  _KEY_H
#define  _KEY_H
#include "reg51.h"
#define uchar unsigned char//自定义无符号字符型为uchar
#define uint unsigned int//自定义无符号整数型为uint
sbit Key = P3^5;//位定义按键为单片机P2.0引脚
sbit LED1 = P1^1;//位定义LED灯为单片机P1.1脚
sbit LED2 = P1^2;//位定义LED灯为单片机P1.2脚
extern uchar  KeyPressLockFlag;//定义按键按下自锁标志位 可被其他.c文件通过#include "其他.h"引用该变量
extern uchar  KeyPressDelay;//定义按键按下延时 可被其他.c文件通过#include "其他.h"引用该变量  
extern uint   KeyPressCount;//定义按键按下计数 可被其他.c文件通过#include "其他.h"引用该变量 
extern uint   KeyDoublePressIntervalTimeCount;//定义按键双击间隔时长计数 可被其他.c文件通过#include "其他.h"引用该变量
extern uint   KeyLongPressIntervalTimeCount;//定义按键长按间隔时长计数 可被其他.c文件通过#include "其他.h"引用该变量
extern uint   KeyType;//声明按键类型变量 可被其他.c文件通过#include "其他.h"引用该变量
extern uint   KeyPressNumber;//声明按键按下数值变量 可被其他.c文件通过#include "其他.h"引用该变量
void KeyScan();//声明按键扫描函数 该函数放在定时器定时2ms的中断函数中扫描
void KeyScanResult();//声明按键扫描结果函数
#endif 

Timer0.c

#include "Timer0.h"
#include "Key.h"
//#include "Digitron.h"
/*****关于通过特殊功能寄存器AUXR设定定时器/计数器模式为1T或12T模式不需分频或需12分频8051系列单片机定时器初值(定时计数初值)计算的知识点*****/
  /****
  时钟周期(又称振荡周期):单片机晶振频率的倒数 例:单片机晶振频率12MHz 则时钟周期=[1/(12*10^6)Hz]s=0.000000083s=0.000083ms=0.083us
  机器周期:单片机执行一条指令过程中需要完成一个基本操作(如:取指、译码、执行等基本操作)所需的时间 8051系列单片机的一个机器周期由6个S周期(状态周期)组成 一个时钟周期定义为一个节拍(用P表示) 二个节拍定义为一个状态周期(用S表示) 那么8051单片机的机器周期由6个状态周期组成 也就是说一个机器周期=6个状态周期=12个时钟周期=[12x[1/(12*10^6)Hz]s]s=0.000001s=0.001ms=1us
  指令周期:单片机取出一条指令且执行完这条指令所需的时间
  以上三者间的关系:指令周期>机器周期>时钟周期
  一、以下是8051单片机定时器用12分频计算定时器初值的一种计算公式(以单片机晶振频率为12MHz 定时器0工作模式为16位定时模式1 需要定时1ms来计算):
   0、计算nT单片机机器周期T公式:T=n*(1/晶振频率)=几us
   1、一个机器周期=12个时钟周期=12乘以单片机晶振频率的倒数=12*[1/(12*10^6)Hz]s=0.000001s=0.001ms=1us
   2、定时时间=定时计数*一个机器周期 1ms=定时计数*1us 定时计数=1ms/1us=1000us/1us=1000次
   3、定时器初值(定时计数初值)=2^n-定时计数 n为几位定时器 此处n=16 则定时器初值(定时计数初值)=2^16-1000=65536-1000=64536 把64536转化成十六进制 拆开成高八位和低八位 高八位放TH0=0xfc或(65536-64536)/256 低八位放TL0=0x18或(65536-64536)%256
  二、以下是8051单片机定时器用12分频或不分频计算定时器初值的另外一种计算公式(以单片机晶振频率为12MHz 定时器0工作模式为16位定时模式1 需要定时1ms来计算):
   1、综合公式:定时器初值(定时计数初值)=2^n-(晶振频率/几分频/定时频率) n为几位定时器 该公式常用于脉冲宽度调制中运算 例如:利用8051系列单片机晶振频率为12MHz的定时器0的16位定时模式1来产生1KHz方波脉冲 由此可知:定时时间=1/定时频率=1/1000Hz=0.001s=1ms=1000us 进而可得:定时器初值(定时计数初值)=2^n-(晶振频率/几分频/定时频率)=2^16-(12MHz/12/1KHz)=2^16-(12*10^6)Hz/12/1000Hz)=65536-1000=64536 把64536转化成十六进制 拆开成高八位和低八位 高八位放TH0=0xfc或(65536-64536)/256或Value >> 8 低八位放TL0=0x18或(65536-64536)%256或=Value 
   2、TH0 = Value >> 8;TL0 = Value;该两句代码解释如下:
  (1)、TH0 = Value >> 8相当于TH0 = (65536-10000)/256=55536/256=216.9375 分析:65536-10000=55536转化成二进制为11011000 11110000 55536/256=216.9375转化成二进制为11011000 由此可看出Value为(65536-10000)=55536的二进制数11011000 11110000右移8位就可以得到55536/256=216.9375的二进制数11011000
  (2)、TL0 = Value相当于TL0 = (65536-时器初值的另外一种计算公式(以单片机晶振频率为12MHz 定时器0工作模式为16位定时模式1 需要定时1ms来计算):
 (一)、以下是8051单片机定时器用12分频计算定时器初值:
     定时器初值(定时计数初值)=2^n-(晶振频率/几分频/定时频率) n为几位定时器 该公式常用于脉冲宽度调制中运算 例如:利用8051系列单片机晶振频率为12MHz的定时器0的16位定时模式1来产生1KHz方波脉冲(相当于定时1ms) 由此可知:定时时间=1/定时频率=1/1000Hz=0.001s=1ms=1000us 进而可得:定时器初值(定时计数初值)=2^n-(晶振频率/几分频/定时频率)=2^16-(12MHz/12/1KHz)=2^16-(12*10^6)Hz/12/1000Hz)=65536-1000=64536 把64536转化成十六进制 拆开成高八位和低八位 高八位放TH0=0xfc或(65536-64536)/256或Value >> 8 低八位放TL0=0x18或(65536-64536)%256或=Value 
 (二)、以下是8051单片机定时器不用分频计算定时器初值:
     定时器初值(定时计数初值)=2^n-(晶振频率/几分频/定时频率) n为几位定时器 该公式常用于脉冲宽度调制中运算 例如:利用8051系列单片机晶振频率为12MHz的定时器0的16位定时模式1来产生1KHz方波脉冲(相当于定时1ms) 由此可知:定时时间=1/定时频率=1/1000Hz=0.001s=1ms=1000us 进而可得:定时器初值(定时计数初值)=2^n-(晶振频率/几分频/定时频率)=2^16-(12MHz/1/1KHz)=2^16-(12*10^6)Hz/1/1000Hz)=65536-12000=53536 把53536转化成十六进制 拆开成高八位和低八位 高八位放TH0=0xd1或(65536-53536)/256或Value >> 8 低八位放TL0=0x20或(65536-53536)%256或=Value
 (三)、TH0 = Value >> 8;TL0 = Value;该两句代码解释如下:
     1、TH0 = Value >> 8相当于TH0 = (65536-10000)/256=55536/256=216.9375 分析:65536-10000=55536转化成二进制为11011000 11110000 55536/256=216.9375转化成二进制为11011000 由此可看出Value为(65536-10000)=55536的二进制数11011000 11110000右移8位就可以得到55536/256=216.9375的二进制数11011000
     2、TL0 = Value相当于TL0 = (65536-10000)%256=55536%256=240 分析:65536-10000=55536转化成二进制为11011000 11110000 55536%256=240转化成二进制为11110000 由此可看出Value为(65536-10000)=55536的二进制数11011000 11110000取低8位就可以得到55536%256=240的二进制数11110000
 (四)、由定时器定时初值(定时计数初值)推导出定时器定时时间步骤如下:
     1、如果定时器定时初值(定时计数初值)是拆开成高八位和低八位赋值形式 如:TH0=0xfc TL0=0x18 先把高八位和低八位赋值组成一个十六位数据0xfc18 转化成十进制数据64536 用2^n-64536算出每秒产生的脉冲数 其中n为几位定时器 再根据公式计算定时时间 如:由公式:每秒产生的脉冲数=晶振频率/几分频/定时频率  转换成:每秒产生的脉冲数=晶振频率x定时频率/几分频 可求:定时频率=(每秒产生的脉冲数x几分频)/晶振频率 进而求出:定时时间=1/定时频率=1/[(每秒产生的脉冲数x几分频)/晶振频率]  转换成:晶振频率/(每秒产生的脉冲数x几分频)=定时时间
     2、如果定时器定时初值(定时计数初值)是十进制数据 如:64536 直接用2^n-64536算出每秒产生的脉冲数 其中n为几位定时器 再根据公式计算定时时间 如:由公式:每秒产生的脉冲数=晶振频率/几分频/定时频率  转换成:每秒产生的脉冲数=晶振频率x定时频率/几分频 可求:定时频率=(每秒产生的脉冲数x几分频)/晶振频率 进而求出:定时时间=1/定时频率=1/[(每秒产生的脉冲数x几分频)/晶振频率]  转换成:晶振频率/(每秒产生的脉冲数x几分频)=定时时间
  ****/
#define uchar unsigned char//自定义无符号字符型为uchar
#define uint unsigned int//自定义无符号整数型为uint
  void Timer0Init()//定时器0的16位定时模式1用12分频定时2ms初始化函数 晶振为12MHz
{
   //AUXR &= 0x7f;//设定定时器/计数器模式为12T
   TMOD &= 0xf0;//设定定时器/计数器工作模式清0
   TMOD |= 0x01;//设定定时器/计数器为定时器 工作模式为16位定时器0模式1
   TH0 = 0xf8;//设定定时器0高8位初值
   TL0 = 0x30;//设定定时器0低8位初值
   TF0 = 0;//定时器0溢出中断标志位清0
   ET0 = 1;//打开定时器0中断开关
   EA = 1;//打开定时器中断总开关
   TR0 = 1;//打开定时器0开关
  } 
  void Timer0() interrupt 1//定时器0的16位定时模式1用12分频定时2ms中断函数 晶振为12MHz
{
   TR0 = 0;//关定时器0开关
   if(DigitronBootTimerFlag == 1)//数码管开机时间标志位置1
 {
    DigitronBootTimer++;//数码管开机时间自加
   }
	 if(DigitronBootTimerFlag == 0)//判断共阳数码管开机时间标志位是否等于0
 { 
    //DigitronDisplayDataSplit();//数码管显示数据分解函数
    //DigitronDisplayData();//数码管显示数据函数
    KeyScan();//按键扫描函数 该函数放在定时器定时2ms的中断函数中扫描
   }
   TH0 = 0xf8;//设定定时器0计数高8位初值
   TL0 = 0x30;//设定定时器0计数低8位初值
   TR0 = 1;//开定时器0开关
  }

Timer0.h

#ifndef  _TIMER0_H
#define  _TIMER0_H
#include "reg51.h"
#define uchar unsigned char//自定义无符号字符型为uchar
#define uint unsigned int//自定义无符号整数型为uint
void Timer0Init();//声明定时器0初始化函数
#endif 
  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值