/************* 本程序功能說明 **************
用STC的MCU的IO方式控制74HC595驅動8位數碼管。
采用定時器0產生時鐘時間
編寫者:dengchao
MCU: STC12C2052AD-DIP20
OSC:11.0592MHz
實現功能:三個按鍵效時,可以實現加或減1;連續加減
調整時,相應內部閃爍
特點:無需任何延時函數,
一個定時實現按鍵消抖和不同時間的產生
總只需6個IO口
程序核心思路:圍繞一個1MS的核心來產生什么何時間
******************************************/
#include "reg51.h"
//新一代 1T 8051系列 單片機系統管理特殊功能寄存器
// 7 6 5 4 3 2 1 0 Reset Value
//sfr PCON = 0x87; //Power Control SMOD SMOD0 LVDF POF GF1 GF0 PD IDL 0001,0000
// 7 6 5 4 3 2 1 0 Reset Value
sfr AUXR = 0x8E; //Auxiliary Register T0x12 T1x12 UART_M0x6 BRTR S2SMOD BRTx12 EXTRAM S1BRS 0000,0000
//-----------------------------------
sfr AUXR1 = 0xA2; //Auxiliary Register 1 - PCA_P4 SPI_P4 S2_P4 GF2 ADRJ - DPS 0000,0000
/************* 本地常量聲明 **************/
unsigned char code duan[]={
// 0 1 2 3 4 5 6 7 8 9 A B C D E F 消隱
0x3F,0x06,0x5B,0x4f,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,0x00}; //段碼
unsigned char code wei[]={0x01,0x02,0x04,0x08}; //位碼
//秒 分 時
unsigned char y3,y4,y5,y6,k1,k2,k3,k4,k5,i,sec,minu,hour;
unsigned int j,sw1,sw2;
/************* 本地變量聲明 **************/
sbit sh_cp = P3^7; //pin 11 SRCLK Shift datala clock
sbit st_cp = P3^5; //pin 12 RCLk store (latch) clock
sbit ds = P3^4; //pin 14 SER datala input
void display(void); //595驅動數碼管動態顯示函數
void disp595(unsigned char datal); //寫一個字節到595芯片
void display1(void); //顯示緩沖區
sbit key1 = P3^2; //功能設置鍵
sbit key2 = P3^3; //加計數鍵
sbit key3 = P3^1; //減計數鍵
void time_out(void); //時、分、秒產生函數
void dinshiqi_init(void); //定時器初始化
void key1_scan(void); //三個獨立按鍵掃描
void key2_scan(void); //時、分加減函數判斷
void key3_scan(void); //時、分鍵按一下1S后,0.2S連續加減數據
unsigned char led_1111[4];//顯示緩沖
bit y1, y2; //20ms定時器標志
/******************主函數*****************/
void main(void)
{
dinshiqi_init(); //定時器初始化
for(i=0; i<4; i++)
led_1111[i] = 0x00; //上電消隱
y3 = 0;
while(1)
{
while(!y2) ; //等待20ms到
y2 = 0;
time_out();
display1();
key1_scan();
}
}
/****************定時器初始化函數******************/
void dinshiqi_init(void)
{
AUXR &= 0x7F; //定時器時鐘12T模式
TMOD &= 0xF0; //設置定時器模式
TMOD |= 0x01; //設置定時器模式
TH0 = (65536 - 922) / 256;
TL0 = (65536 - 922) % 256;
ET0 = 1;
TR0 = 1;
EA = 1;
sec = 0;
minu = 30;
hour = 12;
sw2 = 0;
k5 = 0; //時、分設置切換寄存器
y4 = 0; //加鍵或減鍵按1S的計時寄存器
}
/*************** 秒 分 時 產生函數**************/
void time_out(void)
{
sw1++;
if(sw1>50)
{
sw1 = 0;
sec++; //秒
if(sec>60)
{
sec = 0;
minu++; //分
if(minu>60)
{
minu = 0;
hour++; // 時
if(hour>24)
{
hour=0;
}
}
}
}
if(sw1>25)
y1 = 1; //0.5S閃爍產生和標志位
else
y1 = 0;
}
/****************顯示緩沖區函數******************/
void display1(void)
{
if(k5 == 0) //k5 = 0正常顯示
{
if(y1==1)
{
led_1111[0] = duan[hour/10]; //時
led_1111[1] = duan[hour%10];
led_1111[2] = duan[minu/10]; //分
led_1111[3] = duan[minu%10];
}
else
{
led_1111[0] = duan[hour/10] ;
led_1111[1] = duan[hour%10] ;
led_1111[2] = duan[minu/10] ;
led_1111[3] = duan[minu%10] ;
}
}
else
{
if(k5 == 1) //k5 = 1 時閃爍,進入“時”加減
{
if(y1==1)
{
led_1111[0] = duan[hour/10];
led_1111[1] = duan[hour%10];
}
else
{
led_1111[0] = duan[hour/10]&0x00;
led_1111[1] = duan[hour%10]&0x00;
}
led_1111[2] = duan[minu/10];
led_1111[3] = duan[minu%10];
}
if(k5 == 2) //k5 = 2 分閃爍,進入“分”加減
{
if(y1==1)
{
led_1111[2] = duan[minu/10];
led_1111[3] = duan[minu%10];
}
else
{
led_1111[2] = duan[minu/10]&0x80;
led_1111[3] = duan[minu%10]&0x80;
}
led_1111[0] = duan[hour/10];
led_1111[1] = duan[hour%10];
}
}
}
/***************595驅動數碼管動態顯示函數*******************/
void disp595(unsigned char datal) //發送一個字節
{
unsigned char i;
for(i=0; i<8; i++)
{
if(datal & 0x80)
ds = 1;
else
ds = 0;
sh_cp = 1;
sh_cp = 0;
datal = datal << 1;
}
}
/****************顯示掃描函數******************/
void display(void)
{
if(y1==1)
{
disp595(wei[y3]|0x20); //共陰 輸出位碼
}
else
{
disp595(wei[y3]|0x00); //共陰 輸出位碼
}
disp595(~led_1111[y3]); //共陰 輸出段碼
// disp595(wei[y3]); //共陽 輸出位碼
// disp595(~duan[LED8[y3]]); //共陽 輸出段碼
st_cp = 1;
st_cp = 0;
y3++;
if(y3>3)
{
y3 = 0;
}
}
/**************T0定時器函數****************/
void timer0 (void) interrupt 1 //Timer0 1ms中斷函數
{
TH0 = (65536 - 922) / 256; //重裝定時值
TL0 = (65536 - 922) % 256;
display(); //采用定時器0 1MS接一個數碼管,實現動態顯示
sw2++;
if(sw2>19)
{
sw2 = 0;
y2 = 1; //20ms標志
}
}
/******************三個獨立按鍵掃描*****************/
void key1_scan(void)
{
if(key1==0) k2 = 1; //功能鍵按下k2 = 1
if(key2==0) k2 = 2; //加鍵按下k2 = 2
if(key3==0) k2 = 3; //減鍵按下k2 = 3
if(key2&key3&key1) //三個按鍵都不按時,40MS后所有跟按鍵有關的寄存器清0
{
k4++;
if(k4>2) //40MS后所有跟按鍵有關的寄存器清0
{
k4 = 0;
k2 = 0;
k3 = 0;
y4 = 0;
y5 = 0;
}
}
else
{
if(k2!=k3) //k3 為按鍵消抖寄存器
{
k3 = k2;
if(k2==1)
{
k5++;
if(k5==3)
{
k5 = 0;
sec = 0;
}
}
key2_scan(); //按一次響應一次
}
key3_scan(); //加鍵或減鍵按1S后連續加或減數據
}
}
/*********** 時、分 鍵按一下1S后,0.2S連續加減數據**********/
void key3_scan(void)
{
if(y5==0)
{
if((k2==2)|(k2==3))
{
y4++;
if(y4>50)
{
y4 = 0;
y5 = 1;
}
}
}
if(y5==1) //1S到后,進入0.2s加減數據
{
y6++;
if(y6>10)
{
y6=0;
key2_scan();
}
}
}
/****************** 時、分 加減函數判斷****************/
void key2_scan(void)
{
if(k5==1)
{
if(k2==2)
{
hour++;
if(hour>23) //時
hour = 0;
}
if(k2==3)
{
if(hour==0)
hour = 23;
else
{
hour--;
}
}
}
if(k5==2)
{
if(k2==2)
{
minu++;
if(minu>59) //分
minu = 0;
}
if(k2==3)
{
if(minu==0)
minu = 59;
else
{
minu--;
}
}
}
}
|