#include <reg51.h>
#include <math.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
#define CH451_NOP 0x0000 // 空操作
#define CH451_RESET 0x0201 // 复位
#define CH451_LEVEL 0x0100 // 加载光柱值,需另加7位数据
#define CH451_CLR_BIT 0x0180 // 段位清0,需另加6位数据
#define CH451_SET_BIT 0x01C0 // 段位置1,需另加6位数据
#define CH451_SLEEP 0x0202 // 进入睡眠状态
#define CH451_LEFTMOV 0x0300 // 设置移动方式-左移
#define CH451_LEFTCYC 0x0301 // 设置移动方式-左循环
#define CH451_RIGHTMOV 0x0302 // 设置移动方式-右移
#define CH451_RIGHTCYC 0x0303 // 设置移动方式-右循环
#define CH451_SELF_BCD 0x0380 // 自定义BCD码,需另加7位数据
#define CH451_SYSOFF 0x0400 // 关闭显示、关闭键盘
#define CH451_SYSON1 0x0401 // 开启显示
#define CH451_SYSON2 0x0403 // 开启显示、键盘
#define CH451_SYSON2W 0x0423 // 开启显示、键盘, 真正2线接口
#define CH451_NO_BCD 0x0500 // 设置默认显示方式,可另加3位扫描极限
#define CH451_BCD 0x0580 // 设置BCD译码方式,可另加3位扫描极限
#define CH451_TWINKLE 0x0600 // 设置闪烁控制,需另加8位数据
#define CH451_GET_KEY 0x0700 // 获取按键,返回按键代码
#define CH451_DIG0 0x0800 // 数码管位0显示,需另加8位数据
#define CH451_DIG1 0x0900 // 数码管位1显示,需另加8位数据
#define CH451_DIG2 0x0a00 // 数码管位2显示,需另加8位数据
#define CH451_DIG3 0x0b00 // 数码管位3显示,需另加8位数据
#define CH451_DIG4 0x0c00 // 数码管位4显示,需另加8位数据
#define CH451_DIG5 0x0d00 // 数码管位5显示,需另加8位数据
#define CH451_DIG6 0x0e00 // 数码管位6显示,需另加8位数据
#define CH451_DIG7 0x0f00 // 数码管位7显示,需另加8位数据1
sbit CH451_DCLK = P2^4; // 串行数据时钟上升沿激活
sbit CH451_DIN = P2^5; // 串行数据输出,接CH451的数据输入
sbit CH451_LOAD = P2^6; // 串行命令加载,上升沿激活
sbit CH451_DOUT = P2^7; // INT1,键盘中断和键值数据输入,接CH451的数据输出
sfr P5 = 0xC8; //xxxx,1111 端口5
sfr P4 = 0xC0; //1111,1111 端口4
sbit sp=P4^5; //蜂鸣器
uint Data=9999; // 显示初值,Data的值决定开机显示数值
uchar count = 0;
uint z = 0;
uint temp = 0;
uchar ch451_key=0; // 存放键盘中断中读取的键值
uchar key=0x00;
code uchar table[]={0xBD,0x18,0xD5, //0,1,2,
0xD9,0x78,0xE9, //3,4,5,
0xED,0x98,0xFD,0xF9}; //6,7,8,9
void speaker(void)//蜂鸣器响起
{
uint i,j;
for(j=0;j<250;j++)
{
for(i=0;i<2000;i++)
{
sp=0;
}
for(i=0;i<3000;i++)
{
sp=1;
}
}
sp=1;
}
void delayms(uint xms) //延时子程序
{
uint i,j;
for(i=xms;i>0;i--)
for(j=110;j>0;j--); //延时
}
/*****************写命令时序************************************/
void CH451_write(uint command) //定义一无符号整型变量存储12字节的命令字
{
uchar i;
CH451_LOAD=0;
for(i=0;i<12;i++)
{
CH451_DIN = command&1;
CH451_DCLK =0;
command>>=1;
CH451_DCLK=1;
delayms(10);
}
CH451_LOAD=1;
}
/*****************初始化子程序************************************/
void CH451_init()
{
CH451_write(CH451_RESET); //CH451复位
CH451_write(CH451_SYSON2 );//开启显示、键盘
CH451_write(CH451_NO_BCD);// 设置默认显示方式
CH451_write(CH451_TWINKLE); //设置闪烁控制--正常显示
}
/*****************显示数码管************************************/
void display()
{
temp = Data / 1000;
CH451_write(CH451_DIG4 | table[temp]);
temp = (Data / 100)%10;
CH451_write(CH451_DIG5 | table[temp]);
temp = (Data / 10)%10;
CH451_write(CH451_DIG6 | table[temp]);
temp = Data % 10;
CH451_write(CH451_DIG7 | table[temp]);
}
/********************读取按键中断子程序*****************************/
void gerkey()
{
uchar i; //定义循环变量
uchar command,keycode; //定义控制字寄存器,和中间变量定时器
command=0x07; //读取键值命令的高4位0111B
CH451_LOAD=0; //命令开始
for(i=0;i<4;i++)
{
CH451_DIN=command&1; //低位在前,高位在后
CH451_DCLK=0;
command>>=1; //右移一位
CH451_DCLK=1; //产生时钟上升沿锁通知CH451输入位数据
}
CH451_LOAD=1; //产生加载上升沿通知CH451处理命令数据
keycode=0; //清除keycode
for(i=0;i<7;i++)
{
keycode<<=1; //数据作移一位,高位在前,低位在后
keycode|=CH451_DOUT; //从高到低读入451的数据
CH451_DCLK=0; //产生时钟下升沿通知CH451输出下一位
CH451_DCLK=1;
}
ch451_key=keycode; //保存上次的键值
}
/********************按键扫描子程序*****************************/
void keyscan() //键盘扫描子程序
{
while(1)
{
gerkey();
switch(ch451_key)//按键判断
{
case 0x47://keyG
{
Data++; //Data+1
if(Data>=10000) //限制Data的取值范围
{
Data=9999; //最大显示9999
}
display();
while(ch451_key==0x47) gerkey();
}break;
case 0x46://keyS
{
Data=Data+10; //Data+10
if(Data>=10000) //限制Data的取值范围
{
Data=9999; //最大显示9999
}
display();
while(ch451_key==0x46) gerkey();
}break;
case 0x45://keyB
{
Data=Data+100; //Data+100
if(Data>=10000) //限制Data的取值范围
{
Data=9999; //最大显示9999
}
display();
while(ch451_key==0x45)gerkey();
}break;
case 0x44://keyQ
{
Data=Data+1000; //Data+1000
if(Data>=10000) //限制Data的取值范围
{
Data=9999; //最大显示9999
}
display();
while(ch451_key==0x44)gerkey();
} break;
case 0x4c://keyF
{
Data=0; //复位,显示0000
display();
while(ch451_key==0x4c)gerkey();
}break;
case 0x4d://keyU
{
z=1;
while(ch451_key==0x4e)gerkey();
} break;
case 0x4e://keyK
while(ch451_key==0x4e)gerkey();
break;
}
}
}
void start_timer0() //开中断子程序
{
TMOD=0x01; //定时器0工作方式1
EA = 1; //开启中断总开关
TR0 = 1;//开启T0
ET0 = 1;//打开T0中断开关
}
void stop_timer0() //关中断子程序
{
TR0 = 0;
ET0 = 0;
TF0 = 0;//定时器/计数器0的溢出中断标志位,当T0从初值开始加一计数到产生溢出时,由硬件使TF0置1,直到CPU响应中断由硬件复位
}
void timer0() interrupt 1 //倒计时中断程序timer0,不用调用stop_timer0函数,TF0会自动置0,interrupt 后面的数字表示使用的寄存器组
{
TH0=(65536-9216)/256; //50ms产生一次中断
TL0=(65536-9216)%256;
while (Data!=0)
{
if(z==1)//单位为分
{
display();
count++;
if(count==1200)
{
count=0;
Data--;
}
}
else//默认单位为秒
{
display();
count++;
if(count==20)
{
count=0;
Data--;
}
}
}
}
void main()
{
CH451_init(); //数码管中断初始化
display();
while(1)
{
gerkey();
keyscan(); //键盘输入初值
stop_timer0();
start_timer0();
TR0=0;
if(Data == 0)
{
speaker();
}
}
}
|