1602电子时钟程序
基于51单片机的1602日历时钟程序
if(y == 0)
x |= 0x40 ; //如果显示是在第二行,则x的值加0x40
x |= 0x80 ; //获得x的值
LCD1602_write_cmd(x) ;//写入坐标值到LCD
}
}
/************************************************************
case 3 : sele_count = 3 ; break ;
default : break ;
}
return(self_cou***************************************************
蜂鸣器
************************************************************/
void delay_ms(uint16 count) // 延时时间count*1ms
{ uint16 i;
for(;count>0;count--)
LCD1602_DATA = dat ;
LCD1602_EN = 1 ;
LCD1602_EN = 0 ;
}
/***********************************************************
1602初始化
************************************************************/
uint8 LCD1602_display_self(uint8 count)
1602时钟程序和原理图
XTAL218XTAL119ALE 30EA31PSEN 29RST9P0.0/AD039P0.1/AD138P0.2/AD237P0.3/AD336P0.4/AD435P0.5/AD534P0.6/AD633P0.7/AD732P1.0/T21P1.1/T2EX 2P1.23P1.34P1.45P1.56P1.67P1.78P3.0/RXD 10P3.1/TXD 11P3.2/INT012P3.3/INT113P3.4/T014P3.7/RD17P3.6/WR 16P3.5/T115P2.7/A1528P2.0/A821P2.1/A922P2.2/A1023P2.3/A1124P2.4/A1225P2.5/A1326P2.6/A1427U1AT89C52X1CRYSTALC127pC227pR110kR21kC310uD 714D 613D 512D 411D 310D 29D 18D 07E 6R W 5R S 4V S S 1V D D 2V E E3LCD1LM016LRV11k用1602显示时钟,能调节时分秒,周年月日,P1^0是调节显示位置按一下到秒,第二下到分,。
依次第七次到年,每到一个位置可以通过P1^1、 P1^2来调节对应位置的数据,P1^1是加数据P1^2是减数据。
#include<reg52.h>#define uchar unsigned char #define uint unsigned int sbit rs=P2^0; sbit lcden=P2^2; sbit s1=P1^0; sbit s2=P1^1; sbit s3=P1^2;uchar count,s1num;uchar shi,fen,miao,zhou,ri,yue,nian; uchar code table[]=" 2001-01-01 1"; uchar code table1[]=" 00:00:00"; void delay(uint z) { uint x,y; for(x=0;x<z;x++) for(y=0;y<110;y++); }void w_com(uchar com) { rs=0; lcden=0; P3=com; delay(5); lcden=1;//给高脉冲 delay(5); lcden=0; }/********************************* 写指令*********************************/ void w_data(uchar date) { rs=1; lcden=0; P3=date; delay(5); lcden=1; delay(5); lcden=0; }/********************************* 写数据*********************************/ void init(){uchar num;lcden=0;//初始化使能为0//fen=59;//miao=52;//shi=23;zhou=1;ri=1;yue=1;nian=1;w_com(0x38);//写入显示模式指令码w_com(0x0c);//写入显示开/关及光标指令码w_com(0x06);//当写一个字符后,地址指针加一,光标加一,不动光标不闪烁w_com(0x01); //清零作w_com(0x80);//代表第一行第一位for(num=0;num<15;num++){w_data(table[num]);delay(5);}w_com(0x80+0x40);//代表第二行第一位for(num=0;num<12;num++){ w_data(table1[num]);delay(5);}TMOD=0x01;TH0=0x3c;TL0=0xb0;EA=1;ET0=1;TR0=1;}/*********************************初始化函数*********************************/void w_sfm(uchar add,uchar date)//时分秒{uchar shi,ge;shi=date/10;ge=date%10;w_com(0x80+0x40+add);w_data(0x30+shi);w_data(0x30+ge);}void w_zhou(uchar add,uchar date)//周{uchar z;z=date;w_com(0x80+add);w_data(0x30+z);}void w_ryn(uchar add,uchar date)//日{uchar shi,ge;shi=date/10;ge=date%10;w_com(0x80+add);w_data(0x30+shi);w_data(0x30+ge);}void keyscan(){if(s1==0)//闪烁位置{delay(5);if(s1==0){s1num++;while(!s1);if(s1num==1)//s1键按一下依次从秒分周日月时向左移{TR0=0;w_com(0x80+0x40+0x0b);w_com(0x0f);//左移光标开始闪烁}if(s1num==2){w_com(0x80+0x40+0x08);//w_com(0x0f);TR0=1;}if(s1num==3){w_com(0x80+0x40+0x05);//w_com(0x0f);TR0=1;}if(s1num==4){w_com(0x80+0x0e);TR0=1;}if(s1num==5){w_com(0x80+0x0b);TR0=1;}if(s1num==6){w_com(0x80+0x08);TR0=1;}if(s1num==7){w_com(0x80+0x05);TR0=1;}if(s1num==8){s1num=0;w_com(0x80+0x40+12);w_com(0x0c);//光标恢复原样,不闪烁TR0=1;}}}if(s1num!=0)//用于调节年月日时分秒{if(s2==0){delay(10);if(s2==0){while(!s2);if(s1num==1)//秒升调节{miao++;if(miao==60)miao=0;w_sfm(10,miao);w_com(0x80+0x40+11);}if(s1num==2)//分升调节{fen++;if(fen==60)fen=0;w_sfm(7,fen);w_com(0x80+0x40+8);}if(s1num==3)//时升调节{shi++;if(shi==24)shi=0;w_sfm(4,shi);w_com(0x80+0x40+5);}if(s1num==4)//周升调节{zhou++;if(zhou==8)zhou=1;w_zhou(14,zhou);w_com(0x80+14);}if(s1num==5)//日升调节{ri++;if(yue==1||yue==3||yue==5||yue==7||yue==8||yue==10||yue==12){if(ri==32)ri=1;w_ryn(10,ri);w_com(0x80+11);}if(yue==2){if(ri==29)ri=1;w_ryn(10,ri);w_com(0x80+11);}if(yue==4||yue==6||yue==9||yue==11){if(ri==31)ri=1;w_ryn(10,ri);w_com(0x80+11);}}if(s1num==6)//月升调节{yue++;if(yue==13)yue=1;w_ryn(7,yue);w_com(0x80+8);}if(s1num==7)//年升调节{nian++;if(nian==99)nian=1;w_ryn(4,nian);w_com(0x80+5);}}}if(s3==0){delay(5);if(s3==0){while(!s3);if(s1num==1)//秒降调节{miao--;if(miao==-1)miao=59;w_sfm(10,miao);w_com(0x80+0x40+11);}if(s1num==2)//分降调节{fen--;if(fen==-1)fen=59;w_sfm(7,fen);w_com(0x80+0x40+8);}if(s1num==3)//时降调节{shi--;if(shi==-1)shi=23;w_sfm(4,shi);w_com(0x80+0x40+5);}if(s1num==4)//周降调节{zhou--;if(zhou==0)zhou=7;w_zhou(14,zhou);w_com(0x80+14);}if(s1num==5)//日降调节{ri--;if(ri==0)ri=31;w_ryn(10,ri);w_com(0x80+11);}if(s1num==6)//月降调节{yue--;if(yue==0)yue=12;w_ryn(7,yue);w_com(0x80+8);}if(s1num==7)//年降调节{nian--;if(nian==0)nian=99;w_ryn(4,nian);w_com(0x80+5);}}}}}void main(){init();while(1){keyscan();if(count==16){count=0;miao++;if(miao==60){miao=0;fen++;if(fen==60){fen=0;shi++;if(shi==24){shi=0;zhou++;ri++;if(zhou==8){zhou=1;}w_zhou(14,zhou);if(yue==1||yue==3||yue==5||yue==7||yue==8||yue==10||yue==12){if(ri==32){ri=1;yue++;if(yue==13){yue=1;nian++;if(nian==100)nian=1;w_ryn(4,nian);}w_ryn(7,yue);}w_ryn(10,ri);}if(yue==2){if(ri==29){ri=1;yue++;if(yue==13){yue=1;nian++;if(nian==100)nian=1;w_ryn(4,nian);}w_ryn(7,yue);}w_ryn(10,ri);}if(yue==4||yue==6||yue==9||yue==11){if(ri==31){ri=1;yue++;if(yue==13){yue=1;nian++;if(nian==100)nian=1;w_ryn(4,nian);}w_ryn(7,yue);}w_ryn(10,ri);}}w_sfm(4,shi);}w_sfm(7,fen);}w_sfm(10,miao);}}}void timer0() interrupt 1{TH0=0x3c;TL0=0xb0;count++;}。
基于c51功能最全的电子钟程序(lcd1602)
功能最全的电子钟【单片机】c51数字时钟(带年月日显示)摘要:本设计以单片机为核心,lcd1602显示。
采用独立键盘输入能任意修改当前时间日期和设定闹钟时间。
具有显示年月日(区分闰年和二月),闹钟报警和整点报时功能主程序:/********************************************************************************************************************************************************************************* ****************************************** lcd1602电子钟********************************************************************************************************************************** *************************************************************************************************** ********************/# include <reg52.h># include "lcd16024.h"sbit key1 = P2^0; //调整sbit key2 = P2^1; //加1sbit key3 = P2^2; //减1sbit speaker = P2^3; //蜂鸣器sbit key4 = P2^4; //闹钟设计bit cal_year = 1; //进入判断闰年标志位bit leap_year; //闰年标志位bit calculate = 0; //日加一标记bit run = 0; //闹钟标志bit beep = 0; //整点报时标志//uint8 num = 0; //调整是给的脉冲uint8 code str1[] = "D: ";uint8 code str2[] = "T: ";uint8 code str3[] = "Wek";uint8 daystr[]="2013-07-29 "; //年月日格式uint8 timestr[]="21:30:59 N"; //时分秒格式uint8 daystr1[]="2013-07-29 "; //闹钟年月日格式uint8 timestr1[]="21:30:59 N"; //闹钟时分秒格式uint8 numweek = 0; //星期加1标记char week = 1; //星期char sec = 53; //秒char min = 50; //分char hour = 23; //时uint8 day = 30; // 日uint8 month = 9; //月uint16 year = 2013; //年char week1 = 1; //闹钟星期char sec1 = 58; //闹钟秒char min1 = 50; //闹钟分char hour1 = 23; //闹钟时uint8 day1 = 30; //闹钟日uint8 month1 = 9; //闹钟月uint16 year1 = 2013; //闹钟年uint8 WeekData1; //闹钟星期标记uint8 number = 0; //定时uint8 WeekData; //星期标记uint8 speaker_num; //整点报时次数uint8 scan_key(void); //函数声名/****************************************************************************** ***************************** 更新LCD时间分离读取******************************************************************************************************************* *******/void TimeChange(){//时分秒timestr[7] = sec%10+'0';timestr[6] = sec/10+'0';timestr[4] = min%10+'0';timestr[3] = min/10+'0';timestr[1] = hour%10+'0';timestr[0] = hour/10+'0';//年月日daystr[9] = day%10+'0';daystr[8] = day/10+'0';daystr[6] = month%10+'0';daystr[5] = month/10+'0';daystr[3] = year%10+'0';daystr[2] = year/10%10+'0';daystr[1] = year/100%10+'0';daystr[0] = year/1000+'0';//星期WeekData = week+'0';}/****************************************************************************** ***************************** 闹钟更新LCD时间分离读取******************************************************************************************************************* *******/void TimeChange1(){//时分秒timestr1[7] = sec1%10+'0';timestr1[6] = sec1/10+'0';timestr1[4] = min1%10+'0';timestr1[3] = min1/10+'0';timestr1[1] = hour1%10+'0';timestr1[0] = hour1/10+'0';//年月日daystr1[9] = day1%10+'0';daystr1[8] = day1/10+'0';daystr1[6] = month1%10+'0';daystr1[5] = month1/10+'0';daystr1[3] = year1%10+'0';daystr1[2] = year1/10%10+'0';daystr1[1] = year1/100%10+'0';daystr1[0] = year1/1000+'0';//星期WeekData1 = week1+'0';}/****************************************************************************** ***************************** 初始化系统定时器0 ******************************************************************************************************************* *******/void systimer0_init(void){TMOD |=0x01;//设置为1时用或(|)TMOD &=0xfd;//设置为0时用与(&)TH0 = 0xDC; // 定时10msTL0 = 0x00;EA = 1;ET0=1;TR0=1;EX0 = 1;}/****************************************************************************** ***************************** 闹钟时间设置*************************************************************************************************************** *******/void naozhong(){uint8 number = 1;uint8 a = 0;uint8 b = 0;if(0 == key4){Delay1Ms(5);if(0 == key4){a = 1;LCD_write_command(0xc0+9);LCD_write_command(0x0f);}while(!key4);}while(a){if(0 == key4){Delay1Ms(5);if(0 == key4){a = 0;run = ~run;while(!key4);}}if(run){timestr[9] = 'Y';}else{timestr[9] = 'N';}if(0 == key1){Delay1Ms(5);if(0 == key1){b = 1;}while(!key1);}while(b){if(0 == key1){Delay1Ms(5);if(0 == key1){number++;if(4 == number)b = 0;}while(!key1);if(number == 1){LCD_write_command(0xc0+9);LCD_write_command(0x0f);}if(number == 2){LCD_write_command(0xc0+6);LCD_write_command(0x0f);}if(number == 3){LCD_write_command(0xc0+3);LCD_write_command(0x0f);}}}switch(number){case 1:if(0 == key2) //闹钟秒加1的设置{Delay1Ms(5);if(0 == key2){sec1++;if(60 == sec1){sec1 = 0;}while(!key2);timestr1[7] = sec1%10+'0';timestr1[6] = sec1/10+'0';LCD_write_char(8,1,timestr1[6]);LCD_write_char(9,1,timestr1[7]);LCD_write_command(0xc0+9);}}if(0 == key3) //闹钟秒减1的设置Delay1Ms(5);if(0 == key3){sec1--;if(sec1 < 0){sec1 = 59;}while(!key3);timestr1[7] = sec1%10+'0';timestr1[6] = sec1/10+'0';LCD_write_char(8,1,timestr1[6]);LCD_write_char(9,1,timestr1[7]);LCD_write_command(0xc0+9);}}break;case 2:if(0 == key2) //闹钟分加1的设置{Delay1Ms(5);if(0 == key2){min1++;if(60 == min1){min1 = 0;}while(!key2);timestr1[4] = min1%10+'0';timestr1[3] = min1/10+'0';;LCD_write_char(5,1,timestr1[3]);LCD_write_char(6,1,timestr1[4]);LCD_write_command(0xc0+6);}}if(0 == key3) //闹钟分减1的设置{Delay1Ms(5);if(0 == key3){min1--;if(min1 < 0){min1 = 59;}while(!key3);timestr1[4] = min1%10+'0';timestr1[3] = min1/10+'0';;LCD_write_char(5,1,timestr1[3]);LCD_write_char(6,1,timestr1[4]);LCD_write_command(0xc0+6);}}break;case 3:if(0 == key2) //闹钟时加1的设置{Delay1Ms(5);if(0 == key2){hour1++;if(24 == hour1){hour1 = 0;}while(!key2);timestr1[1] = hour1%10+'0';timestr1[0] = hour1/10+'0';LCD_write_char(2,1,timestr1[0]);LCD_write_char(3,1,timestr1[1]);LCD_write_command(0xc0+3);}}if(0 == key3) //闹钟时减1的设置{Delay1Ms(5);if(0 == key3){hour1--;if(hour1 < 0){hour1 = 23;}while(!key3);timestr1[1] = hour1%10+'0';timestr1[0] = hour1/10+'0';LCD_write_char(2,1,timestr1[0]);LCD_write_char(3,1,timestr1[1]);LCD_write_command(0xc0+3);}}break;case 4:b = 0;LCD_write_command(0x0c);break;}}}LCD_write_command(0x0c);while(!key4);}/****************************************************************************** ***************************** 判断按键进入时间调整*************************************************************************************************************** *******/uint8 scan_key(void){uint8 number = 1;uint8 a = 0;if(0 == key1){Delay1Ms(5);if(0 == key1){while(!key1);a = 1;LCD_write_command(0xc0+9);LCD_write_command(0x0f);}}while(a){if(0 == key1){Delay1Ms(5);if(0 == key1){number++;while(!key1);TR0 = 0;if(number == 2){LCD_write_command(0xc0+6);LCD_write_command(0x0f);}if(number == 3){LCD_write_command(0xc0+3);LCD_write_command(0x0f);}if(number == 4){LCD_write_command(0x80+11);LCD_write_command(0x0f);}if(number == 5){LCD_write_command(0x80+8);LCD_write_command(0x0f);}if(number == 6){LCD_write_command(0x80+5);LCD_write_command(0x0f);}if(number == 7){LCD_write_command(0xc0+14);LCD_write_command(0x0f);}if(8 == number){LCD_write_command(0x0c);a = 0;number = 0;}}}switch(number){case 1:if(0 == key2) //秒加1的设置{Delay1Ms(5);if(0 == key2){sec++;if(60 == sec){sec = 0;}timestr[7] = sec%10+'0';timestr[6] = sec/10+'0';LCD_write_char(8,1,timestr[6]);LCD_write_char(9,1,timestr[7]);LCD_write_command(0xc0+9);while(!key2);}}if(0 == key3) //秒减1的设置{Delay1Ms(5);if(0 == key3){sec--;if(sec < 0){sec = 59;}timestr[7] = sec%10+'0';timestr[6] = sec/10+'0';LCD_write_char(8,1,timestr[6]);LCD_write_char(9,1,timestr[7]);LCD_write_command(0xc0+9);while(!key3);}}break;case 2:if(0 == key2) //分加1的设置{Delay1Ms(5);if(0 == key2){min++;if(60 == min){min = 0;}timestr[4] = min%10+'0';timestr[3] = min/10+'0';;LCD_write_char(5,1,timestr[3]);LCD_write_char(6,1,timestr[4]);LCD_write_command(0xc0+6);while(!key2);}}if(0 == key3) //分减1的设置{Delay1Ms(5);if(0 == key3){min--;if(min < 0){min = 59;}timestr[4] = min%10+'0';timestr[3] = min/10+'0';LCD_write_char(5,1,timestr[3]);LCD_write_char(6,1,timestr[4]);LCD_write_command(0xc0+6);while(!key3);}}break;case 3:if(0 == key2) //时加1的设置{Delay1Ms(5);if(0 == key2){hour++;while(!key2);if(24 == hour){hour = 0;}timestr[1] = hour%10+'0';timestr[0] = hour/10+'0';LCD_write_char(2,1,timestr[0]);LCD_write_char(3,1,timestr[1]);LCD_write_command(0xc0+3);}}if(0 == key3) //时减1的设置{Delay1Ms(5);if(0 == key3){while(!key3);hour--;if(hour < 0){hour = 23;}timestr[1] = hour%10+'0';timestr[0] = hour/10+'0';LCD_write_char(2,1,timestr[0]);LCD_write_char(3,1,timestr[1]);LCD_write_command(0xc0+3);}}break;case 4:if(0 == key2) //日加1的设置{Delay1Ms(5);if(0 == key2){while(!key2);calculate = 1;if(calculate == 1){if(month==1|month==3|month==5|month==7|month==8|month==10|month==12){day++;if(day > 31){day=1;}}if(month==4|month==6|month==9|month==11){day++;if(day > 30){day=1;}}if(month == 2){cal_year = 1;while(cal_year == 1){leap_year = ((year % 4 == 0 && year % 100 != 0)||(year % 400 == 0));cal_year = 0;}if(leap_year==1){day++;if(day > 30){day=1;}}else{day++;if(day > 29){day=1;}}}calculate = 0;}daystr[9] = day%10+'0';daystr[8] = day/10+'0';LCD_write_char(10,0,daystr[8]);LCD_write_char(11,0,daystr[9]);LCD_write_command(0x80+11);}}if(0 == key3) //日减1的设置{Delay1Ms(5);if(0 == key3){while(!key3);calculate = 1;if(calculate == 1){if(month==1|month==3|month==5|month==7|month==8|month==10|month==12){day--;if(day == 0){day=31;}}if(month==4|month==6|month==9|month==11){day--;if(day == 0){day=30;}}if(month == 2){cal_year = 1;while(cal_year == 1){leap_year = ((year % 4 == 0 && year % 100 != 0)||(year % 400 == 0));cal_year = 0;}if(leap_year==1){day--;if(day == 0){day=30;}}else{day--;if(day == 0){day=29;}}}calculate = 0;}daystr[9] = day%10+'0';daystr[8] = day/10+'0';LCD_write_char(10,0,daystr[8]);LCD_write_char(11,0,daystr[9]);LCD_write_command(0x80+11);}}break;case 5:if(0 == key2) //月加1的设置{Delay1Ms(5);if(0 == key2){while(!key2);month++;if(13 == month){month = 1;}daystr[6] = month%10+'0';daystr[5] = month/10+'0';LCD_write_char(7,0,daystr[5]);LCD_write_char(8,0,daystr[6]);LCD_write_command(0x80+8);}}if(0 == key3) //月减1的设置{Delay1Ms(5);if(0 == key3){while(!key3);month--;if(month == 0){month = 12;}daystr[6] = month%10+'0';daystr[5] = month/10+'0';LCD_write_char(7,0,daystr[5]);LCD_write_char(8,0,daystr[6]);LCD_write_command(0x80+8);}}break;case 6:if(0 == key2) //年加1的设置{Delay1Ms(5);if(0 == key2){while(!key2);year++;}daystr[3] = year%10+'0';daystr[2] = year/10%10+'0';daystr[1] = year/100%10+'0';daystr[0] = year/1000+'0';LCD_write_char(2,0,daystr[0]);LCD_write_char(3,0,daystr[1]);LCD_write_char(4,0,daystr[2]);LCD_write_char(5,0,daystr[3]);LCD_write_command(0x80+5);}if (0 == key3) //年减1的设置{Delay1Ms(5);if(0 == key3){while(!key3);year--;if(year == 0){year = 2020;}daystr[3] = year%10+'0';daystr[2] = year/10%10+'0';daystr[1] = year/100%10+'0';daystr[0] = year/1000+'0';LCD_write_char(2,0,daystr[0]);LCD_write_char(3,0,daystr[1]);LCD_write_char(4,0,daystr[2]);LCD_write_char(5,0,daystr[3]);LCD_write_command(0x80+5);}}break;case 7:if(0 == key2) //星期加1的设置{Delay1Ms(5);if(0 == key2){while(!key2);week++;if(7 == week){week = 0;}LCD_write_char(14,1,week+'0');LCD_write_command(0xc0+14);}}if (0 == key3) //星期减1的设置{Delay1Ms(5);if(0 == key3){while(!key3);week--;if(week < 0){week = 6;}LCD_write_char(14,1,week+'0');LCD_write_command(0xc0+14);}}break;case 8:TR0 = 1;break;}}}/****************************************************************************** ***************************** 主函数******************************************************************************************************************* *******/void main(void){systimer0_init();LCD_init();LCD_write_str(0,0,str1);LCD_write_str(0,1,str2);LCD_write_str(13,0,str3);speaker = 0;while (1){TimeChange();scan_key();naozhong();LCD_write_str(2,0,daystr);LCD_write_str(2,1,timestr);LCD_write_char(14,1,WeekData);if(1 == run){if(sec==sec1 & month==month1 & hour==hour){speaker_num =30;beep = 1;}}else{speaker_num =0;beep = 0;}}}/****************************************************************************** ***************************** 定时中断0 ******************************************************************************************************************* *******/void time_0() interrupt 1{TH0 = 0xDC; // 定时10msTL0 = 0x00;number++;if(number ==100){sec++;if(beep){speaker=!speaker;speaker_num--;if(speaker_num == 0){beep=0;speaker = 0;}}if(sec == 60){sec = 0;min++;if(min == 60){min = 0;hour++; //小时加1speaker_num = hour%12; //蜂鸣器响的次数beep = 1;if(hour == 24){hour = 0;calculate = 1;if(calculate == 1) //判断这个月有多少天{if(month==1|month==3|month==5|month==7|month==8|month==10|month==12){day++;if(month==7|month==12){week++;if(7 == week){week = 0;}}else{if(day <= 31){week++;if(7 == week){week = 0;}}}if(day > 31){if(month==7|month==12){day = 1;}else{day=0;}month++;if(month > 12){month=1;year++;cal_year=1;}}}if(month==4|month==6|month==9|month==11) {day++;week++;if(7 == week){week = 0;}if(day > 30){day=1;month++;if(month > 12){month=1;year++;cal_year=1;}}}if(month == 2){while(cal_year == 1){leap_year = ((year % 4 == 0 && year % 100 != 0)||(year % 400 == 0));cal_year = 0;}if(leap_year==1){day++;if(day <= 30){week++;if(7 == week){week = 0;}}if(day > 30){day=1;month++;if(month > 12){month=1;year++;cal_year=1;}}}else{day++;week++;if(7 == week){week = 0;}if(day > 29){day=1;month++;if(month > 12){month=1;year++;cal_year=1;}}}}}calculate=0;}}}}}////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Lcd1602.c子程序:////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /****************************************************************************** ***************************** lcd1602低层函数********************************************************************************************************************* *******/# include <reg52.h># include <intrins.h># include "lcd16024.h"# define LCD_DATA P0 //LCD1602的数据口定义sbit LCD_RS = P0^0; //LCD1602控制线的定义,4位控制方式sbit LCD_RW = P0^1;sbit LCD_EN = P0^2;/****************************************************************************** ***************************** 延时1MS********************************************************************************************************************* *******/void Delay1Us(uint16 n){for(;n>0;n--){_nop_();}}/****************************************************************************** ***************************** 延时1MS********************************************************************************************************************* *******/void Delay1Ms(uint16 n){while(n--){Delay1Us(1000);}}/****************************************************************************** ***************************** 延时1MS********************************************************************************************************************* *******/void LCD_en_write(void){LCD_EN=0;LCD_EN=1;Delay1Us(1);LCD_EN=0;}/****************************************************************************** ************************ LCD写一个字节命令函数************************************************************************************************************ *******/void LCD_write_command(uint8 command){Delay1Us(16);LCD_RS=0;LCD_RW=0;LCD_DATA&=0x0f;LCD_DATA|=command&0xf0;LCD_en_write();command=command<<4;LCD_DATA&=0x0f;LCD_DATA|=command&0xf0;LCD_en_write();}/****************************************************************************** ********************** LCD写一个字节数据函数*************************************************************************************************************** *******/void LCD_write_data(uint8 Data){Delay1Us(16);LCD_RS=1;LCD_RW=0;LCD_DATA&=0x0f;LCD_DATA|=Data&0xf0;LCD_en_write();Data=Data<<4;LCD_DATA&=0x0f;LCD_DATA|=Data&0xf0;LCD_en_write();}/****************************************************************************** ***************************** LCD1602光标定位函数************************************************ x--列0~15;y--行0~1********************************************************************************************************* *******/void LCD_set_xy(uint8 x,uint8 y){uint8 address;if(y==0)address=0x80+x;else address=0xc0+x;LCD_write_command(address);}/***************************************************************************************************** LCD1602 初始化函数,四位显示方式******************************************************************************************************* *******/void LCD_init(){LCD_write_command(0x28);// Delay1Us(40);LCD_write_command(0x28);LCD_write_command(0x0c);LCD_write_command(0x01);LCD_write_command(0x06);Delay1Ms(2);}/****************************************************************************** ***************************** LCD写字符串函数******************************************************* x--列0~15;y--行0~1******************************************************* s指向字符串数组**************************************************************************************************************** *******/void LCD_write_str(uint8 x,uint8 y,uint8 *s){LCD_set_xy(x,y);while(*s){LCD_write_data(*s);s++;}}/****************************************************************************** ***************************** LCD写一个字符函数******************************************************* x--列0~15;y--行0~1******************************************************* d--字符的ASCII码**************************************************************************************************************** *******/void LCD_write_char(uint8 x,uint8 y,uint8 d){LCD_set_xy(x,y);LCD_write_data(d);}/*////////////////////////////////////////////////////////////////// 等待繁忙标志/////////////////////////////////////////////////////////////////void LCD_wait(void){P0 = 0xFF;do{LCD_RS = 0;LCD_RW = 1;LCD_EN = 0;LCD_EN = 1;}while (BUSY == 1);LCD_EN = 0;}*//****************************************************************************** ***************************** LCD1602左移********************************************************************************************************************* *******void LCD_youyi(uint8 y,uint8 *s){LCD_write_str(17,y,s);for(a=0;a<16;a++){LCD_write_command(0x1c); //左移LCD_write_command(0x1c); 为右移Delay1Ms(6);}}*///LCD_write_command(0x0d);//光标闪烁//LCD_write_command(0x0e);//光标显示不闪烁//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Lcd1602.h头文件////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #ifndef _LCD16024_H_#define _LCD16024_H_typedef unsigned char uint8;typedef unsigned int uint16;typedef unsigned long uint32;void Delay1Us(uint16 n);void Delay1Ms(uint16 n);void LCD_write_data(uint8 dat);void LCD_write_command(uint8 com); //BuysC为0时忽略忙检测void LCD_set_xy(uint8 x,uint8 y);void LCD_en_write(void);void LCD_write_char(uint8 x, uint8 y, uint8 Data1);void LCD_write_str(uint8 x, uint8 y,uint8 *s);void LCD_init();//void LCD_wait(void);//void LCD_youyi(uint8 y,uint8 *s);#endif。
万年历1602时钟程序
#include <reg52.h>#include <stdio.h>#define uchar unsigned char#define uint unsigned int#define yh 0x80 //LCD第一行的初始位置,因为LCD1602字符地址首位D7恒定为1(100000000=80)#define er 0x80+0x40 //LCD第二行初始位置(因为第二行第一个字符位置地址是0x40)sbit ds=P2^2; //温度传感器信号线sbit dula=P2^6; //数码管段选线sbit wela=P2^7; //数码管位选线sbit beep=P2^3; //蜂鸣器sbit rs=P3^5; //定义1602液晶RS端sbit lcden=P3^4; //定义1602液晶LCDEN端sbit IO=P1^3; //数据线sbit SCLK=P1^4;sbit RST=P1^5;sbit ACC0=ACC^0;sbit ACC7=ACC^7;sbit key1=P3^4; //设置键sbit key2=P3^5; //加键sbit key3=P3^6; //减键uchar code tab1[]={"20 - - "}; //年显示的固定字符uchar code tab2[]={" : : "};//时间显示的固定字符uchar a,miao,shi,fen,ri,yue,nian,week,key1n,temp;uchar num;float f_temp;void delayms(uint z)//延时函数{uint x,y;for(x=z;x>0;x--)for(y=110;y>0;y--);}void di() //蜂鸣器报警声音{beep=0;delayms(50);beep=1;}uchar BCD_Decimal(uchar bcd)//BCD码转十进制函数,输入BCD,返回十进制{uchar Decimal;Decimal=bcd>>4;return(Decimal=Decimal*10+(bcd&=0x0F));}//DS1302时钟部分子程序//void write_byte(uchar dat)//写一个字节{ACC=dat;RST=1;for(a=8;a>0;a--){IO=ACC0;SCLK=0; //产生上升沿写入数据,从低位写入SCLK=1;ACC=ACC>>1;}}uchar read_byte()//读一个字节{RST=1;for(a=8;a>0;a--){ACC7=IO;SCLK=1; //产生下降沿输出数据,先输出低位,保存到ACC中SCLK=0;ACC=ACC>>1;}return (ACC);}void write_1302(uchar add,uchar dat)//向1302芯片写函数,指定写入地址,数据{RST=0;SCLK=0;RST=1;write_byte(add);write_byte(dat);SCLK=1;RST=0;}uchar read_1302(uchar add)//从1302读数据函数,指定读取数据来源地址{uchar temp;RST=0;SCLK=0;RST=1;write_byte(add);temp=read_byte();SCLK=1;RST=0;return(temp);}void ds1302_init() //1302芯片初始化子函数(2012-06-18,12:00:00,week7) {RST=0;SCLK=0;write_1302(0x8e,0x00); //允许写,禁止写保护write_1302(0x80,0x00); //向DS1302内写秒寄存器80H写入初始秒数据00 write_1302(0x82,0x00);//向DS1302内写分寄存器82H写入初始分数据00 write_1302(0x84,0x12);//向DS1302内写小时寄存器84H写入初始小时数据12write_1302(0x8a,0x07);//向DS1302内写周寄存器8aH写入初始周数据4 write_1302(0x86,0x17);//向DS1302内写日期寄存器86H写入初始日期数据18write_1302(0x88,0x06);//向DS1302内写月份寄存器88H写入初始月份数据06write_1302(0x8c,0x12);//向DS1302内写年份寄存器8cH写入初始年份数据12write_1302(0x8e,0x80); //打开写保护}//18b20温度传感器部分子程序//void ds18b20_init(void) //18B20复位,初始化函数{uint i;ds=0;i=103;while(i>0)i--;ds=1;i=4;while(i>0)i--;}bit tempreadbit(void) //读1位函数{uint i;bit dat;ds=0;i++; //i++ 起延时作用ds=1;i++;i++;dat=ds;i=8;while(i>0)i--;return (dat);}uchar tempread(void) //读1个字节{uchar i,j,dat;dat=0;for(i=1;i<=8;i++){j=tempreadbit();dat=(j<<7)|(dat>>1); //读出的数据最低位在最前面,这样刚好一个字节在DAT里}return(dat);}void tempwritebyte(uchar dat) //向18B20写一个字节数据{uint i;uchar j;bit testb;for(j=1;j<=8;j++){testb=dat&0x01;dat=dat>>1;if(testb) //写 1{ds=0;i++;i++;ds=1;i=8;while(i>0)i--;}else{ds=0; //写 0i=8;while(i>0)i--;ds=1;i++;i++;}}}void tempchange(void) //DS18B20 开始获取温度并转换{ds18b20_init();delayms(1);tempwritebyte(0xcc); // 写跳过读ROM指令tempwritebyte(0x44); // 写温度转换指令}uchar get_temp() //读取寄存器中存储的温度数据{uchar a,b;ds18b20_init();delayms(1);tempwritebyte(0xcc);tempwritebyte(0xbe);a=tempread(); //读低8位b=tempread(); //读高8位temp=b;temp<<=8; //两个字节组合为1个字temp=temp|a;f_temp=temp*0.0625; //温度在寄存器中为12位分辨率位0.0625° temp=f_temp*10+0.5; //乘以10表示小数点后面只取1位,加0.5是四舍五入f_temp=f_temp+0.05;return temp; //temp是整型}////////////////////显示程序//////////////////////////void write_1602com(uchar com)//液晶写命令函数{rs=0;lcden=0;P0=com;delayms(5);lcden=1;delayms(5);lcden=0;}void write_1602dat(uchar date)//液晶写数据函数{rs=1;lcden=0;P0=date;delayms(5);lcden=1;delayms(5);lcden=0;}//温度显示子函数void write_temp(uchar add,uchar dat)//向LCD写温度数据,并指定显示位置{uchar gw,sw;gw=dat%10;//取得个位数字sw=dat/10;//取得十位数字write_1602com(er+add);//er是头文件规定的值0x80+0x40write_1602dat(0x30+sw);//数字+30得到该数字的LCD1602显示码write_1602dat(0x30+gw);//数字+30得到该数字的LCD1602显示码write_1602dat(0xdf);//显示温度的小圆圈符号,0xdf是液晶屏字符库的该符号地址码write_1602dat(0x43); //显示"C"符号,0x43是液晶屏字符库里大写C的地址码}//1602液晶刷新显示年月日函数3为年,6为月,9为日void write_nyr(uchar add,char date){char shi,ge;shi=date/10;ge=date%10;write_1602com(0x80+add);write_1602dat(0x30+shi);write_1602dat(0x30+ge);}//1602液晶刷新显示时分秒函数4为时,7为分,10为秒void write_sfm(uchar add,char date){char shi,ge;shi=date/10;ge=date%10;write_1602com(0x80+0x40+add);write_1602dat(0x30+shi);write_1602dat(0x30+ge);}//写液晶星期显示函数void write_week(char we){write_1602com(0x80+12);switch(we){case 1: write_1602dat('M');delayms(5);write_1602dat('O');delayms(5);write_1602dat('N');break;case 2: write_1602dat('T');delayms(5);write_1602dat('U');delayms(5);write_1602dat('E');break;case 3: write_1602dat('W');delayms(5);write_1602dat('E');delayms(5);write_1602dat('D');break;case 4: write_1602dat('T');delayms(5);write_1602dat('H');delayms(5);write_1602dat('U');break;case 5: write_1602dat('F');delayms(5);write_1602dat('R');delayms(5);write_1602dat('I');break;case 6: write_1602dat('S');delayms(5);write_1602dat('A');delayms(5);write_1602dat('T');break;case 7: write_1602dat('S');delayms(5);write_1602dat('U');delayms(5);write_1602dat('N');break;}}//**************液晶初始化函数***************//void lcd1602_init(){write_1602com(0x38);//设置液晶工作模式,意思:16*2行显示,5*7点阵,8位数据write_1602com(0x0c);//开显示不显示光标write_1602com(0x06);//整屏不移动,光标自动右移write_1602com(0x01);//清显示write_1602com(0x80);//日历显示固定符号从第一行第1个位置之后开始显示write_1602com(yh);//日历显示固定符号从第一行第1个位置之后开始显示for(a=0;a<14;a++){write_1602dat(tab1[a]);//向液晶屏写日历显示的固定符号部分//delay(3);}write_1602com(er);//时间显示固定符号写入位置,从第2个位置后开始显示for(a=0;a<8;a++){write_1602dat(tab2[a]);//写显示时间固定符号,两个冒号//delay(3);}}//****************键盘扫描有关函数**********************void keyscan(){if(key1==0)//---------------key1为功能键(设置键)--------------------{delayms(9);//延时,用于消抖动if(key1==0)//延时后再次确认按键按下{di(); //蜂鸣器报警声音while(!key1);key1n++;if(key1n==9)key1n=1;//设置按键共有秒、分、时、星期、日、月、年、返回,8个功能循环switch(key1n){case 1: TR0=0;//关闭定时器//TR1=0;write_1602com(er+0x09); //设置按键按动一次,秒位置显示光标write_1602com(0x0f); //设置光标为闪烁temp=(miao)/10*16+(miao)%10; //秒数据写入DS1302write_1302(0x8e,0x00);write_1302(0x80,0x80|temp); //miaowrite_1302(0x8e,0x80);break;case 2: write_1602com(er+6);//按2次fen位置显示光标break;case 3: write_1602com(er+3);//按动3次,shi//write_1602com(0x0f);break;case 4: write_1602com(yh+0x0e);//按动4次,week//write_1602com(0x0f);break;case 5: write_1602com(yh+0x0a);//按动5次,ri //write_1602com(0x0f);break;case 6: write_1602com(yh+0x07);//按动6次,yue //write_1602com(0x0f);break;case 7: write_1602com(yh+0x04);//按动7次,nian //write_1602com(0x0f);break;case 8:write_1602com(0x0c); //按动到第8次,设置光标不闪烁TR0=1; //打开定时器temp=(miao)/10*16+(miao)%10;write_1302(0x8e,0x00);write_1302(0x80,0x00|temp); //miao数据写入DS1302write_1302(0x8e,0x80);break;}}}//------------------------------加键key2----------------------------if(key1n!=0)//当key1按下以下。
基于单片机的lcd1602电子时钟设计
基于单片机的LCD1602电子时钟设计一、设计任务和目的1.1、设计任务(1):用单片机设计基于LCD1602的电子时钟,显示时间和日期;(2):误差精度控制在1s/天;(3):具有时间和日期的校准功能;(4):能区分某年是闰年或平年,并对应显示2月份的天数;(5):根据月份的不同显示不同的最大日数;(6):搭建仿真电路图,模拟单片机要实现的功能;(7):焊接单片机开发板;(8):编写程序,下载并调试,实现要求的功能。
1.2、设计目的(1):熟练掌握KEIL软件的使用方法;(2):熟练掌握PROTEUS软件的使用方法;(3):掌握单片机I/O接口的工作原理;(4):掌握LCD显示器的工作原理及编程方法;(5):掌握独立式键盘的工作原理及编程使用方法;(6):掌握单片机的下载使用方法。
二、设计思路和方案论证2.1、设计思路电路总体上分为控制和显示部分。
以单片机最小系统作为核心控制电路,控制LCD显示,具体显示内容及方式由软件来完成;由于有时钟和日期的调节功能需要校准电路和基本的复位电路,复位电路采用按键复位,调节键、加1键、减1键三个按键完成,共需四个按键;计时功能由固定频率的晶振完成(采用11.0592MHz);显示部分主要采用LCD1602作为显示。
2.2、方案论证(1):时钟芯片的选择和论证方案一:采用DS1302时钟芯片实现时钟,DS1302芯片是一种高性能的时钟芯片,可自动对秒、分、时、日、月、年以及闰年补偿的年进行计数,精度也较高,工作电压2.5V~5.5V范围内,功耗也较低,但价格比较贵。
方案二:直接采用单片机定时计数器提供秒信号,使用程序实现秒、分、时、日、月、年计数。
采用此方案实现虽然有一定的时间误差,但可减少芯片的使用,节约成本,易于实现,符合现实选用,所以采用此种作为时钟信号发生器。
(2):显示模块选择方案和论证:方案一:采用点阵式图形LCD12864液晶显示屏,液晶显示屏的显示功能强大,可显示文字,图形,显示多样,清晰可见,但是价格昂贵,需要的接口线多,所以在此设计中不采用点阵式图形LCD12864液晶显示屏。
1602电子时钟程序
#include<reg52.h> //52单片机头文件#define uchar unsigned char //宏定义#define uint unsigned intsbit rs=P1^0; //声明单片机P1口的第一位读写指令还是数据端sbit rw=P1^1; //声明单片机P1口的第二位读写数据端sbit lcden=P1^2; //声明单片机P1口的第三位液晶使能端sbit s1=P2^5; //声明单片机P2口的第六位按键控制端sbit s2=P2^6; //声明单片机P2口的第七位按键控制端sbit s3=P2^7; //声明单片机P2口的第八位按键控制端sbit s4=P2^0; //声明单片机P2口的第一位按键控制端sbit s5=P2^4; //声明单片机P2口的第五位按键控制端sbit a=P3^5; //声明单片机P3口的第六位按键控制端char count,shi,fen,miao,s1num,xp,s5num,date1; //定义有符号字符形变量char nian,tian,yue,nshi,nfen; //定义有符号字符形变量uchar code table[]=" 2000-01-01 Mon "; //定义日期时间数组uchar code table1[]=" 00:00:00";uchar code table2[]=" Alarm clock"; //定义日期时间数组uchar code table3[]=" 00:00";void delay(uint z){uint x,y;for(x=z;x>0;x--) //延时子函数for(y=110;y>0;y--);}void write_com(uchar com) //指令子函数{rs=0; //选择写指令lcden=0; //使能端初始为底P0=com; //将送到要写的指令数据线上delay(5); //延时待数据稳定lcden=1; //使能端给一个高脉冲把数据写入1602液晶delay(5); //延时lcden=0; //拉低使能端完成高脉冲}void write_date(uchar date) //数据子函数{rs=1; //选择写数据lcden=0;P0=date;delay(5);lcden=1;delay(5);lcden=0;}void init() //初始子函数{uchar num; //定义变量用来调用数组rw=0; //选择只写数据到液晶lcden=0; //初始使能端为低电平write_com(0x38); //设置16*2显示,5*7点阵,8位数据接口write_com(0x0c); //开显示,不显示光标write_com(0x06); //写一个字符指针自动加1write_com(0x01); //显示清零,数据指针清零write_com(0x80); //将数据指针定位到第一行第一个字处for(num=0;num<15;num++){write_date(table[num]); //写日期数组数据delay(20);}write_com(0x80+0x40); //选择将时间写到液晶第二行for(num=0;num<12;num++){write_date(table1[num]); //写时间数组数据delay(20);}write_com(0x80+16); //使用移屏操作for(num=0;num<13;num++){write_date(table2[num]); //写闹钟名称delay(20);}write_com(0x80+0x40+16); //选择移屏第二行for(num=0;num<10;num++){write_date(table3[num]); //写闹钟初始值delay(20);}TMOD=0x01; //选择定时器工作方式为方式1TH0=(65536-50000)/256; //装初值TL0=(65536-50000)%256;EA=1; //开总中断ET0=1; //选择定时器零TR0=1; //开定时器零}void write_sfm(uchar add,uchar date ) //子函数写时间日期到液晶上{uchar shi,ge; //定义变量用以分离十位和个位上的数字shi=date/10; //分离十位上的数字ge=date%10; // 分离个位上的数字write_com(0x80+0x40+add) ; //给出写的位置指令write_date(0x30+shi); //写十位上的数字write_date(0x30+ge); //写个位上的数字}void write_sfn(uchar add,uchar date) //子函数写时间日期到液晶上{uchar shi,ge; //定义变量用以分离十位和个位上的数字shi=date/10; //分离十位上的数字ge=date%10; // 分离个位上的数字write_com(0x80+add) ; //给出写的位置指令write_date(0x30+shi); //写十位上的数字write_date(0x30+ge); //写个位上的数字}void keyscan() //按键子函数{{s4=0; //让共同接口置零if(s1==0) //判断s1是否被按下{delay(5); //延时5ms去斗if(s1==0) //再次判断s1是否真被按下{s1num++; //设置变量判断s1被按下几次while(!s1); //松手检测if(s1num==1) //S1被第一次按下{TR0=0; //关定时器write_com(0x80+0x40+11); //确定指针位置在秒钟write_com(0x0f); //开显示显示光标光标闪烁}}if(s1num==2){write_com(0x80+0x40+8); //确定指针位置在分钟}if(s1num==3){write_com(0x80+0x40+5); //确定指针位置在时针}if(s1num==4){write_com(0x80+4); //确定指针位置在时针}if(s1num==5){write_com(0x80+7); //确定指针位置在时针}if(s1num==6){write_com(0x80+10); //确定指针位置在时针}if(s1num==7){write_com(0x80+14); //确定指针位置在时针}if(s1num==8){uchar num ;write_com(0x18) ;write_com(0x18) ;write_com(0x18) ;write_com(0x18) ;write_com(0x18) ;write_com(0x18) ;write_com(0x18) ; //移屏操作write_com(0x18) ;write_com(0x18) ;write_com(0x18) ; //整屏左移同时光标也跟着移动write_com(0x18) ;write_com(0x18) ;write_com(0x18) ;write_com(0x18) ;write_com(0x18) ;write_com(0x18) ;write_com(0x80+0x40+22); //确定指针位置在时针}if(s1num==9){write_com(0x80+0x40+25); //确定指针位置在时针}if(s1num==10){uchar n;while(n<24){n++; //移屏操作write_com(0x18);}s1num=0;n=0;write_com(0x0c); //结束光标显示表开始走TR0=1;}}}if(s1num!=0) //说明已S1被按下{if(s2==0) //判断S2是否被按下{delay(5); //判断S2是否真被按下if(s2==0); //判断S2是否真被按下{while(!s2); //松手检测if(s1num==1) //判断S1被按下一下{miao++; //秒自加一if(miao==60) //判断miao是否为60miao=0; //秒清零write_sfm(10,miao) ; //把秒数据写到指定位置write_com(0x80+0x40+11); //不让指针向后移}if(s1num==2) //判断S1被按下两下{fen++; //分自加一if(fen==60) //判断fen是否为60fen=0; //fen清零write_sfm(7,fen) ; //把fen数据写到指定位置write_com(0x80+0x40+8); //不让指针向后移}if(s1num==3) //判断S1被按下三下{shi++; //shi自加一if(shi==24) //判断shi是否为24shi=0; //shi清零write_sfm(4,shi) ; //把shi数据写到指定位置write_com(0x80+0x40+5); //不让指针向后移}if(s1num==4) //判断S1被按下四下{nian++; //nian自加一write_sfn(3,nian) ; //把年数据写到指定位置write_com(0x80+4); //不让指针向后移}if(s1num==5) //判断S1被按下五下{yue++; //yue自加一if(yue==13) //使月循环加yue=1;write_sfn(6,yue) ; //把月数据写到指定位置write_com(0x80+7); //不让指针向后移}if(s1num==6) //判断S1被按下六下{tian++; //tian自加一if(yue==1,3,5,7,8,10,12){if(tian==32)tian=1;}if(yue==2){if(tian==29)tian=1;}if(yue==4){if(tian==31) //解决不同的月有不同的天的问题tian=1;}if(yue==6){if(tian==31)tian=1;}if(yue==9){if(tian==31)tian=1;}if(yue==11){if(tian==31)tian=1;}write_sfn(9,tian) ; //把天数据写到指定位置write_com(0x80+10); //不让指针向后移}if(s1num==8) //判断S1被按下八下{nshi++; //闹钟的时自加一if(nshi==24)nshi=0;write_sfm(21,nshi) ;write_com(0x80+0x40+22);}if(s1num==9) //判断S1被按下九下{nfen++; //闹钟的分自加一if(nfen==60) //判断nfen是否为60nfen=0; //nfen清零write_sfm(24,nfen) ; //把nfen数据写到指定位置write_com(0x80+0x40+25); //不让指针向后移}}}if(s1num==7) //判断S1被按下七下{if(s5==0){delay(5);if(s5==0){s5num++;while(!s5);if(s5num==1){write_com(0x80+12);write_date(0x4D);write_com(0x80+13);write_date(0x6F); //写星期一write_com(0x80+14);write_date(0x6E);write_com(0x80+14);}if(s5num==2){write_com(0x80+12);write_date(0x54);write_com(0x80+13); //写星期二write_date(0x75);write_com(0x80+14);write_date(0x65);write_com(0x80+14);}if(s5num==3){write_com(0x80+12);write_date(0x57);write_com(0x80+13);write_date(0x65); //写星期三write_com(0x80+14);write_date(0x64);write_com(0x80+14);}if(s5num==4){write_com(0x80+12);write_date(0x54);write_com(0x80+13);write_date(0x68); //写星期四write_com(0x80+14);write_date(0x75);write_com(0x80+14);}if(s5num==5){write_com(0x80+12);write_date(0x46);write_com(0x80+13);write_date(0x72); //写星期五write_com(0x80+14);write_date(0x69);write_com(0x80+14);}if(s5num==6){write_com(0x80+12);write_date(0x53);write_com(0x80+13);write_date(0x61); //写星期六write_com(0x80+14);write_date(0x74);write_com(0x80+14);}if(s5num==7){write_com(0x80+12);write_date(0x53);write_com(0x80+13);write_date(0x75); //写星期日write_com(0x80+14);write_date(0x6E);write_com(0x80+14);}if(s5num==7){s5num=0;}}}}if(s3==0) //判断S3是否被按下{delay(5); //判断S3是否真被按下if(s3==0) //判断S3是否真被按下{while(!s3); //松手检测if(s1num==1) //判断S1被按下一下{miao--; //秒自减一if(miao==-1) //当秒等于-1时miao=59; //把秒赋值为59write_sfm(10,miao); //把秒数据写到指定位置write_com(0x80+0x40+11); //不让指针向后移}if(s1num==2) //判断S1被按下两下{fen--; //分自减一if(fen==-1) //当分等于-1时fen=59; //把分赋值为59write_sfm(7,fen); //把分数据写到指定位置write_com(0x80+0x40+8); //不让指针向后移}if(s1num==3) //判断S1被按下三下{shi--; //时自减一if(shi==-1) //当时等于-1时shi=23; //把时赋值为59write_sfm(4,shi); //把时数据写到指定位置write_com(0x80+0x40+5); //不让指针向后移}if(s1num==4) //判断S1被按下四下{nian--; //年自减一if(nian==-1){nian=0; //不让年少于2000}write_sfn(3,nian); //把时数据写到指定位置write_com(0x80+4); //不让指针向后移}if(s1num==5) //判断S1被按下五下{yue--; //月自减一if(yue==-1) //当月等于-1时yue=12; //把月赋值为12if(yue==0)yue=12; //解决月第一次减不正确的问题write_sfn(6,yue); //把时数据写到指定位置write_com(0x80+7); //不让指针向后移}if(s1num==6) //判断S1被按下六下{tian--; //天自减一if(yue==2){if(tian==-1)tian=28;if(tian==0)tian=28;}if(yue==4){if(tian==-1)tian=30;if(tian==0) // 解决不同的月有不同的天的问题tian=30;}if(yue==6){if(tian==-1)tian=30;if(tian==0)tian=30;}if(yue==9){if(tian==-1)tian=30;if(tian==0)tian=30;}if(yue==11){if(tian==-1)tian=30;if(tian==0)tian=30;}if(yue==1,3,5,7,8,10,12){if(tian==-1)tian=31;if(tian==0)tian=31;}write_sfn(9,tian); //把时数据写到指定位置write_com(0x80+10); //不让指针向后移}if(s1num==8) //判断S1被按下八下{nshi--; //闹钟的时自减一if(nshi==-1)nshi=23;write_sfm(21,nshi) ; //把nshi数据写到指定位置write_com(0x80+0x40+22); //不让指针向后移}if(s1num==9) //判断S1被按下九下{nfen--; //闹钟的分自加一if(nfen==-1) //判断nfen是否为-1nfen=59; //nfen为59write_sfm(24,nfen) ; //把nfen数据写到指定位置write_com(0x80+0x40+25); //不让指针向后移}}}}}void main() //主函数{init(); //初始化函数while(1){keyscan(); //控制按键}}void timer0() interrupt 1 //中断子函数{TH0=(65536-50000)/256; //重装初值TL0=(65536-50000)%256;count++; //用以计时的变量if(count==20) //判断中断时间是否为一秒{count=0; //为一秒count清零重新计时miao++; //秒加一if(miao==60) //判断miao是否为60{miao=0; //为60miao清零fen++; //fen加一if(fen==60) //判断fen是否为60{fen=0; //为60fen清零shi++; //时加一if(shi==24) //判断shi是否为24{shi=0; //为24shi清零tian++; //天自加一s5num++;if(s5num==1){write_com(0x80+12);write_date(0x4D);write_com(0x80+13);write_date(0x6F); //写星期一write_com(0x80+14);write_date(0x6E);write_com(0x80+14);}if(s5num==2){write_com(0x80+12);write_date(0x54);write_com(0x80+13);write_date(0x75); //写星期二write_com(0x80+14);write_date(0x65);write_com(0x80+14);}if(s5num==3){write_com(0x80+12);write_com(0x80+13);write_date(0x65); //写星期三write_com(0x80+14);write_date(0x64);write_com(0x80+14);}if(s5num==4){write_com(0x80+12);write_date(0x54);write_com(0x80+13);write_date(0x68); //写星期四write_com(0x80+14);write_date(0x75);write_com(0x80+14);}if(s5num==5){write_com(0x80+12);write_date(0x46);write_com(0x80+13);write_date(0x72); //写星期五write_com(0x80+14);write_date(0x69);write_com(0x80+14);}if(s5num==6){write_com(0x80+12);write_date(0x53);write_com(0x80+13);write_date(0x61); //写星期六write_com(0x80+14);write_date(0x74);write_com(0x80+14);}if(s5num==7){write_com(0x80+12);write_com(0x80+13);write_date(0x75); //写星期日write_com(0x80+14);write_date(0x6E);write_com(0x80+14);}if(s5num==7){s5num=1;}if(yue==1,3,5,7,8,10,12){if(tian==32)tian=1;}if(yue==4){if(tian==31) //解决天循环问题tian=1;}if(yue==6){if(tian==31)tian=1;}if(yue==9){if(tian==31)tian=1;}if(yue==11){if(tian==31)tian=1;}if(yue==2){if(tian==29)tian=1;}write_sfn(9,tian); //写天到指定位置if(tian==1){yue++;if(yue==13) //月循环{yue=1;}if(yue==1)nian++;write_sfn(3,nian); //写年到指定位置}write_sfn(6,yue); //写月到指定位置}write_sfm(4,shi); //写小时到指定位置}write_sfm(7,fen); //写分钟到指定位置if(shi==nshi&&fen==nfen){uchar n,s;while(n<60){n++;if(s5==0){ //控制闹钟delay(5);if(s5==0){while(!s5);s++;}}if(s!=1){s=0;a=0; delay(50);a=1; delay(50);a=0; delay(50);a=1; delay(50);a=0; delay(50);a=1; delay(50);a=0; delay(50);a=1; delay(50); //蜂鸣器的响与断a=0; delay(50);a=1; delay(50);a=0; delay(50);a=1; delay(50);a=0; delay(50);a=1; delay(50);a=0; delay(50);a=1; delay(50);a=0; delay(50);a=1; delay(50);a=0; delay(50);a=1; delay(50);}}if(n==60){fen++;if(fen==60){fen=0; shi++;} write_sfm(4,shi); //闹钟响一分钟分自加一}write_sfm(7,fen); //写分钟到指定位置n=0;s=0;}}}write_sfm(10,miao); //写秒钟到指定位置}。
用51单片机和1602液晶做的数字钟
用51单片机和1602液晶做的数字钟数字钟是人们日常生活中常见的时间显示设备,它能够精确显示当前的时间,并且兼具简约和实用性。
本文将介绍使用51单片机和1602液晶屏幕制作自己的数字钟的方法。
所需材料在开始制作之前,我们需要准备以下材料: - 51单片机开发板 - 1602液晶屏幕 - 数字时钟芯片RTC(Real-Time Clock) - 面包板和导线 - 电阻和电容 - 编程器和烧录器硬件连接首先,我们需要将51单片机、1602液晶屏幕和RTC芯片连接起来。
根据硬件接口的定义和引脚功能的规定,我们可以进行以下连接: - 将51单片机的VCC 引脚连接到1602液晶屏幕的VCC引脚,用于提供电源。
- 将51单片机的GND引脚连接到1602液晶屏幕的GND引脚,用于地线连接。
- 将51单片机的P0口连接到1602液晶屏幕的数据线D0-D7,用于数据传输。
- 将51单片机的P2口连接到1602液晶屏幕的RS引脚,用于选择数据和命令传输。
- 将51单片机的P3口连接到1602液晶屏幕的EN引脚,用于启用LCD。
此外,还需要将RTC芯片连接到51单片机上,以实现时间的准确显示。
具体的连接方式可以参考RTC芯片的规格说明书。
软件编程完成硬件连接后,我们需要进行软件编程,以便控制51单片机、1602液晶屏幕和RTC芯片的功能。
初始化首先,我们需要对51单片机和1602液晶屏幕进行初始化设置。
这包括设置引脚的功能模式、初始化1602液晶屏幕的显示模式和清空显示区域。
读取时间接下来,我们需要通过RTC芯片来读取当前的时间。
这通常包括读取RTC芯片存储的年、月、日、时、分和秒的数据。
显示时间读取时间后,我们可以将其显示在1602液晶屏幕上。
这可以通过更新特定的LCD显示区域来实现。
我们可以在指定的位置、特定的行和列上显示时间。
更新时间为了实现实时的时间显示,我们需要定期更新显示的时间。
可以使用定时器中断来定期更新时间,并根据需要刷新液晶屏幕上的显示。
1602液晶显示电子钟时间C程序
#include<reg51.h>#define uchar unsigned char#define uint unsigned intsbit RS=P2^0;sbit RW=P2^1;sbit E=P2^2;sbit key1=P2^3;sbit key2=P2^4;sbit key3=P2^5;void delay(void);void init(void);void wc51r(uchar i);void wc51ddr(uchar i);void fbusy(void);void LCD_xianshi(void);void delay_zs(uint z);void tiaoshi(void);uchar hour,hour1,min,min1,sec,sec1,aa,bb,num1,num2,num3,flag;uchar year1,year2,year3,year4,month,month1,month2,day,day1,day2; unsigned int year;uchar tab[]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39};void main(){init();while(1){LCD_xianshi();}}void init(){// key1=1;key2=1;key3=1;num1=12;year=2010;month=11;day=15;// wc51r(0x01);wc51r(0x38);wc51r(0x0c);wc51r(0x06);TMOD=0x01; //工作方式1TH0=(65536-5000)/256; //定时器高位装初值计数溢出一次为50ms TL0=(65536-5000)%256; //定时器低位装初值EA=1; //CPU开中断ET0=1; //允许T0中断// ET1=1;TR0=1; //启动T0工作// TR1=1;}void fbusy(){RW=1;RS=0;E=1;while(!P1&0x80);E=0;delay();}void wc51r(uchar j){fbusy();E=0;RS=0;RW=0;E=1;P1=j;E=0;delay();}void wc51ddr(uchar j){fbusy();E=0;RS=1;RW=0;E=1;P1=j;E=0;delay();}void delay(){uchar i,j;for(j=0;j<10;j++)for(i=0;i<10;i++);}/*void delay_zs(uint z){uint x,y;for(x=z;x>0;x--)for(y=110;y>0;y--);}*/void LCD_xianshi(){year1=year/1000;year2=year/100%10;year3=year%100/10;year4=year%10;month1=month/10;month2=month%10;day1=day/10;day2=day%10;hour=num1/10;hour1=num1%10;min=num2/10;min1=num2%10;sec=num3/10;sec1=num3%10;wc51r(0x84); //起始地址为第1行第1列,0x85为第1行第6列;0xc0为第2行第1列wc51ddr(tab[hour]); //显示1wc51ddr(tab[hour1]); //显示2wc51ddr(0x3a); //显示:wc51ddr(tab[min]); //显示0wc51ddr(tab[min1]); //显示0wc51ddr(0x3a); //显示:wc51ddr(tab[sec]);wc51ddr(tab[sec1]);wc51r(0xc3);wc51ddr(tab[year1]);wc51ddr(tab[year2]);wc51ddr(tab[year3]);wc51ddr(tab[year4]);wc51ddr('-');wc51ddr(tab[month1]);wc51ddr(tab[month2]);wc51ddr('-');wc51ddr(tab[day1]);wc51ddr(tab[day2]);}/*void tiaoshi(void){while(key1){TR0=0;if(key2==0){LCD_xianshi;num3++;if(num3==60){num3=0;num2++;}}else if(key3==0)num2++;}// while(key1);// if(key1==0){ET0=1;TR0=1;flag=0;}}*///************************定时器中断程序**************************// void timer0() interrupt 1{TH0=(65536-50000)/256; //重装计数初值TL0=(65536-50000)%256;aa++;if(aa==20) //计数20次后恰为20x50ms==1s{aa=0;num3++; //秒加1if(num3==60) //秒计数到60后清零{num3=0;num2++;if(num2==60){num2=0;num1++;if(num1==24){num1=0;day++;if(month%2==0){if(day==31){day=0;month++;if(month==13){month=0;year++;}}}else if(month%2==1){if(day==32){day=0;month++;if(month==13){month=0;year++;}}}}}}}}//************************定时器中断程序**************************// /*void timer1() interrupt 3{TH1=(65536-50000)/256; //重装计数初值TL1=(65536-50000)%256;bb++;if(bb%20==0){if(key1==0){ET0=0;TR0=0;flag=1;}}}*/#include <msp430g2452.h>unsigned char table[] ={"0123456789"};unsigned char hanzi1[8]={0x04,0x0f,0x12,0x0f,0x0a,0x1f,0x02,0x02};//年 unsigned char hanzi2[8]={0x0f,0x09,0x0f,0x09,0x0f,0x09,0x13,0x11};//月 unsigned char hanzi3[8]={0x1f,0x11,0x11,0x1f,0x11,0x11,0x1f,0x00};//日unsigned char num;void delay_1ms(void){unsigned int i;for (i=0;i<1140;i++);}void delay_nms(unsigned int n){unsigned int i=0;for (i=0;i<n;i++)delay_1ms();}void write_com(unsigned int com){//lcdrs = 0;P2OUT&= 0xfd; P1OUT = com; delay_nms(5); //lcden = 1;P2OUT|= 0x01; delay_nms(5); P2OUT&= 0xfe; }void write_dat(unsigned int dat) {//lcdrs = 1;P2OUT |= 0x02; P1OUT = dat; delay_nms(5); //lcden=1;P2OUT|= 0x01; delay_nms(5); // lcden=0;P2OUT&= 0xfe; }void init() {write_com(0x38);// write_com(0x0f);// write_com(0x01);// write_com(0x06);// // write_com(0x07);//整屏移动 delay_nms(10); }void CGRAM_LCD(unsigned char *hz,unsigned char temp) {unsigned char s; for(s=0;s<8;s++) {write_com(temp+s);write_dat(*(hz+s)); } }void main(void) {WDTCTL = WDTPW + WDTHOLD; // Stop WDT P1DIR |= 0xff; // P1.2 output P2DIR |= 0xff; init();CGRAM_LCD(hanzi1,0x40); CGRAM_LCD(hanzi2,0x48); CGRAM_LCD(ha nzi3,0x50);write_com(0x80); write_dat(table[2]); delay_nms(100);write_com(0x80+0x01); write_dat(table[0]); delay_nms(100);write_com(0x80+0x02); write_dat(table[1]); delay_nms(100);write_com(0x80+0x03); write_dat(table[2]);delay_nms(100);write_com(0x80+0x04); write_dat(0); delay_nms(100);write_com(0x80+0x06); write_dat(table[6]); delay_nms(100);write_com(0x80+0x07); write_dat(1); delay_nms(100);write_com(0x80+0x09); write_dat(table[2]); delay_nms(100);write_com(0x80+0x0a); write_dat(2); while(1); }。
基于1602液晶的电子时钟设计
基于1602液晶的电子时钟设计电子时钟是一种通过电子装置与液晶显示屏显示时间的设备。
它通常由时钟芯片、控制电路和显示屏组成。
本文将设计一个基于1602液晶显示屏的电子时钟。
电子时钟的设计首先需要选择合适的时钟芯片。
一个常用的时钟芯片是DS1302,它具有低功耗、精准度高等优点,并且非常适合于低成本的时钟设计。
同时,我们也需要一个运行时钟,我们可以使用DS1302芯片内部的时钟信号来驱动1602液晶显示屏。
接下来,我们需要一个控制电路,用于读取DS1302芯片的时间数据,并将其显示在1602液晶显示屏上。
控制电路可以使用单片机,如ATmega16或Arduino开发板。
在编程控制电路之前,我们需要先连接DS1302和1602液晶显示屏。
首先,连接DS1302的VCC引脚至+5V电源,将GND引脚连接到地线,将DS和RST引脚分别连接到单片机的SCL(时钟线)和SDA(数据线)引脚。
然后,将1602液晶显示屏的VCC引脚连接至+5V电源,将GND引脚连接至地线,将RS、RW和E引脚依次连接至单片机的I/O口引脚,将D4至D7引脚依次连接至单片机的I/O口引脚。
接下来,我们编写单片机的程序代码。
首先,我们需要初始化1602液晶显示屏,包括清屏、设置显示模式等。
然后,我们需要初始化DS1302芯片,包括设置时钟、日期等。
接着,我们开始读取DS1302芯片的时间数据,并将其显示在1602液晶显示屏上。
我们可以使用单片机的定时器来控制时间的更新,例如每秒钟更新一次。
最后,我们可以添加其他功能,如闹钟、日期显示等。
在设计电子时钟的过程中,我们需要注意以下几点:1.为了节省能源并延长DS1302芯片的使用寿命,我们可以采用休眠模式,只有在需要更新时间时才唤醒DS1302芯片。
2.我们可以添加按键与单片机的输入输出口进行连接,从而实现时间的调节和设置功能,如设置闹钟、日期等。
3.为了提高显示效果,我们可以调整1602液晶显示屏的对比度和背光亮度,只需调整相关电路元件的参数即可。
基于单片机的LCD1602电子时钟设计
基于单片机的LCD1602电子时钟设计近年来,随着物联网和智能设备的快速发展,电子时钟作为一种常见的智能设备,广泛应用于家庭、办公室等各种场合。
本文将基于单片机设计一款LCD1602电子时钟,实现时间显示、闹钟设置等功能。
一、硬件设计1.单片机选择在本设计中,选择常用的51系列单片机AT89C51,具有丰富的外设资源和强大的处理能力。
该单片机具有8位数据总线、16位地址总线,并且集成了定时/计数器、中断控制器和串行通信接口等外设。
2.显示模块选择3.时钟模块选择通过接入DS1302时钟模块,可以实现实时时钟的功能。
DS1302模块具有时钟计数器、电压检测电路、串行通信接口等,并且具有低功耗特点。
4.控制板设计根据LCD1602的引脚连接方式,设计一个控制板,用于将单片机、显示模块和时钟模块等连接在一起。
同时,需注意设计供电电路、外设输入输出电平等电路。
二、软件设计1.初始化设置通过单片机的GPIO口配置,将LCD1602和DS1302对应的引脚设置为输出模式,同时初始化LCD显示屏并进行清屏操作。
此外,需设置DS1302时钟模块的时钟、日期、闹钟等参数。
2.时间显示通过读取DS1302时钟模块的计数器,获得当前的小时、分钟和秒数,然后将其格式化为HH:MM:SS的形式,并通过LCD显示出来。
3.时间设置通过单片机的外部中断,当用户按下设置按钮后,进入时间设置模式。
在时间设置模式下,用户可以通过按下不同的按键来调整小时、分钟和秒数。
调整完成后,再次按下设置按钮即可保存设置。
4.闹钟设置通过单片机的定时器中断,设定一个闹钟定时器。
当闹钟定时器触发时,触发相应的中断,然后通过LCD显示闹钟提示。
此外,用户也可以通过按下按钮来设置闹钟时间,并通过单片机的外部中断进行处理。
5.闹钟响铃当闹钟时间到达时,触发相应的中断,通过LCD显示闹钟提示,并通过蜂鸣器发出响铃声。
总结通过本设计,可以实现一款功能齐全的LCD1602电子时钟。
基于单片机的1602电子时钟设计
基于单片机的1602电子时钟设计一.实验目的:(1)用单片机设计基于单片机的1602电子时钟显示;(2)熟练掌握Keil软件;(3)熟练掌握Proteus软件仿真;(4)掌握单片机的I/O接口的工作原理;(5)掌握LCD显示器的原理和编程方法;(6)掌握独立式键盘的工作原理和编程方法;(7)掌握单片机下载方法;二.实验要求(1)可实现时钟显示(2)可调整时间三.实验内容(1)画仿真图如图1图1(2)编写程序(3)下载运行(4)运行结果,分析其中的错误四.程序(一)#include <reg51.h>#include <intrins.h>#define uchar unsigned char#define uint unsigned intsbit LCD_RS=P2^0;sbit LCD_RW=P2^1 ;sbit LCD_EN=P2^2;void Delay_ms(uint xms) ;bit lcd_busy();void lcd_wcmd(uchar cmd);void lcd_wdat(uchar dat) ;void lcd_clr() ;void lcd_init() ;/********以下是延时函数********/void Delay_ms(uint xms){uint i,j;for(i=xms;i>0;i--) //i=xms即延时约xms毫秒for(j=110;j>0;j--);}/********以下是LCD忙碌检查函数********/bit lcd_busy(){bit result;LCD_RS = 0;LCD_RW = 1;LCD_EN = 1;_nop_(); _nop_(); _nop_(); _nop_();result = (bit)(P0&0x80);LCD_EN = 0;return result;}/********以下是写指令寄存器IR函数********/void lcd_wcmd(uchar cmd){while(lcd_busy());LCD_RS = 0; LCD_RW = 0; LCD_EN = 0;_nop_(); _nop_();P0 = cmd;_nop_(); _nop_(); _nop_(); _nop_();LCD_EN = 1;_nop_(); _nop_(); _nop_(); _nop_();LCD_EN = 0;}/********以下是写寄存器DR函数********/void lcd_wdat(uchar dat){while(lcd_busy());LCD_RS = 1; LCD_RW = 0; LCD_EN = 0;P0 = dat;_nop_(); _nop_(); _nop_(); _nop_();LCD_EN = 1;_nop_(); _nop_(); _nop_(); _nop_();LCD_EN = 0;}/********以下是LCD清屏函数********/void lcd_clr(){lcd_wcmd(0x01); //清除LCD的显示内容Delay_ms(5);}/********以下是LCD初始化函数********/void lcd_init(){Delay_ms(15); //等待LCD电源稳定lcd_wcmd(0x38); //16*2显示,5*7点阵,8位数据Delay_ms(5);lcd_wcmd(0x38);Delay_ms(5);lcd_wcmd(0x38);Delay_ms(5);lcd_wcmd(0x0c); //显示开,关光标Delay_ms(5);lcd_wcmd(0x06); //移动光标Delay_ms(5);lcd_wcmd(0x01); //清除LCD的显示内容Delay_ms(5);}(二)#include <reg51.h>#include "LCD_drive.h"#define uchar unsigned char#define uint unsigned intuchar year=12,mon=10,day=10,hour=12,min=00,sec=00;uchar count_10ms;sbit k7=P3^0; sbit k1=P3^2; sbit k2=P3^3; sbit k3=P3^4;sbit k4=P3^5; sbit k5=P3^6; sbit k6=P3^7; bit k1_flag=0;uchar code line1_data[] = {"----"};uchar code line2_data[] = {"****"};uchardisp_buf[12]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; void LCD_conv(char in1,in2,in3,in4,in5,in6){disp_buf[0]=in1/10+0x30; disp_buf[1]=in1%10+0x30; disp_buf[2]=in2/10+0x30; disp_buf[3]=in2%10+0x30; disp_buf[4]=in3/10+0x30; disp_buf[5]=in3%10+0x30; disp_buf[6]=in4/10+0x30; disp_buf[7]=in4%10+0x30; disp_buf[8]=in5/10+0x30; disp_buf[9]=in5%10+0x30; disp_buf[10]=in6/10+0x30; disp_buf[11]=in6%10+0x30; }void LCD_disp(){lcd_wcmd(0x04|0x80);lcd_wdat(disp_buf[0]); lcd_wdat(disp_buf[1]);lcd_wdat(0xb0);lcd_wdat(disp_buf[2]); lcd_wdat(disp_buf[3]);lcd_wdat(0xb0);lcd_wdat(disp_buf[4]); lcd_wdat(disp_buf[5]);lcd_wcmd(0x44|0x80);lcd_wdat(disp_buf[6]); lcd_wdat(disp_buf[7]);lcd_wdat(0x3a);lcd_wdat(disp_buf[8]); lcd_wdat(disp_buf[9]);lcd_wdat(0x3a);lcd_wdat(disp_buf[10]); lcd_wdat(disp_buf[11]);}void timer1() interrupt 3{TH1=0xdc; TL0=0x00;count_10ms++;if(count_10ms>=100){count_10ms=0; sec++;if(sec>=60){sec=0; min++;if(min>=60){min=0; hour++;if(hour>=24){hour=0; day++;if(day>=30){day=1; mon++;if(mon>=12){mon=1; year++;} }}} } }}void keyprocess(){TR1=0;if(k2==0){Delay_ms(10);if(k2==0){while(!k2); year++; }}if(k3==0){Delay_ms(10);if(k3==0){while(!k3); mon++;if(mon>12){mon=0;} } }if(k4==0){Delay_ms(10);if(k4==0){while(!k4); day++;if(day>30){day=0;} } }if(k5==0){Delay_ms(10);if(k5==0){while(!k5); hour++;if(hour==24){hour=0;} }}if(k6==0){Delay_ms(10);if(k6==0){while(!k6); min++; if(min==60) {min=0;} }}if(k7==0){Delay_ms(10);if(k7==0){while(!k7);TR1=1; k1_flag=0;} }}void timer1_init(){TMOD=0x10;TH1=0xdc; TL1=0x00;EA=1; ET1 =1; TR1 =1;}void main(){uchar i;P0=0xff; P2=0xff;timer1_init ();lcd_init(); lcd_clr();lcd_wcmd(0x00|0x80);i=0;while(line1_data[i]!='\0'){lcd_wdat(line1_data[i]); i++;}lcd_wcmd(0x0c|0x80); i=0;while(line1_data[i]!='\0'){lcd_wdat(line1_data[i]); i++;}lcd_wcmd(0x40|0x80); i=0;while(line2_data[i]!='\0'){lcd_wdat(line2_data[i]); i++;}lcd_wcmd(0x4c|0x80); i=0;while(line2_data[i]!='\0'){lcd_wdat(line2_data[i]); i++;}while(1){if(k1==0){Delay_ms(10);if(k1==0){while(!k1);k1_flag=1;}}if(k1_flag==1)keyprocess();LCD_conv(year,mon,day,hour,min,sec); LCD_disp();}}。
1602液晶显示程序(时钟)
// ************1602液晶显示程序************ #include<reg52.h>#define uchar unsigned char#define uint unsigned intsbit lcden=P2^2; //液晶使能位sbit lcdrw=P2^1; //液晶读写位sbit lcdrs=P2^0; //数据命令选择位uchar shi,fen,miao;uchar code time1[]="DATA: 2011-4-19";uchar code time2[]="TIME: 00:00:00";void w_cmd(uint date);void w_data(uint date);void w_cht(uchar add,uchar date);//************初始化及相关子函数*********** void delay(uchar x){uchar y,z;for(y=x;y>0;y--)for(z=110;z>0;z--);}void init() //1602液晶初始化{uchar i,j;lcden=0; //初始使能端lcdrw=0; // 写数据选择w_cmd(0x38);w_cmd(0x01);w_cmd(0x0c);w_cmd(0x06);w_cmd(0x80);for(i=0;i<15;i++)w_data(time1[i]);w_cmd(0x80+0x40);for(j=0;j<15;j++)w_data(time2[j]); //上电初始显示数据}void w_cmd(uint date) //“写”命令子程序{lcdrs=0;P0=date;delay(5);lcden=1;delay(5);lcden=0;}void w_data(uint date) //”写“数据子程序{lcdrs=1;P0=date;delay(3);lcden=1;delay(5);lcden=0;}void intrupt() //"TO中断"初始{TMOD=0x01; //选择16位定时器0x01 EA=1; //开总中断ET0=1; //开“T0”中断允许位TH0=(65536-50000)/256;TL0=(65536-50000)%256; //定时器装初值TR0=1;}void w_cht(uchar add,uchar date) //时间改变函数{uchar date1,date2;w_cmd(0x80+0x40+add);date1=date/10;date2=date%10;w_data(0x30+date1);w_data(0x30+date2);}//********主函数**************void main(){init();intrupt();while(1);}//*******T0中断子程序************* void T_rupt() interrupt 1{uchar flag; //定义标志位TH0=(65536-50000)/256;TL0=(65536-50000)%256; //赋初值flag++;if(20==flag){flag=0;miao++;if(60==miao){miao=0;fen++;if(60==fen){fen=0;shi++;if(24==shi){shi=0;}w_cht(7,shi);}w_cht(10,fen);}w_cht(13,miao);}}。
(完整word版)1602液晶时钟程序(51单片机)
1602液晶时钟程序程序按郭天袢《新概念51单片机C语言教程》第十四章扩展显示年、月、日、星期调节功能。
1)时间显示在1602液晶上,并按秒实时更新2)能调节按键调整时、分、秒、年、月、日和星期3)每次按键按下时有短滴声响声4)断电后下次上电会接着上次断电前的时间数继续运行原理图如图//原代码如下:#include<reg52.h>//#include"24c02.h"#define uchar unsigned char#define uint unsigned int#include"24c02.h"sbit dula=P2^6;sbit wela=P2^7;sbit LCDEN=P3^4;sbit LCDRS=P3^5;sbit s1=P3^0;//定义按键--功能键sbit s2=P3^1;//定义按键--增大键sbit s3=P3^2;//定义按键--减小键sbit rd=P3^7;//按键公共脚sbit beep=P2^3;//定义蜂鸣器脚uchar count,s1_num;//定义中断次数计数变量功能键按键次数变量uchar week,day,month,year;//定义变量:星期日月年char miao,shi,fen;//定义秒分时变量uchar code table[]=" 2012-11-28 Wed";//void write_week(char we);//显示星期几函数void delay(uint z){uint x,y;for(x=z;x>0;x--)for(y=110;y>0;y--);}void di()//蜂鸣器响一声函数{beep=0;delay(100);beep=1;}void write_com(uchar com) //液晶写命令函数{LCDRS=0;P0=com;delay(5);LCDEN=1;delay(5);LCDEN=0;}void write_date(uchar date) //液晶写数据函数{LCDRS=1;P0=date;delay(5);LCDEN=1;delay(5);LCDEN=0;}void write_week(char we) //写星期几显示函数{write_com(0x80+12);switch(we){case 1: write_date('M');delay(5); //星期一Mondaywrite_date('o');delay(5);write_date('n');delay(5);break;case 2: write_date('T');delay(5); //星期二Tuesdaywrite_date('u');delay(5);write_date('e');delay(5);break;case 3: write_date('W');delay(5); //Wednesdaywrite_date('e');delay(5);write_date('d');delay(5);break;case 4: write_date('T');delay(5); //Thursdaywrite_date('h');delay(5);write_date('u');delay(5);break;case 5: write_date('F');delay(5); //星期五Fridaywrite_date('r');delay(5);write_date('i');delay(5);break;case 6: write_date('S');delay(5); //星期六Saturdaywrite_date('a');delay(5);write_date('t');delay(5);break;case 7: write_date('S');delay(5); //星期日Sundaywrite_date('u');delay(5);write_date('n');delay(5);break;default: break;}}void write_sfm(uchar add,uchar date) //写时分秒函数{uchar shiwei,gewei;shiwei=date/10;gewei=date%10;write_com(0x80+0x40+add);//设置显示位置write_date(0x30+shiwei);//加上0x30是因为数字变成字符串需要加上0x30,看ASCII码值与字符的关系write_date(0x30+gewei);}void write_year_month_day(uchar add,uchar day) //写年月日数函数{uchar shi,ge;shi=day/10;ge=day%10;write_com(0x80+add);//设置显示位置write_date(0x30+shi);//加上0x30是因为数字变成字符串需要加上0x30,看ASCII码值与字符的关系write_date(0x30+ge);}void init() //初始化函数{uchar num;rd=0;beep=1;dula=0;wela=0;LCDEN=0;//将使能端置0以完成高脉冲fen=0;miao=0;shi=0;count=0;//计数初始为0init_24c02();write_com(0x38);//设置16*2显示,5*7点阵,8位数据接口write_com(0x0c);//设置开显示,不显示光标write_com(0x06);//写一个字符后地址指针自动加1write_com(0x01);//显示清0,数据指针清0write_com(0x80); //设置显示初始坐标for(num=0;num<15;num++) //显示年月日{write_date(table[num]);delay(5);}write_com(0x80+0x40+6); //写出时间显示部分的两个冒号write_date(0x3a);delay(5);write_com(0x80+0x40+9);write_date(0x3a);delay(5);miao=read_add(1);//开机上电时读取24c02 IIC的数据赋值fen=read_add(2);shi=read_add(3);week=read_add(4);//读取星期几day=read_add(5);//读取多少日month=read_add(6);year=read_add(7);write_sfm(10,miao);//分别送去液晶显示write_sfm(7,fen);write_sfm(4,shi);write_week(week);//开机从24c02读取的星期几数从新写入液晶显示出来write_year_month_day(9,day);write_year_month_day(6,month);write_year_month_day(3,year);//定时器初始化TMOD=0x01; //设置定时器0工作模式1TH0=(65536-45876)/256; //定时器装初值TL0=(65536-45876)%256;EA=1; //开总中断ET0=1; //打定时器0中断TR0=1; //启动定时器0}void keyscan() //按键扫描函数{if(s1==0){delay(5);if(s1==0){s1_num++; //功能键按下次数记录while(!s1); //按键释放确认di();if(s1_num==1) //只按一次按键时TR0=0; //关闭定时器write_com(0x80+0x40+11);write_com(0x0f); //打开光标闪烁}if(s1_num==2) //第二次按下光标闪烁定位到分钟位置{write_com(0x80+0x40+8);}if(s1_num==3) //第三次按下光标闪烁定位到小时位置{write_com(0x80+0x40+5);}/**************************************if(s1_num==4) //第三四次按下退出{s1_num=0;write_com(0x0c); //取消光标闪栎TR0=1; //启动定时器使时钟开始走}***************************************/if(s1_num==4) //光标处星期{write_com(0x80+14);}if(s1_num==5) //光标处日{write_com(0x80+10);}if(s1_num==6) //光标处月{write_com(0x80+7);}if(s1_num==7) //光标处年{write_com(0x80+4);}if(s1_num==8) //当第八次按功能键时退出光标闪烁及开始计时{s1_num=0;write_com(0x0c); //取消光标闪栎TR0=1; //启动定时器使时钟开始走}}if(s1_num!=0){if(s2==0)//增加键确认按下{delay(5);if(s2==0){while(!s2);di();if(s1_num==1){miao++;if(miao==60)miao=0;write_sfm(10,miao);write_com(0x80+0x40+11);write_add(1,miao);}if(s1_num==2){fen++;if(fen==60)fen=0;write_sfm(7,fen);write_com(0x80+0x40+8);write_add(2,fen);}if(s1_num==3){shi++;if(shi==24)shi=0;write_sfm(4,shi);write_com(0x80+0x40+5);write_add(3,shi);}if(s1_num==4)//按四次功能键后光标至星期几处,可调节星期几{week++;if(week==8)week=1;write_week(week);write_com(0x80+14); //写一个字符后光标会移一位,所以要重新定义光标位置write_add(4,week);}if(s1_num==5) //光标至显示日处,可调节多少日{day++;if(day==32)day=1;write_year_month_day(9,day);write_com(0x80+10);write_add(5,day);}if(s1_num==6) //光标至显示月处调节月份{month++;if(month==13)month=1;write_year_month_day(6,month);write_com(0x80+7);write_add(6,month);}if(s1_num==7){year++;if(year==100)year=00;write_year_month_day(3,year);write_com(0x80+4);write_add(7,year);}}}if(s3==0) //确认减小键被按下{delay(5);//按键防抖延时if(s3==0) //确认减小键被按下{while(!s3);di();if(s1_num==1){miao--;if(miao==-1)miao=59;write_sfm(10,miao);write_com(0x80+0x40+11);write_add(1,miao);}if(s1_num==2){fen--;if(fen==-1)fen=59;write_sfm(7,fen);write_com(0x80+0x40+8);write_add(2,fen);}if(s1_num==3){shi--;if(shi==-1)shi=23;write_sfm(4,shi);write_com(0x80+0x40+5);write_add(3,shi);}if(s1_num==4){week--;if(week==0)week=7;write_week(week);write_com(0x80+14); //写一个字符后光标会移一位,所以要重新定义光标位置write_add(4,week);}if(s1_num==5)//光标至显示日处,可调节多少日{day--;if(day==0)day=31;write_year_month_day(9,day);write_com(0x80+10);//光标位置移回在显示多少日的个位write_add(5,day);}if(s1_num==6) //光标至显示月处调节月份{month--;if(month==0)month=12;write_year_month_day(6,month);write_com(0x80+7);write_add(6,month);}if(s1_num==7){year--;if(year==-1)year=99;write_year_month_day(3,year);write_com(0x80+4);write_add(7,year);}}}}}void main(){init();//首先初始化各数据while(1){keyscan(); //按键扫描函数}}void timer0() interrupt 1 //定时器0中断服务程序{TH0=(65536-45876)/256;TL0=(65536-45876)%256;count++; //中断次数累加,计数if(count==20) //50微秒乘以20等于1秒{count=0;miao++;if(miao==60) //秒加到60则进位分钟{miao=0; //同时秒数清0fen++;if(fen==60) //分钟加到60则进位小时{fen=0; //同时分钟清0shi++;if(shi==24) //小时加到24则小时清0{shi=0;}write_sfm(4,shi);//小时若变化则重新写入write_add(3,shi);//写入24c02存储起来,小时数的写入地址为3 }write_sfm(7,fen);//分钟若变化则重新写入write_add(2,fen);}write_sfm(10,miao);//秒若变化则重新写入write_add(1,miao);}}/***********************************24C02.h头文件,将以下源代码需存为与保存的C代码根目录下。
1602液晶电子时钟程序51单片机
1602液晶电子时钟程序[日期:2009-06-11 ] [来源:net 作者:佚名] [字体:大中小] (投递新闻)连线图:; DB0---DPROT.0 DB4---DPROT.4 RS-------------P1.2; DB1---DPROT.1 DB5---DPROT.5 RW-------------P1.3; DB2---DPROT.2 DB6---DPROT.6 E--------------P1.4; DB3---DPROT.3 DB7---DPROT.7 VLCD接10K可调电阻到GND*#include "reg52.h"//头文件#include "intrins.h"#define uchar unsigned char//宏定义#define uint unsigned int//宏定义sbit RS=P1^2;//定义I/O的硬件接口sbit RW=P1^3;sbit E=P1^4;sbit led_1=P1^7;//;;;LED秒闪烁uchar Hours=0;//定义小时uchar Minutes=0;//定义分钟uchar Seconds=0;//定义秒bit Seconds_Scintillation=1;//定义秒闪烁标志#define DPDR P0//并行数据接口定义uchar code DispTab_1[]={'0','1','2','3','4','5','6','7','8','9'};//1602:0-9 数字uchar code DispTab_2[]={'A','B','C','D','E','a','b','c','d','e'};//1602:A-e 字母uchar DispBuf[8]; //8字节的显示缓冲区char char_char_1[]={" "};//定义字符串char char_char_2[]={" "};//定义空字符串void delay(uint z)//1ms延时{uchar x,x1;for(;z>0;z--){for(x=0;x<114;x++){for(x1=0;x1<1;x1++);}}}void Timer0() interrupt 1{static uchar Count_50;//uchar temp;TH0=0xb7;TL0=0xff;//定时时间为20ms,每20ms中断一次Count_50++;if(Count_50==50)//20ms*50=1秒{ Seconds_Scintillation=~Seconds_Scintillation; led_1=~led_1;Count_50=0;Seconds++;if(Seconds==60){Seconds=0;Minutes++;if(Minutes==60){Minutes=0;Hours++;if(Hours==24){Hours=0;}}}}if(Seconds_Scintillation==1)//秒闪烁标志判断DispBuf[6]=':';elseDispBuf[6]=' ';DispBuf[0]=Hours/10;//转换成10进制显示DispBuf[1]=Hours%10;DispBuf[2]=Minutes/10;DispBuf[3]=Minutes%10;DispBuf[4]=Seconds/10;DispBuf[5]=Seconds%10;temp=DispBuf[0];DispBuf[0]=DispTab_1[temp];//查表取字符temp=DispBuf[1];DispBuf[1]=DispTab_1[temp];temp=DispBuf[2];DispBuf[2]=DispTab_1[temp];temp=DispBuf[3];DispBuf[3]=DispTab_1[temp];temp=DispBuf[4];DispBuf[4]=DispTab_1[temp];temp=DispBuf[5];DispBuf[5]=DispTab_1[temp];}void write_Directive(uchar a)//写指令{RS=0;RW=0;delay(1);E=0;DPDR=a;delay(1);E=1;delay(1);E=0;delay(1);}void write_Data(uchar a)//写数据{RS=1;RW=0;delay(1);E=0;DPDR=a;delay(1);E=1;delay(1);E=0;delay(1);}void init()//初始化{ uchar i;TMOD=0x01;TH0=0xb7;TL0=0xff;//定时时间为20ms,每20ms中断一次ET0=1; //开T0中断EA=1; //开总中断TR0=1; //T0开始运行DispBuf[6]=':';delay(15);write_Directive(0x38);delay(5);write_Directive(0x38);delay(5);write_Directive(0x38);write_Directive(0x01);write_Directive(0x02);//初始化后数据地址为0x80;即第一行,第一个位置write_Directive(0x0c);//不显示光标write_Directive(0x80+0x40);//第二行第一位地址for(i=0;i<16;i++){write_Data(char_char_1[i]);//显示字符串" "}}void write_Data_String()//显示时间函数{write_Directive(0x80+0x04);//第一行,第五个位置地址write_Data(DispBuf[0]);//第一行,第五个位置write_Data(DispBuf[1]);//第一行,第六个位置write_Data(DispBuf[6]);//第一行,第七个位置write_Data(DispBuf[2]);//第一行,第八个位置write_Data(DispBuf[3]);//第一行,第九个位置write_Data(DispBuf[6]);//第一行,第十个位置write_Data(DispBuf[4]);//第一行,第十一个位置write_Data(DispBuf[5]);//第一行,第十二个位置}void main(){init();while(1){write_Data_String();//调用写连续的16 个字符,1表示第一行;2表示第二行delay(100);//延时100ms,扫描一次}}液晶显示器以其微功耗、体积小、显示内容丰富、超薄轻巧的诸多优点,在袖珍式仪表和低功耗应用系统中得到越来越广泛的应用。
1602中断实现电子时钟程序
int main(void)
{
uchar i;
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
init();
Delay50us(30);
lcd_wcmd(0x84);
for (i=0;i<8;i++)
for(;t>0;t--)
for(j=19;j>0;j--);
}
lcd_bz() //read_stat() 读状态
{
unsigned char result;
P1DIR &= 0x00;
RST_RS;
SET_RW ;
SET_E ;
_nop_();
Delay50us(30);
lcd_wcmd(0x38);
Delay50us(30);
lcd_bz();
lcd_wcmd(0x38); //显示模式设置
lcd_bz();
lcd_wcmd(0x08); //显示关闭
{
fe
lcd_wcmd(0x85+0x40);
lcd_bz();
lcd_wdat(fenh+0x30);
lcd_bz();
lcd_wdat(fenl+0x30);
lcd_bz();
#define SET_E P2OUT |=BIT2
#define RST_E P2OUT &=~BIT2
#define Busy 0x80
unsigned int miaoh=0,miaol=0,fenh=0,fenl=0;
LCD1602电子时钟设计
电子时钟设计班级:电子1001姓名:***学号:**********指导老师:***一、实验目的学习利用AT89C52进行任务设计,练习使用52单片机内部的定时器进行计时。
学习ds1302时钟芯片和ds18b20温度传感器的使用。
学习用模块化编程进行较长程序的编写。
二、设计要求:(1)利用lcd1602液晶显示屏作为显示模块,用AT89C52进行控制,要求用ds18b02测量显示即时温度,温度报警,用ds1302时钟芯片为单片机提供时间数据。
具有定时功能。
(2)要求时间和定时时间可调,并且在闹铃报时的时候可以用按键进行关闭。
并且可以用按键关闭打开定时功能。
(3)利用keil uVision4编译软件进行编译。
(4)完成实验要求,写出实验报告。
三、电子元件列表四、工作现象本时钟具有显示年月日时分秒星期、温度和温度报警的功能。
实验用时钟芯片ds1302来提供秒、分、时、星期、日期、月份和年份的数据,显示部分采用液晶显示模块lcd1602,右上方显示星期,左下角显示温度,右下角显示闹铃的开关状态。
用温度传感器ds18b20来测量温度。
另外,闹铃用pxo888音乐芯片来报时,用蜂鸣器做温度报警发声器。
具体各部分功能及操作下面将做介绍:ds1302给单片机at89c52提供年、月、日、时、分、秒、星期,ds18b20采集温度的数据,经单片机的处理送到液晶显示屏lcd1602上显示,实验设置的报警温度为30*c,由于程序有点长,已达到52单片机内存的极限,所以没加调整报警温度的功能,并且在天正时间的过程中能能加,不能减。
现在开始介绍具体的操作步骤:key1为调整时间和日期的按键,按下key1键,lcd1602上的光标按时分星期日月年的顺序进行移动,光标所到处按key3键可以调整相应的数据信息。
Key2键是闹钟调整键,本实验只提供了设置时间来调整闹钟,不设计年月日和星期,按下key2键,光标在时分之间切换,光标所到处按key3调整相应数据。
1602液晶显示(年月日时分秒星期)
电子钟—1602液晶显示(年月日时分秒星期)/* 以下是电子钟的c51源程序,用1602液晶显示,虽然程序很庞大,但容易看懂。
改程序花了我两三天的时间才弄好的,现在放在此分享。
*/#include<AT89X52.H>#include<intrins.h>#define uchar unsigned char#define uint unsigned int#define T 49998#define T1 64536sbit rs=P2^0;sbit rw=P2^1;sbit en=P2^2;uchar key,n,loca=0,allow=0,cout;uchar week;uchar time[6]={0,6,15,12,30,0}; //对应、月、日、时、分、秒?uint year=2009;void delay(uint ms){uint i;for(;ms>0;ms--){for(i=246;i>0;i--);}}void timer0() interrupt 1{TH0=(65536-T)/256;TL0=(65535-T)%256;n++;}void time_addsec(){if(20<=n){n=0;time[5]++; //产生秒}}uchar key_scan(){uchar i,j,key,temp;uchar code scan[]={0xfe,0xfd,0xfb,0xf7};uchar code keyb[]={0x7e,0xbe,0xde,0xee,0x7d,0xbd,0xdd,0xed,0x7b,0xbb,0xdb,0xeb,0x77,0xb7,0xd7,0xe7};for(i=0;i<4;i++){P3=scan[i];_nop_();temp=P3;if(temp!=scan[i]){for(j=0;j<16;j++){if(keyb[j]==P3){delay(50);// while(keyb[j]==P3);//松手操作// delay(20);// while(keyb[j]==P3);key=j+1;break;}if(keyb[j] != P3){key=0;}}}}return key;}bit lcd_bz()//1602检忙{bit v;rs=0;rw=1;en=1;_nop_();v=(bit)(P0&0x80);en=0;return v;}void lcd_wcmd(uchar cmd)//1602写命令{while(lcd_bz());rs=0;rw=0;en=0;_nop_();P0=cmd;_nop_();en=1;_nop_();_nop_();en=0;_nop_();rs=0;}void lcd_wdat(uchar dat)//1602写数据{while(lcd_bz());rs=1;rw=0;en=0;_nop_();P0=dat;_nop_();en=1;_nop_();;en=0;}void lcd_wstr(uchar *str)//1602写字符串{uchar i;for(i=0;str[i]!='\0';i++){lcd_wdat(str[i]);}}void lcd_pos(uchar pos)//光标定位{while(lcd_bz());lcd_wcmd(pos|0x80);}/*void lcd_cur(){switch(loca){case 0 : lcd_pos(0x46); case 1 : lcd_pos(0x49); case 2 : lcd_pos(0x05); case 3 : lcd_pos(0x08); case 4 : lcd_pos(0x0b); }}*/void lcd_rmove()//光标右移{if(1==allow){if(loca >= 0 && loca < 5) {loca++;}}}void lcd_lmove(){if(1==allow){if(loca > 0 && loca <= 5) {loca--;}}}void lcd_addtime()//调时间加{uint dat ;if(1==allow)switch(loca){case 0 :{dat=year;dat++;year=dat;delay(100);break;}case 1 :{dat=time[1];dat++;if(dat>12)dat=1;time[1]=dat;delay(100);break; }case 2 :{dat=time[2];dat++;if(dat>30)dat=1;time[2]=dat;delay(100);break; }case 3 :{dat=time[3];dat++;if(dat>24)dat=1;time[3]=dat;delay(100);break; }case 4 :{dat=time[4];dat++;if(dat>60)dat=1;time[4]=dat;delay(100);break; }case 5 :{dat=time[5];dat++;if(dat>60)dat=1;time[5]=dat;delay(100);break; }}}void lcd_detime()//调时间减{int dat ;if(1==allow)switch(loca){case 0 :{dat=year;dat--;if(dat<0)dat=2000;year=dat;delay(100);break;}case 1 :{dat=time[1];dat--;if(dat<0)dat=12;time[1]=dat;delay(100);break; }case 2 :{dat=time[2];dat--;if(dat<0)dat=30;time[2]=dat;delay(100);break; }case 3 :{dat=time[3];dat--;if(dat<0)dat=23;time[3]=dat;delay(100);break; }case 4 :{dat=time[4];dat--;if(dat<0)dat=59;time[4]=dat;delay(100);break; }case 5 :{dat=time[5];dat--;if(dat<0)dat=59;time[5]=dat;delay(100);break;}}}void function(){uchar key=key_scan();switch(key){case 5 : lcd_lmove();break;case 6 : lcd_rmove();break;case 7 : lcd_addtime();break;case 8 : lcd_detime();break;case 9 : lcd_wcmd(0x0f);allow=1;break; //显示光标case 10 : lcd_wcmd(0x0c);allow=0;break; //关闭光标}}bit year_tell() //判断是否闰年是1 否0{if((year%4 == 0 && year%100 !=0) || year%400 == 0) return 1;else return 0;}uint count1(uint year , uchar mon , uchar day)//以下count1到count3都是为了计算对应的星期{uint m;switch(mon){case 1 : m=366-day; break;case 2 : m=335-day; break;case 3 : m=306-day; break;case 4 : m=275-day; break;case 5 : m=245-day; break;case 6 : m=214-day; break;case 7 : m=184-day; break;case 8 : m=153-day; break;case 9 : m=122-day; break;case 10 : m=92-day; break;case 11 : m=61-day; break;case 12 : m=31-day; break;default : ;}if(!(year%4 == 0 && year%100 != 0 || year%400 == 0)){if(mon<=2){m=m-1;}}return(m);}uint count2(uint year , uchar mon , uchar day){uint m;if(year%4 == 0 && year%100 != 0 || year%400 == 0){m=366-count1(year , mon , day);}else{m=365-count1(year , mon , day);}return m;}uint count3(uint year1 , uint year2){uint m=0;uchar i;uint n=year2-year1;for(i=1;i<n;i++){if((year1+i)%4 == 0 && (year1+i)%100 != 0 || (year1+i)%400 == 0) {m+=366;}else{m+=365;}}return m;}uchar week_tell()//判断对应的星期{uchar w;w=(count1(1901,1,7)+count2(year,time[1],time[2])+count3(1901,year)+1)%7; if(w!=0)return w;else return 7;}void timecount()//时间计算{if(time[5]>=60) //sec{time[5]=0;time[4]++;}if(time[4]>=60)//min{time[4]=0;time[3]++;}if(time[3]>=24)//hour{time[3]=0;time[2]++; //day}switch(time[1]) //mon{case 1 : if(time[2]>=31){time[2]=0; time[1]++;}case 2 :if(1==year_tell()){if(time[2]>29){time[2]=0; time[1]++;}}else{if(time[2]>28){time[2]=0; time[1]++;}}case 3 : if(time[2]>=31){time[2]=0; time[1]++;}case 4 : if(time[2]>=30){time[2]=0; time[1]++;}case 5 : if(time[2]>=31){time[2]=0; time[1]++;}case 6 : if(time[2]>=30){time[2]=0; time[1]++;} case 7 : if(time[2]>=31){time[2]=0; time[1]++;} case 8 : if(time[2]>=31){time[2]=0; time[1]++;} case 9 : if(time[2]>=30){time[2]=0; time[1]++;} case 10 : if(time[2]>=31){time[2]=0; time[1]++;} case 11 : if(time[2]>=30){time[2]=0; time[1]++;} case 12 : if(time[2]>=31){time[2]=0; time[1]++;} }if(time[1]>12){time[1]=0;year++;}}/*void lcd_clear(){lcd_wcmd(0x01);_nop_();}*/void lcd_display(uchar p)//液晶显示{uchar i,j;uchar str_com[14];str_com[13]=year/1000;str_com[12]=(year/100)%10;str_com[11]=(year%100)/10;str_com[10]=year%10;str_com[9]=time[1]/10;str_com[8]=time[1]%10;str_com[7]=time[2]/10;str_com[6]=time[2]%10;str_com[5]=time[3]/10;str_com[4]=time[3]%10;str_com[3]=time[4]/10;str_com[2]=time[4]%10;str_com[1]=time[5]/10;str_com[0]=time[5]%10;if(0==p)//非设定状态{lcd_pos(0x07);for(i=0,j=0;i<8;i++,j++){if(2==i || 5==i){lcd_wdat(':');j--;}elselcd_wdat(str_com[j]+48);}lcd_pos(0x49);for(i=6,j=6;i<16;i++,j++){if(8==i || 11==i){lcd_wdat('-');j--;}elselcd_wdat(str_com[j]+48);}delay(1 );lcd_wcmd(0x06);lcd_pos(0x4c);switch(week_tell()){case 1 : lcd_wstr("Mon");break;case 2 : lcd_wstr("Tue");break;case 3 : lcd_wstr("Wen");break;case 4 : lcd_wstr("Thu");break;case 5 : lcd_wstr("Fri");break;case 6 : lcd_wstr("Sat");break;case 7 : lcd_wstr("Sun");break;}delay(1 );lcd_wcmd(0x04);}else if(1==p)//时间设定状态{lcd_pos(0x07);lcd_wdat(str_com[0]+48);lcd_wdat(str_com[1]+48);switch(loca) //下面是让光标定在选择位,以便光标稳定的闪烁{case 0 : lcd_pos(0x43);break; case 1 : lcd_pos(0x46);break; case 2 : lcd_pos(0x49);break; case 3 : lcd_pos(0x01);break; case 4 : lcd_pos(0x04);break; case 5 : lcd_pos(0x07);break; }}}void lcd_init()//液晶初始化{delay(15);lcd_wcmd(0x38);delay(5);lcd_wcmd(0x38);delay(5);lcd_wcmd(0x38);while(lcd_bz());lcd_wcmd(0x0e);while(lcd_bz());lcd_wcmd(0x01);}void init(){TMOD=0x11;TH0=(65536-T)/256;TL0=(65536-T)%256;TH1=T1;TL1=T1;EA=1;TR0=1;ET0=1;TR1=0;ET1=1;}main(){init();lcd_init();while(1){// delay(3);// lcd_clear();delay(1 );lcd_wcmd(0x04);time_addsec();timecount();function();lcd_display(1);cout++;if(cout>=50){cout=0;lcd_display(0);}}}//程序到此结束,估计看了有点晕,不过没关系,程序是没有错的,定时很准,经调试在几个小时之后也达到分秒不差,晶振是12M。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
#include<reg52.h> //52单片机头文件#define uchar unsigned char //宏定义#define uint unsigned intsbit rs=P1^0; //声明单片机P1口的第一位读写指令还是数据端sbit rw=P1^1; //声明单片机P1口的第二位读写数据端sbit lcden=P1^2; //声明单片机P1口的第三位液晶使能端sbit s1=P2^5; //声明单片机P2口的第六位按键控制端sbit s2=P2^6; //声明单片机P2口的第七位按键控制端sbit s3=P2^7; //声明单片机P2口的第八位按键控制端sbit s4=P2^0; //声明单片机P2口的第一位按键控制端sbit s5=P2^4; //声明单片机P2口的第五位按键控制端sbit a=P3^5; //声明单片机P3口的第六位按键控制端char count,shi,fen,miao,s1num,xp,s5num,date1; //定义有符号字符形变量char nian,tian,yue,nshi,nfen; //定义有符号字符形变量uchar code table[]=" 2000-01-01 Mon "; //定义日期时间数组uchar code table1[]=" 00:00:00";uchar code table2[]=" Alarm clock"; //定义日期时间数组uchar code table3[]=" 00:00";void delay(uint z){uint x,y;for(x=z;x>0;x--) //延时子函数for(y=110;y>0;y--);}void write_com(uchar com) //指令子函数{rs=0; //选择写指令lcden=0; //使能端初始为底P0=com; //将送到要写的指令数据线上delay(5); //延时待数据稳定lcden=1; //使能端给一个高脉冲把数据写入1602液晶delay(5); //延时lcden=0; //拉低使能端完成高脉冲}void write_date(uchar date) //数据子函数{rs=1; //选择写数据lcden=0;P0=date;delay(5);lcden=1;delay(5);lcden=0;}void init() //初始子函数{uchar num; //定义变量用来调用数组rw=0; //选择只写数据到液晶lcden=0; //初始使能端为低电平write_com(0x38); //设置16*2显示,5*7点阵,8位数据接口write_com(0x0c); //开显示,不显示光标write_com(0x06); //写一个字符指针自动加1write_com(0x01); //显示清零,数据指针清零write_com(0x80); //将数据指针定位到第一行第一个字处for(num=0;num<15;num++){write_date(table[num]); //写日期数组数据delay(20);}write_com(0x80+0x40); //选择将时间写到液晶第二行for(num=0;num<12;num++){write_date(table1[num]); //写时间数组数据delay(20);}write_com(0x80+16); //使用移屏操作for(num=0;num<13;num++){write_date(table2[num]); //写闹钟名称delay(20);}write_com(0x80+0x40+16); //选择移屏第二行for(num=0;num<10;num++){write_date(table3[num]); //写闹钟初始值delay(20);}TMOD=0x01; //选择定时器工作方式为方式1TH0=(65536-50000)/256; //装初值TL0=(65536-50000)%256;EA=1; //开总中断ET0=1; //选择定时器零TR0=1; //开定时器零}void write_sfm(uchar add,uchar date ) //子函数写时间日期到液晶上{uchar shi,ge; //定义变量用以分离十位和个位上的数字shi=date/10; //分离十位上的数字ge=date%10; // 分离个位上的数字write_com(0x80+0x40+add) ; //给出写的位置指令write_date(0x30+shi); //写十位上的数字write_date(0x30+ge); //写个位上的数字}void write_sfn(uchar add,uchar date) //子函数写时间日期到液晶上{uchar shi,ge; //定义变量用以分离十位和个位上的数字shi=date/10; //分离十位上的数字ge=date%10; // 分离个位上的数字write_com(0x80+add) ; //给出写的位置指令write_date(0x30+shi); //写十位上的数字write_date(0x30+ge); //写个位上的数字}void keyscan() //按键子函数{{s4=0; //让共同接口置零if(s1==0) //判断s1是否被按下{delay(5); //延时5ms去斗if(s1==0) //再次判断s1是否真被按下{s1num++; //设置变量判断s1被按下几次while(!s1); //松手检测if(s1num==1) //S1被第一次按下{TR0=0; //关定时器write_com(0x80+0x40+11); //确定指针位置在秒钟write_com(0x0f); //开显示显示光标光标闪烁}}if(s1num==2){write_com(0x80+0x40+8); //确定指针位置在分钟}if(s1num==3){write_com(0x80+0x40+5); //确定指针位置在时针}if(s1num==4){write_com(0x80+4); //确定指针位置在时针}if(s1num==5){write_com(0x80+7); //确定指针位置在时针}if(s1num==6){write_com(0x80+10); //确定指针位置在时针}if(s1num==7){write_com(0x80+14); //确定指针位置在时针}if(s1num==8){uchar num ;write_com(0x18) ;write_com(0x18) ;write_com(0x18) ;write_com(0x18) ;write_com(0x18) ;write_com(0x18) ;write_com(0x18) ; //移屏操作write_com(0x18) ;write_com(0x18) ;write_com(0x18) ; //整屏左移同时光标也跟着移动write_com(0x18) ;write_com(0x18) ;write_com(0x18) ;write_com(0x18) ;write_com(0x18) ;write_com(0x18) ;write_com(0x80+0x40+22); //确定指针位置在时针}if(s1num==9){write_com(0x80+0x40+25); //确定指针位置在时针}if(s1num==10){uchar n;while(n<24){n++; //移屏操作write_com(0x18);}s1num=0;n=0;write_com(0x0c); //结束光标显示表开始走TR0=1;}}}if(s1num!=0) //说明已S1被按下{if(s2==0) //判断S2是否被按下{delay(5); //判断S2是否真被按下if(s2==0); //判断S2是否真被按下{while(!s2); //松手检测if(s1num==1) //判断S1被按下一下{miao++; //秒自加一if(miao==60) //判断miao是否为60miao=0; //秒清零write_sfm(10,miao) ; //把秒数据写到指定位置write_com(0x80+0x40+11); //不让指针向后移}if(s1num==2) //判断S1被按下两下{fen++; //分自加一if(fen==60) //判断fen是否为60fen=0; //fen清零write_sfm(7,fen) ; //把fen数据写到指定位置write_com(0x80+0x40+8); //不让指针向后移}if(s1num==3) //判断S1被按下三下{shi++; //shi自加一if(shi==24) //判断shi是否为24shi=0; //shi清零write_sfm(4,shi) ; //把shi数据写到指定位置write_com(0x80+0x40+5); //不让指针向后移}if(s1num==4) //判断S1被按下四下{nian++; //nian自加一write_sfn(3,nian) ; //把年数据写到指定位置write_com(0x80+4); //不让指针向后移}if(s1num==5) //判断S1被按下五下{yue++; //yue自加一if(yue==13) //使月循环加yue=1;write_sfn(6,yue) ; //把月数据写到指定位置write_com(0x80+7); //不让指针向后移}if(s1num==6) //判断S1被按下六下{tian++; //tian自加一if(yue==1,3,5,7,8,10,12){if(tian==32)tian=1;}if(yue==2){if(tian==29)tian=1;}if(yue==4){if(tian==31) //解决不同的月有不同的天的问题tian=1;}if(yue==6){if(tian==31)tian=1;}if(yue==9){if(tian==31)tian=1;}if(yue==11){if(tian==31)tian=1;}write_sfn(9,tian) ; //把天数据写到指定位置write_com(0x80+10); //不让指针向后移}if(s1num==8) //判断S1被按下八下{nshi++; //闹钟的时自加一if(nshi==24)nshi=0;write_sfm(21,nshi) ;write_com(0x80+0x40+22);}if(s1num==9) //判断S1被按下九下{nfen++; //闹钟的分自加一if(nfen==60) //判断nfen是否为60nfen=0; //nfen清零write_sfm(24,nfen) ; //把nfen数据写到指定位置write_com(0x80+0x40+25); //不让指针向后移}}}if(s1num==7) //判断S1被按下七下{if(s5==0){delay(5);if(s5==0){s5num++;while(!s5);if(s5num==1){write_com(0x80+12);write_date(0x4D);write_com(0x80+13);write_date(0x6F); //写星期一write_com(0x80+14);write_date(0x6E);write_com(0x80+14);}if(s5num==2){write_com(0x80+12);write_date(0x54);write_com(0x80+13); //写星期二write_date(0x75);write_com(0x80+14);write_date(0x65);write_com(0x80+14);}if(s5num==3){write_com(0x80+12);write_date(0x57);write_com(0x80+13);write_date(0x65); //写星期三write_com(0x80+14);write_date(0x64);write_com(0x80+14);}if(s5num==4){write_com(0x80+12);write_date(0x54);write_com(0x80+13);write_date(0x68); //写星期四write_com(0x80+14);write_date(0x75);write_com(0x80+14);}if(s5num==5){write_com(0x80+12);write_date(0x46);write_com(0x80+13);write_date(0x72); //写星期五write_com(0x80+14);write_date(0x69);write_com(0x80+14);}if(s5num==6){write_com(0x80+12);write_date(0x53);write_com(0x80+13);write_date(0x61); //写星期六write_com(0x80+14);write_date(0x74);write_com(0x80+14);}if(s5num==7){write_com(0x80+12);write_date(0x53);write_com(0x80+13);write_date(0x75); //写星期日write_com(0x80+14);write_date(0x6E);write_com(0x80+14);}if(s5num==7){s5num=0;}}}}if(s3==0) //判断S3是否被按下{delay(5); //判断S3是否真被按下if(s3==0) //判断S3是否真被按下{while(!s3); //松手检测if(s1num==1) //判断S1被按下一下{miao--; //秒自减一if(miao==-1) //当秒等于-1时miao=59; //把秒赋值为59write_sfm(10,miao); //把秒数据写到指定位置write_com(0x80+0x40+11); //不让指针向后移}if(s1num==2) //判断S1被按下两下{fen--; //分自减一if(fen==-1) //当分等于-1时fen=59; //把分赋值为59write_sfm(7,fen); //把分数据写到指定位置write_com(0x80+0x40+8); //不让指针向后移}if(s1num==3) //判断S1被按下三下{shi--; //时自减一if(shi==-1) //当时等于-1时shi=23; //把时赋值为59write_sfm(4,shi); //把时数据写到指定位置write_com(0x80+0x40+5); //不让指针向后移}if(s1num==4) //判断S1被按下四下{nian--; //年自减一if(nian==-1){nian=0; //不让年少于2000}write_sfn(3,nian); //把时数据写到指定位置write_com(0x80+4); //不让指针向后移}if(s1num==5) //判断S1被按下五下{yue--; //月自减一if(yue==-1) //当月等于-1时yue=12; //把月赋值为12if(yue==0)yue=12; //解决月第一次减不正确的问题write_sfn(6,yue); //把时数据写到指定位置write_com(0x80+7); //不让指针向后移}if(s1num==6) //判断S1被按下六下{tian--; //天自减一if(yue==2){if(tian==-1)tian=28;if(tian==0)tian=28;}if(yue==4){if(tian==-1)tian=30;if(tian==0) // 解决不同的月有不同的天的问题tian=30;}if(yue==6){if(tian==-1)tian=30;if(tian==0)tian=30;}if(yue==9){if(tian==-1)tian=30;if(tian==0)tian=30;}if(yue==11){if(tian==-1)tian=30;if(tian==0)tian=30;}if(yue==1,3,5,7,8,10,12){if(tian==-1)tian=31;if(tian==0)tian=31;}write_sfn(9,tian); //把时数据写到指定位置write_com(0x80+10); //不让指针向后移}if(s1num==8) //判断S1被按下八下{nshi--; //闹钟的时自减一if(nshi==-1)nshi=23;write_sfm(21,nshi) ; //把nshi数据写到指定位置write_com(0x80+0x40+22); //不让指针向后移}if(s1num==9) //判断S1被按下九下{nfen--; //闹钟的分自加一if(nfen==-1) //判断nfen是否为-1nfen=59; //nfen为59write_sfm(24,nfen) ; //把nfen数据写到指定位置write_com(0x80+0x40+25); //不让指针向后移}}}}}void main() //主函数{init(); //初始化函数while(1){keyscan(); //控制按键}}void timer0() interrupt 1 //中断子函数{TH0=(65536-50000)/256; //重装初值TL0=(65536-50000)%256;count++; //用以计时的变量if(count==20) //判断中断时间是否为一秒{count=0; //为一秒count清零重新计时miao++; //秒加一if(miao==60) //判断miao是否为60{miao=0; //为60miao清零fen++; //fen加一if(fen==60) //判断fen是否为60{fen=0; //为60fen清零shi++; //时加一if(shi==24) //判断shi是否为24{shi=0; //为24shi清零tian++; //天自加一s5num++;if(s5num==1){write_com(0x80+12);write_date(0x4D);write_com(0x80+13);write_date(0x6F); //写星期一write_com(0x80+14);write_date(0x6E);write_com(0x80+14);}if(s5num==2){write_com(0x80+12);write_date(0x54);write_com(0x80+13);write_date(0x75); //写星期二write_com(0x80+14);write_date(0x65);write_com(0x80+14);}if(s5num==3){write_com(0x80+12);write_com(0x80+13);write_date(0x65); //写星期三write_com(0x80+14);write_date(0x64);write_com(0x80+14);}if(s5num==4){write_com(0x80+12);write_date(0x54);write_com(0x80+13);write_date(0x68); //写星期四write_com(0x80+14);write_date(0x75);write_com(0x80+14);}if(s5num==5){write_com(0x80+12);write_date(0x46);write_com(0x80+13);write_date(0x72); //写星期五write_com(0x80+14);write_date(0x69);write_com(0x80+14);}if(s5num==6){write_com(0x80+12);write_date(0x53);write_com(0x80+13);write_date(0x61); //写星期六write_com(0x80+14);write_date(0x74);write_com(0x80+14);}if(s5num==7){write_com(0x80+12);write_com(0x80+13);write_date(0x75); //写星期日write_com(0x80+14);write_date(0x6E);write_com(0x80+14);}if(s5num==7){s5num=1;}if(yue==1,3,5,7,8,10,12){if(tian==32)tian=1;}if(yue==4){if(tian==31) //解决天循环问题tian=1;}if(yue==6){if(tian==31)tian=1;}if(yue==9){if(tian==31)tian=1;}if(yue==11){if(tian==31)tian=1;}if(yue==2){if(tian==29)tian=1;}write_sfn(9,tian); //写天到指定位置if(tian==1){yue++;if(yue==13) //月循环{yue=1;}if(yue==1)nian++;write_sfn(3,nian); //写年到指定位置}write_sfn(6,yue); //写月到指定位置}write_sfm(4,shi); //写小时到指定位置}write_sfm(7,fen); //写分钟到指定位置if(shi==nshi&&fen==nfen){uchar n,s;while(n<60){n++;if(s5==0){ //控制闹钟delay(5);if(s5==0){while(!s5);s++;}}if(s!=1){s=0;a=0; delay(50);a=1; delay(50);a=0; delay(50);a=1; delay(50);a=0; delay(50);a=1; delay(50);a=0; delay(50);a=1; delay(50); //蜂鸣器的响与断a=0; delay(50);a=1; delay(50);a=0; delay(50);a=1; delay(50);a=0; delay(50);a=1; delay(50);a=0; delay(50);a=1; delay(50);a=0; delay(50);a=1; delay(50);a=0; delay(50);a=1; delay(50);}}if(n==60){fen++;if(fen==60){fen=0; shi++;} write_sfm(4,shi); //闹钟响一分钟分自加一}write_sfm(7,fen); //写分钟到指定位置n=0;s=0;}}}write_sfm(10,miao); //写秒钟到指定位置}。