单片机.docx
- 文档编号:29259675
- 上传时间:2023-07-21
- 格式:DOCX
- 页数:33
- 大小:583.20KB
单片机.docx
《单片机.docx》由会员分享,可在线阅读,更多相关《单片机.docx(33页珍藏版)》请在冰豆网上搜索。
单片机
《51单片机》课程设计
姓名:
李志宏
学号:
201130095016
系别:
电子信息工程系
班级:
2班
指导老师:
邓婷
完成时间:
2013年1月3号
题目:
利用12864显示屏实现万年历
序言
在现代生活中时间,对每个人来说越来越重要。
掌握着时间的人,才能适应日渐加快社会进步节奏,不被社会淘汰。
因此我们需要一个万年历才能满足我们的需求。
但是传统的万年历有着体积较大不易携带等众多缺点。
于是我们想到了利用现今的电子技术。
设计并制造一个电子万年历。
来克服传统万年历的缺点。
并为其添加新的功能。
来满足人们对此的需求。
1)设计任务和要求
1、显示年月日时分秒及星期信息。
2、具有可调整日期和时间功能
3、增加闰年计算功能
4、可测温度和可调温度上下线
2)原理电路和程序设计:
一:
控制MCU
本次设计采用的芯片为:
STC89C52,宏晶公司的51系列单片机,价格便宜,在国内使用者非常多。
支持串口下载,使用非常方便,且具有很大的价格优势。
缺点是仅支持串口下载,不支持在线下载,使用中会有些不方便。
由于本设计对控制芯片的要求不高,才用此芯片就能达到设计任务的要求。
因此我们选用了此芯片为此次控制MCU。
二:
时钟模块
用时钟芯片DS1302。
优点是同步串行通信,仅使用3个IO口,占用最少的
单片机资源;其内部功能强大。
更重要的是其价格便宜,具有非常高的性价
比。
缺点是串行通信,控制比较复杂。
但是它具有比较简单的硬件架构,方
便设计使用。
甚至在其损坏时,普通人也能按照说明重新更换。
三:
系统框图;
3).设计PCB原理图
主控制芯片采用STC89C52,最小系统包括晶振电路、复位电路、下载接口。
时钟芯片使用DS1302,该模块电路原理图如下图。
时钟电路采用的是ds1302芯片,DS1302是美国DALLAS公司推出的一种高性能、低功耗、带RAM的实时时钟电路,它可以对年、月、日、周日、时、分、秒进行计时,具有闰年补偿功能,工作电压为2.5V~5.5V。
采用三线接口与CPU进行同步通信,并可采用突发方式一次传送多个字节的时钟信号或RAM数据。
工作电压与单片机的输入电压比较适合。
DS1302引脚叙述。
DS1302寄存器命令叙述。
DS1302和单片机的连接很简单。
只需一根复位线,一根时钟线,一根数据线即可。
同时它本身还需要接一个32.768KHz的晶振来提供时钟源。
对于晶振的两端可以分别接一个6PF左右的电容以提高晶振的精确度。
同时可以在第8脚接上一个3.6V的可充电的电池。
当系统正常工作时可以对电池进行涓流充电。
当系统掉电时,DS1302由这个电池提供的能量继续工作。
液晶显示模块采用了12864.低电源电压(VDD:
+3.0--+5.5V)。
显示分辨率:
128×64点。
内置汉字字库,提供8192个16×16点阵汉字(简繁体可选) 。
内置 128个16×8点阵字符。
在12864的2、3脚上接上10k的可调电阻,通过调节可调电阻的阻值,调整12864的对比度。
通过单片机对12864进行写指令写数据等操作,完成对12864的显示操作。
通过1820进行读数据,将读出来的数据进行进制转换,转换后送到12864显示。
DS18B20是单总线的数字温度传感器。
其与单片机的接口只需要一根数据线即可。
当然连线简单意味着软件处理上可能要麻烦一点。
下面来看看它的优点
看看它的靓照。
外形和我们常用的三极管没有什么两样哦。
DS18B20的内部存储器分为以下几部分ROM:
存放该器件的编码。
前8位为单线系列的编码(DS18B20的编码是19H)后面48位为芯片的唯一序列号。
在出场的时候就已经设置好,用户无法更改。
最后8位是以上56位的CRC码。
RAM:
DS18B20的内部暂存器共9个字节。
其中第一个和第二个字节存放转换后的温度值。
第二个和第三个字节分别存放高温和低温告警值。
(可以用RAM指令将其拷贝到EEPROM中)第四个字节为配置寄存器。
第5~7个字节保留。
第9个字节为前8个字节的CRC码。
DS18B20的温度存放如上图所示。
其中S位符号位。
当温度值为负值时,S=1,反之则S=0。
我们把得到的温度数据乘上对应的分辨率即可以得到转换后的温度值。
DS18B20的通讯协议:
在对DS18B20进行读写编程时,必须严格保证读写的时序。
否则将无法读取测温结果。
根据DS18B20的通讯协议,主机控制DS18B20完成温度转换必须经过3个步骤:
每一次读写之前都要对DS18B20进行复位,复位成功后发送一条ROM指令,最后发送RAM指令。
这样才能对DS18B20进行预定的操作。
复位要求主机将数据线下拉500us,然后释放,DS18B20收到信号后等待16~160us然后发出60~240us的存在低脉冲,主机收到此信号表示复位成功。
上图即DS18B20的复位时序图。
下面是读操作的时序图
这是写操作的时序图
4)电路工作原理;
本电路包含时钟模块、显示模块、温度控制模块。
只要按照PCB原理图连接控制即可完成本次设计的硬件要求。
电路实现的基本功能是电子万年历。
通过液晶LCD12864,可显示年月日、时分秒、星期等基本信息。
即同时具备显示环境温度的功能。
5)电路和程序调试过程与结果:
本设计完成了设计任务的所有要求。
单片机采用STC89C52,编译环境为keil,程序使用C语音进行编写。
电路设计使用proteus仿真软件进行仿真调试,在AltiumDesigner上设计原理图并绘制PCB图。
设计硬件制作比较顺利,很快就把PCB板做好。
接着,主要是程序的调试。
程序调试的难点在于设计的功能模块过多,程序结构比较复杂,使得调试起来比较费时间调试结果:
1、完成设计任务的要求1:
显示年月日、时分秒、及星期信息。
2、完成设计任务的要求2:
具有可调整日期和时间功能。
3、增加功能:
实时显示环境气温。
6)程序说明
/****************************************************************************/
(1)//初始化LCM
voidLCM_init(void)
{
LCM_psb=0;
LCM_WriteDatOrCom(0,0x30);/*30---基本指令动作*/
LCM_WriteDatOrCom(0,0x01);/*清屏,地址指针指向00H*/
Delay(100);
LCM_WriteDatOrCom(0,0x06);/*光标的移动方向*/
LCM_WriteDatOrCom(0,0x0c);/*开显示,关游标*/
}
/******************************************************************************
/*****************************************************************************/
//设置1302的初始时间
voidInit_1302(void)//(2007年1月1日00时00分00秒星期一)
{ucharcctt;
cctt=Read1302(0x80);
if(cctt&0x80)
{
Write1302(0x8e,0x00);//允许写操作
Write1302(0x8c,0x09);//年
Write1302(0x8a,0x02);//星期
Write1302(0x88,0x01);//月
Write1302(0x86,0x01);//日
Write1302(0x84,0x00);//小时
Write1302(0x82,0x00);//分钟
Write1302(0x80,0x00);//秒
Write1302(0x8e,0x80);//禁止写操作
}
}/
(2)unsignedintReadTemperature(void)//读取温度
{
unsignedchara=0;
unsignedcharb=0;
unsignedintt=0;
floattt=0;
Init_DS18B20();
WriteOneChar(0xCC);//跳过读序号列号的操作
WriteOneChar(0x44);//启动温度转换
Init_DS18B20();
WriteOneChar(0xCC);//跳过读序号列号的操作
WriteOneChar(0xBE);//读取温度寄存器
a=ReadOneChar();//读低8位
b=ReadOneChar();//读高8位
t=b;
t<<=8;
t=t|a;
tt=t*0.0625;
t=tt*10+0.5;//放大10倍输出并四舍五入
return(t);
}
(3)//调时用加1程序
voidSet_time(unsignedcharsel)//根据选择调整的相应项目加1并写入DS1302
{
signedcharaddress,item;
signedcharmax,mini;
LCM_WriteDatOrCom(0,0x9a);
LCM_WriteString("调整");
if(sel==7){w=0;e=0;
LCM_clr();//清屏
updata();//刷新数据
LCM_w_mm();//刷新分
LCM_w_ss();
nl();}
if(sel==6){LCM_WriteString("秒钟");address=0x80;max=59;mini=0;}//秒7
if(sel==5){LCM_WriteString("分钟");address=0x82;max=59;mini=0;}//分钟6
if(sel==4){LCM_WriteString("小时");address=0x84;max=23;mini=0;}//小时5
if(sel==3){LCM_WriteString("星期");address=0x8a;max=7;mini=1;}//星期4
if(sel==2){LCM_WriteString("日期");address=0x86;max=31;mini=1;}//日3
if(sel==1){LCM_WriteString("月份");address=0x88;max=12;mini=1;}//月2
if(sel==0){LCM_WriteString("年份");address=0x8c;max=99;mini=0;}//年1
//读取1302某地址上的数值转换成10进制赋给item
item=((Read1302(address+1))/16)*10+(Read1302(address+1))%16;
if(KEY_2==0)
{
item++;//数加1
}
if(KEY_4==0){
item--;//数减1
}
if(item>max)item=mini;//查看数值有效范围
if(item Write1302(0x8e,0x00);//允许写操作 Write1302(address,(item/10)*16+item%10);//转换成16进制写入1302 Write1302(0x8e,0x80);//写保护,禁止写操作 updata();//刷新数据 LCM_w_mm();//刷新分 LCM_w_ss();//刷新秒 nl(); } (4)/*****************************************************************************/ //向LCM中填写年数据 voidLCM_w_yy(void){ //if(Read1302(0x8d)! =yy){ yy=Read1302(0x8d); LCM_WriteDatOrCom(0,0x80); LCM_WriteString("20"); LCM_WriteDatOrCom(0,0x81); LCM_WriteDatOrCom(1,(yy/16)+0x30); LCM_WriteDatOrCom(1,yy%16+0x30); LCM_WriteDatOrCom(0,0x82); LCM_WriteString("年"); nl(); yy1=(((yy/16)+0x30)*10)+(yy%16+0x30); leap=((yy1+2000)%4==0&&(yy1+2000)%100! =0)||((yy1+2000)%400==0)? 1: 0; if(leap==1) { LCM_WriteDatOrCom(0,0x98); LCM_WriteString("闰年"); } else { LCM_WriteDatOrCom(0,0x98); LCM_WriteString(""); } } /*****************************************************************************/ //向LCM中填写月数据 voidLCM_w_mo(void){ mo=Read1302(0x89); LCM_WriteDatOrCom(0,0x83); if(mo/16! =0){LCM_WriteDatOrCom(1,(mo/16)+0x30);}//十位消隐 else{LCM_WriteDatOrCom(1,0x20);}//同上 LCM_WriteDatOrCom(1,mo%16+0x30); LCM_WriteDatOrCom(0,0x84); LCM_WriteString("月"); nl(); } /*****************************************************************************/ //星期处理并送入LCM的指定区域 voidLCM_w_xq(void){ unsignedcharsel; xq=Read1302(0x8b); sel=(Read1302(0x8b))%16;//字节低4位的BCD码放入sel LCM_WriteDatOrCom(0,0x97);//写入指定区域(97H第二行第8个字) if(sel==7){LCM_WriteString("日");}// if(sel==6){LCM_WriteString("六");}// if(sel==5){LCM_WriteString("五");}// if(sel==4){LCM_WriteString("四");}// if(sel==3){LCM_WriteString("叁");}// if(sel==2){LCM_WriteString("二");}// if(sel==1){LCM_WriteString("一");}//星期一 LCM_WriteDatOrCom(0,0x95); LCM_WriteString("星期"); } /*****************************************************************************/ //向LCM中填写日数据 voidLCM_w_dd(void){ dd=Read1302(0x87); LCM_WriteDatOrCom(0,0x85); if(dd/16! =0){LCM_WriteDatOrCom(1,(dd/16)+0x30);}//十位消隐 else{LCM_WriteDatOrCom(1,0x20);}//同上 LCM_WriteDatOrCom(1,dd%16+0x30); LCM_WriteDatOrCom(0,0x86); LCM_WriteString("日"); nl(); } /*****************************************************************************/ //向LCM中填写小时数据 voidLCM_w_hh(void){ if(Read1302(0x85)! =hh){ hh=Read1302(0x85); if(hh>0x07&&hh<0x22&&w==0){ beep=0; DelayM(100); beep=1; } } LCM_WriteDatOrCom(0,0x88); LCM_WriteDatOrCom(1,(hh/16)+0x30); LCM_WriteDatOrCom(1,hh%16+0x30); } /*****************************************************************************/ //向LCM中填写分钟数据 voidLCM_w_mm(void){ if(Read1302(0x83)! =mm){ mm=Read1302(0x83); if(w==0){ updata();//刷新数据 } } LCM_WriteDatOrCom(0,0x89); LCM_WriteDatOrCom(1,0x3a);//": " LCM_WriteDatOrCom(1,(mm/16)+0x30); LCM_WriteDatOrCom(1,mm%16+0x30); LCM_WriteDatOrCom(1,0x3a);//"." } /*****************************************************************************/ //刷新数据 voidupdata(void){ LCM_w_hh();//刷新小时 LCM_w_dd();//刷新日 LCM_w_xq();//更新星期值 LCM_w_mo();//刷新月 LCM_w_yy();//刷新年 nl(); } /*****************************************************************************/ //向LCM中填写秒数据 voidLCM_w_ss(void){ unsignedinti=0; unsignedchara=0,b=0,c=0; if(Read1302(0x81)! =ss){//判断是否需要更新 ss=Read1302(0x81);//更新数据 LCM_WriteDatOrCom(0,0x8b);//秒值在LCM上的写入位置 LCM_WriteDatOrCom(1,(ss/16)+0x30);//写十位 LCM_WriteDatOrCom(1,ss%16+0x30);//写个位 LCM_w_mm();//刷新分 nl(); LCM_WriteDatOrCom(0,0x8d);//温度在LCM上的写入位置 i=ReadTemperature();//读温度并送显 a=i/100; LCM_WriteDatOrCom(1,a+0x30);//显示温度十位 b=i/10-a*10; LCM_WriteDatOrCom(1,b+0x30);//个位 LCM_WriteDatOrCom(1,0x2e);//"." c=i-a*100-b*10; LCM_WriteDatOrCom(1,c+0x30);//小位1位 LCM_WriteString("℃");//度C }} (5)月份数据表 codeucharday_code1[9]={0x0,0x1f,0x3b,0x5a,0x78,0x97,0xb5,0xd4,0xf3}; codeuintday_code2[3]={0x111,0x130,0x14e}; /* 函数功能: 输入BCD阳历数据,输出BCD阴历数据(只允许1901-2099年) 调用函数示例: Conversion(c_sun,year_sun,month_sun,day_sun) 如: 计算2004年10月16日Conversion(0,0x4,0x10,0x16); c_sun,year_sun,month_sun,day_sun均为BCD数据,c_sun为世纪标志位,c_sun=0为21世 纪,c_sun=1为19世纪 调用函数后,原有数据不变,读c_moon,year_moon,month_moon,day_moon得出阴历BCD数据 */ bitc_moon; dataucharyear_moon,month_moon,day_moon,week; /*子函数,用于读取数据表中农历月的大月或小月,如果该月为大返回1,为小返回0*/ bitget_moon_day(ucharmonth_p,uinttable_addr) { uchartemp; switch(month_p){ case1: {temp=year_code[table_addr]&0x08; if(temp==0)return(0);elsereturn (1);} case2: {temp=year_code[table_addr]&0x04; if(temp==0)return(0);elsereturn (1);} case3: {temp=year_code[table_addr]&0x02; if(temp==0)return(0);elsereturn (1);} case4: {temp=year_code[table_addr]&0x01; if(temp==0)return(0);elsereturn (1);} case5: {temp=year_code[table_addr+1]&0x80; if(temp==0)return(0);elsereturn (1);} case6: {temp=year_code[table_addr+1]&0x40; if
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 单片机