单片机自制时钟(可实现年月日星期时分秒显示、按键校准)
/*RS->p1.0;RW->p1.1;EN->p2.5;A->VCC;K->GND*/
/*K1->P3.4;K2->p3.5;K3->p3.6 */
/*晶振11.0592M */
/*Edited by Feng */
/*2021/8/8 */
/*功能:可显示年、月、日、时分秒、星期 */
#include<reg52.h>
#include<intrins.h>
sbit EN = P2^5;
sbit RS = P1^0;
sbit RW = P1^1;
sbit SET_TIME_BIT_KEY = P3^4;
sbit INC_BIT_NUM_KEY = P3^5;
sbit END_CHANGE_TIME = P3^6;
#define DataPort P0
#define RS_CLR RS=0
#define RS_SET RS=1
#define RW_CLR RW=0
#define RW_SET RW=1
#define EN_CLR EN=0
#define EN_SET EN=1
bit ending;
int year;
unsigned char count,second,minute,hour,date,month,week,display_time[14];
unsigned char character[10]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39};
unsigned char double_dot[8]={0x00,0x08,0x00,0x00,0x00,0x08,0x00,0x00};
unsigned char week_group[7][3]={{'S','u','n'},{'M','o','n'},{'T','u','e'},{'W','e','d'},{'T','h','u'},{'F','r','i'},{'S','a','t'}};
unsigned char days_num_this_month[12]={31,28,31,30,31,30,31,31,30,31,30,31};
/*------------------------------------------------
uS延时函数,含有输入参数 unsigned char t,无返回值
unsigned char 是定义无符号字符变量,其值的范围是
0~255 这里使用晶振12M,精确延时请使用汇编,大致延时
长度如下 T=tx2+5 uS
------------------------------------------------*/
void DelayUs2x(unsigned char t)
{
while(--t);
}
/*------------------------------------------------
mS延时函数,含有输入参数 unsigned char t,无返回值
unsigned char 是定义无符号字符变量,其值的范围是
0~255 这里使用晶振12M,精确延时请使用汇编
------------------------------------------------*/
void DelayMs(unsigned char t)
{
while(t--)
{
//大致延时1mS
DelayUs2x(245);
DelayUs2x(245);
}
}
/*------------------------------------------------
判忙函数
------------------------------------------------*/
bit LCD_Check_Busy(void)
{
DataPort= 0xFF;
RS_CLR;
RW_SET;
EN_CLR;
_nop_();
EN_SET;
return (bit)(DataPort & 0x80);
}
/*------------------------------------------------
写入命令函数
------------------------------------------------*/
void LCD_Write_Com(unsigned char com)
{
while(LCD_Check_Busy()); //忙则等待
RS_CLR;
RW_CLR;
EN_SET;
DataPort= com;
_nop_();
EN_CLR;
}
/*------------------------------------------------
写入数据函数
------------------------------------------------*/
void LCD_Write_Data(unsigned char Data)
{
while(LCD_Check_Busy()); //忙则等待
RS_SET;
RW_CLR;
EN_SET;
DataPort= Data;
_nop_();
EN_CLR;
}
/*------------------------------------------------
写入字符函数
------------------------------------------------*/
void LCD_Write_Char(unsigned char x,unsigned char y,unsigned char Data)
{
if (y == 0)
{
LCD_Write_Com(0x80 + x);
}
else
{
LCD_Write_Com(0xC0 + x);
}
LCD_Write_Data( Data);
}
/*------------------------------------------------
初始化函数
------------------------------------------------*/
void LCD_Init(void)
{
LCD_Write_Com(0x38); /*显示模式设置*/
DelayMs(5);
LCD_Write_Com(0x38);
DelayMs(5);
LCD_Write_Com(0x38);
DelayMs(5);
LCD_Write_Com(0x38);
LCD_Write_Com(0x08); /*显示关闭*/
LCD_Write_Com(0x01); /*显示清屏*/
LCD_Write_Com(0x06); /*显示光标移动设置*/
DelayMs(5);
LCD_Write_Com(0x0C); /*显示开及光标设置*/
}
void TIMER0init(void)
{
TMOD = 0x01;
TH0 = 0x4C;
TL0 = 0x00;
EA = 1;
ET0 = 1;
TR0 = 1;
}
void TIMER0process(void) interrupt 1
{
void time_transfer(void);
TH0=0x4C;
TL0=0x00;
count--;
time_transfer();
}
void time_transfer(void)
{
if(count==0)
{
count=20;
second++;
}
if(second==60)
{
second=0;
minute++;
}
if(minute==60)
{
minute=0;
hour++;
}
if(hour==24)
{
hour=0;
date++;
week++;
}
if(date==1+days_num_this_month[month-1])
{
date=1;
month++;
}
if(week==7)
{
week=0;
}
if(month==13)
{
month=1;
year++;
if(year%4==0)
days_num_this_month[1]=29;
else
days_num_this_month[1]=28;
}
display_time[0]=year/1000;
display_time[1]=(year%1000)/100;
display_time[2]=((year%1000)%100)/10;
display_time[3]=(((year%1000)%100)%10);
display_time[4]=month/10;
display_time[5]=month%10;
display_time[6]=date/10;
display_time[7]=date%10;
display_time[8]=hour/10;
display_time[9]=hour%10;
display_time[10]=minute/10;
display_time[11]=minute%10;
display_time[12]=second/10;
display_time[13]=second%10;
}
void set_init_time(void)
{
year=2021;
month=8;
date=8;
hour=12;
minute=0;
second=0;
week=0;
if(year%4==0)
{
days_num_this_month[1]=29;
}
display_time[0]=year/1000;
display_time[1]=(year%1000)/100;
display_time[2]=((year%1000)%100)/10;
display_time[3]=(((year%1000)%100)%10);
display_time[4]=month/10;
display_time[5]=month%10;
display_time[6]=date/10;
display_time[7]=date%10;
display_time[8]=hour/10;
display_time[9]=hour%10;
display_time[10]=minute/10;
display_time[11]=minute%10;
display_time[12]=second/10;
display_time[13]=second%10;
}
void LCD_display(void)
{
LCD_Write_Char(1,0,character[display_time[0]]);
LCD_Write_Char(2,0,character[display_time[1]]);
LCD_Write_Char(3,0,character[display_time[2]]);
LCD_Write_Char(4,0,character[display_time[3]]);
LCD_Write_Char(6,0,character[display_time[4]]);
LCD_Write_Char(7,0,character[display_time[5]]);
LCD_Write_Char(9,0,character[display_time[6]]);
LCD_Write_Char(10,0,character[display_time[7]]);
LCD_Write_Char(4,1,character[display_time[8]]);
LCD_Write_Char(5,1,character[display_time[9]]);
LCD_Write_Char(7,1,character[display_time[10]]);
LCD_Write_Char(8,1,character[display_time[11]]);
LCD_Write_Char(10,1,character[display_time[12]]);
LCD_Write_Char(11,1,character[display_time[13]]);
LCD_Write_Char(12,0,week_group[week][0]);
LCD_Write_Char(13,0,week_group[week][1]);
LCD_Write_Char(14,0,week_group[week][2]);
}
void write_diy_character(void)
{
unsigned char index;
LCD_Write_Com(0x40);
for(index=0;index<8;index++)
{
LCD_Write_Data(double_dot[index]);
}
LCD_Write_Com(0xC6); //显示地址
LCD_Write_Data(0x00); //向DDRAM写入
LCD_Write_Com(0xC9); //显示地址
LCD_Write_Data(0x00); //向DDRAM写入
LCD_Write_Char(5,0,0xB0);
LCD_Write_Char(8,0,0xB0);
}
void delay500ms(void) //误差 -0.000000000068us
{
unsigned char a,b,c;
for(c=98;c>0;c--)
for(b=127;b>0;b--)
for(a=17;a>0;a--);
_nop_(); //if Keil,require use intrins.h
}
void dislpay_bit_flicker(unsigned bit_num)
{
unsigned char corresponding_line,corresponding_row=0;
switch(bit_num)
{
case 0:corresponding_line=1;break;
case 1:corresponding_line=2;break;
case 2:corresponding_line=3;break;
case 3:corresponding_line=4;break;
case 4:corresponding_line=6;break;
case 5:corresponding_line=7;break;
case 6:corresponding_line=9;break;
case 7:corresponding_line=10;break;
case 8:corresponding_line=4;break;
case 9:corresponding_line=5;break;
case 10:corresponding_line=7;break;
case 11:corresponding_line=8;break;
case 12:corresponding_line=10;break;
case 13:corresponding_line=11;
}
if(bit_num>=8)
corresponding_row=1;
while(SET_TIME_BIT_KEY)
{
LCD_Write_Char(corresponding_line,corresponding_row,character[display_time[bit_num]]);
delay500ms();
LCD_Write_Char(corresponding_line,corresponding_row,0x5F);
delay500ms();
if(INC_BIT_NUM_KEY==0)
{
display_time[bit_num]++;
if(display_time[bit_num]>9)
display_time[bit_num]=0;
}
if(END_CHANGE_TIME==0)
{
ending=1;break;
}
}
LCD_Write_Char(corresponding_line,corresponding_row,character[display_time[bit_num]]);
}
void work_from_new_time(void)
{
unsigned char old_date=date;
year=display_time[0]*1000+display_time[1]*100+display_time[2]*10+display_time[3];
month=display_time[4]*10+display_time[5];
date=display_time[6]*10+display_time[7];
week=(week+date-old_date)%7;
hour=display_time[8]*10+display_time[9];
minute=display_time[10]*10+display_time[11];
second=display_time[12]*10+display_time[13];
}
void change_time(void)
{
unsigned char key_press_count=0;
while((key_press_count<14)&&(ending==0))
{
dislpay_bit_flicker(key_press_count);
delay500ms();
delay500ms();
key_press_count++;
}
work_from_new_time();
}
void main(void)
{
LCD_Init();//初始化LCD
write_diy_character();
set_init_time();//设置初始时间
LCD_display();
change_time();
TIMER0init();//初始化计时器0
while(1)
{
LCD_display();
}
}
|