您的位置:首页 > 其它

使用DS3231SN制作数字时钟

2016-08-05 15:33 381 查看
本项目使用STC15W4K58S4单片机作为控制部分,其速度是传统单片机的12倍。使用有2片74H595驱动的四位数码管显示。

由按键实现时间的调整,时间和温度的切换。通过串口的输出显示,实现对程序的监控,方便debug。

DS3231SN的温度传感,精确到0.25°

DS3231SN的时钟,支持两路闹钟,拥有内部晶振,在有备用电源情况下,精准的进行计时。

DS3231SN支持电压测量。

完整整项目下载:http://download.csdn.net/detail/c1194758555/9596071

DN3231SN中文数据手册:http://download.csdn.net/detail/c1194758555/9596066

项目所用的全部头文件:

####################################################################

IIC通信:

IIC.h

#ifndef _IIC_H_
#define _IIC_H_

#define uchar unsigned char

/*模拟IIC通信*/
#define SCL   P03
#define SDA   P04

void start(void);          /*通信开始*/
void stop(void);           /*通信停止*/
uchar send_bit(uchar dat); /*发送一个bit*/
char Read_bit(void);       /*读取一个bit*/
uchar ASLK(uchar Bit);     /*应答信号*/

#endif

######################################################################

######################################################################

数据的读写:

write_or_read.h

#ifndef _READ_OR_WRITE_H_
#define _READ_OR_WRITE_H_
#include "IIC.h"

uchar W_char(uchar Add,uchar Dat);
char R_w_add_char(uchar Add);
uchar bcd_hex(uchar bcd);
uchar hex_bcd(uchar hex);

#endif

########################################################################

########################################################################

初始化设置时间:

DS3231.h

#ifndef _DS3231_H_
#define _DS3231_H_
#include "IIC.h"

/*存储时间*/
extern          char Time[8];
extern unsigned char Hour;
extern unsigned char Minutes;
extern unsigned char Seconds;
extern          char Wdh;
extern          char Wdl;
extern unsigned char ERRON;

/*地址的定义*/

#define H   0x02
#define M   0x01
#define S   0x00
#define WDH 0x11
#define WDL 0x12
#define Con 0x0e
#define Pws 0x0f
#define A_W 0xD0
#define A_R 0xD1

uchar Get_H(void);       /*获得小时*/
uchar Get_M(void);       /*获得分钟*/
uchar Get_S(void);       /*获得秒*/
uchar Get_WDH(void);     /*获取温度整数位*/
uchar Get_WDL(void);     /*获取温度小数位*/

uchar init_DS3231(uchar con);                                   /*初始化DS3231*/
uchar Set_time(uchar data_H,uchar data_M,uchar data_S);         /*设置时间*/

#endif
#################################################################################

#################################################################################

对时间设置,时间温度切换控制,时间温度显示:

Interrupt.h

#ifndef _Interrupt_H_
#define _Interrupt_H_
#include "IIC.h"

#define init(x) x ? Read_WD() : Read_SJ()

void init_0(void);     /*初始化定时器0*/
void set_time_key(uchar f); /*设置时间加1*/
void Read_WD(void);  /*读取温度*/
void Read_SJ(void);  /*读取时间*/
void display_us(unsigned int tt); /*μ秒级*/
void display_ms(unsigned int tt);  /*微妙级*/

#endif

###################################################################################

对按键的操作:

key.h

#ifndef _KEY_H_
#define _KEY_H_
#include "IIC.h"

/*按键输入*/
#define key1 P20
#define key2 P21
#define key3 P22
#define key4 P23

extern unsigned char KEY;

uchar Key_NO(void); /*按键检测*/

#endif

###################################################################################

###################################################################################

串口通信,方便debug:

uart.h

#ifndef _UART_H_
#define _UART_H_

void init_uart1(void);    /*初始化串口*/
void OutChar(char c);     /*输出一个字符*/
void OutString(char* str); /*输出一个字符串*/
void Out_Time_WD(void);    /*输出温度或时间*/

#endif

#######################################################################################


模拟IIC通信函数:

#include <STC15W4K58S4.h>
#include "Interrupt.h"
#include "IIC.h"
#include "uart.h"

