单片机课程设计报告

更新时间:2023-03-20 06:34:01 阅读量: 实用文档 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

单片机课程设计报告

基于DS1307的多功能时钟系统

摘要:以AT89S52单片机为控制核心,通过实时时钟芯片DS1307和数字温度传感器DS18B20构成了一个多功能的数字时钟系统。本报告详细介绍了整个系统的硬件组成结构、工作原理和系统的软件程序设计。系统采用液晶LCD128*64作为显示器,具有实时时间与日历显示、环境温度显示、按键调时、闹铃定时等功能。软件程序采用均采用C语言编写,便于移植与升级。

关键词:实时时钟日历 单片机 DS1307 DS18B20 LCD128*64

引言

目前家用的数字电子钟,多数只能显示小时、分钟等信息,功能单一,而且大都采用LED数码管作为显示器件,功耗大,不能令消费者满意。为此,我开发了一款多功的数字式电子钟,它可以显示年、月、日、小时、分钟等时间信息,同时可以显示环境的温度信息。还具有按键调时、设定闹铃等功能,而且通过一块3.18V的备用电池,在单片机断电后让时钟芯片DS1307独立工作,因此每次给单片机上电即可显示当前时间,无需调整。时钟采用LCD作为显示器,界面友好,功耗低。

一、系统的硬件构成

系统以AT89S52单片机作为核心控制器件,外围主要有实时时钟芯片DS1307、温度传感器DS18B20等,均为串行通信器件,使得系统线路简单可靠性高。系统结构框图1所示。

图1 系统结构框图

1.1 单片机主控模块

系统采用AT89S52单片机作为控制核心。AT89S52单片机与MCS_51系列单片机产品兼容,采用了Flash存储器结构,可以在线下载程序,易于日后的升级。它主要负责各个模块的初始化工作;设置定时器、寄存器的初值;读取并处理时间、温度等信息;处理按键响应;控制液晶实时显示等。

单片机课程设计报告

硬件电路连接如图2所示。系统采用12M晶振;P2.0,P2.1,P2.2口为单片机与液晶显示器连接的控制和通信的数据端口;C_RESET和R_RESET组成系统上电复位电路; P2.6和P2.7为单片机与时钟芯片DS1307通信的端口; P2.3为闹铃的控制端口;P1.6为单片机与温度传感器DS18B20的通信端口;P1.0,P1.1为按键模块的接口。

图2 单片机主控电路

1.2 实时时钟日历模块

系统采用DS1307实时时钟芯片。

电路连接如图3。Y2为32.768kHz的晶振,为时钟芯片提供计时脉冲;Vbat为DS1307的备用电源,以便在没有主电源的情况下能够保存时间信息和一些重要的数据;两个电阻为I2C总线的上拉电阻。

⑴DS1307是美国DALLAS公司推出的一种高性能、低功耗的实时时钟芯片,它是一款I2C总线接口的时钟日历芯片,采用两线与CPU进行通信,片内含有8个特殊功能寄存器和56bit的SRAM。

主要技术性能指标:具有秒、分、时、日、星期、月、年的计数功能,并且具有12小时制和24小时制的计数模式,可自动调整每月的天数,具有闰年调整的功能,具有自动掉电保护和上电复位的功能。 ⑴ DS1307的引脚功能

DS1307的引脚图如图3所示,采用8引脚双列直插dip封装,芯片内部结

单片机课程设计报告

构图如图4所示。各个引脚功能如下:

Vcc:主电源;

Vbat:备份电源。当Vbat>Vcc+0.2V时,由Vcc2向DS1307供电,当Vbat< Vcc时,由Vcc向DS1307供电; GND:逻辑地;

SCL:I2C总线时钟线; SDA:I2C总线数据线; SQW/OUT:

图3 DS1307的引脚分配

图4 DS1307的内部结构

⑵ DS1307的内部寄存器

DS1302有关日历、时间的寄存器共有12个,其中有7个寄存器(读时81h~8Dh,写时80h~8Ch),存放的数据格式为BCD码形式,如图5所示。

小时寄存器(85h、84h)的位7用于定义DS1302是运行于12小时模式还是

