#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();
}
}
}
|