基于51单片机、DS1302时钟模块的电子闹钟设计

  • Post author:
  • Post category:其他


提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档



提示:以下是本篇文章正文内容,下面案例可供参考



一、设计原理



1.DS1302介绍

DS1302 是美国DALLAS公司推出的一种高性能、低功耗、带RAM的实时时钟电路,它可以对年、月、日、周、时、分、秒进行计时,具有闰年补偿功能,工作电压为2.0V~5.5V。该芯片采用普通32.768kHz晶振,DS1302 工作时功耗很低,保持数据和时钟信息时功率小于1mW,非常适合用于制作电子钟。

DS1302芯片管脚和实例电路如图:

在这里插入图片描述

在这里插入图片描述

DS1302共8个引脚,其中VCC供电口共有两个,VCC1为主供电口,VCC2为备用供电口,备用电源口可以保证DS1302在主供电断电情况下依然可以正常计时,使用过程中仅使用VCC2备用电源作为供电,可保证完整功能。

DS1302需要与单片机交互的接口为,SCLK、I/O、RST三个,与单片机的数据交换使用I/O接口,为串行通信模式。SCLK为串行时钟输入引脚,保证数据同步传输。RST为复位口。

DS1302命令字和对应的操纵如下图:

在这里插入图片描述

DS1302向单片机返回的时间日期数值采用压缩BCD码,即用16进制数表示10进制数,比如返回55秒对应的值为0x55,在数据解算时需要按照16进制规则计算。



2.闹钟音乐播放原理

闹钟音乐使用无源蜂鸣器播放,基本原理为通过单片机向无源蜂鸣器输出不同频率的方波信号,无源蜂鸣器则对应播放出不同音调的声音,即播放出不同的音符。通过连续播放不同音符并控制每个音符播放的时间,可以组合成完整的音乐。

单片机输出不同频率的方波使用定时中断实现,首先将每个音符对应的中断计时时间储储存在单片机中,通过在程序中不断改变中断的时间,可以控制单片机输出方波的频率。以此利用无源蜂鸣器播放出音乐。



二、程序设计

程序共包括4个文件,分别为main.c、DS1302.h、ds1302.c、music.h三个部分。其中main.c为主程序文件,主要包括lcd1602显示相关函数、可调时钟日期函数、闹钟函数;DS1302.h为ds1302.c的声明文件,声明ds1302.c中的相关函数;ds1302.c中定义了单片机与DS1302芯片通信的主要函数文件,主要包括命令输入,数据读取和输入;music.h定义了音乐播发函数,用于闹钟调用。

以下为示例代码,完整代码免费分享,见文末。



1.DS1302.h

#ifndef __DS1302_H
#define __DS1302_H

void Write_Ds1302(unsigned char temp);	      //向DS1302写命令函数
void Write_Ds1302_Byte( unsigned char address,unsigned char dat ); //用户输入的时间日期输入DS1302函数
unsigned char Read_Ds1302_Byte( unsigned char address );    //读取DS1302时间日期函数
#endif



2.ds1302.c

代码如下(示例):

#include <reg52.h>
#include <intrins.h>


//定义引脚
sbit SCK=P2^0;//CLK		
sbit SDA=P2^1;//DIO		
sbit RST = P2^2;//CE												

void Write_Ds1302(unsigned  char temp) 
{
	unsigned char i;
	for (i=0;i<8;i++)     	
	{ 
		SCK=0;			  //开传输
		SDA=temp&0x01;	  //与0x01相与,每次只取temp最后一位发送
		temp>>=1; 		  //temp右移位
		SCK=1;			  //该位传输结束
	}
}   

void Write_Ds1302_Byte( unsigned char address,unsigned char dat )     
{
 	RST=0; _nop_();
 	SCK=0; _nop_();
 	RST=1; _nop_();  
 	Write_Ds1302(address);		//写入对应寄存器输入地址
 	Write_Ds1302(dat);			//向对应寄存器中输入数据
 	RST=0; 
}

unsigned char Read_Ds1302_Byte ( unsigned char address )
{
 	unsigned char i,temp=0x00;
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
 	RST=1;	_nop_();
 	Write_Ds1302(address);		  //写入对应寄存器读取地址
 	for (i=0;i<8;i++) 			  //串口读取
 	{		
		SCK=0;
		temp>>=1;				  //temp右移位
 		if(SDA)	temp|=0x80;	      //如果IO口给高电平,temp最高位置1,相当于保存IO的高电平数据
		                          //如果IO口给低电平,temp不操作,保持0,相当于保存IO的低电平数据
 		SCK=1;
	} 
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
	SCK=1;	_nop_();
	SDA=0;	_nop_();
	SDA=1;	_nop_();
	return (temp);				  //以char类型返回temp的数据
}



