本项目使用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 = 1000;
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));
}
}