void start(void) /*开始通信*/
{
SDA = 1;

display_us(1);

SCL = 1;

display_us(5); /*高电平必须持续大于5μ秒*/

SDA = 0;

display_us(5);

SCL = 0;

display_us(2);

}

void stop(void) /*停止通信*/
{

SCL = 1;

display_us(1);

SDA = 0;

display_us(5);

SDA = 1;
display_us(3);

}

uchar ack(void)  /*检测从机应答信号*/
{
uchar ans;

SDA = 1;

display_us(2);

SCL = 1;

display_us(3);

ans = SDA;

SCL = 0;

display_us(2);

return ans;
}

uchar send_bit(uchar dat) /*发送一个字节*/
{
uchar i;
uchar j;

for(i = 0; i < 8; i++)
{
if((dat << i) & 0x80)
j = SDA = 1;
else
j = SDA = 0;

SCL = 1;
display_us(5);

SCL = 0;
display_us(1);
}
display_us(2);

return ack();
}

char Read_bit(void)  /*读取一个字节*/
{
uchar i;
char date = 0;

SDA = 1;

for(i = 0; i < 8; i++)
{
display_us(1);

SCL = 0;
display_us(5);

SCL = 1;
display_us(3);

date = date << 1;

if(SDA)
date += 1;

display_us(2);
}

SCL = 0;
display_us(2);

return date;
}

uchar ASLK(uchar Bit) /*主机应答信号*/
{
uchar ans = 1;

if(!Bit)
SDA = 0;
else
SDA = 1;
display_us(2);

SCL = 1;
display_us(5);

SCL = 0;
display_us(2);

return ans;
}


对数据的操纵函数:

#include "read_or_write.h"
#include "IIC.h"
#include "DS3231.h"
#include "Interrupt.h"
#include "uart.h"

uchar bcd_hex(uchar bcd)         /*bcd码转换为十六进制*/
{
uchar temp = bcd & 0x0f;
bcd = bcd >> 4;
bcd %= 0xf;

return bcd *10 + temp;
}

uchar hex_bcd(uchar hex)        /*十六进制转化为BCD码*/
{
uchar temp = hex / 10;
temp = temp << 4;

OutChar(((temp + (hex % 10)) / 16 )+ '0');
OutChar(((temp + (hex % 10) ) % 16 )+ '0');
OutChar('\r');
OutChar('\n');

return temp + hex % 10;
}

uchar W_char(uchar Add,uchar Dat) /*写数据*/
{
start();

if(send_bit(A_W))
return 0;

if(send_bit(Add))
return 0;

if(send_bit(Dat))
return 0;

stop();

display_us(2);

return 1;
}

char R_char()                    /*读取一个字符*/
{
char temp;

start();

if(send_bit(A_R))
return 0;

temp = Read_bit();

ASLK(1);

stop();

return temp;
}

char R_w_add_char(uchar Add)  /*读取数据*/
{
char temp;
start();

if(send_bit(A_W))
return 0;

if(send_bit(Add))
return 0;

display_us(2);

temp = R_char();

return temp;
}


对DS3231SN的设置:

#include "IIC.h"
#include "read_or_write.h"
#include "DS3231.h"
#include "uart.h"

char Time[8];                               /*存储时间*/
unsigned char Hour;                         /*小时*/
unsigned char Minutes;                      /*分钟*/
unsigned char Seconds;                      /*秒*/
char Wdh;
char Wdl;
unsigned char ERRON;                          /*出错标志*/

uchar init_DS3231(uchar con)                  /*初始化DS3231*/
{
uchar f = 0;
f = W_char(Con,con);
return f;
}

uchar Get_H(void)                                       /*获得小时*/
{
uchar temp = R_w_add_char(H);
temp = bcd_hex(temp);
temp &= 0x3f;
return temp;
}

uchar Get_M(void)                                       /*获得分钟*/
{
uchar temp = R_w_add_char(M);
temp = bcd_hex(temp);
return temp;
}

uchar Get_S(void)                                       /*获得秒*/
{
uchar temp = R_w_add_char(S);
temp = bcd_hex(temp);
return temp;
}