3.music.h

#ifndef __music_H
#define __music_H

#include <reg52.h>
#include <stdio.h>

sbit beep = P2^3;
sbit key1=P1^0;

unsigned char timer0h, timer0l, time;

//设置好高低音对应的频率
code unsigned char high_v[] = {
    0xF8, 0xF9, 0xFA, 0xFA, 0xFB, 0xFB, 0xFC,//低音1234567
    0xFC, 0xFC, 0xFD, 0xFD, 0xFD, 0xFD, 0xFE,//中音1234567 
    0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFF,//高音1234567
};

code unsigned char low_v[] = {
    0x8C, 0x56, 0x22, 0x64, 0x04, 0x90, 0x0C,//低音1234567
    0x44, 0xAA, 0x08, 0x32, 0x82, 0xC8, 0x06,//中音1234567
    0x22, 0x56, 0x84, 0x9A, 0xC0, 0xE4, 0x02,//高音1234567
};



4.main.c

#include<reg52.h>
#include "ds1302.h"
#include "music.h"

typedef unsigned char u8;
typedef unsigned char u16;

sbit lcdrs=P2^6;    //定义LCD寄存器选择位。高电平时选择数据位寄存器,低电平时选择指令寄存器
sbit lcdrw=P2^5;	//定义LCD读写信号位。高电平时读操作,低电平时写操作。
sbit lcden=P2^7;	//定义LCD使能端
sbit k1=P1^0;
sbit k2=P1^1;
sbit k3=P1^2;
sbit sound=P2^3;

void ds1302_init();
void ds1302_read();
void diplay();
void delay(unsigned int x);
void delay_ms(unsigned int n);
void control();
void time_alter();
void alarm_alter();
void lcdwritecmd (unsigned char cmd);	       //用来给LCD输入指令
void lcdwritedata(unsigned char dat);		       //用来给LCD输入要显示的数据
void clear();
void lcdinit();
void showstring(unsigned char b[]);
void delay_ms(unsigned int n);
void alarm_sound();

u8 code read_addr[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d}; 
u8 code write_addr[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};
u8 code number[] = "0123456789:. ";
unsigned char code low[10] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09};
unsigned char code high[10] = {0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80,0x90};

//01秒02分03时 4日 5月 周6 07年
u8 timer[]={0x00,0x00,0x00,0x04,0x05,0x06,0x07};
//闹钟设置10秒00分00时 音乐2
u8 alarms[]={0x10,0x00,0x00,0x04};
unsigned int choose;



三、电路图

在这里插入图片描述




四、运行结果



1.proteus仿真

Lcd1602正确显示时间日期,测试CONTROL、K1、K2按钮,所有功能正常。proteus中使用发光二极管D1代表实际开发版上发声元件,当闹钟开始时,蜂鸣器播放选择的音乐,lcd1602显示“alarm!!!”字样,按下CONTROL自动结束闹钟,回到正常显示,同时闹钟不消除,下次同一时间继续响应闹钟。

时间日期显示:

在这里插入图片描述

响应闹钟:

在这里插入图片描述



2.开发板实验

将程序下载到开发版,依照上述电路图正确连线,lcd1602正常显示时间日期,闹钟正常响应,蜂鸣器播放设定的音乐。所有现象与proteus仿真一致。

在这里插入图片描述



五、总结

编译过程中,因为在程序中定义了大量的变量,使得变量所需存储空间一度超出了单片机允许的128字节data,查询相关资料后可知,对于那些仅在程序中读取而不需要更改的变量,可以使用code、xdata数据类型,保存在单片机的其他储存空间之中,可以很好地解决变量溢出的问题。

注意:在proteus仿真或者开发板实验的时候,如果遇到按键响应过快的问题(即按下一次按键后,单片机判断按键被按下多次),可以尝试更改代码中按键后的延时时间实现。例如下图画红线位置:

在这里插入图片描述



六、附件

1.DS.uvproj(Keil项目文件,以下为项目下包括文件)

main.c

ds1302.h

ds1302.c

music.h

2.clock.pdsprj(proteus仿真项目文件)

下载地址:

基于51单片机、DS1302时钟模块的电子闹钟设计.rar



版权声明:本文为qq_57058973原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。