数字时钟设计
功能描述
1、初始化
1)关闭蜂鸣器、继电器等无关外设;
2)DS1302设备初始化时钟为 23 时 59 分 50 秒。
2、显示功能
3、按键功能
1)按键 S4 定义为时钟启停按键,控制DS1302的启动和暂停(可使用中断方式)。
2)按键 S5、S6、S7 定义为“加”按键,每次在暂停状态下,按下该按键对应的时、分、秒单元增加 1 个单位。(S5–>时、S6–>分、S7–>秒)
这里要用到SPI总线协议
SPI(Serial Peripheral Interface,串行外围设备接口),是Motorola公司提出的一种同步串行接口技术,是一种高速、全双工、同步通信总线,在芯片中只占用四根管脚用来控制及数据传输,节约了芯片pin的数目,同时为PCB在布局上节省了空间。正是由于这种简单易用的特性,现在越来越多的芯片上都集成了SPI技术。
SPI主要用于EEPROM、Flash、RTC(实时时钟)、ADC(数模转换器)、DSP(数字信号处理器)以及数字信号解码器上。目前应用中的数据速率可达几Mbps。
ds1302.h 头文件代码如下
#ifndef __ds1302_h
#define __ds1302_h
void Write_Ds1302(unsigned char temp);//写入数据
void Write_Ds1302_Byte( unsigned char address,unsigned char dat );//写字节
unsigned char Read_Ds1302_Byte ( unsigned char address );//读取字节
#endif
ds1302.c 底层驱动,比赛中会提供,不做要求
#include <STC15F2K60S2.H>
#include <intrins.h>
sbit SCK=P1^7; //时钟引脚
sbit SDA=P2^3;
sbit RST = P1^3; //复位引脚,当RST=1时,所有数据传输初始化,允许对ds1302操作
void Write_Ds1302(unsigned char temp)
{
unsigned char i;
for (i=0;i<8;i++)
{
SCK=0;
SDA=temp&0x01;
temp>>=1;
SCK=1;
SCK=0;
}
}
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;
if(SDA)
temp|=0x80;
SCK=1;
SCK=0;
}
RST=0; _nop_();
//SCK=0; _nop_();
//SCK=1; _nop_();
SDA=0; _nop_();
SDA=1; _nop_();
return (temp);
}
#include <STC15F2K60S2.H>
#include"ds1302.h"
#define uchar unsigned char
#define uint unsigned int
uchar code display_num[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf};//0-9数码管编码表
uchar code adress[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};位选表左到右
uchar buff[8],flag=0;//buff数组存储要显示的每位数字 flag=1才能进行加操作
uchar Trg,cont,i=0,shi,fen,miao,keycount=0;keyflag=0;
static uchar setfen,setmiao,setshi;
void init() //初始化单片机
{
P2=0xa0;P0=0x00;P2=0x00;//关继电器蜂鸣器
P2=0x80;P0=0xff;P2=0x00;//关led灯
}
void stop()//启停子函数
{
Write_Ds1302_Byte(0x8e,0);//写保护,置零,关掉保护才能写数据
if(miao<0x80)
{
Write_Ds1302_Byte(0x80,miao|0x80);//高位为1,停止
flag=1;//可以进行加操作
}
else
{
Write_Ds1302_Byte(0x80,miao&0x7f);//高位值0,启动
flag=0;
}
Write_Ds1302_Byte(0x8e,0x80);//打开保护
}
void readtime()//读取时间
{
EA=0;//关中断
shi=Read_Ds1302_Byte(0x85);//时存在0x85里
fen=Read_Ds1302_Byte(0x83);//同理,这些地址都是固定的
miao=Read_Ds1302_Byte(0x81);
EA=1;//开中断
buff[0]=shi/16;//注意读出来的时bsd码,十六进制,要转换成十进制
buff[1]=shi%16;
buff[2]=10;//显示横杠
buff[3]=fen/16;
buff[4]=fen%16;
buff[5]=10;
buff[6]=(miao/16)&0x07;
buff[7]=miao%16;
}
void readkey()//读取键值
{
uchar ReadData=P3^0xff;
Trg=ReadData&(ReadData^cont);
cont=ReadData;
}
void key_function()//按键功能
{
if(Trg&0x08)//启停
stop();
if((Trg&0x01)&&flag==1)//s7£¬Ãë
{
setmiao=Read_Ds1302_Byte(0x81);//读秒,注意setmiao是bcd码
Write_Ds1302_Byte(0x8e,0x00);//关写保护
setmiao=((setmiao>>4)&0x07)*10+(setmiao&0x0f)+1;//变成十进制,加一
setmiao=setmiao%60;//边界情况
Write_Ds1302_Byte(0x80,(setmiao/10<<4|setmiao%10)|0x80);//写入,但是要注意|0x80高位置1,不然数据出错,意思是暂停,停止秒
Write_Ds1302_Byte(0x8e,0x80);//关闭写保护
}
if((Trg&0x02)&&flag==1)//同理设置分,但是发送时不要|0x80
{
setfen=Read_Ds1302_Byte(0x83);
Write_Ds1302_Byte(0x8e,0x00);
setfen=(setfen/16)*10+setfen%16+1;
setfen=setfen%60;
Write_Ds1302_Byte(0x82,(setfen/10)*16+setfen%10);
Write_Ds1302_Byte(0x8e,0x80);
}
if((Trg&0x04)&&flag==1)//s5,时
{
setshi=Read_Ds1302_Byte(0x85);
Write_Ds1302_Byte(0x8e,0x00);
setshi=(setshi/16)*10+setshi%16+1;
setshi=setshi%24;
Write_Ds1302_Byte(0x84,(setshi/10)*16+setshi%10);
Write_Ds1302_Byte(0x8e,0x80);
}
}
void Timer0Init(void) //1ms,STC生成
{
EA=1;ET0=1;//这两个启动一定要加,否则不生效
AUXR |= 0x80; //
TMOD &= 0xF0; //
TMOD |= 0x01;
TL0 = 0xCD; //赋初值
TH0 = 0xD4;
TF0 = 0; //清除标志位
TR0 = 1; //启动T0
}
void time0()interrupt 1
{
TL0 = 0xCD; //可以不要,会自动重载的
TH0 = 0xD4;
keycount++;
if(keycount==10)
{
keyflag=1;
keycount=0;
}//10ms扫描一次键盘
P2=0xc0;P0=adress[i];P2=0x00;
P2=0xe0;P0=display_num[buff[i]];P2=0x00;
i++;
if(i==8)
i=0;
}
void set_sfm(uchar shi,uchar fen,uchar miao)//发送时分秒
{
Write_Ds1302_Byte(0x8e,0);
Write_Ds1302_Byte(0x80,(miao/10)*16+miao%10);
Write_Ds1302_Byte(0x82,(fen/10)*16+fen%10);
Write_Ds1302_Byte(0x84,(shi/10)*16+shi%10);
Write_Ds1302_Byte(0x8e,0x80);
}
void main()
{
init();
Timer0Init();
set_sfm(23,59,50);//初始化时间
while(1)
{
readtime();//读取时间
if(keyflag)
{
readkey();
key_function();
}
}
}
此题需要注意,启停,还有bcd码转化,还有秒位的控制。显示部分,按键部分都很常规。