本帖子中采用了STC89C52作为MCU,DS3231作为时钟源,P10LED屏作为显示屏,显示效果如下几图和一个短视频。在这里值得一提的是P10供电电源问题,标准供电电压为5V,由于是远距离观看屏显示,在室内观看时亮度太高,非常刺眼,最关键是非常耗电,经过试验,把供电电压高低到2.3V左右就可以了,且电流只100MA左右,用普通的手机充电器供电都完全可以了。我再蒙上一层半透光的膜片效果更好了。
制作出来的实物图如下:






程序文件:
#include <reg52.h>#include <intrins.h> //#define uchar unsigned char //#define uint unsigned int #define NOP _nop_() #define u8 unsigned char #define u16 unsigned int sbit OE = P2^0; //P10 sbit A1 = P2^1; //P10 sbit B1 = P2^2; //P10 sbit SHCP=P2^4; //P10 11脚SHCP 移位时钟 sbit STCP=P2^3; //P10 12脚STCP 锁存时钟 sbit DATA=P2^5; //P10 数据输入 //时钟DS3231接口 sbit DSSDA =P2^7;//接时钟DS3231的SDA脚于P2.7 sbit DSSCL=P2^6; //接时钟DS3231的SCL脚于P2.6 sbit LED=P1^2; //定义LED端口 //sbit LED1=P1^3; sbit SHEZ=P3^7; //设置键,从年、月、日、周、时、分、秒顺序移动;键值1-7 sbit JIA=P3^6; //设置键值为1-7时,对应值加1; sbit JIAN=P3^5; //设置键值为1-7时,对应值减1; sbit QUED=P3^4; //完成设置后,使设置键的键值为0,保存到DS3231,完成时间的修改 u8 code shisu[28][8]= //时钟数字 { {0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x38},//0 {0x00,0x18,0x38,0x18,0x18,0x18,0x18,0x3c},//1 {0x00,0x38,0x44,0x44,0x08,0x10,0x20,0x7c},//2 {0x00,0x38,0x44,0x04,0x18,0x04,0x44,0x38},//3 {0x00,0x08,0x18,0x28,0x48,0x7c,0x08,0x08},//4 {0x00,0x7c,0x40,0x78,0x04,0x04,0x44,0x38},//5 {0x00,0x38,0x44,0x40,0x78,0x44,0x44,0x38},//6 {0x00,0x7c,0x44,0x08,0x10,0x10,0x10,0x10},//7 {0x00,0x38,0x44,0x44,0x38,0x44,0x44,0x38},//8 {0x00,0x38,0x44,0x44,0x3c,0x04,0x44,0x38},//9 {0x20,0x3c,0x48,0x3c,0x28,0x7e,0x08,0x08},//10年 {0x00,0x3e,0x22,0x3e,0x22,0x3e,0x22,0x46},//11月 {0x00,0xfe,0x92,0xba,0xfe,0xba,0xaa,0xba},//12周 {0x00,0x02,0xe2,0xaf,0xe2,0xaa,0xe2,0x06},//13时 {0x00,0x28,0x24,0x42,0xbc,0x14,0x24,0x4c},//14分 {0x00,0x74,0x2e,0xf5,0x26,0x74,0xa8,0x30},//15秒 {0x00,0x00,0x00,0x02,0x7f,0x00,0x00,0x00},//16一 {0x00,0x00,0x3c,0x00,0x00,0x00,0x7e,0x00},//17二 {0x00,0x00,0x3c,0x00,0x3c,0x00,0x7e,0x00},//18三 {0x00,0xfe,0xaa,0xaa,0xaa,0xce,0x82,0xfe},//19四 {0x00,0x3c,0x10,0x10,0x3c,0x14,0x24,0x7e},//20五 {0x00,0x20,0x10,0x7c,0x00,0x28,0x44,0x00},//21 六 {0x00,0x3e,0x22,0x22,0x3e,0x22,0x22,0x3e},//22日 {0x00,0x00,0x00,0x01,0x00,0x00,0x01,0x00},//23 : {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, //24 无显示 {0x00,0x60,0x6c,0x12,0x10,0x10,0x12,0x0c}, //25℃ {0x00,0x00,0xf8,0x20,0x22,0x20,0x22,0x20}, //26 T: {0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00} //27 - }; u8 code shisuz[4][8]= //十位数 { {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, //0 {0x00,0x20,0x60,0x20,0x20,0x20,0x20,0x20}, //1 {0x00,0xc0,0x20,0x20,0x60,0x80,0x80,0x60}, //2 {0x00,0xc0,0x20,0x20,0xc0,0x20,0x20,0xc0} //3 }; u8 code shisuy[10][8]= //个位数 { {0x00,0x06,0x09,0x09,0x09,0x09,0x09,0x06},//0 {0x00,0x02,0x06,0x02,0x02,0x02,0x02,0x07},//1 {0x00,0x06,0x09,0x09,0x01,0x02,0x04,0x0f},//2 {0x00,0x06,0x09,0x01,0x06,0x01,0x09,0x06},//3 {0x00,0x02,0x06,0x0a,0x0a,0x0f,0x02,0x02},//4 {0x00,0x0f,0x08,0x0e,0x01,0x01,0x09,0x06},//5 {0x00,0x06,0x09,0x08,0x0e,0x09,0x09,0x06},//6 {0x00,0x0f,0x09,0x02,0x02,0x02,0x02,0x02},//7 {0x00,0x06,0x09,0x09,0x06,0x09,0x09,0x06},//8 {0x00,0x06,0x09,0x09,0x07,0x01,0x09,0x06},//9 }; u8 table1[2][32];//P10写屏变量 u8 T[7]=0,hp=0,js=0,sz,tt; //定义时间变量:秒、分、时、周、日、月、年;换屏变量,温度 bit f; //定义温度符号 void DS3231_IIC_delay(void); //延时函数 void DS3231_IIC_start(void) ; //起始信号 void DS3231_IIC_stop(void); //停止信号 void DS3231_IIC_Tack(void); //接收应答 void DS3231_IIC_write_byte(u8 Data); //写入一个字节的数据函数 u8 DS3231_IIC_read_byte(void); //读取1个字节数据函数 void DS3231_IIC_single_byte_write(u8 Waddr,u8 Data); //写入数据函数 u8 DS3231_IIC_single_byte_read(u8 Waddr); //读取数据函数 void DS3231_IIC_lianxu_read(void); //连续读取0H-06H中的数据 void DS3231_IIC_Init(void); //初始化 void Init_Timer0(void); //定时零提供秒闪 void dushu(u8 n); //写数据 void KEY(void); //按键函数 void get_T(void); //温度获取 /*******************************************************************************************/ /*******************************************************************************************/ void Delay1ms(u16 mm) //11.0592MHz { u8 i, j,k; _nop_(); for(k=0;k<mm;k++) { i = 2; j = 199; do { while (--j); } while (--i); } } //P10数据串行输入 void serial_input(u8 dat) { u16 m; for(m=0;m<8;m++) { if(dat & 0x80) DATA=0; // else DATA=1; //修改取反 SHCP=0; SHCP=1; NOP; NOP; SHCP=0; NOP; NOP; dat=dat<<1; } } /*******************************************************************************************/ //P10并出 void serial_output() { STCP=1; NOP; NOP; STCP=0; } /*******************************************************************************************/ /*******************************************************************************************/ //P10行显控制 void HC138_scan(u8 temp) { OE=1; A1=0x01 & temp; B1=0x01 &(temp>>1); } /*******************************************************************************************/ //读取数字函数 void dushu(u8 n) //参数0正常显示,参数1为设置 { u8 i; if(n==0) { for(i=0;i<8;i++) table1[0][2*i]=shisu[T[2]>>4][i];//上部 0 for(i=0;i<8;i++) if(LED==1) table1[0][2*i+1]=shisu[T[2]&0x0f][i]|shisu[23][i]; else table1[0][2*i+1]=shisu[T[2]&0x0f][i];//上部 1|shisuz[2][i] for(i=0;i<8;i++) table1[1][2*i]=shisu[T[1]>>4][i];//上部 2 for(i=0;i<8;i++) table1[1][2*i+1]=shisu[T[1]&0x0f][i];//上部 3 switch(hp) { case 0:{ for(i=8;i<16;i++) table1[0][2*i]=shisuz[T[6]>>4][i-8]|shisuy[T[6]&0x0f][i-8]; //下部 0 for(i=8;i<16;i++) table1[0][2*i+1]=shisu[10][i-8]; //下部 1 年字 for(i=8;i<16;i++) table1[1][2*i]=shisuz[T[5]>>4][i-8]|shisuy[T[5]&0x0f][i-8]; //下部 2 周字 for(i=8;i<16;i++) table1[1][2*i+1]=shisu[11][i-8]; //下部 3 月 } break; //显示年月 case 1:{ for(i=8;i<16;i++) table1[0][2*i]=shisuz[T[4]>>4][i-8]|shisuy[T[4]&0x0f][i-8]; //下部 0 for(i=8;i<16;i++) table1[0][2*i+1]=shisu[22][i-8]; //下部 1 日字 for(i=8;i<16;i++) table1[1][2*i]=shisu[12][i-8]; //下部 2 周字 for(i=8;i<16;i++) table1[1][2*i+1]=shisu[T[3]+15][i-8]; //下部 3 } break; //显示日和星期 case 2:{ get_T(); //首先获取温度 if(f==0) for(i=8;i<16;i++) table1[0][2*i]=shisu[26][i-8]; //下部 首位显示T: else for(i=8;i<16;i++) table1[0][2*i]=shisu[27][i-8]; //下部首位显示- for(i=8;i<16;i++) table1[0][2*i+1]=shisu[tt/10][i-8]; //下部 1 for(i=8;i<16;i++) table1[1][2*i]=shisu[tt%10][i-8]; //下部 2 for(i=8;i<16;i++) table1[1][2*i+1]=shisu[25][i-8]; //下部 3 } break; //显示温度 } } else { /********************设置日期时上半部分显示内容*************************************/ switch(sz) { case 1:{ //修改年份 for(i=0;i<8;i++) table1[0][2*i]=shisu[T[6]/10][i];//上部 0 年的十位,不闪烁 for(i=0;i<8;i++) if(LED==1) table1[0][2*i+1]=shisu[T[6]%10][i]; else table1[0][2*i+1]=shisu[24][i];//上部 1 for(i=0;i<8;i++) table1[1][2*i]=shisu[10][i];//上部 2 显示年 for(i=0;i<8;i++) table1[1][2*i+1]=shisu[24][i];//上部 3 不显示 } break; case 2:{ //修改月份 for(i=0;i<8;i++) table1[0][2*i]=shisu[T[5]/10][i];//上部 0 月的十位,不闪烁 for(i=0;i<8;i++) if(LED==1) table1[0][2*i+1]=shisu[T[5]%10][i]; else table1[0][2*i+1]=shisu[24][i];//上部 1 for(i=0;i<8;i++) table1[1][2*i]=shisu[11][i];//上部 2 显示月 for(i=0;i<8;i++) table1[1][2*i+1]=shisu[24][i];//上部 3 不显示 } break; case 3:{ //修改日期 for(i=0;i<8;i++) table1[0][2*i]=shisu[T[4]/10][i];//上部 0 日的十位,不闪烁 for(i=0;i<8;i++) if(LED==1) table1[0][2*i+1]=shisu[T[4]%10][i]; else table1[0][2*i+1]=shisu[24][i];//上部 1 for(i=0;i<8;i++) table1[1][2*i]=shisu[22][i];//上部 2 显示日 for(i=0;i<8;i++) table1[1][2*i+1]=shisu[24][i];//上部 3 不显示 } break; case 4:{ //修改星期 for(i=0;i<8;i++) table1[0][2*i]=shisu[24][i];//上部 0 星期的十位,不显示 for(i=0;i<8;i++) if(LED==1) table1[0][2*i+1]=shisu[T[3]][i]; else table1[0][2*i+1]=shisu[24][i];//上部 1|shisuz[2][i] for(i=0;i<8;i++) table1[1][2*i]=shisu[12][i];//上部 2 显示周 for(i=0;i<8;i++) table1[1][2*i+1]=shisu[24][i];//上部 3 不显示 } break; case 5:{ //修改小时 for(i=0;i<8;i++) table1[0][2*i]=shisu[T[2]/10][i];//上部 0 小时的十位,不闪烁 for(i=0;i<8;i++) if(LED==1) table1[0][2*i+1]=shisu[T[2]%10][i]; else table1[0][2*i+1]=shisu[24][i];//上部 1|shisuz[2][i] for(i=0;i<8;i++) table1[1][2*i]=shisu[13][i];//上部 2 显示时 for(i=0;i<8;i++) table1[1][2*i+1]=shisu[24][i];//上部 3 不显示 } break; case 6:{ //修改分钟 for(i=0;i<8;i++) table1[0][2*i]=shisu[T[1]/10][i];//上部 0 分钟的十位,不闪烁 for(i=0;i<8;i++) if(LED==1) table1[0][2*i+1]=shisu[T[1]%10][i]; else table1[0][2*i+1]=shisu[24][i];//上部 1|shisuz[2][i] for(i=0;i<8;i++) table1[1][2*i]=shisu[14][i];//上部 2 显示分 for(i=0;i<8;i++) table1[1][2*i+1]=shisu[24][i];//上部 3 不显示 } break; case 7:{ //修改秒钟 for(i=0;i<8;i++) table1[0][2*i]=shisu[T[0]/10][i];//上部 0 秒的十位,不闪烁 for(i=0;i<8;i++) if(LED==1) table1[0][2*i+1]=shisu[T[0]%10][i]; else table1[0][2*i+1]=shisu[24][i];//上部 1|shisuz[2][i] for(i=0;i<8;i++) table1[1][2*i]=shisu[15][i];//上部 2 显示秒 for(i=0;i<8;i++) table1[1][2*i+1]=shisu[24][i];//上部 3 不显示 } break; } /*************设置日期时下部均不显示************************/ for(i=8;i<16;i++) table1[0][2*i]=shisu[24][i-8]; //下部 0 for(i=8;i<16;i++) table1[0][2*i+1]=shisu[24][i-8]; //下部 1 for(i=8;i<16;i++) table1[1][2*i]=shisu[24][i-8]; //下部 2 for(i=8;i<16;i++) table1[1][2*i+1]=shisu[24][i-8]; //下部 3 } } /*******************************************************************************************/ //P10整屏显示 void display(void) { u8 i,j,k; for(k=0;k<4;k++) //显示的四行 { for(j=0;j<2;j++) //显示3、4列 { for(i=0;i<2;i++) // 显示1、2列 { serial_input(table1[j][3*8+2*k+i]); serial_input(table1[j][2*8+2*k+i]); serial_input(table1[j][1*8+2*k+i]); serial_input(table1[j][0*8+2*k+i]); } } serial_output(); HC138_scan(k); } } /*******************************************************************************************/ /*******************************************************************************************/ /*******************************************************************************************/ /*******************************************************************************************/ void main() { // u8 i, Waddr=0; Init_Timer0(); Delay1ms(1); DS3231_IIC_Init(); /* T[0]=0x00; //0秒 T[1]=0x01; //50分 T[2]=0x22; //23点 T[3]=0x05; //星期日 T[4]=0x07; //7日 T[5]=0x05; //5月 T[6]=0x21; //21年 for(i=0;i<7;i++) //写入日期和时间 { DS3231_IIC_single_byte_write(Waddr,T[i]); Waddr++; } */ Delay1ms(2); //display(); DS3231_IIC_lianxu_read(); //连续读取0H-06H中的数据 Delay1ms(2); dushu(0); while(1) { /* if(LED==1) { DS3231_IIC_lianxu_read(); //连续读取0H-06H中的数据 dushu(); }*/ display(); //显示 KEY(); //键盘扫描 if(sz!=0) dushu(1); /*Delay1ms(); Delay1ms(); Delay1ms(); Delay1ms(); */ } } void DS3231_IIC_delay(void) //延时函数 { u8 i; for(i=0;i<1;i++); } void DS3231_IIC_start(void) //起始信号 { DSSDA=1; DSSCL=1; DS3231_IIC_delay(); DSSDA=0; DS3231_IIC_delay(); DSSCL=0; } void DS3231_IIC_stop(void) //停止信号 { DSSDA=0; DS3231_IIC_delay(); DSSCL=1; DS3231_IIC_delay(); DSSDA=1; DS3231_IIC_delay(); } void DS3231_IIC_Tack(void) //接收应答 { DSSCL=1; //拉高SCL DS3231_IIC_delay(); while(DSSDA==1); //由P2.7读入1,表示3231无应答,需要等待 DS3231_IIC_delay(); DSSCL=0; //拉低SCL DS3231_IIC_delay(); } void DS3231_IIC_write_byte(u8 Data) //写入一个字节的数据函数 { u8 i; for (i=0;i<8;i++) { if(Data&0x80) DSSDA=1; else DSSDA=0; DS3231_IIC_delay(); DSSCL=1; DS3231_IIC_delay(); DSSCL=0; DS3231_IIC_delay(); Data=Data<<1; } } u8 DS3231_IIC_read_byte(void) //读取1个字节数据函数 { u8 i,Data; for(i=0;i<8;i++) { DSSCL=1; DS3231_IIC_delay(); Data=Data<<1; DS3231_IIC_delay(); if(DSSDA) Data=Data|0x01; DSSCL=0; DS3231_IIC_delay(); } return Data; } void DS3231_IIC_single_byte_write(u8 Waddr,u8 Data) //写入数据函数 { DS3231_IIC_start(); DS3231_IIC_write_byte(0xd0);//DS3231的地址 DS3231_IIC_Tack(); DS3231_IIC_write_byte(Waddr);//欲写入的地址 DS3231_IIC_Tack(); DS3231_IIC_write_byte(Data);//欲写入的地址数据 DS3231_IIC_Tack(); DS3231_IIC_stop(); } u8 DS3231_IIC_single_byte_read(u8 Waddr) //读取数据函数 { u8 Data; DS3231_IIC_start(); DS3231_IIC_write_byte(0xd0);//DS3231的地址 DS3231_IIC_Tack(); DS3231_IIC_write_byte(Waddr);//欲读取的地址,本质上是移动指针 DS3231_IIC_Tack(); DS3231_IIC_stop(); DS3231_IIC_start(); DS3231_IIC_write_byte(0xd1);//告诉3231欲读取指针所指寄存器内容 DS3231_IIC_Tack(); Data=DS3231_IIC_read_byte(); DS3231_IIC_delay(); DS3231_IIC_stop(); return Data; } void DS3231_IIC_lianxu_read(void) //连续读取0H-06H中的数据 { u8 i,Waddr; Waddr=0x00; for(i=0;i<7;i++) { T[i]=DS3231_IIC_single_byte_read(Waddr); Waddr=Waddr+1; } } void DS3231_IIC_Init(void) //初始化 { DSSDA=1; DSSCL=1; DS3231_IIC_single_byte_write(0x0e,0x00); } /*********温度获取***************/ void get_T(void) { u8 Tem_L,Tem_H; Tem_H=DS3231_IIC_single_byte_read(0x11); //温度 高字节 整数部分 Tem_L=DS3231_IIC_single_byte_read(0x12); //温度 低字节 小数部分 Tem_L = (Tem_L>>6)*0.25+0.5; //小数部分四舍五入 tt=Tem_H+Tem_L; f=Tem_H>>7 ; //是1的话表示负温度,0为正温度 } /*------------------------------------------------ 定时器初始化子程序 ------------------------------------------------*/ void Init_Timer0(void) { TMOD |= 0x01; //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响 //TMOD |= 0x11; TH0=(65536-2000)/256; //给定初值 2毫秒 TL0=(65536-2000)%256; EA=1; //总中断打开 ET0=1; //定时器中断打开 TR0=1; //定时器开关打开 /*TMOD |= 0x10; //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响 TH1=0x00; //给定初值,这里使用定时器最大值从0开始计数一直到65535溢出 TL1=0x00; //EA=1; //总中断打开 ET1=1; //定时器中断打开 TR1=1; //定时器开关打开 IT1=1;*/ } /*------------------------------------------------ 定时器中断子程序 ------------------------------------------------*/ void Timer0_isr(void) interrupt 1 //using 1 { static unsigned char num; TH0=(65536-2000)/256; //重新赋值 2毫秒 TL0=(65536-2000)%256; num++; if(num==250) { num=0; js++; LED=~LED; //指示灯反相,可以看到闪烁 if(sz==0) { dushu(0); if(js==10) { js=0; hp++; if(hp==3) hp=0; DS3231_IIC_lianxu_read(); //连续读取0H-06H中的数据 } } /*display(); */ } } /* //外部中断解码程序 void intersvr1(void) interrupt 2 using 1 { LED1=~LED1; //LED1闪烁 } */ /*------------------------------------------------ 定时器中断子程序 ------------------------------------------------ void Timer1_isr(void) interrupt 3 using 1 { TH1=(65536-2000)/256; //重新赋值 TL1=(65536-2000)%256; ss++; if(ss==250) { ss=0; LED=~LED; //LED闪烁 } }*/
复制代码