基于STC12C5A60S2系列1T 8051单片机的TM1638键盘数码管模块的数码管显示与单片机连接的按键的按键值的功能

基于STC12C5A60S2系列1T 8051单片机的TM1638键盘数码管模块的数码管显示与单片机连接的按键的按键值应用

  • STC12C5A60S2系列1T 8051单片机管脚图
  • STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式及配置
  • STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式介绍
  • TM1638键盘数码管模块概述
  • TM1638键盘数码管模块特性说明
  • TM1638键盘数码管模块管脚定义
  • TM1638键盘数码管模块管脚功能说明
  • TM1638键盘数码管模块按键读取原理
  • TM1638键盘数码管模块按键读取时序
  • TM1638键盘数码管模块显示地址寄存器
  • TM1638键盘数码管模块键扫数据寄存器
  • TM1638键盘数码管模块数据寄存器
  • TM1638键盘数码管模块数据命令寄存器
  • TM1638键盘数码管模块地址命令寄存器
  • TM1638键盘数码管模块显示控制命令寄存器
  • TM1638键盘数码管模块数码管串行数据传输
    • 数据接收(写数据)
    • 数据读取(读数据)
  • TM1638键盘数码管模块串行数据地址传输模式时序图
    • 地址自动加1模式时序图
    • 固定地址模式时序图
  • TM1637键盘数码管模块程序设计流程图
    • 地址自动加1模式的程序设计流程图
    • 固定地址模式的程序设计流程图
  • TM1638键盘数码管模块应用电路
    • TM1638键盘数码管模块驱动共阴数码管硬件电路
    • TM1638键盘数码管模块驱动共阳数码管硬件电路
  • TM1638键盘数码管模块电气参数
  • TM1638键盘数码管模块的数码管显示与单片机连接的按键的按键值编程
  • TM1638键盘数码管模块的数码管显示与单片机连接的按键的按键值实验现象

STC12C5A60S2系列1T 8051单片机管脚图

在这里插入图片描述在这里插入图片描述

STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式及配置

在这里插入图片描述

STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式介绍

在这里插入图片描述在这里插入图片描述

TM1638键盘数码管模块概述

TM1638是带键盘扫描接口的LED(发光二极管显示器)驱动控制专用电路,内部集
成有MCU 数字接口、数据锁存器、LED 高压驱动、键盘扫描等电路。主要应用于冰箱、
空调 、家庭影院等产品的高段位显示屏驱动。

TM1638键盘数码管模块特性说明

• 采用功率CMOS 工艺
• 显示模式 10 段×8 位
• 键扫描(8×3bit)
• 辉度调节电路(占空比8 级可调)
• 串行接口(CLK,STB,DIO)
• 振荡方式:RC 振荡(450KHz+5%)
• 内置上电复位电路
• 采用SOP28封装

TM1638键盘数码管模块管脚定义

在这里插入图片描述

TM1638键盘数码管模块管脚功能说明

在这里插入图片描述

TM1638键盘数码管模块按键读取原理

在这里插入图片描述在这里插入图片描述

TM1638键盘数码管模块按键读取时序

在这里插入图片描述

TM1638键盘数码管模块显示地址寄存器

在这里插入图片描述

TM1638键盘数码管模块键扫数据寄存器

在这里插入图片描述在这里插入图片描述

TM1638键盘数码管模块数据寄存器

在这里插入图片描述

TM1638键盘数码管模块数据命令寄存器

在这里插入图片描述

TM1638键盘数码管模块地址命令寄存器

在这里插入图片描述

TM1638键盘数码管模块显示控制命令寄存器

在这里插入图片描述

TM1638键盘数码管模块数码管串行数据传输

数据接收(写数据)

在这里插入图片描述

数据读取(读数据)

在这里插入图片描述

TM1638键盘数码管模块串行数据地址传输模式时序图

地址自动加1模式时序图

在这里插入图片描述

固定地址模式时序图

在这里插入图片描述

TM1637键盘数码管模块程序设计流程图

地址自动加1模式的程序设计流程图

在这里插入图片描述

固定地址模式的程序设计流程图

在这里插入图片描述

TM1638键盘数码管模块应用电路

TM1638键盘数码管模块驱动共阴数码管硬件电路

在这里插入图片描述

TM1638键盘数码管模块驱动共阳数码管硬件电路

在这里插入图片描述

TM1638键盘数码管模块电气参数

在这里插入图片描述在这里插入图片描述在这里插入图片描述

TM1638键盘数码管模块的数码管显示与单片机连接的按键的按键值编程

main.c

#include <stc12c5a60s2.h>
#include "Timer0.h"
#include "Key.h"
#include "Digitron.h"
#include "TM1638OfI2C.h"
//#include"intrins.h"
#define uchar unsigned char//自定义无符号字符型为uchar
#define uint unsigned int//自定义无符号整数型为uint
 void PortModeSet()//端口模式设置函数
{
  P0M1 = 0x00;
  P0M0 = 0x00;
  P1M1 = 0x00;
  P1M0 = 0x00;
  P2M1 = 0x00;
  P2M0 = 0x00;
  P3M1 = 0x00;
  P3M0 = 0x00;
  P4M1 = 0x00;
  P4M0 = 0x00;
 }
 void main()//主函数
{
  PortModeSet();//端口模式设置函数
//  Uart1Init();//串行口1工作模式1的8位串行口波特率可变初始化函数 波特率为9600bps 晶振为12MHz
  Timer0Init();//定时器0的16位定时模式1用12分频定时2ms初始化函数 晶振为12MHz
  DigitronBootDisplay();//数码管开机显示函数
  TM1638OfI2CInit();//TM1638键盘数码管模块初始化函数 
//  TM1637AutomaticDisplay();//TM1637键盘数码管模块自动显示函数
  while(1)//主循环
 { 
   KeyScanResult();//按键扫描结果函数
  }
 }

TM1638OfI2C.c