PM,24小时模式。当为高时,选择12小时模式。在12小时模式时,位5是AM/

当为1时,表示PM。在24小时模式时,位5是第二个10小时位。

秒寄存器(81h、80h)的位7定义为时钟暂停标志(CH)。当该位置为1时,时钟振荡器停止,DS1302处于低功耗状态;当该位置为0时,时钟开始运行。

控制寄存器(8Fh、8Eh)的位7是写保护位(WP),其它7位均置为0。在任何的对时钟和RAM的写操作之前,WP位必须为0。当WP位为1时,写保护位防止对任一寄存器的写操作。

单片机课程设计报告

图5 DS1307的时间寄存器

⑶ DS1307 硬件电路设计

DS1307采用与CPU进行通信,电路连接简单。DS1307的内部振荡电路结构如图6所示,在芯片内部连接有两个电容,目的是为了使晶振起振,所以在电路设计中就不需要另外再加电容了,电路图如图7所示,其中晶振采用的是32.768kHz,经内部电路分频后可获得一个标准的秒脉冲信号;电阻R_SCL、R_SDA是I2C总线的上拉电阻。

图6 DS1307的内部振荡电路

图7 DS1307的电路连接

1.3温度传感器模块

系统采用DS18B20作为温度传感器。它是美国DSLLAS公司推出的单总线数字温度传感器,它具有微型化、低功耗、高性能、抗干扰能力强、易匹配处理器

单片机课程设计报告

等优点。处理器与DS18B20通信只需要一根数据线即可,同时该数据线还可以向挂接的DS18B20供电。它可以直接将温度转化成串行数字信号处理,与模拟温度传感器相比,DS18B20省去了信号调理、A/D转换等前向通道处理电路,从而使得系统线路简单,成本低廉。 它的主要技术性能指标:

(1) 电压范围:+3.0~+5.5V(可用数据线供电) (2) 测温范围:-55℃~+125℃

(3) 通过编程可实现9~12位的数字读数方式,测温分辨率可达0.0625℃ (4) 可自设定非易失性的报警上下限值。

电路连接如图8所示。其中DQ为数据输入/输出端口,R_Up 为数据线的上拉电阻,确保数据传输的可靠性。

图8 温度传感器电路

1.4闹铃模块

系统采用蜂鸣器作为闹铃输出。

电路连接如图9所示。电路中采用PNP管9012来控制蜂鸣器的开关,由图可以看出当Bell引脚为高电平时,PNP管截止,蜂鸣器不工作;当Bell引脚为低电平时,PNP管导通,蜂鸣器工作。其中R2为限流电阻。

图9 闹铃电路

1.5键盘模块

键盘模块设置了两个按键:KEY1,KEY2。其中用KEY1长按来控制菜单的主模式,短按为使设定值上升;用KEY2短按来使设定值减小。

电路连接如图2所示。2个上拉电阻可以保证在没有按键输入时,进入单片机四个I/O口的按键状态均为高电平,防止干扰产生;当有按键按下时,相应的口线被拉低。软件上采用查询的方式,用定时器定时对按键状态进行扫描,确保系统的实时性。

1.6液晶显示模块

单片机课程设计报告

系统中采用LCD128*64作为显示器件输出信息。与传统的LED数码管显示器件相比,液晶显示模块具有体积小、功耗低、显示内容丰富等优点,而且不需要外加驱动电路,现在液晶显示模块已经是单片机应用设计中最常用的显示器件了。LCD128*64可以显示4行8个汉字,并行工作时具有8位数据总线D0-D7,和RS、R/W、E三个控制端口,串行工作时只有CS,SID,CLK三个通信口,本次设计就是采用串行通信,可以节省单片机IO口的使用,工作电压为5V,并且带有字符对比度调节和背光设置。

管脚功能简介:

引脚号 引脚名称 方向 功能说明

1 VSS 2 VDD 3 V0 4 RS(CS) 5 R/W(SID) 6 E(CLK) 7 DB0 8 DB1 9 DB2 10 DB3 11 DB4 12 DB5 13 DB6 14 DB7 15 PSB 16 NC 17 /RET H/L 18 NC 19 LED_A - 20 LED_K -

