基于stc51单片机的LCD1602显示时间_的电子万年历(显示当前温度)
1 课设所需软件简介
1.1 Keil uVision4的简要介绍
2009年2月发布Keil μVision4,Keil μVision4引入灵活的窗口管理系统,使开发人员能够使用多台监视器,并提供了视觉上的表面对窗口位置的完全控制的任何地方。新的用户界面可以更好地利用屏幕空间和更有效地组织多个窗口,提供一个整洁,高效的环境来开发应用程序。新版本支持更多最新的ARM芯片,还添加了一些其他新功能。
2011年3月ARM公司发布最新集成开发环境RealView MDK开发工具中集成了最新版本的Keil uVision4,其编译器、调试工具实现与ARM器件的最完美匹配。
Keil C51开发系统基本知识Keil C51开发系统基本知识
1. 系统概述
Keil C51软件提供丰富的库函数和功能强大的集成开发调试工具,全Windows界面。另外重要的一点,只要看一下编译后生成的汇编代码,就能体会到Keil C51生成的目标代码效率非常之高,多数语句生成的汇编代码很紧凑,容易理解。在开发大型软件时更能体现高级语言的优势。下面详细介绍Keil C51开发系统各部分功能和使用。
2. Keil C51单片机软件开发系统的整体结构
C51工具包的整体结构,uVision与Ishell分别是C51 for Windows和for Dos的集成开发环境(IDE),可以完成编辑、编译、连接、调试、仿真等整个开发流程。开发人员可用IDE本身或其它编辑器编辑C或汇编源文件。然后分别由C51及C51编译器编译生成目标文件(.OBJ)。目标文件可由LIB51创建生成库文件,也可以与库文件一起经L51连接定位生成绝对目标文件(.ABS)。ABS文件由OH51转换成标准的Hex文件,以供调试器dScope51或tScope51使用进行源代码级调试,也可由仿真器使用直接对目标板进行调试,也可以直接写入程序存贮器如EPROM中。
使用独立的Keil仿真器时,注意事项:
* 仿真器标配11.0592MHz的晶振,但用户可以在仿真器上的晶振插孔中换插其他频率的晶振。
* 仿真器上的复位按钮只复位仿真芯片,不复位目标系统。
* 仿真芯片的31脚(/EA)已接至高电平,所以仿真时只能使用片内ROM,不能使用片外ROM;但仿真器外引插针中的31脚并不与仿真芯片的31脚相连,故该仿真器仍可插入到扩展有外部ROM(其CPU的/EA引脚接至低电平)的目标系统中使用。
优点:
1.Keil C51生成的目标代码效率非常之高,多数语句生成的汇编代码很紧凑,容易理解。在开发大型软件时更能体现高级语言的优势。
2.与汇编相比,C语言在功能上、结构性、可读性、可维护性上有明显的优势,因而易学易用。用过汇编语言后再使用C来开发,体会更加深刻。Keil C51软件提供丰富的库函数和功能强大的集成开发调试工具,全Windows 界面。
图1.1 KEIL操作界面
1.2 STC-ISP的简要介绍
STC-ISP 是一款单片机下载编程烧录软件,是针对STC系列单片机而设计的,可下载STC89系列、12C2052 系列和12C5410等系列的STC单片机,使用简便,现已被广泛使用。
操作说明如下:
(1) 打开STC-ISP,如下图界面,在MCU Type栏目下选中单片机,如
STC89C52RC。
图1.2 ISP操作界面
(2) 根据您的9针数据线连接情况选中COM端口,波特率一般保持默认,如果遇到下载问题,可以适当下调一些。
(3) 先确认硬件连接正确,点击“打开文件”并在对话框内找到您要下载的HEX文件。
图1.3 选择HEX文件
(4)选择所要下载的文件,这样可以使您在每次编译KEIL时HEX代码能自动加载到STC-ISP,点击“Download/下载”。
(5) 手动按下电源开关便即可把可执行文件HEX写入到单片机内,如图是正在写入程序截图。
(6)程序写入完毕,目标板开始运行程序结果。
图2.2 设计流程图
3 单元芯片电路的设置及总体设计
3.1 DS1302芯片引脚功能
DS1302 是美国DALLAS公司推出的一种高性能、低功耗、带RAM的实时时钟电路,它可以对年、月、日、周日、时、分、秒进行计时,具有闰年补偿功能,工作电压为2.5V~5.5V。采用三线接口与CPU进行同步通信,并可采用突发方式一次传送多个字节的时钟信号或RAM数据。DS1302内部有一个31×8的用于临时性存放数据的RAM寄存器。DS1302是DS1202的升级产品,与DS1202兼容,但增加了主电源/后备电源双电源引脚,同时提供了对后备电源进行涓细电流充电的能力。
DS1302的引脚排列,其中Vcc1为后备电源,VCC2为主电源。在主电源关闭的情况下,也能保持时钟的连续运行。DS1302由Vcc1或Vcc2两者中的较大者供电。当Vcc2大于Vcc1+0.2V时,Vcc2给DS1302供电。当Vcc2小于Vcc1时,DS1302由Vcc1供电。X1和X2是振荡源,外接32.768kHz 晶振。RST是复位/片选线,通过把RST输入驱动置高电平来启动所有的数据传送。RST输入有两种功能:首先,RST接通控制逻辑,允许地址/命令序列送入移位寄存器;其次,RST提供终止单字节或多字节数据的传送手段。当RST为高电平时,所有的数据传送被初始化,允许对DS1302进行操作。如果在传送过程中RST置为低电平,则会终止此次数据传送,I/O引脚变为高阻态。上电运行时,在Vcc>2.0V之前,RST必须保持低电平。只有在SCLK 为低电平时,才能将RST置为高电平。I/O为串行数据输入输出端(双向),后面有详细说明。SCLK为时钟输入端。下图为DS1302的引脚功能图:
图3.1 DS1302引脚图
管脚描述:
X1 X2 32.768KHz 晶振管脚
GND 地
RST 复位脚
I/O 数据输入/输出引脚
SCLK 串行时钟
Vcc1,Vcc2 电源供电管脚
此外,拓展中用到了DS18B20温度传感器,其使用与DS1302比较类似,因此这里不再赘述。
3.2 DS1302的使用方法
使用DS1302时,要对其引脚和寄存器进行特殊设置,以实现所需功能。引脚设置后面会提及,这里不做说明,主要讲一下程序的编写。DS1302的的工作过程中包过读写一个字节数据等过程,下面做相应的解释。
/********************************
功能:往DS1302写入数据
*********************************/
void W1302(uchar ucAddr, uchar ucDa)
{
T_RST = 0;
T_CLK = 0;
T_RST = 1;
RTInputByte(ucAddr); /* 地址,命令*/
RTInputByte(ucDa); /* 写1Byte数据*/
T_CLK = 1;
T_RST = 0;
}
/********************************
功能:读取DS1302某地址的数据
*********************************/
uchar R1302(uchar ucAddr)
{
uchar ucData;
T_RST = 0;
T_CLK = 0;
T_RST = 1;
RTInputByte(ucAddr); /* 地址,命令*/
ucData = RTOutputByte(); /* 读1Byte数据*/
T_CLK = 1;
T_RST = 0;
return(ucData);
}
/***********************************
功能:设置初始时间
************************************/
void Set1302(uchar *pClock)
{
uchar i;
uchar ucAddr = 0x80;
EA = 0;
W1302(0x8e,0x00); /* 控制命令,WP=0,写操作?*/ for(i =7; i>0; i--)
{
W1302(ucAddr,*pClock); /* 秒分时日月星期年*/
pClock++;
ucAddr +=2;
}
W1302(0x8e,0x80); /* 控制命令,WP=1,写保护?*/
EA = 1;
}
/******************************
功能:读取DS1302当前时间
*******************************/
void Get1302(uchar ucCurtime[])
{
uchar i;
uchar ucAddr = 0x81;
EA = 0;
for (i=0; i<7; i++)
{
ucCurtime[i] = R1302(ucAddr);/*格式为: 秒分时日月星期年*/
ucAddr += 2;
}
EA = 1;
}
3.3 LCD1602引脚功能
1602液晶也叫1602字符型液晶它是一种专门用来显示字母、数字、符号等的点阵型液晶模块它有若干个5X7或者5X11等点阵字符位组成,每个点阵字符位都可以显示一个字符。每位之间有一个点距的间隔每行之间也有间隔起到了字符间距和行间距的作用,正因为如此所以他不能显示图形n1602LCD是指显示的内容为16X2,即可以显示两行,每行16个字符液晶模块(显示字符和数字)。
图3.2 LCD1602引脚图
1602采用标准的16脚接口,其中:
第1脚:VSS为电源地
第2脚:VDD接5V电源正极
第3脚:V0为液晶显示器对比度调整端,接正电源时对比度最弱,接地电源时对比度最高(对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度)。
第4脚:RS为寄存器选择,高电平1时选择数据寄存器、低电平0时选择指令寄存器。
第5脚:RW为读写信号线,高电平(1)时进行读操作,低电平(0)时进行写操作。
第6脚:E(或EN)端为使能(enable)端。
第7~14脚:D0~D7为8位双向数据端。
第15~16脚:空脚或背灯电源。15脚背光正极,16脚背光负极。
3.4 LCD1602的使用
LCD1602的使用与前面的DS1302的使用有类似的地方,包括引脚的设置和对应的编程,引脚的设置后面会提及到,这里只涉及对应的编程。
/*LCD1602 延时*/
void Lcd_delay(uchar ms)
{
uchar j;
while(ms--){
for(j=0;j<250;j++)
{;}
}
}
/*LCD1602 忙等待*/
void Lcd_busy_wait(){
Lcd_rs = 0;
Lcd_rw = 1;
Lcd_en = 1;
Lcd_data = 0xff;
while (Lcd_data&0x80);
Lcd_en = 0;
/*LCD1602 命令字写入*/
}
void Lcd_command_write(uchar command)
{
Lcd_busy_wait();
Lcd_rs = 0;
Lcd_rw = 0;
Lcd_en = 0;
Lcd_data = command;
Lcd_en = 1;
Lcd_en = 0;
}
/*LCD1602 初始化*/
void Init_lcd()
{
Lcd_delay(20);
Lcd_command_write(0x38);
Lcd_delay(100);
Lcd_comman/*LCD1602 延时*/d_write(0x38);
Lcd_delay(50);
Lcd_command_write(0x38);
Lcd_delay(10);
Lcd_command_write(0x08);
Lcd_command_write(0x01);
Lcd_command_write(0x06);
Lcd_command_write(0x0c);
Lcd_data = 0xff; /*释放数据端口*/
}
void Lcd_char_write(uchar x_pos,y_pos,lcd_dat) /*LCD1602 字符写入*/ {
x_pos &= 0x0f; /* X位置范围0~15 */
y_pos &= 0x01; /* Y位置范围0~ 1 */
if(y_pos==1) x_pos += 0x40;
x_pos += 0x80;
Lcd_command_write(x_pos);
Lcd_busy_wait();
Lcd_rs = 1;
Lcd_rw = 0;
Lcd_en = 0;
Lcd_data = lcd_dat;
Lcd_en = 1;
Lcd_en = 0;
Lcd_data = 0xff; /*释放数据端口*/
}
4 整体电路设计和程序
由上面的分析可以得到实验的电路图如下:
图4.1 仿真电路图
设计源代码如下:
/**************************************************************** 程序名称: LCD1602显示时间显示当前温度
*****************************************************************/
/*头文件*/
#include
#include
#define uint unsigned int
#define uchar unsigned char
#define nop() _nop_()
sbit s1=P1^0;
sbit s2=P1^1;
sbit s3=P1^2;
sbit s4=P1^3;
sbit DQ =P1^3; //定义DS18B20通信端口
sbit lcd_rs_port = P2^4; /*定义LCD控制端口*/
sbit lcd_rw_port = P2^5;
sbit lcd_en_port = P2^6;
#define lcd_data_port P0
sbit led_latch_port = P2^5; /*发光二极管寄存器LE引脚*/
sbit sled_latch_port = P3^6; /*数码管寄存器LE引脚*/
sbit T_CLK = P3^6; /*实时时钟时钟线引脚*/
sbit T_IO = P3^4; /*实时时钟数据线引脚*/
sbit T_RST = P3^5; /*实时时钟复位线引脚*/
sbit ACC0 = ACC^0;
sbit ACC7 = ACC^7;
uchar code mun_to_char[] = {"0123456789ABCDEF"}; /*定义数字跟ASCII 码的关系*/
uchar data time_data_buff[7]={0x50,0x59,0x23,0x31,0x12,0x04,0x12};/*格式为: 秒分时日月星期年*/
uchar data lcd1602_line1[]={" 2000/00/00 000 "};
uchar data lcd1602_line2[]={" 00:00:00 00.0"};
uchar code Weeks[][3]={{"SUN"},{"MON"},{"TUE"},{"WED"},{"THU"},{"FRI"},{"SAT"},{"SUN"}};
/**************************************************************** 函数名:RTInputByte()
功能:实时时钟写入一字节
说明:往DS1302写入1Byte数据(内部函数)
入口参数:d 写入的数据
返回值:无
****************************************************************/
void RTInputByte(uchar d)
{
uchar i;
ACC = d;
for(i=8; i>0; i--)
{
T_IO = ACC0; /*相当于汇编中的RRC */
T_CLK = 1;
T_CLK = 0;
ACC = ACC >> 1;
}
}
/**************************************************************** 函数名:RTOutputByte()
功能:实时时钟读取一字节
说明:从DS1302读取1Byte数据(内部函数)
入口参数:无
返回值:ACC
****************************************************************/
uchar RTOutputByte(void)
{
uchar i;
for(i=8; i>0; i--)
{
ACC = ACC >>1; /*相当于汇编中的RRC */
ACC7 = T_IO;
T_CLK = 1;
T_CLK = 0;
}
return(ACC);
}
/**************************************************************** 函数名:W1302()
功能:往DS1302写入数据
说明:先写地址,后写命令/数据(内部函数)
调用:RTInputByte() , RTOutputByte()
入口参数:ucAddr: DS1302地址, ucData: 要写的数据
返回值:无
****************************************************************/void W1302(uchar ucAddr, uchar ucDa)
{
T_RST = 0;
T_CLK = 0;
T_RST = 1;
RTInputByte(ucAddr); /* 地址,命令*/
RTInputByte(ucDa); /* 写1Byte数据*/
T_CLK = 1;
T_RST = 0;
}
/***************************************************************
函数名:R1302()
功能:读取DS1302某地址的数据
说明:先写地址,后读命令/数据(内部函数)
调用:RTInputByte() , RTOutputByte()
入口参数:ucAddr: DS1302地址
返回值:ucData :读取的数据
****************************************************************/uchar R1302(uchar ucAddr)
{
uchar ucData;
T_RST = 0;
T_CLK = 0;
T_RST = 1;
RTInputByte(ucAddr); /* 地址,命令*/
ucData = RTOutputByte(); /* 读1Byte数据*/
T_CLK = 1;
T_RST = 0;
return(ucData);
}
/****************************************************************
函数名:Set1302()
功能:设置初始时间
说明:先写地址,后读命令/数据(寄存器多字节方式)
调用:W1302()
入口参数:pClock: 设置时钟数据地址格式为: 秒分时日月星期年7Byte (BCD码)1B 1B 1B 1B 1B 1B 1B
返回值:无
****************************************************************/void Set1302(uchar
*pClock)
{
uchar i;
uchar ucAddr = 0x80;
EA = 0;
W1302(0x8e,0x00); /* 控制命令,WP=0,写操作?*/
for(i =7; i>0; i--)
{
W1302(ucAddr,*pClock); /* 秒分时日月星期年*/
pClock++;
ucAddr +=2;
}
W1302(0x8e,0x80); /* 控制命令,WP=1,写保护?*/ EA = 1;
}
/****************************************************************
函数名:Get1302()
功能:读取DS1302当前时间
说明:
调用:R1302()
入口参数:ucCurtime: 保存当前时间地址。当前时间格式为: 秒分时日月星期年
7Byte (BCD码) 1B 1B 1B 1B 1B 1B 1B
返回值:无
****************************************************************/void
Get1302(uchar ucCurtime[])
{
uchar i;
uchar ucAddr = 0x81;