#include "TM1638OfI2C.h"
//#include "Key.h"
//#include "Digitron.h"
#include"intrins.h"
#define uchar unsigned char//自定义无符号字符型为uchar
#define uint unsigned int//自定义无符号整数型为uint

 void TM1638OfI2CWriteByte(uchar Data)//TM1638键盘数码管模块写字节函数
{
  uchar i;//声明字节位个数变量
  for (i = 0; i < 8; i++)//循环字节位个数
 {
   TM1638CLK = 0;//拉低TM1638键盘数码管模块时钟线端口 让TM1638键盘数码管模块进行输出字节某位操作
   TM1638DIO =  Data & 0x01;//取出该数据的字节最低位 如何取出该数据的字节最低位?为什么是&0x01?而不是|0x01?以两个数据的字节来说明 如:0000 0010 和 0000 0011 它们的最低位分别为0和1 &0x01后是0和1 也是它们的最低位0和1 如果|0x01后都是1 就再也不是它们原来的最低位0和1 
   Data >>= 1;//取出该数据的字节最低位后 剩余字节往右移一位 形成新的数据的字节
   TM1638CLK = 1;//拉高TM1638键盘数码管模块时钟线端口 结束TM1638键盘数码管模块输出字节某位操作
  }
 }
 
 void TM1638OfI2CWriteCommand(uchar Command)//TM1638键盘数码管模块写命令函数
{
  TM1638STB = 0;//拉低TM1638键盘数码管模块片选线端口 让TM1638键盘数码管模块进行写操作
  TM1638OfI2CWriteByte(Command);//通过TM1638键盘数码管模块写字节函数来写命令
  TM1638STB = 1;//拉高TM1638键盘数码管模块片选线端口 结束TM1638键盘数码管模块写操作
 }

 void TM1638OfI2CWriteData(uchar Address,uint Data)//TM1638键盘数码管模块写数据函数 在指定的显示地址写入数据
{
  TM1638STB = 0;//拉低TM1638键盘数码管模块片选线端口 让TM1638键盘数码管模块进行写操作
  TM1638OfI2CWriteByte(0x00 | Address);//通过TM1638键盘数码管模块写字节函数来写显示地址
  TM1638OfI2CWriteByte(Data);//通过TM1638键盘数码管模块写字节函数来写数据
  TM1638STB = 1;//拉高TM1638键盘数码管模块片选线端口 结束TM1638键盘数码管模块写操作
 }
 
/***** 
 uhar TM1638OfI2CReadByte()//TM1638键盘数码管模块读字节函数
{
  uchar i;//声明字节位个数变量
  uchar ByteData = 0;//声明字节数据变量
  TM1638DIO = 1;//拉高TM1638键盘数码管模块数据线端口 读入数据
  for(i = 0; i < 8; i++)//循环字节位个数
 {
   ByteData >>= 1;//字节数据往右移一位 形成新的数据的字节 如:1010 1010 右移一位 变为0101 0101
   TM1638CLK = 0;//拉低TM1638键盘数码管模块时钟线端口 让TM1638键盘数码管模块进行读取字节某位操作
   if(TM1638DIO)//判断TM1638键盘数码管模块数据线端口是否为高电平
   ByteData |= 0x80;//置该数据的字节最高位为1 其余位不变 如何置该数据的字节最高位为1?为什么是|=0x80?而不是&=0x80?以两个数据的字节来说明 如:0100 0000 和 1000 0000 它们的最高位分别为0和1 |=0x80后都是1 也是它们的最高位都置为1 如果&=0x80后最高位分别是0和1 就再也不是它们原来的最高位都置为1 
   TM1638CLK = 1;//拉高TM1638键盘数码管模块时钟线端口 结束TM1638键盘数码管模块读取字节某位操作
  }
  return ByteData;//返回字节数据
 }
*****/ 

/***** 
 uchar TM1638OfI2CReadKey()//TM1638键盘数码管模块读按键函数
{
  uchar KeyByteArrary[4];//声明按键字节值数组变量
  uchar i;//声明按键字节值数组个数变量 
  uchar KeyValue = 0;//声明按键数值变量
  TM1638STB=0;//拉低TM1638键盘数码管模块片选线端口 让TM1638键盘数码管模块进行读操作
  TM1638OfI2CWriteByte(0x42); //设置TM1638键盘数码管模块的数据命令寄存器 写键扫数据命令 注意:这里要先写完4个字节键值才能将TM1638STB置1 否则写键值无效
  for (i = 0; i < 4; i++)//循环按键字节值数组中字节值个数 共有4个按键字节值
  KeyByteArrary[i] = TM1638OfI2CReadByte();//发送TM1638ReadByte(0x42)读键扫数据命令后 开始读取按键数据BYTE1—BYTE4共4个字节 从低位开始读取数据 TM1638键盘数码管模块上的K和KS引脚对应的按键按下时 相对应的按键字节值内的字节位为1
  TM1638STB=1;//拉高TM1638键盘数码管模块片选线端口 结束TM1638键盘数码管模块进行读操作
  for (i = 0; i < 4; i++)//循环按键字节值数组中字节值个数 共有4个按键字节值
  KeyValue |= KeyByteArrary[i] << i;//通过按键字节值循环取值来确定TM1638键盘数码管模块上的K引脚下对应的KS系列八个按键的前四个按键按键字节值   
  for (i = 0; i < 8; i++)//循环TM1638键盘数码管模块上的K引脚下对应的KS系列八个按键
  if ((0x01 << i) == KeyValue)//判断TM1638键盘数码管模块上的K引脚下对应的KS系列八个按键是否按下
  break;//跳出
  return i;//返回TM1638键盘数码管模块上的KS引脚对应的按键号
 } 
*****/ 

/*****
 uchar TM1638ScanKey()//TM1638键盘数码管模块扫描按键函数
{
  uchar KeyByteArrary[4];//声明按键字节值数组变量
  uchar i;//声明按键字节值数组个数变量 
  uchar KeyValue = 0;//声明按键数值变量
  TM1638STB=0;//拉低TM1638键盘数码管模块片选线端口 让TM1638键盘数码管模块进行读操作
  TM1638OfI2CWriteByte(0x42); //设置TM1638键盘数码管模块的数据命令寄存器 写键扫数据命令 注意:这里要先写完4个字节键值才能将TM1638STB置1 否则写键值无效
  for (i = 0; i < 4; i++)//循环按键字节值数组中字节值个数 共有4个按键字节值
  KeyByteArrary[i] = TM1638OfI2CReadByte();//发送TM1638ReadByte(0x42)读键扫数据命令后 开始读取按键数据BYTE1—BYTE4共4个字节 从低位开始读取数据 TM1638键盘数码管模块上的K和KS引脚对应的按键按下时 相对应的按键字节值内的字节位为1
  TM1638STB=1;//拉高TM1638键盘数码管模块片选线端口 结束TM1638键盘数码管模块进行读操作
  for (i = 0; i < 4; i++)//循环按键字节值数组中字节值个数 共有4个按键字节值
  KeyValue |= KeyByteArrary[i] << i;//通过按键字节值循环取值来确定TM1638键盘数码管模块上的K引脚下对应的KS系列八个按键的前四个按键按键字节值   
  for (i = 0; i < 8; i++)//循环TM1638键盘数码管模块上的K引脚下对应的KS系列八个按键
  if ((0x01 << i) == KeyValue)//判断TM1638键盘数码管模块上的K引脚下对应的KS系列八个按键是否按下
  break;//跳出
  return i;//返回TM1638键盘数码管模块上的KS引脚对应的按键号
 }
*****/