电路连接如图10。 模块的电源地 模块的电源正端

LCD 驱动电压输入端

H/L 并行的指令/数据选择信号;串行的片选信号 H/L 并行的读写选择信号;串行的数据口 H/L 并行的使能信号;串行的同步时钟 H/L 数据0 H/L 数据1 H/L 数据2 H/L 数据3 H/L 数据4 H/L 数据5 H/L 数据6 H/L 数据7

H/L 并/串行接口选择:H-并行;L-串行 空脚

复位 低电平有效 空脚

背光源正极(LED+5V) 背光源负极(LED-OV)

单片机课程设计报告

图10 液晶显示电路

总的硬件电路如下图:

二、系统的软件设计

系统的软件设计可以分为几个部分,首先是各个模块的底层驱动程序编写,而后是系统联机调试,编写上层系统程序。本系统软件程序主要包括:液晶LCD128*64的底层驱动模块、时钟芯片DS1307的底层驱动模块、传感器DS18B20的底层驱动模块、键盘扫描模块,闹钟模块等。系统的软件流程图如图11。

单片机课程设计报告

图11 系统软件流程图

(1)DS1307 软件程序设计

DS1307 是基于I2C总线接口的时钟芯片,软件上完全与I2C总线完全兼容。

a) I2C总线的驱动程序

I2C总线在传送数据时,必须确认传送数据的开始和结束。而且每传送一个字节,要发送一个应答位(0);在一个周期发送结束后,要发送一个应答位(1)。具体如图12所示,三种信号的格式如下:

启动信号:当时钟总线SCL为高电平时,数据线SDA由高电平跳变为低电

平定义为“启动”信号。

停止信号:当时钟总线SCL为高电平时,数据线SDA由低电平跳变为高电

平定义为“结束”信号。 应答位: 当主器件发送完一字节的数据后,后面必须跟一个应答位(ACK)。

在时钟高电平期间,如果数据线SDA为低电平代表一个字节的传送结束,并准备下一个要传送的字节;在时钟高电平期间,如果数据线SDA为低电平代表一个传送周期结束,准备下一个传送周期。

单片机课程设计报告

2

图12 IC总线的数据传送格式

b) DS1307的读写控制

DS1307的写控制

图13是DS1307的写控制格式,首先发送启动信号,然后发送的第一个字节是用来控制芯片的地址以及读写控制为(D0:0 –写),之后是应答位,然后发送其它字节数据,在最后发送一个结束标志的应答位,紧跟着是停止信号。

图13 CPU写数据模式

DS1307的读控制

图14是DS1307的读控制格式,首先发送启动信号,然后发送的第一个字节是用来控制芯片的地址以及读写控制为(D0:1 –读),之后是应答位,然后发送其它字节数据,在最后发送一个结束标志的应答位,紧跟着是停止信号。

图14 CPU读数据模式

(2)DS18B20 是One-wire总线接口的芯片,软件上对时序的要求特别高。 根据DS18B20的通讯协议,主机控制DS18B20完成温度转换必须经过三个步骤:每一次读写之前都要对DS18B20进行复位,复位成功后发送一条ROM指令,最后发送RAM指令,这样才能对DS18B20进行预定的操作。复位要求主CPU将数据线下拉500微秒,然后释放,DS18B20收到信号后等待16~60微秒左右,后发出60~240微秒的存在低脉冲,主CPU收到此信号表示复位成功。

单片机课程设计报告

DS18B20的指令如下:

(3)键盘处理模块,可以设定成边沿触发或者电平触发方式。

整个系统的软件设计均采用C语言开发,因此这些器件的底层程序均可以移植到其它系统中,这就是采用C语言开发的最大的优点。

各程序模块如下: 1.预定义

*******************************************************************************/

#include "KEYS.h" #include <at89x51.h> #include <stdlib.h> #include <intrins.h> #include <stdio.h>

/***********************************************************************/

2.端口定义 sbit CS =P2^0 ; sbit SCK=P2^2 ;

sbit SID=P2^1 ; //定义引脚

