基于AT89S52芯片+LCD1602液晶显示+DS12C887时钟模块的数字时钟

1. 前提

51单片机,通过实验箱实现实时数字时钟,这里选用DS12C887时钟模块进行实验内容。

2. 目标

使用更为精准的DS12C887时钟模块进行时钟的设置,使用蜂鸣器进行时间按键按下调整的提示音,使用LCD1602模块进行时钟内容的显示。

3. 代码

整体配置文件与接口如下

#define uchar unsigned char
#define uint unsigned int

/**
 *蜂鸣器接口 
 */
sbit beep = P2 ^ 3;

/**
 *LCD1602接口 
 */
sbit rs = P2 ^ 0;
sbit rw = P2 ^ 1;
sbit en = P2 ^ 2;

sbit s1 = P3 ^ 0; //功能键
sbit s2 = P3 ^ 1; //增加键
sbit s3 = P3 ^ 2; //减少键

/**
 *DS12887接口 
 */
sbit dsas = P1 ^ 2;
sbit dsrw = P1 ^ 3; //12887WR
sbit dsrd = P1 ^ 4; //接RD
sbit dscs = P1 ^ 5;
sbit dsirq = P3 ^ 7;

//其它变量定义
uchar flag, key;
char year, month, day, week, shi, fen, miao;

//液晶固定显示内容
uchar code table[] = " 20  -  -      ";
uchar code table1[] = "      :  :  ";

//函数申明
void write_ds(uchar, uchar);
uchar read_ds(uchar);

主函数文件如下

#include <reg52.h>
#include "init.h"
/*------------------------------------------------
              延时函数
------------------------------------------------*/
void delay(uint z)
{
	uint x, y;
	for (x = z; x > 0; x--)
		for (y = 110; y > 0; y--);
}
/*------------------------------------------------
              蜂鸣器模块
------------------------------------------------*/
void di()
{
	beep = 0;
	delay(100);
	beep = 1;
}

/*------------------------------------------------
              DS12C877模块
------------------------------------------------*/
void write_ds(uchar add, uchar date)
{ //写12C887函数
	dscs = 0;  //片选输入,低电平有效
	dsas = 1;  //地址选通输入脚,将AD0~AD7上的地址信息锁存到DS12C887
	dsrd = 1;  //数据选择输入引脚,上升沿时,将内部信息传到AD0~AD7
	dsrw = 1;  //读写输入端,高电平读,低电平写
	P0 = add; //先写地址
	dsas = 0;
	dsrw = 0;
	P0 = date; //再写数据
	dsrw = 1;
	dsas = 1;
	dscs = 1;
}
/**
 * 读12C887函数
 */
uchar read_ds(uchar add)
{
	uchar ds_date;
	dsas = 1;
	dsrd = 1;
	dsrw = 1;
	dscs = 0;
	P0 = add; //先写地址
	dsas = 0;
	dsrd = 0;
	P0 = 0xff;
	ds_date = P0; //再读数据
	dsrd = 1;
	dsas = 1;
	dscs = 1;
	return ds_date;
}

/**
 * 初始化设置设置DS12C887模块,以后不必再写入
 */
void initDS12C887()
{

	write_ds(0x0A, 0x20); //打开振荡器
	write_ds(0x0B, 0x26); //设置24小时模式,数据二进制格式

	//首次上电初始化时间函数,给予寄存器初始化
	write_ds(0, 30); //秒
	write_ds(1, 0);
	write_ds(2, 28); //分
	write_ds(3, 0);
	write_ds(4, 8); //时
	write_ds(5, 0);
	write_ds(6, 6);	 //周
	write_ds(7, 26); //日
	write_ds(8, 12); //月
	write_ds(9, 20); //年
}
/*------------------------------------------------
              LCD1602模块
------------------------------------------------*/
/**
 *LCD1602写指令函数
*/
void write_com(uchar com)
{
	rs = 0; //RS位置0, 选择指令寄存器
	en = 0;
	P0 = com;
	delay(3);
	en = 1;
	delay(3);
	en = 0;
}
/**
 *LCD1602写数据函数
*/
void write_date(uchar date)
{
	rs = 1; //RS位置1, 选择数据寄存器
	en = 0;
	P0 = date;
	delay(3);
	en = 1;
	delay(3);
	en = 0;
}
/**
	 * 加载LCD1602初始值
	 */
void initWriteLCD1602()
{
	uchar num;
	/**
	 * 写入第一行数据
	 */
	write_com(0x80);
	for (num = 0; num < 15; num++) //写入液晶固定部分显示
	{
		write_date(table[num]);
		delay(1);
	}
	/**
	 * 写入第二行数据
	 */
	write_com(0xc0);
	for (num = 0; num < 11; num++)
	{
		write_date(table1[num]);
		delay(1);
	}
}
//初始化函数
void init()
{

	EA = 1;	 //打开总中断
	EX1 = 1; //开外部中断1		IE中断允许控制寄存器
	IT1 = 1; //设置负跳变沿触发中断	   Tcon

	en = 0;
	rw = 0;
	key = 0; //判断按键的次数

	initDS12C887();

    //1602液晶初始化
	write_com(0x38);
	write_com(0x0c);
	write_com(0x06);
	write_com(0x01);

	initWriteLCD1602();
}
/**
 *对DS12C877传过来的时间,出现按键修改时进行分离送入LCD1602 
 */
