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