/*****
 void TM1638AutomaticDisplay()//TM1638键盘数码管模块自动显示函数
{
  uchar i;//声明循环变量
  TM1638STB = 0;//拉低TM1638键盘数码管模块片选线端口 让TM1638键盘数码管模块进行写操作
  TM1637OfI2CWriteByte(0x40);//40H:显示地址自动加1模式 44H:固定地址模式 本程序采用自加1模式
  TM1638STB = 1;//拉高TM1638键盘数码管模块片选线端口 结束TM1638键盘数码管模块写操作
  
  TM1638STB = 0;//拉低TM1638键盘数码管模块片选线端口 让TM1638键盘数码管模块进行写操作
  TM1637OfI2CWriteByte(0xc0);//设置TM1638键盘数码管模块显示地址寄存器从首地址开始显示
  for(i = 0;i < 16;i++)//循环TM1638键盘数码管模块显示地址寄存器
 {
   TM1637OfI2CWriteByte(0x3f);//写数据
  }
  TM1638STB = 1;//拉高TM1638键盘数码管模块片选线端口 结束TM1638键盘数码管模块写操作
  
  TM1638STB = 0;//拉低TM1638键盘数码管模块片选线端口 让TM1638键盘数码管模块进行写操作
  TM1637OfI2CWriteByte(0x8f);//开TM1638键盘数码管模块显示 显示亮度最大
  TM1638STB = 1;//拉高TM1638键盘数码管模块片选线端口 结束TM1638键盘数码管模块写操作
 }
*****/
 
 void TM1638RegularDisplay(uchar Address, uint Value)//TM1638键盘数码管模块固定显示函数
{
//  TM1638STB = 0;//拉低TM1638键盘数码管模块片选线端口 让TM1638键盘数码管模块进行写操作
//  TM1638OfI2CWriteByte(0x44);//40H:显示地址自动加1模式 44H:固定地址模式 本程序采用固定模式
  TM1638OfI2CWriteCommand(0x44);//TM1638键盘数码管模块写命令函数 40H:显示地址自动加1模式 44H:固定地址模式 本程序采用固定模式
//  TM1638STB = 1;//拉高TM1638键盘数码管模块片选线端口 结束TM1638键盘数码管模块写操作
  
//  TM1638STB = 0;//拉低TM1638键盘数码管模块片选线端口 让TM1638键盘数码管模块进行写操作
  TM1638OfI2CWriteData(Address,Value);//TM1638键盘数码管模块写数据函数 在指定的显示地址写入数据
//  TM1638OfI2CWriteByte(Address);//设置TM1638键盘数码管模块显示地址寄存器
//  TM1638OfI2CWriteByte(Value);//写数据
//  TM1638STB = 1;//拉高TM1638键盘数码管模块片选线端口 结束TM1638键盘数码管模块写操作
  
//	TM1638STB = 0;//拉低TM1638键盘数码管模块片选线端口 让TM1638键盘数码管模块进行写操作
//	TM1638OfI2CWriteByte(0x8f);//开TM1638键盘数码管模块显示 显示亮度最大
//	TM1638STB = 1;//拉高TM1638键盘数码管模块片选线端口 结束TM1638键盘数码管模块写操作
 }

 void TM1638OfI2CInit(void)//TM1638键盘数码管模块初始化函数
{
  unsigned char i;//声明TM1638键盘数码管模块的数码管显示寄存器的寄存器单元变量
  TM1638OfI2CWriteCommand(0x88);//设置TM1638键盘数码管模块的显示控制寄存器 使数码管显示开 数码管辉度为1/16
  TM1638OfI2CWriteCommand(0x40);//设置TM1638键盘数码管模块的数据命令寄存器 地址增加模式设置 自动地址增加
  TM1638STB=0;//拉低TM1638键盘数码管模块片选线端口 让TM1638键盘数码管模块进行写操作
  TM1638OfI2CWriteByte(0xc0);//设置TM1638键盘数码管模块的地址命令寄存器 初始显示地址为0x00
  for(i = 0;i < 16;i++)//循环TM1638键盘数码管模块的数码管显示控制寄存器的16位寄存器单元
  TM1638OfI2CWriteByte(0x00);//设置TM1638键盘数码管模块的数码管显示控制寄存器的16位寄存器单元内容清零
  TM1638STB=1;//拉高TM1638键盘数码管模块片选线端口 结束TM1638键盘数码管模块写操作
 }

TM1638OfI2C.h

#ifndef  _TM1638OFI2C_H
#define  _TM1638OFI2C_H
#include "STC12C5A60S2.h"
#define	uchar unsigned char	//定义无符号字符
#define	uint  unsigned int	//定义无符号整形
//TM1638键盘数码管模块引脚定义
sbit TM1638DIO=P1^3;//定义单片机P1.3端口为TM1638键盘数码管模块数据线端口
sbit TM1638CLK=P1^2;//定义单片机P1.2端口为TM1638键盘数码管模块时钟线端口
sbit TM1638STB=P1^1;//定义单片机P1.1端口为TM1638键盘数码管模块片选线端口
void TM1638OfI2CWriteByte(unsigned char Data);//TM1638键盘数码管模块写字节函数
void TM1638OfI2CWriteCommand(unsigned char Command);//TM1638键盘数码管模块写命令函数
void TM1638OfI2CWriteData(unsigned char Address,unsigned char Data);//TM1638键盘数码管模块写数据函数 在指定的显示地址写入数据
//uchar TM1638OfI2CReadByte();//TM1638键盘数码管模块读字节函数
//uchar TM1638OfI2CReadKey();//TM1638键盘数码管模块读按键函数
// uchar TM1638ScanKey();//TM1638键盘数码管模块扫描按键函数
//void TM1638AutomaticDisplay();//TM1638键盘数码管模块自动显示函数
extern void TM1638RegularDisplay(uchar Address, uint Value);//TM1638键盘数码管模块固定显示函数
void TM1638OfI2CInit();//TM1638键盘数码管模块初始化函数 
#endif 

Key.c