单片机课程设计报告

//#define Busy 0x80 //用于检测LCM状态字中的Busy标识 sbit SDA=P2^7 ; //DS1307 Serial-Data Input pin 5 sbit SCLK=P2^6; //DS1307 Serial-Clock Input pin 6

sbit menu=P1^0; sbit up=P1^1; sbit down=P1^2;

#define bell_on P2&=~(1<<3) #define bell_off P2|=(1<<3)

3.函数及全局变量声明

/***********************************************************************/ sbit CS =P2^0 ; sbit SCK=P2^2 ;

sbit SID=P2^1 ; //定义引脚

sbit SDA=P2^7 ; //DS1307 Serial-Data Input pin 5 sbit SCLK=P2^6; //DS1307 Serial-Clock Input pin 6

sbit menu=P1^0; sbit up=P1^1; sbit down=P1^2;

#define bell_on P2&=~(1<<3) #define bell_off P2|=(1<<3)

volatile unsigned char menu_status=0,key_time=0;

volatile unsigned char ring_time=0,alarm_hour2=0,alarm_minute2=4,alarm_2_ok=0, alarm_2_en=1,alarm_2_off=0;

volatile unsigned char year;week=0,second=0,minute=0,hour=0,day=0,month=0; //分别保存秒、分、时、天、月、年的变量

/***********************************************************************/

void refresh(void);

void display_alarm_time(void); void lcd_clear_one(void);

void LCD_prints(unsigned char *puts); void key_ctrl(void); void delay10ms(void);

void SendByte(unsigned char Dbyte); unsigned char ReceiveByte(void); void CheckBusy( void );

void WriteCommand( unsigned char Cbyte );

单片机课程设计报告

void WriteData( unsigned char Dbyte ); unsigned char ReadData( void ); void Delay(unsigned int MS); void LcmInit( void );

void LcmClearTXT( void );

void PutStr(unsigned char row,unsigned char col,unsigned char *puts); void writeword(unsigned char row,unsigned char col,unsigned char * puts); void setadd(unsigned char row,unsigned char col);

/***********************************************************************/

void set_year(void); void set_month(void); void set_day(void); void set_hour(void); void set_minute(void); void set_weekday(void); void set_nhour(void); void set_nminute(void); void set_onoff(void); void set_over(void); //void naozhong(void);

/**************************************************************************/

void I2C_delay(void);//I2C delay function void I2C_start(void);//I2C start function void I2C_stop(void);//I2C stop function

void I2C_send_ack(bit k);//I2C send responsion function

void I2C_write_byte(unsigned char dat);//I2C bus write byte function unsigned char I2C_read_byte(void);//I2C bus read byte function

/***********************************************************************/

/***********************************************************************/

void delay_1820(unsigned char i); Init_DS18B20(void); ReadOneChar(void);

WriteOneChar(unsigned char dat); ReadTemperature(void);

/**********************************************/

/***********************************************************************/

void Initial(void);//system initize function void Display(void);//RTC display function

单片机课程设计报告

/***********************************************************************/

unsigned char Write1307(unsigned char add,dat);//write information to ds1307 unsigned char Read1307(unsigned char add);//read information from ds1307 void Read_RTC(void);//read RTC void Set_RTC(void);//set RTC

unsigned char set_rtc_code[7]={0,0,10,2,6,6,6}; unsigned char reset_rtc_code[7];

code unsigned char rtc_address[7]={0x00,0x01,0x02,0x03,0x04,0x05,0x06}; unsigned char read_rtc_code[7]; unsigned char ntime[2]={0,0}; bit ntime_flag=0; unsigned char i=0;

/***********************************************************************/

4.I2C驱动程序

/******************************** I2C PART START *********************/

void I2C_delay(void) {

_nop_();_nop_();_nop_();_nop_(); }

/***********************************************************************/

void I2C_start(void) {

SDA=1; _nop_(); SCLK=1; _nop_(); SDA=0; _nop_(); SCLK=0; _nop_(); }

/***********************************************************************/

void I2C_stop(void) {

SDA=0; _nop_();

单片机课程设计报告

_nop_(); SDA=1; _nop_(); SCLK=0; _nop_(); }