uchar Get_WDH(void)                                    /*获得温度整数位*/
{
return R_w_add_char(WDH);
}

uchar Get_WDL(void)                                    /*获得温度小数位*/
{
return R_w_add_char(WDL);
}


对时间温度的切换,时间的设置,定时器的初始化:

#include <STC15W4K58S4.h>
#include "Interrupt.h"
#include "IIC.h"
#include "DS3231.h"
#include "led.h"
#include "led.h"
#include "key.h"
#include "uart.h"

void display_us(unsigned int tt) /*μ秒级*/
{
while(tt--);
}

void display_ms(unsigned int tt) /*毫妙级*/
{

while(tt--)
{
display_us(100);
}
}

void init_0(void) /*定时器0中断初始化,用于显示时间*/
{
TMOD &= ~0x0f;
AUXR &= ~0x80;
TH0 = 65036 >> 8;
TL0 = 65036;
TR0 = 1;
ET0 = 1;
EA = 1;
}

void Read_WD(void)  /*读取温度*/
{
uchar Wdh,Wdl;
unsigned int tt;
unsigned int t;
init_DS3231(0x3C);

do
{
Wdh = Get_WDH();
Wdl = Get_WDL();

Wdl = Wdl >> 6;
Wdl &= 0x03;
Wdl *= 25;

Time[3] = Wdh / 10;
Time[2] = Wdh % 10;
Time[1] = Wdl / 10;
Time[0] = Wdl % 10;
Out_Time_WD();

tt = 1000;
while(tt--)
{
t = 1000;
while(t--)
{
KEY = Key_NO();
if(KEY == 3)
return;
}
}
}
while(KEY == 0 || KEY == 1);
}

void set_time_key(uchar f) /*更改时间位*/
{
if(f == 1)
{
Hour += 1;
if(Hour >= 24)
Hour = 0;
Time[3] = Hour / 10;
Time[2] = Hour % 10;
}
else if(f == 2)
{
Minutes += 1;
if(Minutes > 59)
Minutes = 0;

Time[1] = Minutes / 10;
Time[0] = Minutes % 10;
}
}

void Read_SJ(void)  /*读取时间*/
{
unsigned int tt;
unsigned int t;
uchar j = 1;
init_DS3231(0x1C);

do
{

Hour =  Get_H();
Minutes = Get_M();
Seconds = Get_S();

Time[3] = Hour / 10;
Time[2] = Hour % 10;
Time[1] = Minutes / 10;
Time[0] = Minutes %10;
Out_Time_WD();
tt = 1000;
while(tt--)
{
t = 1
cdec
000;
while(t--)
{
KEY = Key_NO();
if(KEY ==1 || KEY == 3)
return;
}
}
}
while(KEY == 0);
}


按键检测:

#include <STC15W4K58S4.h>
#include "Interrupt.h"
#include "key.h"
#include "IIC.h"
#include "uart.h"

unsigned char KEY;

uchar Key_NO(void)               /*按键检测*/
{
unsigned int time = 1000;
if(!key1  || !key2 || !key3 || !key4)
{
OutString("有键按下\r\n");
display_ms(10);
if(!key1 || !key2 || !key3  || !key4)
{
if(!key1)
{
OutString("key1\r\n");
while(!key1 && time--)
display_us(1000);
return 1;
}

if(!key2)
{
OutString("key2\r\n");
while(!key2 && time--)
display_us(1000);
return 2;
}

if(!key3)
{
OutString("key3\r\n");
while(!key3 && time--)
display_us(1000);
return 3;
}

if(!key4)
{
OutString("key4\r\n");
while(!key4 && time--);
return 4;
}
}

}
return 0;
}


led的显示:

#include <STC15W4K58S4.h>
#include "led.h"

const unsigned char table[12] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x7F}; /*段码*/

void S_CLK()   /*移位信号*/
{
SCLK = 0;
SCLK = 1;
}

void R_CLK() /*位选信号*/
{
RCLK = 0;
RCLK = 1;
}

