忘了是用51单片机还是用国产的单片机做的了,模仿十来块钱的手表,功能几乎完全一样。
把当时实验的视频加上。
哈哈哈,其实是我大三上学习单片机的时候做的,好久没发了,完全复制分享下。
#include
#include
#define DEBUG
#ifdef DEBUG
int DebugNum=222;
#endif
#define uchar unsigned char
#define UP 80
#define DOWN 20
#define LEFT 40
#define RIGHT 60
#define NULL 0
uchar TimeDly=0; //定义闹钟延时单位秒
uchar key=0; //按键的键值
uchar flagm=0; //矩阵键盘扫描标志位
uchar count=0; //记菜单左键被按下的次数,相当于手边中左下一个键被按下
uchar ScanCount=0; //记录扫描的次数,输入时间用
//uchar MtCount=0; //定义矩阵键盘输入时间的次数
bit Flag=0; //按键是否按下标志
bit SecendFlag=1; //定义一个秒标志位,作用是没一秒,时和分之间的小数点闪一次
bit AlarmFlag=0; //闹钟时间到达标志位
bit RingFlag=0; //响铃标志位,让铃声可以是每秒响一次
//sbit ring=P1^0;
sbit ring=P3^4; //蜂鸣器
uchar year=16,month=1,day=3; //定义年月日变量
uchar ms10=0; //定义计时器变量,用定时器1
uchar chour=0;
uchar cmin=0;
uchar csecends=0;
uchar amin=1; //set alarm time and flag
uchar ahour=0;
uchar tm50=0; //定义时间寄存器,时分秒、50ms,250us
uchar tu250=0;
uchar secends=0;
uchar min=0;
uchar hour=0;
/* 定义数码管显示模块接口对应的端口 */
sbit DIG_DATA = P0^2; // 74HC595的数据输入引脚
sbit DIG_SHCP = P0^4; // 74HC595的移位脉冲引脚
sbit DIG_STCP = P2^3; // 74HC595的锁存脉冲引脚
/* 变量定义 */
unsigned char DigBuf[4]; //定义数码管显示缓冲区
code unsigned char Segment[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; // 数字段码,Segment[0]~Segment[9]分别对应数字0~9的段码
code unsigned char Select[] = {0xff,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; // 位选,Select[0]为全选,Select[1]~Select[8]分别对应第1位(最右侧)~第8位(最左侧)
code char change[17]={0,7,8,9,'1',4,5,6,'2',1,2,3,'3',0,'.','=','4'}; //按键键值检测转换表
code uchar loop[10][2]={0xfe,0x04,0xfe,0x02,0xfe,1,0xfd,1,0xfb,1,0xf7,1,0xf7,0x02,0xf7,0x04,0xef,0x04,0xdf,0x04}; //显示好看而已
uchar loops=0;
void DelayMs(int ms); //@12.000MHz
void Init(); //初始化定时器
void CheckLegal(); //检测各个时间值是否合法,如果不合法则复位
char ScanSg(); //扫描单按键 每次按键只返回一次1
char ScanMt(); //扫描矩阵按键 同上
void SetTime(uchar *hour,uchar *min);//设置时间
void ShowTime(); //显示时间
void ShowCount(); //显示计数器
void ShowAlarm(); //显示闹钟时间
void ShowData(); //显示日期
uchar ifleap(uchar years);//判断是否是瑞年
uchar maxday(uchar year,uchar month);/*每个月的天数*/
uchar week(uchar years,uchar month,uchar day); //输入年月日,返回星期几
void DigOutput(unsigned char SelectByte, unsigned char SegmentByte);//移出数据
void DigShowNumber(unsigned char DigSelect, unsigned char Number, bit Dp);//显示一个数
/*---------------------------------------------------------------------------------------------------------*/
/**********************************************
主函数,读取并显示DS18B20的温度
**********************************************/
void main()
{
Init();
while(1)
{
CheckLegal(); // 时间数据监测修正
if(ScanSg()) // 是否有按键事件
{
#ifdef DEBUG
DigShowNumber(1,key/10,0);
#endif
if(AlarmFlag)
AlarmFlag=0;
if(count)
{
if(count==1) //计时器
{
if(key==UP)
TR1=~TR1;
else if(key==DOWN || key==RIGHT) //清零
{
TR1=0;
ms10=0;
chour=0;
cmin=0;
csecends=0;
}
}
else if(count==2) //如果LEFT被按下两次对应功能为设置闹钟
{
SetTime(&ahour,&amin);
#ifdef DEBUG
while(DebugNum)
{
ShowAlarm();
DebugNum--;
DigShowNumber(1,key/10,0);
}
DebugNum=222;
#endif
}
else if(count==3) //如果LEFT被按下三次对应功能为设置时间
{
SetTime(&hour,&min);
}
else if(count==4) //如果按下四次,设置年月日
SetTime(&month,&day);
}
}
else if(count==1)
ShowCount();
else if(count==2)
{
ShowAlarm();
DigShowNumber(2,ScanCount+1,0);
}
else if(count==3)
{
ShowTime();
DigShowNumber(2,ScanCount+1,0);
}
else if(count==4)
{
ShowData();
DigShowNumber(1,ScanCount+1,0);
}
else if(key==UP && Flag==1) //show the alarm clock
ShowAlarm();
else if(key==DOWN && Flag==1) //undetermined 可以是日期,农历,星期几
ShowData();
else
ShowTime();
}
}
/**********************************************
功能:
中断计时
输入参数:
无
输出参数:
无
返回值:
**********************************************/
void intt0() interrupt 1
{
//TH0=0x3C; //50ms
//TL0=0xC0;
tu250++;
if(tu250==200)
{
if(AlarmFlag && RingFlag) //如果是闹钟时间并且可以响铃,取反蜂鸣器
ring = ~ring;
tu250=0;
tm50++;
if(tm50==20)
{
if(AlarmFlag) //如果为闹钟时间,则闹钟间隔一秒响应
RingFlag =~RingFlag;
else //否则全部清零,避免蜂鸣器在闹钟之后一直响
{
ring=0;
RingFlag = 0;
}
SecendFlag=~SecendFlag; //每秒小点闪烁一次
tm50=0;
secends++;
loops++;
if(loops==10)
loops=0;
if(TimeDly) //用一个时间每秒自减,直到运行时间剩余等于0,停止闹钟,消除标志位
{
TimeDly--;
if(!TimeDly)
AlarmFlag=0;
}
if(secends==60) //计时
{
min++;
if(hour==ahour && min==amin)
{
AlarmFlag=1;
TimeDly=30;
}
secends=0;
if(min==60)
{
hour++;
min=0;
if(hour==24)
{
hour=0;
day++;
if(day > maxday(year,month))
{
day=1;
month++;
if(month > 12)
{
month=1;
year++;
}
}
}
}
}
}
}
}
void intt1() interrupt 3
{
TH1=55536/256; //10ms计时器,用来做钟表的定时器功能
TL1=55536%256;
TR1=1;
ms10++;
if(ms10>=100)
{
ms10=0;
csecends++;
}
if(csecends>=60)
{
cmin++;
csecends=0;
}
if(cmin>=60)
{
chour++;
cmin=0;
}
if(chour>=24)
chour=0;
}
void DelayMs(int ms) //@12.000MHz
{
uchar i,j;
while(--ms)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
void CheckLegal() //检测各个时间值是否合法,如果不合法则复位
{
if(hour>24)
hour=0;
if(min>60)
min=0;
if(secends>60)
secends=0;
if(ahour>24)
hour=0;
if(amin>60)
min=0;
if(day>31)
day=0;
if(month>12)
{
year++;
month=0;
}
}
uchar ifleap(uchar years) //判断是否是瑞年
{
uchar leap;
int year=2000;
year += (int)years;
if(year%4==0)
{
if(year%100==0)
{
if(year%400==0)
leap=1;
else
leap=0;
}
else
leap=1;
}
else
leap=0;
return leap;
}
uchar maxday(uchar year,uchar month) /*计算一个月的最大天数*/
{
uchar leap,max;
leap=ifleap(year);
if(month==4 ||
month==6 ||
month==9 ||
month==11)
max=30;
else if(month==2 && leap==0)
max=28;
else if(month==2 && leap==1)
max=29;
else
max=31;
return max;
}
uchar week(uchar years,uchar month,uchar day) //输入年月日,返回星期几
{
uchar c,y,w;
int year=2000;
year += years;
if(month<3)
{
year=year-1;
month=month+12;
}
c=year/1000*10+(year-(year/1000)*1000)/100;
y=year-c*100;
w=y+y/4+c/4-2*c+26*(month+1)/10+day-1;
w=w%7;
if(w==0)
w=7;
return w;
}
/*************************************
*
*function: scan singe key down
*
*input: void
*
*out: if keydown return back 1,else 0
*
**************************************/
char ScanSg()
{
char temp=0x0F;
P1 = 0x0F;
if(Flag==1 && P1==0x0F)
Flag=0;
if(P1!=0x0F && Flag==0)
{
DelayMs(10);
if(P1!=0x0F)
{
Flag=1;
temp &= P1;
//TimeDly=speed;
switch(temp)
{
case(0X07): key=RIGHT; return 1;
case(0X0b): key=DOWN; return 1;
case(0X0d): key=UP; return 1;
case(0X0e):
key=LEFT;
count++;
if(count==5)
count=0;
return 1;
}
}
return 0;
}
else
return 0;
}
/*************************************
*
*function: scan muti key down
*
*input: void
*
*out: if keydown return back 1,else 0
*
**************************************/
char ScanMt()
{
char i;
char temp=0x0FE,count=0x0F0;
P1 = 0x0FE;
for(i=0; i<4; i++)
{
if(flagm==(1+i) && P1==temp)
flagm=0;
if(P1!=temp && flagm==0)
{
DelayMs(10);
if(P1!=temp)
{
flagm=i+1;
count &= P1;
//TimeDly=speed;
switch(count)
{
case(0X70): key=i*4+4; return 1;
case(0X0B0):key=i*4+3; return 1;
case(0X0D0):key=i*4+2; return 1;
case(0X0E0):key=i*4+1; return 1;
}
}
}
temp = _crol_(temp,1);
P1=temp;
count=0x0F0;
}
return 0;
}
void Init()
{
ring=0;
TMOD=0x12;
TH1=55536/256;
TL1=55536%256;
TH0=6; //0x3C
TL0=6; //0xC0
ET0=1;
ET1=1;
EA=1;
TR0=1;
}
/*---------------------------------------------------------------------------------------------------------*/
/* 数码管显示相关函数 */
/**********************************************
功能:
输出位选字节和段码字节
输入参数:
SelectByte: 位选字节
SegmentByte: 段码字节
输出参数:
无
返回值:
**********************************************/
void DigOutput(unsigned char SelectByte, unsigned char SegmentByte)
{
unsigned char i;
DIG_SHCP = 0; // 74HC595的移位脉冲引脚输出低电平
DIG_STCP = 0; // 74HC595的锁存脉冲引脚输出低电平
/* 将段码字节(共8位,高位在前)移入74HC595芯片 */
for(i=0; i<8; i++)
{
/* 判断数据的最高位,如果最高位是1,数据引脚输出高电平;如果是0,输出低电平 */
if(SegmentByte&0x80)
{
DIG_DATA = 1;
}
else
{
DIG_DATA = 0;
}
_nop_();
/* 输出74HC595芯片的数据移位脉冲,每输出一个移位脉冲,74HC595内部的数据移动一位 */
DIG_SHCP = 1;
_nop_();
DIG_SHCP = 0;
_nop_();
/* 要输出的数据左移一位,即为下一位数据的输出作准备 */
SegmentByte <<= 1;
}
/* 将位选字节(共8位,高位在前)移入74HC595芯片 */
for(i=0; i<8; i++)
{
if(SelectByte&0x80)
{
DIG_DATA = 1;
}
else
{
DIG_DATA = 0;
}
_nop_();
DIG_SHCP = 1;
_nop_();
DIG_SHCP = 0;
_nop_();
SelectByte <<= 1;
}
/* 输出74HC595芯片的数据锁存脉冲,即将74HC595芯片接收到的最新数据输出到芯片的所有数据引脚 */
DIG_STCP = 1;
_nop_();
DIG_STCP = 0;
_nop_();
}
/**********************************************
功能:
在某位显示数字
输入参数:
DigSelect: 数码管位选择(1——8,即最右到最左)
Number: 数字(0——9)
Dp: 小数点(1:显示;0:不显示)
输出参数:
无
返回值:
**********************************************/
void DigShowNumber(unsigned char DigSelect, unsigned char Number, bit Dp)
{
if((0
if(Dp)
{
DigOutput(Select[DigSelect],(Segment[Number]&~0x80)); //点亮小数点
}
else
{
DigOutput(Select[DigSelect],(Segment[Number]|0x80)); //熄灭小数点
}
}
}
void ShowTime()
{
DigShowNumber(8,hour/10,0);
DigShowNumber(7,hour%10,SecendFlag);
DigShowNumber(6,min/10,0);
DigShowNumber(5,min%10,0);
DigOutput(loop[loops][1],loop[loops][0]);
}
/*************************************
*
*function: show count time.min,secend,10ms
*
*input: void
*
*out: void
*
**************************************/
void ShowCount()
{
DigShowNumber(8,chour/10,0);
DigShowNumber(7,chour%10,1);
DigShowNumber(6,cmin/10,0);
DigShowNumber(5,cmin%10,1);
DigShowNumber(4,csecends/10,0);
DigShowNumber(3,csecends%10,1);
DigShowNumber(2,ms10/10,0);
DigShowNumber(1,ms10%10,0);
}
void ShowAlarm()
{
DigShowNumber(8,ahour/10,0);
DigShowNumber(7,ahour%10,1);
DigShowNumber(6,amin/10,0);
DigShowNumber(5,amin%10,0);
}
void ShowData()
{
uchar weekday;
weekday=week(year,month,day);
DigShowNumber(8,year/10,0);
DigShowNumber(7,year%10,1);
DigShowNumber(6,month/10,0);
DigShowNumber(5,month%10,1);
DigShowNumber(4,day/10,0);
DigShowNumber(3,day%10,0);
if(Flag)
DigShowNumber(1,weekday,0);
}
void SetTime(uchar *hour,uchar *min)
{
/***********加入的矩阵输入*****************
uchar temp; //矩阵键盘用
if(ScanMt())
{
temp = change[key];
if(0 <= temp <=9)
{
if(ScanCount==0)
*hour += 10*temp;
else if(ScanCount==1)
*hour = temp;
else if(ScanCount==2)
*min += 10*temp;
else
*min=temp;
ScanCount++;
if(ScanCount==4)
ScanCount=0;
}
}
*******************************************/
if(key==UP)
{
switch(ScanCount)
{
case 0: (*min)++; break;
case 1: (*min) += 10; break;
case 2: (*hour)++; break;
case 3: (*hour) += 10; break;
}
}
else if(key==DOWN)
{
switch(ScanCount)
{
case 0: (*min)--; break;
case 1: (*min) -= 10; break;
case 2: (*hour)--; break;
case 3: (*hour) -= 10; break;
}
}
else if(key==RIGHT)
{
ScanCount++;
if(ScanCount==4)
ScanCount=0;
}
}