/***********************************************************************/

void I2C_send_ack(bit k) {

SDA=k; I2C_delay(); SCLK=1; I2C_delay(); SCLK=0; }

/***********************************************************************/

void I2C_write_byte(unsigned char dat) {

unsigned char i; for (i=0;i<8;i++) {

SCLK=0; I2C_delay();

SDA=(bit)(dat&0x80); dat<<=1; I2C_delay(); SCLK=1; I2C_delay(); }

SCLK=0; }

/***********************************************************************/

unsigned char I2C_read_byte(void) {

unsigned char i,dat; for (i=0;i<8;i++) {

SCLK=0; I2C_delay();

单片机课程设计报告

I2C_delay(); SCLK=1;

I2C_delay(); if(SDA)

dat|=0x80>>i; }

SCLK=0;

return (dat); }

5.DS1307驱动程序

/******************************** DS1307 PART START ****************/

unsigned char Write1307(unsigned char add,dat) {

unsigned char temp; temp=dat/10; temp<<=4;

temp=dat%10+temp;

I2C_start();

I2C_write_byte(0xD0); I2C_send_ack(0);

I2C_write_byte(add); I2C_send_ack(0);

I2C_write_byte(temp); I2C_send_ack(1); I2C_stop();

return (0); }

/***********************************************************************/

unsigned char Read1307(unsigned char add) {

unsigned char temp,dat; I2C_start();

I2C_write_byte(0xD0); I2C_send_ack(0); I2C_write_byte(add);

单片机课程设计报告

I2C_send_ack(1); I2C_stop();

I2C_start();

I2C_write_byte(0xD1); I2C_send_ack(0); dat=I2C_read_byte(); I2C_send_ack(1); I2C_stop();

temp=dat/16; dat=dat%16;

dat=dat+temp*10;

return (dat); }

/***********************************************************************/

void Read_RTC(void) {

unsigned char i,*p; p=rtc_address; for(i=0;i<7;i++) {

read_rtc_code[i]=Read1307(*p); p++; } }

/***********************************************************************/

void Set_RTC(void) {

unsigned char i,*p; p=rtc_address; for(i=0;i<7;i++) {

Write1307(*p,set_rtc_code[i]); p++; } }

/******************************** DS1307 PART STOP ****************/

6.LCD12864驱动程序

单片机课程设计报告

/******************** LCD PART START *******************************/

