OLED12864+DS3231的万年历制作,带农历,大字体(单片机源码+实物)
最近逛论坛,看到有做OLED 屏幕显示的万年历,但都没有把农历加进去;我这个把农历加上了,时分秒大字体显示;温度是读的DS3231的温度显示出来的;OLED12864和DS3231时钟芯片都是IIC通信的,共用时钟线和数据线,接线简单;4个按键(设置,+,-,退出),校时的时候,按设置键,相应的位会闪烁,再按+-调整,设置键按到第8次就退出设置,设置的位较多,中途按退出键也可以退出设置。单片机:用12T,或1T的都可以,我用的STC12C5A60S2,1T刷新快些;DS3231是买的模块;OLED是0.96寸黄蓝双色的,实物比照片好看,就是太小了,{:smile:}{:smile:}附件里有完整的源代码。
制作出来的实物图如下:
部分源代码:
[*]#include "reg51.h"
[*]#include "intrins.h"
[*]#include "codetab.h"
[*]#include "nongli.h"
[*]
[*]
[*]#define uintunsigned 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; //退出
[*]
[*]uchara1,a2,a3,a4; //按键消抖用
[*]uchardisflag=0; //时间调整相关
[*]
[*]
[*]
[*]#define Brightness 0xcf //
[*]#define X_WIDTH 128
[*]#define Y_WIDTH 64
[*]
[*]/********************************************************************************************************
[*]** DS3231常数定义
[*]********************************************************************************************************/
[*]#define DS3231_WriteAddress 0xD0 //器件写地址
[*]#define DS3231_ReadAddress0xD1 //器件读地址
[*]#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);
[*]}
代码:
手上刚好有片STC12C5A60S2,可以玩下 感觉有点像论坛里的一个作品… 谢谢分享 有空可以做一下
这段关于2月的判断不对吧 soma 发表于 2024-3-21 18:07
这段关于2月的判断不对吧
芯片里面有万年历, 学习一下 屏幕有点小啊 谢谢分享 {:4_250:}
页:
[1]
2