最近逛论坛,看到有做OLED 屏幕显示的万年历,但都没有把农历加进去;我这个把农历加上了,时分秒大字体显示;温度是读的DS3231的温度显示出来的;OLED12864和DS3231时钟芯片都是IIC通信的,共用时钟线和数据线,接线简单;4个按键(设置,+,-,退出),校时的时候,按设置键,相应的位会闪烁,再按+-调整,设置键按到第8次就退出设置,设置的位较多,中途按退出键也可以退出设置。单片机:用12T,或1T的都可以,我用的STC12C5A60S2,1T刷新快些;DS3231是买的模块;OLED是0.96寸黄蓝双色的,实物比照片好看,就是太小了,

制作出来的实物图如下:
1.jpg

部分源代码:
#include "reg51.h"
  • #include "intrins.h"
  • #include "codetab.h"
  • #include "nongli.h"
  • #define uint  unsigned int
  • #define uchar unsigned char
  • // ------------------------------------------------------------
  • // IO口模拟I2C通信
  • // ------------------------------------------------------------
  • sbit SCL=P3^6; //串行时钟
  • sbit SDA=P3^7; //串行数据
  • sbit KEY1=  P3^0;                  //调整
  • sbit KEY2=  P3^1;                  //++
  • sbit KEY3=  P3^2;                  //--
  • sbit KEY4=  P3^3;                  //退出
  • uchar  a1,a2,a3,a4;                      //按键消抖用
  • uchar  disflag=0; //时间调整相关
  • #define        Brightness        0xcf //
  • #define X_WIDTH         128
  • #define Y_WIDTH         64
  • /********************************************************************************************************
  • **         DS3231常数定义
  • ********************************************************************************************************/
  • #define DS3231_WriteAddress 0xD0    //器件写地址
  • #define DS3231_ReadAddress  0xD1    //器件读地址
  • #define DS3231_SECOND       0x00    //秒
  • #define DS3231_MINUTE       0x01    //分
  • #define DS3231_HOUR         0x02    //时
  • #define DS3231_WEEK         0x03    //星期
  • #define DS3231_DAY          0x04    //日
  • #define DS3231_MONTH        0x05    //月
  • #define DS3231_YEAR         0x06    //年
  • #define DS3231_TEMPERATUREH 0x11    //温度寄存器高字节(8位)        整数部分
  • #define DS3231_TEMPERATUREL 0x12    //温度寄存器低字节(低2位) 小数部分
  • #define NACK    1
  • #define ACK     0
  • uchar shan_count; //:号闪烁计时变量
  • uchar shan_js;    //校时闪烁计时变量
  • bit flag;                //校时闪烁标志
  • char hour,minute,second,year,month,day,date,week;
  • uint TH3231;
  • bit        ack;                //应答标志位
  • /*********************OLED驱动程序用的延时程序************************************/
  • /*void delay(unsigned int z)
  • {
  •         unsigned int x,y;
  •         for(x=z;x>0;x--)
  •                 for(y=1100;y>0;y--);  
  • }        */
  • void        Delay5US()           //@12.000MHz           延时5us
  • {
  •    _nop_(); _nop_();        _nop_();_nop_(); //1T单片机用4个nop,12T用1个nop
  • }
  • /**************************/
  • void Timer0Init(void)                //10毫秒@11.0592MHz
  • {
  • //        AUXR &= 0x7F;                //定时器时钟12T模式
  •         TMOD &= 0xF0;                //设置定时器模式
  •         TMOD |= 0x01;                //设置定时器0,16位模式
  •         TL0 = 0x00;                //设置定时初值
  •         TH0 = 0xDC;                //设置定时初值
  •         TF0 = 0;                //清除TF0标志
  •         TR0 = 1;                //定时器0开始计时
  •         ET0 = 1;
  •         EA = 1;
  • }
  • /**********************************************
  • //IIC Start
  • **********************************************/
  • void IIC_Start()
  • {
  •    SCL = 1;               
  •    SDA = 1;
  •    SDA = 0;
  •    SCL = 0;
  • }
  • /**********************************************
  • //IIC Stop
  • **********************************************/
  • void IIC_Stop()
  • {
  •    SCL = 0;
  •    SDA = 0;
  •    SCL = 1;
  •    SDA = 1;
  • }
  • /********************************************************************************************************
  • **         3231
  • ********************************************************************************************************/
  • uchar        BCD2HEX(uchar val)
  • {
  •         return        ((val>>4)*10)+(val&0x0f);
  • }
  • uchar        HEX2BCD(uchar val)
  • {
  •         return        (((val%100)/10)<<4)|(val%10);
  • }
  • void SendByte(uchar c)
  • {
  •     uchar BitCnt;
  •    
  •     for(BitCnt=0;BitCnt<8;BitCnt++)         //要传送的数据长度为8位
  •     {
  •         if((c<<BitCnt)&0x80)
  •             SDA=1;                          //判断发送位
  •         else
  •             SDA=0;     
  •         SCL=1;                            //置时钟线为高,通知被控器开始接收数据位
  •         Delay5US();                       //保证时钟高电平周期大于4μs   
  •         SCL=0;
  •     }
  •     SDA=1;                                  //8位发送完后释放数据线,准备接收应答位
  •     SCL=1;
  •     Delay5US();
  •     if(SDA==1)
  •         ack=0;   
  •     else
  •         ack=1;                              //判断是否接收到应答信号
  •     SCL=0;
  •     Delay5US();
  • }           
  • uchar RcvByte()
  • {
  •    uchar retc;
  •    uchar BitCnt;
  •    retc=0;
  •    SDA=1;                           //置数据线为输入方式
  •    for(BitCnt=0;BitCnt<8;BitCnt++)
  •    {
  •         SCL=0;                      //置时钟线为低,准备接收数据位      
  •         Delay5US();                 //时钟低电平周期大于4.7μs                       
  •         SCL=1;                      //置时钟线为高使数据线上数据有效
  •         Delay5US();
  •         retc=retc<<1;
  •         if(SDA==1)
  •             retc=retc+1;            //读数据位,接收的数据位放入retc中
  •         Delay5US();
  •    }
  •    SCL=0;
  •    return(retc);
  • }                           
  • void Ack_I2C(bit a)
  • {
  •         SDA        =        a;  
  •     SCL=1;                     
  •     Delay5US();             //时钟低电平周期大于4us   
  •     SCL=0;                  //清时钟线,钳住I2C总线以便继续接收
  •     Delay5US();   
  • }                                            
  • uchar write_byte(uchar addr, uchar write_data)
  • {
  •     IIC_Start();
  •     SendByte(DS3231_WriteAddress);
  •     if (ack == 0)
  •         return 0;
  •    
  •     SendByte(addr);   
  •     if (ack == 0)
  •         return 0;
  •    
  •     SendByte(write_data);
  •     if (ack == 0)
  •         return 0;
  •    
  •     IIC_Stop();
  •     Delay5US();      
  •     Delay5US();      
  •     return 1;
  • }                                          
  • uchar read_current()
  • {
  •     uchar read_data;
  •     IIC_Start();
  •     SendByte(DS3231_ReadAddress);
  •     if(ack==0)
  •         return(0);              
  •     read_data = RcvByte();
  •     Ack_I2C(1);
  •     IIC_Stop();
  •     return read_data;
  • }                                                
  • uchar read_random(uchar random_addr)
  • {
  •     uchar Tmp;
  •         IIC_Start();
  •     SendByte(DS3231_WriteAddress);
  •     if(ack==0)
  •         return(0);            
  •     SendByte(random_addr);
  •     if(ack==0)
  •         return(0);
  •         Tmp=read_current();
  •         if(random_addr==DS3231_HOUR)
  •                 Tmp&=0x3f;
  •                                             
  •     return(BCD2HEX(Tmp));//都转10进制输出
  • }
  • /***********************/
  • uchar read_random1(uchar random_addr)  //这个是读温度函数
  • {
  •     uchar Tmp;
  •         write_byte(0x0e,0x20);//0x0e寄存器的CONV位置1开启温度转换,要这句,温度实时刷新,这句不要,温度要64s才刷新1次
  •         IIC_Start();
  •     SendByte(DS3231_WriteAddress);
  •     if(ack==0)
  •         return(0);            
  •     SendByte(random_addr);
  •     if(ack==0)
  •         return(0);
  •         Tmp=read_current();
  •         return Tmp;
  • }                                 
  • void ModifyTime(uchar address,uchar num)
  • {
  •     uchar temp=0;
  •            if(address>6 && address <0) return;
  •     temp=HEX2BCD(num);
  •         write_byte(address,temp);
  • }
  • 复制代码