使用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通信函数:
对数据的操纵函数:
对DS3231SN的设置:
对时间温度的切换,时间的设置,定时器的初始化:
按键检测:
led的显示:
串口通信,方便debug:
main函数:
由按键实现时间的调整,时间和温度的切换。通过串口的输出显示,实现对程序的监控,方便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)); } }
相关文章推荐
- DHT11实现温度湿度的数码管显示
- 嵌入式Linux裸机开发(十三)——I2C通信
- 解析I2C通信协议
- 十五.ARM裸机学习之I2C通信详解
- 可以浏览的国外网站(学习和放松)
- 阿里2017校园招聘电话面试总结
- Oracle中有关Group by 中avg();sum();min();max();count();的运用整理(Oracle的执行顺序)
- 《Python基础教程 第2版·修订版》 字典:当索引不好用时(一)
- Retrofit 使用flatmap操作符时处理错误、异常
- Insight mvc:resources cache-period 解析
- Unity Editor中使用AssetBundle里的shader遇到的问题
- HDU-5795-A Simple Nim-博弈(SG函数)打表找规律
- java数据转换error:java.math.BigDecimal cannot be cast to java.lang.Double
- 【ArcGIS for JavaScript】加载地图,并标注点
- android6.0蓝牙配对加入提示音
- KMP算法
- CentOS 安装 jdk
- Hadoop权威指南:MapReduce应用开发
- 读书笔记四
- 如果读取图像的图像出现坏图,无法读取的怎么办?怎么自动跳过坏的图像,而读取下一张?