/************* 本程序功能说明 **************
用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--;
}
}
}
}
|