void led_on(unsigned char led_num) /*点亮一个LED*/
{
unsigned char i ;
for(i = 0; i < 8; i++)
{
if(led_num & 0x80)
DIO = 1;
else
DIO = 0;
led_num <<= 1;
S_CLK();
}
}

void led_one(unsigned char LEDNO, unsigned char NO) /*扫描一遍四个数码管*/
{

led_on(LEDNO);
led_on(NO);
R_CLK();
}


串口通信,方便debug:

#include <STC15W4K58S4.h>
#include "Interrupt.h"
#include "DS3231.h"

void init_uart1(void) /*初始化串口*/
{
SCON |= 0x50;
TMOD &= ~0xf0;
AUXR |= 0x40;
AUXR &= 0xFE;
TH1 = 65224 >> 8;
TL1 = 65224;
ET1 = 0;

TR1 = 1;
}

void OutChar(char c) /*输出一个字符*/
{
SBUF  = c;
while(!TI);
TI = 0;
}

void Out_Time_WD(void) /*输出时间或温度*/
{
uchar temp;
char i;
for(i = 3; i >= 0; i--)
{
temp = Time[i] + '0';
OutChar(temp);
}
OutChar('\r');
OutChar('\n');
}

void OutString(char* str) /*输出字符串*/
{
while(*str != '\0')
OutChar(*str++);

}


main函数:

#include <STC15W4K58S4.h>
#include "read_or_write.h"
#include "Interrupt.h"
#include "led.h"
#include "IIC.h"
#include "key.h"
#include "uart.h"
#include "DS3231.h"

static uchar f = 0;                              /*时间温度状态切换标志量*/
static uchar flag;                               /*设置时间使用的状态变量*/
static unsigned int SUM = 1000;                  /*设置时间时相应位闪动的时间间隔*/
static unsigned int NO;
int main()
{
uchar set;
KEY = 0;                                 	/*按键*/
ERRON = 1;                                /*出错标志位*/
flag = 0;

/*设置为准双向输出*/

P2M0 = 0x00;
P2M1 = 0x00;

Time[0] = 5;
Time[1] = 5;
Time[2] = 5;
Time[3] = 5;
init_uart1();                             /*初始化串口,用于监控代码运行,方便调试*/
init_0();

init_DS3231(0x1C);                         /*初始化DS3231*/

//OutChar(Set_time(0x0C,0x01,0x0) + '0');  /*设置时间*/

Out_Time_WD();
init(f);                                 /*初始化定时器0,显示时间*/

Out_Time_WD();

while(1)
{
OutString("进入while\r\n");
switch(KEY)
{
case 1:
if(!f)
{
flag = 1;
while(flag < 3)
{
set = Key_NO();          /*检测按键变化*/

switch(set)
{
case 1: { if(flag == 1) W_char(H,hex_bcd(Hour)); if(flag == 2) W_char(M,hex_bcd(Minutes)); flag += 1; }			break;       /*分钟位开始闪烁*/
case 2: set_time_key(flag); break;   /*加1*/
}
}

display_ms(100);
flag = 0;
KEY = 0;

}
init(f);                           /*时间正常显示*/
break;

case 3:
f = !f;                            /*切换状态*/
init(f);                           /*显示为设置的工作状态*/
break;
}
}
}

/*定时器1的中断函数,用于刷新led数码管*/
void init_time0() interrupt 1
{
uchar i,k;
uchar j = 1;

if(flag ==1)
{
if(NO >= SUM)
{
i = 0;
k = 4;
}
else
{
i = 0;
k = 2;
}
}
else if(flag == 2)
{
if(NO >= SUM)
{
i = 0;
k = 4;
}
else
{
i = 2;
k = 4;
}
}
else
{
i = 0;
k = 4;
}

if(NO == 2*SUM)
NO = 0;
NO += 1;

for(;i < k; i++)
{
if(f && i == 2)
{
led_one((table[Time[i]] & 0x7F),(j << i));
}
else if(!f && i == 2 && NO <= SUM && !flag)
{
led_one((table[Time[i]] & 0x7F),(j << i));
}
else
led_one(table[Time[i]],(j << i));
}
for(i= 0;i < 4; i++)
{
led_one(0xff,(j << i));
}

}


                                                                       
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息