精选优质文档-----倾情为你奉上一、设计任务:1、设计任务:设计并制作一个数字钟2、设计要求: l 显示年月日时分秒及星期信息l 具有可调整日期和时间功能l 增加闰年计算功能l 显示部分由LCD1602完成二、方案论证:1.显示部分:显示部分是本次设计的重要部分,一般有以下两种方案:方案一:采用LED显示,分静态显示和动态显示对于静态显示方式,所需的译码驱动装置很多,引线多而复杂,且可靠性也较低而对于动态显示方式,虽可以避免静态显示的问题,但设计上如果处理不当,易造成亮度低,有闪烁等问题方案二:采用LCD显示LCD液晶显示具有丰富多样性、灵活性、电路简单、易于控制而且功耗小等优点,对于信息量多的系统,是比较适合的鉴于上述原因,我们采用方案二2.数字时钟:数字时钟是本设计的核心的部分根据需要可采用以下两种方案实现:方案一:方案完全用软件实现数字时钟原理为:在单片机内部存储器设三个字节分别存放时钟的时、分、秒信息利用定时器与软件结合实现1秒定时中断,每产生一次中断,存储器内相应的秒值加1;若秒值达到60,则将其清零,并将相应的分字节值加1;若分值达到60,则清零分字节,并将时字节值加1;若时值达到24,则将时字节清零。
该方案具有硬件电路简单的特点,但当单片机不上电,程序将不执行而且由于每次执行程序时,定时器都要重新赋初值,所以该时钟精度不高方案二:方案采用Dallas公司的专用时钟芯片DS1302该芯片内部采用石英晶体振荡器,其芯片精度不大于10ms/年,且具有完备的时钟闹钟功能,因此,可直接对其以用于显示或设置,使得软件编程相对简单为保证时钟在电网电压不足或突然掉电等突发情况下仍能正常工作,芯片内部包含锂电池当电网电压不足或突然掉电时,可使系统自动转换到内部锂电池供电系统而且即使系统不上电,程序不执行时,锂电池也能保证芯片的正常运行,以备随时提供正确的时间基于时钟芯片的上述优点,本设计采用方案二完成数字时钟的功能三、总体方案:本设计采用STC89C52RC单片机作为本系统的控制模块单片机可把由DS1302、LCD液晶显示模块中的数据利用软件来进行处理,从而把数据传输到显示模块,实现日历和修改的显示以LCD液晶显示器为显示模块,把单片机传来的数据显示出来,并且显示多样化在显示电路中,主要靠按键来实现日期的修改和选择四、系统硬件设计:1. STC89C52RC单片机最小系统:最小系统包括晶体振荡电路、复位开关和电源部分。
图1为STC89C52RC单片机的最小系统图1单片机最小系统2.时钟模块:时钟模块采用DS1302芯片,DS1302是DALLAS公司推出的涓流充电时钟芯片内含有一个实时时钟/日历和31字节静态RAM通过简单的串行接口与单片机进行通信实时时钟/日历电路提供秒分时日日期月年的信息每月的天数和闰年的天数可自动调整时钟操作可通过AM/PM指示决定采用24或12小时格式DS1302与单片机之间能简单地采用同步串行的方式进行通信仅需用到三个口线:RST复位、I/O数据线、SCLK串行时钟时钟/RAM的读/写数据以一个字节或多达31个字节的字符组方式通信DS1302工作时功耗很低,保持数据和时钟信息时功率小于1mW,其接线电路如图2所示:图2时钟模块3. LCD液晶显示模块:LCD液晶显示模块采用LCD1602型号,具有很低的功耗,正常工作时电流仅2.0mA/5.0V通过编程实现自动关闭屏幕能够更有效的降低功耗LCD1602分两行显示,每行可显示多达16个字符LCD1602液晶模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,通过内部指令可实现对其显示多样的控制,并且还能利用空余的空间自定义字符。
其接线如图3所示:图3LCD液晶显示五、整体电路:1.电路如下图:图4 整体电路2.Altium Designer布线图图5 Altium Designer布线图3.手动布线PCB图图6PCB图六、数字时钟使用说明:1) 调整时间设定:在时间显示界面中按K1键后,进入时间调整,选择需要修改的或设定的时间按K2键对应内容加1, K3键减1,K4键确定时间设定并退出设置2) 调整屏幕显示/背光亮度:调整左上方的蓝色变阻器可调整LCD显示灰度LCD背光亮度3) 复位键(K5):按下该键系统复位,系统从头开始执行程序如遇故障可按下该键进行系统复位复位不会造成时间、生日和闹铃等信息的丢失七、心得体会:1.将理论教学与实践相结合,使我对于单片机的实际应用有了较深刻的认识 2.让我熟悉电子系统设计的全过程,提高了我对设计课题的分析能力、编程能力及解决实际问题的综合能力3.对于Protues软件有了更加深入的了解,仿真这方面有很大的缺点,程序时序不对软件直接忽略了,因此在这方面花了好多时间进行调试同时在与老师和同学的交流过程中,互动学习,将知识融会贯通通过自己的努力,做出了一个万年历,对以后的学习是一个莫大的鼓舞,激起了我的学习兴趣和开发创新思维。
八、程序及解释:#include #include #include #define uint unsigned int#define uchar unsigned charunsigned char code displaywelcome[]={" Welcome To My Lcd Timer"};//欢迎界面unsigned char code displaywish[]={"通信102闭光俭"}; //欢迎界面sbit IO= P2^3; //DS1302数据线sbit SCLK = P2^4; //DS130时钟线sbit RST = P2^5; //DS1302复位线sbit RS = P2^0; //LCD数据/命令选择端sbit RW = P2^1; //LCD读/写控制sbit EN = P2^2; //LCD使能端sbit K1=P3^4; //选择sbit K2=P3^5; //加sbit K3=P3^6; //减sbit K4=P3^7; //确定uchar tCount=0;uchar MonthsDays[]={0,31,0,31,30,31,30,31,31,30,31,30,31};uchar *WEEK[]={"SUN","MON","TUS","WEN","THU","FRI","SAT"};uchar LCD_DSY_BUFFER1[]={"DATE 00-00-00 "}; //显示格式uchar LCD_DSY_BUFFER2[]={"TIME 00:00:00 "};uchar DateTime[7]; //所读取的日期时间char Adjust_Index=-1; //当前调节的时间对象:,,分,是,日,月,年(1,2,3,4,6)uchar Change_Flag[]= "-MHDM-Y"; //(分,时,日,月,年)(不调节秒与周)void DelayMS(uint ms) //延时程序{ uchar i; while(ms--){for(i=0;i<120;i++);}}void Write_A_Byte_TO_DS1302(uchar x) //向DS1302写入一字节{ uchar i; SCLK=0; for(i=0;i<8;i++){ IO=x&0x01; //每一位与1与存入IO中 SCLK=1;SCLK=0; //一个高脉冲将数据送入液晶控制器 x>>=1; // 右移 }}uchar Get_A_Byte_FROM_DS1302() //从DS1302读取一字节{ uchar i,b=0x00; for(i=0;i<8;i++){ b |= _crol_((uchar)IO,i); SCLK=1;SCLK=0; //每一个高脉冲读取一位数据 } return b/16*10+b%16; //返回BCD码}uchar Read_Data(uchar addr) //从DS1302指定位置读数据{ uchar dat; RST = 0;SCLK=0;RST=1; //RST高电平时读/写 Write_A_Byte_TO_DS1302(addr); //先写入地址 dat = Get_A_Byte_FROM_DS1302(); SCLK=1;RST=0; return dat;}void Write_DS1302(uchar addr,uchar dat) //向DS1302某地址写入数据{ RST=0;SCLK=0;RST=1; Write_A_Byte_TO_DS1302(addr); Write_A_Byte_TO_DS1302(dat); SCLK=1;RST=0; //高脉冲写入数据}void SET_DS1302() //设置时间{ uchar i; //写控制字,取消写保护 Write_DS1302(0x8E,0x00); //分时日月年依次写入 for(i=1;i<7;i++) { Write_DS1302(0x80+2*i,(DateTime[i]/10<<4)|(DateTime[i]%10)); //分的起始地址(0x82),后面依次是时,日,月,周,年,写入地址每次递增2 } Write_DS1302(0x8E,0x80); //加保护}void GetTime()//读取当前日期时间{ uchar i; for(i=0;i<7;i++){ DateTime[i]=Read_Data(0X81+2*i);}}uchar Read_LCD_State()//读LCD状态{ uchar state; RS=0;RW=1;EN=1; //输出:D0~D7=状态字 DelayMS(1); state=P0; //从P0口读LCD状态 EN = 0;DelayMS(1); return state;}void LCD_Busy_Wait() // 忙等待{ while((Read_LCD_State()&0x80)==0x80); DelayMS(5);} void Write_LCD_Data(uchar dat) //向LCD写数据{ LCD_Busy_Wait(); RS=1;EN=0;RW=0; //写数据,EN为高脉冲, P0=dat;EN=1;DelayMS(1);EN=0; }void Write_LCD_Command(uchar cmd) //写LCD指令{ LCD_Busy_Wait(); RS=0;EN=0; RW=0; //写指令,EN高脉冲,输出:D0~D7=数据 P0=cmd;EN=1;DelayMS(1);EN=0; }void Init_LCD() //LCD初始化{ Write_LCD_Command(0x38); //设置16*2显示,5*7点阵,8位数据接口 DelayMS(1); Write_LCD_Command(0x01); 。