void write_sfm(uchar add, char date)
{ //1602液晶刷新时分秒函数4为时,7为分,10为秒
	char shi, ge;
	shi = date / 10;
	ge = date % 10;

	write_com(0xc0 + add);
	write_date(0x30 + shi);
	write_date(0x30 + ge);
}
void write_nyr(uchar add, char date)
{ //1602液晶刷新年月日函数3为年,6为分,9为秒
	char shi, ge;
	shi = date / 10;
	ge = date % 10;

	write_com(0x80 + add);
	write_date(0x30 + shi);
	write_date(0x30 + ge);
}
void write_week(char we)
{ //写液晶星期显示函数
	write_com(0x80 + 12);
	switch (we)
	{
	case 1:
		write_date('M');
		delay(5);
		write_date('O');
		delay(5);
		write_date('N');
		break;
	case 2:
		write_date('T');
		delay(5);
		write_date('U');
		delay(5);
		write_date('E');
		break;
	case 3:
		write_date('W');
		delay(5);
		write_date('E');
		delay(5);
		write_date('D');
		break;
	case 4:
		write_date('T');
		delay(5);
		write_date('H');
		delay(5);
		write_date('U');
		break;
	case 5:
		write_date('F');
		delay(5);
		write_date('R');
		delay(5);
		write_date('I');
		break;
	case 6:
		write_date('S');
		delay(5);
		write_date('A');
		delay(5);
		write_date('T');
		break;
	case 7:
		write_date('S');
		delay(5);
		write_date('U');
		delay(5);
		write_date('N');
		break;
	}
}

/*------------------------------------------------
              键盘扫描模块
------------------------------------------------*/
void keyscan()
{
	if (s1 == 0) //检测S1端口
	{
		delay(5);

		key++; //记录按下次数
		flag = 1;
		while (!s1)
			;
		di();
		switch (key)
		{ //光标闪烁点定位
		case 1:
			write_com(0xc0 + 11);
			write_com(0x0f);
			break;
		case 2:
			write_com(0xc0 + 8);
			break;
		case 3:
			write_com(0xc0 + 5);
			break;
		case 4:
			write_com(0x80 + 14);
			break;
		case 5:
			write_com(0x80 + 10);
			break;
		case 6:
			write_com(0x80 + 7);
			break;
		case 7:
			write_com(0x80 + 4);
			break;
		case 8:
			key = 0;
			write_com(0x0c);
			flag = 0;
			write_ds(0, miao);
			write_ds(2, fen);
			write_ds(4, shi);
			write_ds(6, week);
			write_ds(7, day);
			write_ds(8, month);
			write_ds(9, year);
			break;
		}
	}
	if (key != 0) //只有当S1按下后,才检测S2和S3
	{
		if (s2 == 0)
		{
			delay(1);

			while (!s2);
			di();
			switch (key)
			{ //根据功能键次数调节相应数值
			case 1:
				miao++;
				if (miao == 60)
					miao = 0;
				write_sfm(10, miao);
				write_com(0xc0 + 11);
				break;
			case 2:
				fen++;
				if (fen == 60)
					fen = 0;
				write_sfm(7, fen);
				write_com(0xc0 + 8);
				break;
			case 3:
				shi++;
				if (shi == 24)
					shi = 0;
				write_sfm(4, shi);
				write_com(0xc0 + 5);
				break;
			case 4:
				week++;
				if (week == 8)
					week = 1;
				write_week(week);
				write_com(0x80 + 14);
				break;
			case 5:
				day++;
				if (day == 32)
					day = 1;
				write_nyr(9, day);
				write_com(0x80 + 10);
				break;
			case 6:
				month++;
				if (month == 13)
					month = 1;
				write_nyr(6, month);
				write_com(0x80 + 7);
				break;
			case 7:
				year++;
				if (year == 100)
					year = 0;
				write_nyr(3, year);
				write_com(0x80 + 4);
				break;
			}
		}
		if (s3 == 0)
		{
			delay(1);

			while (!s3);
			di();
			switch (key)
			{ //根据功能键次数调节相应数值
			case 1:
				miao--;
				if (miao == -1)
					miao = 59;
				write_sfm(10, miao);
				write_com(0xc0 + 11);
				break;
			case 2:
				fen--;
				if (fen == -1)
					fen = 59;
				write_sfm(7, fen);
				write_com(0xc0 + 8);
				break;
			case 3:
				shi--;
				if (shi == -1)
					shi = 23;
				write_sfm(4, shi);
				write_com(0xc0 + 5);
				break;
			case 4:
				week--;
				if (week == 0)
					week = 7;
				write_week(week);
				write_com(0x80 + 14);
				break;
			case 5:
				day--;
				if (day == 0)
					day = 31;
				write_nyr(9, day);
				write_com(0x80 + 10);
				break;
			case 6:
				month--;
				if (month == 0)
					month = 12;
				write_nyr(6, month);
				write_com(0x80 + 7);
				break;
			case 7:
				year--;
				if (year == -1)
					year = 99;
				write_nyr(3, year);
				write_com(0x80 + 4);
				break;
			}
		}
	}
}

void main() //主函数
{
	init(); //调用初始化函数
	while (1)
	{
		keyscan(); //按键扫描

		if (flag == 0) //正常工作时进入这里
		{
			keyscan(); //按键扫描
			
			//读取12C887数据
			year = read_ds(9);
			month = read_ds(8);
			day = read_ds(7);
			week = read_ds(6);
			shi = read_ds(4);
			fen = read_ds(2);
			miao = read_ds(0);

			//传入液晶显示时分秒
			write_nyr(3, year);
			write_nyr(6, month);
			write_nyr(9, day);
			write_week(week);
			write_sfm(4, shi);
			write_sfm(7, fen);
			write_sfm(10, miao);
		}
	}
}

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天宇龙腾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值