#include "Key.h"
//#include "Uart.h"
//#include "Timer0.h"
//#include "TM1637OfI2C.h"
#define	uchar unsigned char	//定义无符号字符
#define	uint  unsigned int	//定义无符号整形
#define KeyPressDeshakeTime 15//自定义按键按下消抖时间为20ms	
#define KeyLongPressDelayTime 100//自定义按键长按延时时间为200ms
//uchar ClearKeyPressFlag = 0;//定义清零按键按下标志位变量为0
//uchar SetKeyFlag = 0;//定义设置按键标志位变量为0
//uchar SetKeyPressCountFlag = 1;//定义设置按键按下计数标志位变量为1
//uchar SetKeyShortPressLcokFlag = 0;//定义设置按键短按按下锁定标志位变量为0
uchar AddKeyPressLcokFlag = 0;//定义增加按键锁定标志位变量为0
uchar AddKeyShortPressLcokFlag = 0;//定义增加按键短按按下锁定标志位变量为0
uchar AddKeyLongPressLcokFlag = 0;//定义增加按键长按按下锁定标志位变量为0
uchar DecKeyPressLcokFlag = 0;//定义减少按键锁定标志位变量为0
uchar DecKeyShortPressLcokFlag = 0;//定义减少按键短按按下锁定标志位变量为0
uchar DecKeyLongPressLcokFlag = 0;//定义减少按键长按按下锁定标志位变量为0
//uchar SetKeyShortPressCount = 0;//定义设置按键短按按下计数变量为0
//uchar SetKeyShortPressFlag = 0;//定义设置按键短按按下标志位变量为0
//uchar SetKeyShortPressCountFlag = 1;//定义设置按键短按按下计数标志位变量为1
//uchar SetKeyLongPressLcokFlag = 0;//定义设置按键长按按下锁定标志位变量为0
//uchar SetKeyLongPressCount = 0;//定义设置按键长按按下计数变量为0
//uchar SetKeyLongPressFlag = 0;//定义设置按键长按按下标志位变量为0
//uint  SetKeyLongPressCountFlag = 1;//定义设置按键长按按下计数标志位变量为0
uint  KeyPressDelayTime = 0;//定义按键按下延时时间变量为0
uint  KeyLiftDelayTime = 0;//定义按键弹起延时时间变量为0
uint  KeyPressNumber = 0;//定义按键按下数值变量为0
uint  KeyPressNumberLcokFlag = 0;//定义按键按下数值锁定标志位变量为0
uint  KeyPressAddress = 0;//定义按键按下地址变量为0
uint  KeyPressAddressCount = 0;//定义按键按下地址计数变量为0
uint  KeyType = 0;//定义按键类型变量为0
//  uint KeyScan ()//带按键返回值的按键扫描函数
  void KeyScan ()//按键扫描函数
{  	  
 
   if((AddKey == 0) && (AddKeyPressLcokFlag == 0))//增加按键按下
 {	  
	DecKeyPressLcokFlag = 1;//减少按键按下锁定标志位变量置1 防止增加按键按下时 有减少按键按下 从而实现增加减少按键互不干扰
	KeyPressDelayTime++;//按键按下延时时间变量自加
	if((AddKeyShortPressLcokFlag == 0) && (AddKeyLongPressLcokFlag == 0))//增加按键短按按下锁定标志位变量为0与增加按键长按按下锁定标志位变量为0 一是为了增加按键第1次能短按 二是为了增加按键第1次短按后 如果不松手一直按着 会激活增加按键短按锁定标志位置1 跳出增加按键短按 进入增加按键长按 三是为了增加按键长按后松手 防止进入短按 从而实现短按与长按互不干扰 
  {	 
	 if(KeyPressDelayTime > KeyPressDeshakeTime)//判断按键按下延时时间变量是否大于按键按下消抖时间
   {
      KeyPressDelayTime = 0;//按键按下延时时间变量清0 为了跳出设置按键短按延时 进入设置按键长按延时
	  AddKeyShortPressLcokFlag = 1;//增加按键短按按下锁定标志位变量置1 跳出增加按键短按 进入增加按键长按 防止增加按键长按时进入短按 从而实现短按与长按互不干扰
	 }
    }
	 if(KeyPressDelayTime > KeyLongPressDelayTime)//判断按键按下延时时间变量是否大于按键长按延时时间
   {
      KeyPressDelayTime = 0;//按键按下延时时间变量清0 重启下一步按键按下延时操作
	  AddKeyShortPressLcokFlag = 0;//增加按键短按按下锁定标志位变量置1 防止增加按键长按后松手进入短按 从而实现短按与长按互不干扰 
      AddKeyLongPressLcokFlag = 1;//增加按键长按按下锁定标志位变量置1 一是为了增加按键长按按下后松手再触发其他功能作判断依据 二是为了增加按键长按后松手 防止进入短按 从而实现短按与长按互不干扰
	  KeyType = 1;//此处是增加按键长按
	 }
  }
 
	
   else if((DecKey == 0) && (DecKeyPressLcokFlag == 0))//减少按键按下
 {	 
	AddKeyPressLcokFlag = 1;//增加按键按下锁定标志位变量置1 防止减少按键按下时 有增加按键按下 从而实现增加减少按键互不干扰
	KeyPressDelayTime++;//按键按下延时时间变量自加
	if((DecKeyShortPressLcokFlag == 0) && (DecKeyLongPressLcokFlag == 0))//减少按键短按按下锁定标志位变量为0与减少按键长按按下锁定标志位变量为0 一是为了减少按键第1次能短按 二是为了减少按键第1次短按后 如果不松手一直按着 会激活减少按键短按锁定标志位置1 跳出减少按键短按 进入减少按键长按 三是为了减少按键长按后松手 防止进入短按 从而实现短按与长按互不干扰 
  {	 
	 if(KeyPressDelayTime > KeyPressDeshakeTime)//判断按键按下延时时间变量是否大于按键按下消抖时间
   {
      KeyPressDelayTime = 0;//按键按下延时时间变量清0 为了跳出设置按键短按延时 进入设置按键长按延时
	  DecKeyShortPressLcokFlag = 1;//减少按键短按按下锁定标志位变量置1 跳出减少按键短按 进入减少按键长按 防止减少按键长按时进入短按 从而实现短按与长按互不干扰
	 }
    }
	 else if(KeyPressDelayTime > KeyLongPressDelayTime)//判断按键按下延时时间变量是否大于按键长按延时时间
   {
      KeyPressDelayTime = 0;//按键按下延时时间变量清0 重启下一步按键按下延时操作
	  DecKeyShortPressLcokFlag = 0;//减少按键短按按下锁定标志位变量置1 防止减少按键长按后松手进入短按 从而实现短按与长按互不干扰 
      DecKeyLongPressLcokFlag = 1;//减少按键长按按下锁定标志位变量置1 一是为了减少按键长按按下后松手再触发其他功能作判断依据 二是为了减少按键长按后松手 防止进入短按 从而实现短按与长按互不干扰
	  KeyType = 2;//此处是减少按键长按
	 }
   } 
   //以下表示减少按键弹起或没按下
   else if(DecKeyShortPressLcokFlag == 1)//表示短按过 判断减少按键短按按下锁定标志位变量是否为1 为了减少按键短按按下后松手再触发其他功能 而不受其他抖动影响
 {
	KeyPressDelayTime = 0;//按键按下延时时间变量清0 重启下一步按键按下延时操作
    KeyLiftDelayTime++;//按键弹起延时时间变量自加
	if(KeyLiftDelayTime > KeyPressDeshakeTime)//判断按键弹起延时时间变量是否大于按键按下消抖时间
  { 
	 KeyLiftDelayTime = 0;//按键弹起延时时间变量清0 重启下一步按键弹起延时操作
	 DecKeyShortPressLcokFlag = 0;//减少按键短按按下锁定标志位变量置0 为了重启下一步减少按键短按按下操作
	 DecKeyLongPressLcokFlag = 0;//减少按键长按按下锁定标志位变量置0 为了重启下一步减少按键长按按下操作
	 KeyType = 2;//此处是减少按键短按 对于按键计数或按键类型触发操作 建议要放在按键弹起后再计数 此处就是
     AddKeyPressLcokFlag = 0;//解除增加按键按下锁定标志位	
	}
   }
   //以下表示减少按键弹起或没按下
   else if(DecKeyLongPressLcokFlag == 1)//表示长按过 判断减少按键长按按下锁定标志位变量是否为1 为了减少按键长按按下后松手再触发其他功能 而不受其他抖动影响
 {
    KeyPressDelayTime = 0;//按键按下延时时间变量清0 重启下一步按键按下延时操作
    KeyLiftDelayTime++;//按键弹起延时时间变量自加
    if(KeyLiftDelayTime > KeyPressDeshakeTime)//判断按键弹起延时时间变量是否大于按键按下消抖时间
  { 
	 KeyLiftDelayTime = 0;//按键弹起延时时间变量清0 重启下一步按键弹起延时操作
	 DecKeyLongPressLcokFlag = 0;//减少按键长按按下锁定标志位变量置0 为了重启下一步减少按键长按按下操作
	 DecKeyShortPressLcokFlag = 0;//减少按键短按按下锁定标志位变量置0 为了重启下一步减少按键短按按下操作
     AddKeyPressLcokFlag = 0;//解除增加按键按下锁定标志位	
   }
  }

 
   else//增加按键弹起或没按下 
 {
	KeyPressDelayTime = 0;//按键按下延时时间变量清0 重启下一步按键按下延时操作
    if(AddKeyShortPressLcokFlag == 1)//表示短按过 判断增加按键短按按下锁定标志位变量是否为1 为了增加按键短按按下后松手再触发其他功能 而不受其他抖动影响
  {
	 KeyLiftDelayTime++;//按键弹起延时时间变量自加
	 if(KeyLiftDelayTime > KeyPressDeshakeTime)//判断按键弹起延时时间变量是否大于按键按下消抖时间
   { 
	  KeyLiftDelayTime = 0;//按键弹起延时时间变量清0 重启下一步按键弹起延时操作
	  AddKeyShortPressLcokFlag = 0;//增加按键短按按下锁定标志位变量置0 为了重启下一步增加按键短按按下操作
	  AddKeyLongPressLcokFlag = 0;//增加按键长按按下锁定标志位变量置0 为了重启下一步增加按键长按按下操作
	  KeyType = 1;//此处是增加按键短按 对于按键计数或按键类型触发操作 建议要放在按键弹起后再计数 此处就是
	  DecKeyPressLcokFlag = 0;//解除减少按键按下锁定标志位	
	 }
	}
    if(AddKeyLongPressLcokFlag == 1)//表示长按过 判断增加按键长按按下锁定标志位变量是否为1 为了增加按键长按按下后松手再触发其他功能 而不受其他抖动影响
  {
	 KeyLiftDelayTime++;//按键弹起延时时间变量自加
	 if(KeyLiftDelayTime > KeyPressDeshakeTime)//判断按键弹起延时时间变量是否大于按键按下消抖时间
   { 
	  KeyLiftDelayTime = 0;//按键弹起延时时间变量清0 重启下一步按键弹起延时操作
	  AddKeyLongPressLcokFlag = 0;//增加按键长按按下锁定标志位变量置0 为了重启下一步增加按键长按按下操作
	  AddKeyShortPressLcokFlag = 0;//增加按键短按按下锁定标志位变量置0 为了重启下一步增加按键短按按下操作
	  DecKeyPressLcokFlag = 0;//解除减少按键按下锁定标志位		 
	 }
	}
   }
    
  } 
  void KeyScanResult()//按键扫描结果函数
{
   switch(KeyType)//按键类型筛选位
 {
	case 1 ://按键按下数值变量单击或连击增加触发位
		    KeyPressNumber++;//按键按下数值自加
            if(KeyPressNumber > 9999)//如果按键按下数值大于9999
           {
             KeyPressNumber = 0;//按键按下数值置0
            }            
            KeyType = 0;//按键类型清0
            break;//跳出
    case 2 ://按键按下数值变量单击或连击减少触发位
            KeyPressNumber--;//按键按下数值自减
            if(KeyPressNumber == 0 || KeyPressNumber == 65535)//如果按键按下数值等于0或65535
           {
             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 "STC12C5A60S2.h"
#define	uchar unsigned char	//定义无符号字符
#define	uint  unsigned int	//定义无符号整形
sbit AddKey = P3^5;//增加按键
sbit DecKey = P3^4;//减少按键
//sbit SetKey = P3^3;//设置按键
//sbit ClearKey = P3^2;//复位按键
//sbit led0 = P1^5;//短按LED指示灯
//sbit led1 = P1^6;//长按LED指示灯
//sbit led2 = P1^7;//复位LED指示灯
//extern uchar ClearKeyPressFlag;//声明清零按键按下标志位变量
//extern uchar SetKeyFlag;//声明设置按键标志位变量
//extern uchar SetKeyPressCountFlag;//声明设置按键按下计数标志位变量
//extern uchar SetKeyShortPressLcokFlag;//声明设置按键短按按下锁定标志位变量
extern uchar AddKeyPressLcokFlag;//声明增加按键锁定标志位变量
extern uchar AddKeyShortPressLcokFlag;//声明增加按键短按按下锁定标志位变量
extern uchar AddKeyLongPressLcokFlag;//声明增加按键长按按下锁定标志位变量
extern uchar DecKeyPressLcokFlag;//声明减少按键锁定标志位变量
extern uchar DecKeyShortPressLcokFlag;//声明减少按键短按按下锁定标志位变量
extern uchar DecKeyLongPressLcokFlag;//声明减少按键长按按下锁定标志位变量
//extern uchar SetKeyShortPressCount;//声明设置按键短按按下计数变量
//extern uchar SetKeyShortPressFlag;//声明设置按键短按按下标志位变量置
//extern uchar SetKeyShortPressCountFlag;//声明设置按键短按按下计数标志位变量
//extern uchar SetKeyLongPressLcokFlag;//声明设置按键长按按下锁定标志位变量
//extern uchar SetKeyLongPressCount;//声明设置按键长按按下计数变量
//extern uchar SetKeyLongPressFlag;//声明设置按键长按按下标志位变量
//extern uint  SetKeyLongPressCountFlag;//声明设置按键长按按下计数标志位变量
extern uint KeyPressDelayTime;//声明按键按下延时时间变量 可被其他.c文件通过#include "其他.h"引用该变量
extern uint  KeyLiftDelayTime;//声明按键弹起延时时间变量
extern uint  KeyPressNumber;//声明按键按下数值变量
extern uint  KeyPressNumberLcokFlag;//声明按键按下数值锁定标志位变量
extern uint  KeyPressAddress;//声明按键按下地址变量
extern uint  KeyPressAddressCount;//声明按键按下地址计数变量为0
extern uint  KeyType;//声明按键类型变量
void KeyScan ();//按键扫描函数
//void AddKeyShortLongPressScan ();//增加按键短按长按扫描函数
//void DecKeyShortLongPressScan ();//减少按键短按长按扫描函数
//extern uint KeyScan ();//带有按键返回值的按键扫描函数
void KeyScanResult();//按键扫描结果函数
#endif 

Digitron.c

#include "Digitron.h"
#include "Key.h"
//#include "Uart.h"
#include "Timer0.h" 
#include "TM1638OfI2C.h"
#define uchar unsigned char//自定义无符号字符型为uchar
#define uint unsigned int//自定义无符号整数型为uint
//uchar code DigitronBitCodeArray[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};//定义八位共阴数码管位码数组变量 为什么不是{0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f} 这才是定义八位共阴数码管位码数组变量 不对吗? 在不使用NPN三极管驱动 用单片机端口直接连接驱动 位码数组是对的 但数码管亮度不够 因此使用了NPN型三极管(比如S8050)来驱动共阴数码管位选 NPN型三极管(比如S8550)基极输入高电平才能导通 解释:共阴数码管 阴极是公共端 对应位选 低电平选通 阳极是显示端 对应段选 高电平选通 由于共阴数码管阴极公共端接单片机来驱动共阴数码管阳极显示端 共阴数码管的亮度会比较低 需要借助NPN型三极管的集电极连接共阴数码管阴极公共端 而NPN型三极管的基电极串个限流电阻连接单片机端口 通过单片机端口输出高电平到NPN型三极管的基电极 从而导通NPN型三极管 放大流过共阴数码管的电流 这样共阴数码管的亮度才会比较亮    
uchar code DigitronSegmentCodeArray[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x40,0x00};//定义共阴数码管显示0到F数据及符号“—”及熄灭数组变量
//uchar code DigitronSegmentCodeOfPointArray[] = {0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef,0xf7,0xfc,0xb9,0xde,0xf9,0xf1,0x40,0x00};//定义带小数点共阴数码管显示0.到F.数据及符号“—”及熄灭数组变量
//uchar code DigitronBitCodeArray[] = {0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//定义八位共阳数码管位码数组变量 为什么不是{0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80} 这才是定义八位共阳数码管位码数组变量 不对吗? 在不使用PNP三极管驱动 用单片机端口直接连接驱动 位码数组是对的 但数码管亮度不够 因此使用了PNP型三极管(比如S8550)来驱动共阳数码管位选 PNP型三极管(比如S8550)基极输入低电平才能导通 解释:共阳数码管 阳极是公共端 对应位选 高电平选通 阴极是显示端 对应段选 低电平选通 由于共阳数码管阳极公共端接单片机来驱动共阳数码管阴极显示端 共阳数码管的亮度会比较低 需要借助PNP型三极管的集电极连接共阳数码管阳极公共端 而PNP型三极管的基电极串个限流电阻连接单片机端口 通过单片机端口输出低电平到PNP型三极管的基电极 从而导通PNP型三极管 由外接电源来驱动共阳数码管 这样共阳数码管的亮度才会比较亮    
//uchar code DigitronBitCodeArray[] = {0x08,0x04,0x02,0x01,0x80,0x40,0x20,0x10};//定义八位共阳数码管位码数组变量
//uchar code DigitronSegmentCodeArray[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0xbf,0xff};//定义共阳数码管显示0到F数据及符号“—”及熄灭数组变量
//uchar code DigitronSegmentCodeOfPointArray[] = {0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0x08,0x03,0x46,0x21,0x06,0x0e,0xbf,0xff};//定义带小数点共阳数码管显示0.到F.数据及符号“—”及熄灭数组变量
//uchar DigitronSegmentCode = 0;//定义共阳数码管段码变量为0
uchar DigitronSegmentCode = 0;//定义共阴数码管段码变量为0
//uchar DigitronBitCode = 0;//定义共阳数码管位码变量为0
//uchar DigitronCacheDataArray[] = {0,0,0,0};//定义共阳数码管缓存数据数组变量
uchar DigitronCacheDataArray[] = {0,0,0,0};//定义共阴数码管缓存数据数组变量
//uchar DigitronBootTimerFlag = 1;//定义共阳数码管开机时间标志位变量 
uchar DigitronBootTimerFlag = 1;//定义共阴数码管开机时间标志位变量 
uint  DigitronBootTimer = 0;//定义数码管开机时间变量
//uint KeyPressNumber = 0;//定义按键按下数值变量
//extern uchar Data;//取用外部定义的数据变量
//extern uint KeyPressNumber;//如果在Key.c文件下已经定义按键按下数值变量KeyPressNumber 则以此语句来引用Key.c文件下的按键按下数值变量KeyPressNumber 否则先在Key.c文件下定义按键按下数值变量KeyPressNumber 接着在Key.h文件下的用extern关键字声明按键按下数值变量KeyPressNumber 最后通过在其他.c文件下#include "Key.h" 就可以引用在Key.c文件下已经定义的按键按下数值变量KeyPressNumber
  void DigitronBootDisplay()//数码管开机显示函数
{
   do
  {
    //if(DigitronBootTimer == 500 )//如果数码管开机时间等于1s
    LED0 = ~ LED0;//LED灯亮灭更新
   }while(DigitronBootTimer <= 500);//当数码管开机时间小于5s
   DigitronBootTimerFlag = 0;//数码管开机时间标志位清0
   LED0 = 1;//LED灯熄灭
  }
  void DigitronDisplayDataSplit()//数码管显示数据分解函数
{
   DigitronCacheDataArray[0] = KeyPressNumber / 1000;//数码管千位数据显示
   DigitronCacheDataArray[1] = KeyPressNumber / 100 % 10;//数码管百位数据显示
   DigitronCacheDataArray[2] = KeyPressNumber / 10 % 10;//数码管十位数据显示
   DigitronCacheDataArray[3] = KeyPressNumber % 10;//数码管个位数据显示
	 
//	 DigitronCacheDataArray[0] = Data / 1000;//数码管千位数据显示
//   DigitronCacheDataArray[1] = Data / 100 % 10;//数码管百位数据显示
//   DigitronCacheDataArray[2] = Data / 10 % 10;//数码管十位数据显示
//   DigitronCacheDataArray[3] = Data % 10;//数码管个位数据显示
  if(KeyPressNumber < 1000)//如果累积时间变量小于1000
 {
   DigitronCacheDataArray[0] = 17;//数码管千位数据不显示
  }
  else
 {
   DigitronCacheDataArray[0] = KeyPressNumber / 1000;//数码管千位数据显示
  }
  if(KeyPressNumber < 100)//如果累积时间变量小于100
 {
   DigitronCacheDataArray[1] = 17;//数码管百位数据不显示
  }
  else
 {
   DigitronCacheDataArray[1] = KeyPressNumber / 100 % 10;//数码管百位数据显示
  }
  if(KeyPressNumber < 10)//如果累积时间变量小于10
 {
   DigitronCacheDataArray[2] = 17;//数码管十位数据不显示
  }
  else
 {
   DigitronCacheDataArray[2] = KeyPressNumber / 10 % 10;//数码管十位数据显示
  }
  DigitronCacheDataArray[3] = KeyPressNumber % 10;//数码管个位数据显示
 }
  void DigitronDisplayData()//数码管显示数据函数  
{  
   static uchar i = 0;//定义静态数码管管位变化变量
//   DigitronSegmentCode = 0xff;//数码管段码消影
//   DigitronBitCode = 0xff;//数码管位码消影
   switch(i)//数码管管位变化筛选
 {
    case 0 ://数码管千位显示
//            DigitronSegmentCode = 0xff;//数码管段码消影
            DigitronSegmentCode = DigitronSegmentCodeArray[DigitronCacheDataArray[0]];//数码管千位的段码显示
//            DigitronBitCode = DigitronBitCodeArray[0];//数码管千位码显示
            TM1638RegularDisplay(0xc0, DigitronSegmentCode);//TM1638键盘数码管模块第四个数码管固定显示数码管千位的段码
//            SN74HC595SendData16Bit(DigitronSegmentCode,DigitronBitCode);//SN74HC595发送数据给4个数码管的段和位函数
            i++;//数码管管位变化自加1
            break;//跳出
    case 1 ://数码管百位显示
//            DigitronSegmentCode = 0xff;//数码管段码消影
            DigitronSegmentCode = DigitronSegmentCodeArray[DigitronCacheDataArray[1]];//数码管百位的段码显示
//            DigitronBitCode = DigitronBitCodeArray[1];//数码管百位码显示
            TM1638RegularDisplay(0xc2, DigitronSegmentCode);//TM1638键盘数码管模块第三个数码管固定显示数码管百位的段码
//            SN74HC595SendData16Bit(DigitronSegmentCode,DigitronBitCode);//SN74HC595发送数据给4个数码管的段和位函数
            i++;//数码管管位变化自加1
            break;//跳出 
    case 2 ://数码管十位显示
//            DigitronSegmentCode = 0xff;//数码管段码消影
            DigitronSegmentCode = DigitronSegmentCodeArray[DigitronCacheDataArray[2]];//数码管十位的段码显示
//            DigitronBitCode = DigitronBitCodeArray[2];//数码管十位码显示
            TM1638RegularDisplay(0xc4, DigitronSegmentCode);//TM1638键盘数码管模块第二个数码管固定显示数码管十位的段码
//            SN74HC595SendData16Bit(DigitronSegmentCode,DigitronBitCode);//SN74HC595发送数据给4个数码管的段和位函数
            i++;//数码管管位变化自加1
            break;//跳出
    case 3 ://数码管个位显示
//            DigitronSegmentCode = 0xff;//数码管段码消影
            DigitronSegmentCode = DigitronSegmentCodeArray[DigitronCacheDataArray[3]];//数码管个位的段码显示
//            DigitronBitCode = DigitronBitCodeArray[3];//数码管个位码显示
            TM1638RegularDisplay(0xc6, DigitronSegmentCode);//TM1638键盘数码管模块第一个数码管固定显示数码管个位的段码
//            SN74HC595SendData16Bit(DigitronSegmentCode,DigitronBitCode);//SN74HC595发送数据给4个数码管的段和位函数
            i = 0;//数码管管位变化清0
            break;//跳出
    default:break;//跳出
   }
  }

Digitron.h

#ifndef  _DIGITRON_H
#define  _DIGITRON_H
#include "STC12C5A60S2.h"
#define uchar unsigned char//自定义无符号字符型为uchar
#define uint unsigned int//自定义无符号整数型为uint
//#define DigitronSegmentCode P0//自定义共阳数码管段码端口为单片机P0组引脚
//#define DigitronBitCode P2//自定义共阳数码管位码端口为单片机P2组引脚
sbit LED0 = P1^0;//位定义LED灯为单片机P1.0脚
//extern uchar DigitronSegmentCode;//声明共阳数码管段码变量
extern uchar DigitronSegmentCode;//声明共阴数码管段码变量
//extern uchar DigitronBitCode;//声明共阳数码管位码变量
//extern uchar code DigitronBitCodeArray[];//声明八位共阳数码管位码数组变量 可被其他.c文件通过#include "其他.h"引用该变量
//extern uchar code DigitronSegmentCodeArray[];//声明共阳数码管显示0到F数据及符号“—”及熄灭数组变量 可被其他.c文件通过#include "其他.h"引用该变量
extern uchar code DigitronSegmentCodeArray[];//声明共阴数码管显示0到F数据及符号“—”及熄灭数组变量 可被其他.c文件通过#include "其他.h"引用该变量
//extern uchar DigitronCacheDataArray[];//声明共阳数码管缓存数据数组变量 可被其他.c文件通过#include "其他.h"引用该变量
extern uchar DigitronCacheDataArray[];//声明共阴数码管缓存数据数组变量 可被其他.c文件通过#include "其他.h"引用该变量
//extern uchar DigitronBootTimerFlag;//声明共阳数码管开机时间标志位变量 可被其他.c文件通过#include "其他.h"引用该变量
extern uchar DigitronBootTimerFlag;//声明共阴数码管开机时间标志位变量 可被其他.c文件通过#include "其他.h"引用该变量
extern uint DigitronBootTimer;//声明数码管开机时间变量 可被其他.c文件通过#include "其他.h"引用该变量
//extern uint KeyPressNumber;//声明按键按下数值变量 可被其他.c文件通过#include "其他.h"引用该变量
void DigitronBootDisplay();//声明数码管开机显示函数
void DigitronDisplayDataSplit();//声明数码管显示数据分解函数
void DigitronDisplayData();//声明数码管显示数据函数
#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();//数码管显示数据函数
//    SetKeyScan();//设置按键扫描函数 该函数放在定时器定时2ms的中断函数中扫描
	KeyScan();//按键扫描函数 该函数放在定时器定时2ms的中断函数中扫描
   }
   TH0 = 0xf8;//设定定时器0计数高8位初值
   TL0 = 0x30;//设定定时器0计数低8位初值
   TR0 = 1;//开定时器0开关
  }

Timer0.h

#ifndef  _TIMER0_H
#define  _TIMER0_H
#include "STC12C5A60S2.h"
#define uchar unsigned char//自定义无符号字符型为uchar
#define uint unsigned int//自定义无符号整数型为uint
void Timer0Init();//声明定时器0初始化函数
#endif 

TM1638键盘数码管模块的数码管显示与单片机连接的按键的按键值实验现象

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/647762.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【设计模式】JAVA Design Patterns——Static Content Hosting(静态内容托管模式)

&#x1f50d;目的 将静态内容部署到基于云的存储服务&#xff0c;该服务可以将它们直接交付给客户端。 这可以减少对昂贵计算实例的需求。 &#x1f50d;解释 真实世界例子 全球性的营销网站&#xff08;静态内容&#xff09;需要快速的部署以开始吸引潜在的客户。为了将托管…

【STL】C++ vector基本使用

目录 一 vector常见构造 1 空容器构造函数&#xff08;默认构造函数&#xff09; 2 Fill 构造函数 3 Range 构造函数 4 拷贝构造函数 5 C11构造 二 vector迭代器 1 begin && end 2 rbegin && rend 3 补充排序 三 vector 容量操作 1 size 2 resize …

Gin框架学习笔记(六)——gin中的日志使用

gin内置日志组件的使用 前言 在之前我们要使用Gin框架定义路由的时候我们一般会使用Default方法来实现&#xff0c;我们来看一下他的实现&#xff1a; func Default(opts ...OptionFunc) *Engine {debugPrintWARNINGDefault()engine : New()engine.Use(Logger(), Recovery())…

探秘SpringBoot默认线程池:了解其运行原理与工作方式(@Async和ThreadPoolTaskExecutor)

文章目录 文章导图Spring封装的几种线程池SpringBoot默认线程池TaskExecutionAutoConfiguration&#xff08;SpringBoot 2.1后&#xff09;主要作用优势使用场景如果没有它 2.1版本以后如何查看参数方式一&#xff1a;通过Async注解--采用ThreadPoolTaskExecutordetermineAsync…

LiveGBS流媒体平台GB/T28181用户手册-基础配置:信令服务配置、流媒体服务配置、白名单、黑名单、更多配置

LiveGBS流媒体平台GB/T28181用户手册-基础配置:信令服务配置、流媒体服务配置、白名单、黑名单、更多配置 1、基础配置1.1、信令服务配置1.2、白名单1.3、黑名单1.4、流媒体服务配置 2、搭建GB28181视频直播平台 1、基础配置 LiveGBS相关信令服务配置和流媒体服务配置都在这里…

React 中Redux结合React-Redux使用类组件版本(一)

一、Redux是什么&#xff1f; 1.Redux是一个专门用于状态管理的js库 2.它可以用在React、Angular、Vue的项目中&#xff0c;但基本与React配合使用。 3.作用&#xff1a;集中式管理React应用中多个组件共享的状态。 二、Redux 工作流程 三、Redux的三个核心概念 1.action 动…

在AndroidStudio创建虚拟手机DUB-AI20

1.DUB-AI20介绍 DUB-AL20是华为畅享9全网通机型。 华为畅享9采用基于Android 8.1定制的EMUI 8.2系统&#xff0c;最大的亮点是配置了1300万AI双摄、4000mAh大电池以及AI人脸识别功能&#xff0c;支持熄屏快拍、笑脸抓拍、声控拍照、手势拍照等特色的拍照功能&#xff0c;支持移…

搭建属于自己的 Git 仓库:GitLab

搭建属于自己的 Git 仓库&#xff1a;使用 GitLab 文章目录 搭建属于自己的 Git 仓库&#xff1a;使用 GitLab什么是 GitLab&#xff1f;准备工作安装 Docker使用Docker Compose 快速构建GitLab1、从docker compose快速搭建GitLab2、部署到服务器并访问3、浏览器访问 在现代软件…

Ant Design pro 6.0.0 搭建使用以及相关配置

一、背景 在选择一款比较合适的中台的情况下&#xff0c;挑选了有arco design、ant design pro、soybean、vue-pure-admin等中台系统&#xff0c;经过筛选就选择了ant design pro。之前使用过arco design 搭建通过组件库拼装过后台管理界面&#xff0c;官方文档也比较全&#…

数据库SQL语言实战(十)(最后一篇)

目录 前言 练习题 实验八 实验九 题目一 题目二 总结 前言 本篇练习题的重点有两个&#xff1a; 一、测试提交commit和回滚rollback的作用,了解锁等待、授权等知识。 二、学会复制表结构、学会插入数据&#xff0c;特别是学会如何避免重复插入&#xff0c;也就是如何避…

I2C SPI UART TCP/UDP AD/DA PWM大总结

I2C SPI UART TCP/UDP AD/DA PWM大总结 1. I2C总线描述1.1 基础协议内容1.1.1 通信时序1.1.2 一般通讯时序1.1.3 Burst模式 2. SPI总线2.1 基础协议内容 3. UART4. TCP/UDP5. AD/DA5.1 AD的原理5.2 DA的原理 6. PWM 1. I2C总线描述 I2C的特点&#xff1a;半双工&#xff0c;同步…

起保停电路工作原理

一、电路组成 起保停电路由电源保护设备&#xff08;空气开关&#xff09;、交流接触器、启动按钮、停止按钮和用电设备组成。 起保停电路的组成部分通常可分为四个部分&#xff1a; 保护部分&#xff1a;&#xff08;空气开关&#xff09;在电流或电压超出一定范围时自动切断…

计网期末复习指南:物理层(物理层的任务、香农公式、常用信道复用技术)

前言&#xff1a;本系列文章旨在通过TCP/IP协议簇自下而上的梳理大致的知识点&#xff0c;从计算机网络体系结构出发到应用层&#xff0c;每一个协议层通过一篇文章进行总结&#xff0c;本系列正在持续更新中... 计网期末复习指南&#xff08;一&#xff09;&#xff1a;计算机…

SpringBoot学习小结之RocketMQ

文章目录 前言一、架构设计1.1 架构图1.2 消息1.3 工作流程 二、部署2.1 单机2.2 集群 三、Springboot Producter3.1 准备3.2 pom依赖、yml 配置3.3 普通消息3.4 顺序、批量、延迟消息3.5 事务消息 四、Springboot Consumer4.1 配置4.2 普通Push消费4.3 回复4.4 集群和广播4.5 …

兆原数通基于Apache SeaTunnel的探索实践

随着大数据技术的不断发展&#xff0c;数据同步工具在企业中的应用变得愈发重要。为了满足复杂多样的业务需求&#xff0c;找到一款高效、灵活的数据同步工具变得尤为关键。 在这篇文章中&#xff0c;我们将分享兆原数通研发经理李洪军对Apache SeaTunnel的选择、应用及经验。这…

蓝桥杯物联网竞赛_STM32L071KBU6_关于size of函数产生的BUG

首先现象是我在用LORA发送信息的时候&#xff0c;左边显示长度是8而右边接收到的数据长度却是4 我以为是OLED显示屏坏了&#xff0c;又或者是我想搞创新用了const char* 类型强制转换数据的原因&#xff0c;结果发现都不是 void Function_SendMsg( unsigned char* data){unsi…

【代码随想录】动态规划经典题

前言 更详细的在大佬的代码随想录 (programmercarl.com) 本系列仅是简洁版笔记&#xff0c;为了之后方便观看 做题步骤 含义公式初始化顺序检查 确定dp数组以及下标的含义递推公式dp数组如何初始化遍历顺序打印dp数组&#xff08;看哪里有问题&#xff09; 斐波那契数 c…

高性能推理框架漫谈

传统模型分布式推理框架 Tensorflow servingPytorch ServingTriton Server 大语言模型的推理框架 其中&#xff0c; VLLM 后端接入了Ray 框架&#xff0c; 作为调度请求的分发处理&#xff1b;除此之外&#xff0c;还包括Nvidia 最新推出的TensorRT-LLM&#xff0c; 增加了对…

若依 ruoyi-vue 用户账号前后端参数校验密码 手机号 邮箱

前端 <el-dialog :title"title" :visible.sync"open" width"800px" append-to-body><el-form ref"form" :model"form" :rules"rules" label-width"120px"><el-row><el-col :span…

IOT技术怎么落地?以宝马,施耐德为例

物联网技术 物联网&#xff08;IoT&#xff09;技术正逐渐成为数字化工厂转型的核心驱动力。本文将通过实际案例&#xff0c;探讨IoT技术如何促进制造业的数字化转型&#xff0c;提高生产效率&#xff0c;降低成本&#xff0c;并提升产品质量。 1. 物联网技术简介 物联网技术通…