unsigned char code AC_TABLE[]={

0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, //第一行汉字位置 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97, //第二行汉字位置 0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f, //第三行汉字位置 0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f, //第四行汉字位置 } ;

//串口发送一个字节

void SendByte(unsigned char Dbyte) {

unsigned char i ; for(i=0 ;i<8 ;i++) {

SCK = 0 ;

Dbyte=Dbyte<<1 ; //左移一位

SID = CY ; //移出的位给SID SCK = 1 ; SCK = 0 ; } }

//串口接收一个字节

//仅在读取数据的时候用到

//而读出的数据是一次只能读出4bit的 unsigned char ReceiveByte(void) {

unsigned char n,x,y ; x=y=0 ;

for(n=0 ;n<8 ;n++) {

x=x<<1 ; SCK = 0 ;

SCK = 1 ; SCK = 0 ; if(SID) x++ ; }

for(n=0 ;n<8 ;n++) {

y=y<<1 ; SCK = 0 ; SCK = 1 ; SCK = 0 ;

单片机课程设计报告

if(SID) y++ ; }

return ((0xf0&x)+(0x0f&y)) ; }

void CheckBusy( void ) {

do SendByte(0xfc) ; //11111,RW(1),RS(0),0 while(0x80&ReceiveByte()) ; //BF(.7)=1 Busy }

void WriteCommand( unsigned char Cbyte ) {

CS = 1 ;

CheckBusy() ;

SendByte(0xf8) ; //11111,RW(0),RS(0),0 SendByte(0xf0&Cbyte) ; //高四位

SendByte(0xf0&Cbyte<<4) ;//低四位(先执行<< ;) CS = 0 ; }

void WriteData( unsigned char Dbyte ) {

CS = 1 ;

CheckBusy() ;

SendByte(0xfa) ; //11111,RW(0),RS(1),0 SendByte(0xf0&Dbyte) ; //高四位

SendByte(0xf0&Dbyte<<4) ;//低四位(先执行<< ;) CS = 0 ; }

/*unsigned char ReadData( void ) {

CheckBusy() ;

SendByte(0xfe) ; //11111,RW(1),RS(1),0 return ReceiveByte() ; }*/

void Delay(unsigned int MS) {

unsigned char us,usn ;

while(MS!=0) //for 12M { usn = 2 ;

while(usn!=0)

单片机课程设计报告

{

us=0xf5 ;

while (us!=0){us-- ;} ; usn-- ; } MS-- ; } }

void LcmInit( void ) {

WriteCommand(0x30) ; //8BitMCU,基本指令集合

WriteCommand(0x03) ; //AC归0,不改变DDRAM内容

WriteCommand(0x0C) ; //显示ON,游标OFF,游标位反白OFF WriteCommand(0x01) ; //清屏,AC归0

WriteCommand(0x06) ; //写入时,游标右移动 }

void lcd_clear_one(void) {

unsigned char i; for(i=0;i<16;i++) WriteData(' '); }

//文本区清RAM函数 void LcmClearTXT( void ) {

unsigned char i ;

WriteCommand(0x30) ; //8BitMCU,功能设定,基本指令集合 WriteCommand(0x80) ; //AC归起始位 for(i=0 ;i<64 ;i++) WriteData(0x20) ;

}void setadd(unsigned char row,unsigned char col) {

WriteCommand(AC_TABLE[8*row+col]) ; }

void writeword(unsigned char row,unsigned char col,unsigned char * puts) {

WriteCommand(0x30) ; //8BitMCU,基本指令集合 WriteCommand(AC_TABLE[8*row+col]) ; //起始位置 while((*puts) != '\0') //判断字符串是否显示完毕 {

WriteData(*puts) ; puts++ ;

单片机课程设计报告

} }

void LCD_prints(unsigned char *puts) {

WriteCommand(0x30) ;

while((*puts) != '\0') //判断字符串是否显示完毕 {

WriteData(*puts) ; puts++ ; } }

void PutStr(unsigned char row,unsigned char col,unsigned char *puts) {

WriteCommand(0x30) ; //8BitMCU,基本指令集合 WriteCommand(AC_TABLE[8*row+col]) ; //起始位置 while(*puts != '\0') //判断字符串是否显示完毕 {

if(col==8) //判断换行

{ //若不判断,则自动从第一行到第三行 col=0 ; row++ ; }

if(row==4) row=0 ; //一屏显示完,回到屏左上角 WriteCommand(AC_TABLE[8*row+col]) ; WriteData(*puts) ; //一个汉字要写两次 puts++ ;

WriteData(*puts) ; puts++ ; col++ ; } }

/******************** LCD PART STOP *******************************/

7.DS18B20程序

/***************************************18B20********************************************/

sbit DQ =P1^6; //定义通信端口

单片机课程设计报告

void delay_1820(unsigned char i) {

while(i--); }

//初始化函数

Init_DS18B20(void) {

unsigned char x=0; DQ = 1; //DQ复位

delay_1820(8); //稍做延时

DQ = 0; //单片机将DQ拉低

delay_1820(80); //精确延时 大于 480us DQ = 1; //拉高总线 delay_1820(14);

x=DQ; //稍做延时后 如果x=0则初始化成功 x=1则初始化失败 delay_1820(20); }

//读一个字节

ReadOneChar(void) {

unsigned char i=0; unsigned char dat = 0; for (i=8;i>0;i--) {

DQ = 0; // 给脉冲信号 dat>>=1;

DQ = 1; // 给脉冲信号 if(DQ)

dat|=0x80; delay_1820(4); }

return(dat); }

//写一个字节

WriteOneChar(unsigned char dat) {

unsigned char i=0; for (i=8; i>0; i--) {

本文来源:https://www.bwwdw.com/article/xym1.html

Top