基于51单片机和OLED12864、DS3231、独立按键的万年历可调时钟

系列文章目录


前言

一开始用STC12C5A60S2来做,晶振频率为12.000MHz,但是由于OLED12864和DS3231都是I2C协议进行通信,并且计算耗时较长,导致秒的显示不能及时更新,会有卡顿的现象,就换成了STC32G12K128来做。

用到外设有:OLED12864,DS3231,独立按键。

频率:1T@30.0000MHz。

效果查看/操作演示:B站搜索“甘腾胜”或“gantengsheng”查看。
源代码下载:B站对应视频的简介有工程文件下载链接。

一、效果展示

(1)如果是公历节日则第四行显示公历节日(如果当天有多个公历节日,则轮流显示),没公历节日则第四行显示月日时的干支。
在这里插入图片描述
在这里插入图片描述

(2)如果是节气,则星期和节气轮流显示。
在这里插入图片描述

(3)如果是农历节日,则温度和农历节日轮流显示。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

(4)如果公历节日超过8个字,主界面不显示,正常走时模式按K2切换到显示更多界面,就可以显示了。显示更多界面除了显示超过8个字的公历节日,还显示年月日时的干支
在这里插入图片描述
在这里插入图片描述

二、原理分析

1、农历日期、节气、节日、干支、星期的计算

农历日期、节气、节日(农历&公历)、干支、星期的计算跟LCD12864版本的是一样的,简单的原理分析可以看我另一篇博客:

基于51单片机和LCD12864、DS3231、独立按键的万年历可调时钟+温度显示

2、OLED12864的显示

OLED12864跟LCD12864相比,优点是省电、接线少,缺点是数据传输速率较慢,且需要自行取模,将字模数据存储在单片机的ROM空间,再自行写出驱动函数进行显示。(LCD12864模块内置有字符字模,可以轻松显示汉字和ASCII码,而OLED12864模块是没有内置字符字模)

本代码的OLED12864的驱动函数,是基于江协科技的OLED使用教程分享的代码进行修改的。江协科技分享的代码功能是很强大的,除了可以显示ASCII码(8X16和6X8的都可以)和汉字(16X16),还可以绘图(点、矩形、三角形、圆、椭圆、圆弧等,可以选择填充或者不填充)和取反(全屏或区域取反,方便做菜单),等等。

本代码只用到了汉字和ASCII码的显示函数,显示内容无需跟OLED的页对齐,可以在任意位置显示,非常方便。也正因为如此,函数的计算量较大,所以就有了前言所说的情况,用STC12C5A60S2这款单片机时,秒的显示会有卡顿的现象,改为了使用STC32G12K128,频率设置为30.000MHz,加快计算的速度。

将代码改成字体显示只能和OLED的每一页对齐,代码会简单很多,计算量也少很多。但是我觉得没必要了。用江协科技的函数显示字符有更高的自由度,方便做其他项目时能更好地自定义显示。

详细的OLED原理和使用教程,请看B站江协科技的视频:OLED显示屏模块教学

三、各模块代码

1、延时函数

h文件

#ifndef	__DELAY_H__
#define	__DELAY_H__
 
void Delay(unsigned int xms);
 
#endif

c文件

/**
  * @brief	延时函数,延时xms毫秒
  * @param	xms 延时的时间,范围:0~65535
  * @retval	无
  */
void Delay(unsigned int xms)	//1T@30.0000MHz
{
	unsigned long edata i;
	while(xms)
	{
		i=7500UL;
		while(i) i--;
		xms--;
	}
}

2、DS3231时钟芯片

h文件

#ifndef	__DS3231_H__
#define	__DS3231_H__
 
extern char Time[];
extern char Alarm[];
void DS3231_I2C_Start(void);
void DS3231_I2C_Stop(void);
void DS3231_I2C_SendByte(unsigned char Byte);
unsigned char DS3231_I2C_ReceiveByte(unsigned char AckBit);
void DS3231_WriteByte(unsigned char WordAddress,unsigned char Data);
unsigned char DS3231_ReadByte(unsigned char WordAddress);
void DS3231_SetTime(void);
void DS3231_ReadTime(void);
void DS3231_SetAlarm(void);
void DS3231_ReadAlarm(void);
void DS3231_ConvertT(void);
unsigned char DS3231_CheckBusy(void);
float DS3231_ReadT(void);

#endif

c文件

#include <STC32G.H>
#include <INTRINS.H>

#define DS3231_ADDRESS 0xD0	//DS3231的I2C地址

//DS3231引脚定义
sbit DS3231_SDA=P2^4;
sbit DS3231_SCL=P2^5;

//DS3231的时间地址:年,月,日,时,分,秒,星期
unsigned char code TimeAddress[7]={0x06,0x05,0x04,0x02,0x01,0x00,0x03,};

//DS3231的闹钟地址:A1日期/星期,A1时,A1分,A1秒,A2日期/星期,A2时,A2分
unsigned char code AlarmAddress[7]={0x0A,0x09,0x08,0x07,0x0D,0x0C,0x0B,};

//时间数组:年,月,日,时,分,秒,星期
char Time[]={25,3,12,11,23,53,3};	//时间设置的初始值

//闹钟数组:A1日期/星期,A1时,A1分,A1秒,A2日期/星期,A2时,A2分
char Alarm[]={1,6,7,0,1,6,7};	//闹钟设置的初始值

/**
  * @brief  DS3231私有延时函数
  * @param  无
  * @retval 无
  */
void DS3231_Delay(void)	//	@30.0000MHz
{
	unsigned long edata i;
	i=2UL;
	while(i){i--;}
}

/**
  * @brief  I2C开始
  * @param  无
  * @retval 无
  */
void DS3231_I2C_Start(void)
{
	DS3231_SDA=1;
	DS3231_Delay();
	DS3231_SCL=1;
	DS3231_Delay();
	DS3231_SDA=0;
	DS3231_Delay();
	DS3231_SCL=0;
	DS3231_Delay();
}

/**
  * @brief  I2C停止
  * @param  无
  * @retval 无
  */
void DS3231_I2C_Stop(void)
{
	DS3231_SDA=0;DS3231_Delay();
	DS3231_SCL=1;DS3231_Delay();
	DS3231_SDA=1;DS3231_Delay();
}

/**
  * @brief  I2C发送一个字节
  * @param  Byte 要发送的字节
  * @retval 无
  */
void DS3231_I2C_SendByte(unsigned char Byte)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		DS3231_SDA=Byte&(0x80>>i);DS3231_Delay();
		DS3231_SCL=1;DS3231_Delay();
		DS3231_SCL=0;DS3231_Delay();
	}
	DS3231_SCL=1;DS3231_Delay();	//额外一个时钟,不处理应答信号
	DS3231_SCL=0;DS3231_Delay();
}

/**
  * @brief  I2C接收一个字节
  * @param  AckBit 要发送的应答位,0为应答,1为非应答
  * @retval 接收到的一个字节数据
  */
unsigned char DS3231_I2C_ReceiveByte(unsigned char AckBit)
{
	unsigned char i,Byte=0x00;
	DS3231_SDA=1;DS3231_Delay();
	for(i=0;i<8;i++)
	{
		DS3231_SCL=1;DS3231_Delay();
		if(DS3231_SDA){Byte|=(0x80>>i);}
		DS3231_SCL=0;DS3231_Delay();
	}
	DS3231_SDA=AckBit;DS3231_Delay();	//发送应答位
	DS3231_SCL=1;DS3231_Delay();
	DS3231_SCL=0;DS3231_Delay();
	return Byte;
}

/**
  * @brief  DS3231写入一个字节
  * @param  WordAddress 要写入字节的地址
  * @param  Data 要写入的数据
  * @retval 无
  */
void DS3231_WriteByte(unsigned char WordAddress,unsigned char Data)
{
	DS3231_I2C_Start();
	DS3231_I2C_SendByte(DS3231_ADDRESS);
	DS3231_I2C_SendByte(WordAddress);
	DS3231_I2C_SendByte(Data);
	DS3231_I2C_Stop();
}

/**
  * @brief  DS3231读取一个字节
  * @param  WordAddress 要读出字节的地址
  * @retval 读出的数据
  */
unsigned char DS3231_ReadByte(unsigned char WordAddress)
{
	unsigned char Data;
	DS3231_I2C_Start();
	DS3231_I2C_SendByte(DS3231_ADDRESS);
	DS3231_I2C_SendByte(WordAddress);
	DS3231_I2C_Start();
	DS3231_I2C_SendByte(DS3231_ADDRESS|0x01);
	Data=DS3231_I2C_ReceiveByte(1);
	DS3231_I2C_Stop();
	return Data;
}

/**
  * @brief  DS3231设置时间,调用之后,Time数组的数字会被设置到DS3231中
  * @param  无
  * @retval 无
  */
void DS3231_SetTime(void)
{
	unsigned char i;
	for(i=0;i<7;i++)	//依次写入:年,月,日,时,分,秒,星期
	{
		DS3231_WriteByte(TimeAddress[i],Time[i]/10*16+Time[i]%10);	//十进制转换为BCD码
	}
}

/**
  * @brief  DS3231读取时间,调用之后,DS3231中的数据会被读取到Time数组中
  * @param  无
  * @retval 无
  */
void DS3231_ReadTime(void)
{
	unsigned char Temp,i;
	for(i=0;i<7;i++)	//依次读取:年,月,日,时,分,秒,星期
	{
		Temp=DS3231_ReadByte(TimeAddress[i]);
		Time[i]=Temp/16*10+Temp%16;	//BCD码转十进制后读取
	}
}

/**
  * @brief  DS3231设置闹钟数据
  * @param  无
  * @retval 无
  */
void DS3231_SetAlarm(void)
{
	unsigned char i;
	for(i=0;i<7;i++)	//依次写入:A1日期/星期,A1时,A1分,A1秒,A2日期/星期,A2时,A2分
	{
		DS3231_WriteByte(AlarmAddress[i],Time[i]/10*16+Time[i]%10);	//十进制转换为BCD码
	}
}

/**
  * @brief  DS3231读取闹钟数据
  * @param  无
  * @retval 无
  */
void DS3231_ReadAlarm(void)
{
	unsigned char Temp,i;
	for(i=0;i<7;i++)	//依次读取:A1日期/星期,A1时,A1分,A1秒,A2日期/星期,A2时,A2分
	{
		Temp=DS3231_ReadByte(AlarmAddress[i]);
		Alarm[i]=Temp/16*10+Temp%16;	//BCD码转十进制后读取
	}
}

/**
  * @brief  DS3231转换温度
  * @param  无
  * @retval 无
  */
void DS3231_ConvertT(void)
{
	unsigned char Data;
	Data=DS3231_ReadByte(0x0E);
	DS3231_WriteByte(0x0E,Data|0x20);
}

/**
  * @brief  DS3231检查是否已转换完温度
  * @param  无
  * @retval 无
  */
unsigned char DS3231_CheckBusy(void)
{
	unsigned char BusyState;
	BusyState=DS3231_ReadByte(0x0F);
	BusyState&=0x04;
	return BusyState;
}

/**
  * @brief  DS3231读取温度
  * @param  无
  * @retval 无
  */
float DS3231_ReadT(void)
{
	unsigned char TM,TL;
	int Temp;
	float T;
	TM=DS3231_ReadByte(0x11);
	TL=DS3231_ReadByte(0x12);
	Temp=(TM<<8)|TL;
	Temp>>=6;
	T=Temp/4.0;
	return T;
}

3、四位独立按键

h文件

#ifndef __KEYSCAN_H__
#define __KEYSCAN_H__

unsigned char Key(void);
void Key_Tick(void);

#endif

c文件

#include <STC32G.H>

sbit Key1=P3^4;
sbit Key2=P3^5;
sbit Key3=P3^6;
sbit Key4=P3^7;

unsigned char KeyNumber;

/**
  * @brief  获取独立按键键码
  * @brief  主程序中获取键码值之后键码值清零,在下一次定时器扫描按键之前再次获取键码值,一定会返回0
  * @param  无
  * @retval 按下按键的键码,范围:0~12,0表示无按键按下
  */
unsigned char Key(void)
{
	unsigned char KeyTemp=0;
	KeyTemp=KeyNumber;
	KeyNumber=0;
	return KeyTemp;
}

/**
  * @brief  按键驱动函数,在中断中调用
  * @param  无
  * @retval 无
  */
void Key_Tick(void)
{
	static unsigned char NowState,LastState;
	static unsigned int KeyCount;
	
	LastState=NowState;	//保存上一次的按键状态
	
	NowState=0;	//如果没有按键按下,则NowState为0
	//获取当前按键状态
	if(Key1==0){NowState=1;}
	if(Key2==0){NowState=2;}
	if(Key3==0){NowState=3;}
	if(Key4==0){NowState=4;}
	
	//如果上个时间点按键未按下,这个时间点按键按下,则是按下瞬间
	if(LastState==0)
	{
		switch(NowState)
		{
			case 1:KeyNumber=1;break;
			case 2:KeyNumber=2;break;
			case 3:KeyNumber=3;break;
			case 4:KeyNumber=4;break;
			default:break;
		}
	}
	
	//如果上个时间点按键按下,这个时间点按键按下,则是一直按住按键
	if(LastState && NowState)
	{
		KeyCount++;
		if(KeyCount>=15)	//按下超过300ms才被检测为长按(定时器中断函数中每隔20ms检测一次按键)
		{
			if(LastState==1 && NowState==1){KeyNumber=5;}
			if(LastState==2 && NowState==2){KeyNumber=6;}
			if(LastState==3 && NowState==3){KeyNumber=7;}
			if(LastState==4 && NowState==4){KeyNumber=8;}
		}
	}
	else
	{
		KeyCount=0;
	}
	
	//如果上个时间点按键按下,这个时间点按键未按下,则是松手瞬间
	if(NowState==0)
	{
		switch(LastState)
		{
			case 1:KeyNumber=9;break;
			case 2:KeyNumber=10;break;
			case 3:KeyNumber=11;break;
			case 4:KeyNumber=12;break;
			default:break;
		}
	}
	
}

4、农历日期、节日、干支

h文件

#ifndef __LUNARTIME__
#define __LUNARTIME__

extern unsigned char LunarYear,LunarMonth,LunarDay; //农历年月日全局变量
extern unsigned char LunarLeapMonth;  //农历闰月全局变量,无时为0
unsigned char IsLeapYear(unsigned char Year);
unsigned char GetWeek(unsigned char Year,unsigned char Month,unsigned char Day);
unsigned char GetLunarDays(unsigned char LunarYear,unsigned char LunarMonth);
unsigned char GetLunarLeapMonth(unsigned char LunarYear);
void ConvertSolarToLunar(unsigned char Year,unsigned char Month,unsigned char Day);
unsigned char IsLunarNewYear(unsigned char Year,unsigned char Month,unsigned char Day);
unsigned char GetSolarTerms(unsigned char Year,unsigned char Month,unsigned char Day);
char GetSolarTermsMonth(unsigned char Year,unsigned char Month,unsigned char Day);
unsigned char GetMonthGanZhi(char SolarTermsMonth);
unsigned int CalculateDays(unsigned char Year,unsigned char Month,unsigned char Day);

#endif

c文件

#include <STC32G.H>

extern char Time[];	//时间缓存(声明这个数组是在外部定义的)
unsigned char MonthDays[]={31,28,31,30,31,30,31,31,30,31,30,31};	//平年每个月份的天数表
unsigned int code AccumulatedDays1[]={0,31,59,90,120,151,181,212,243,273,304,334};	//平年月份累计天数表
unsigned int code AccumulatedDays2[]={0,31,60,91,121,152,182,213,244,274,305,335};	//闰年月份累计天数表
unsigned char LunarYear,LunarMonth,LunarDay; //农历年月日全局变量
unsigned char LunarLeapMonth;  //农历闰月全局变量,无时为0
//2000年各月第一天星期表(用来自动计算所设置日期的星期值)
unsigned char code Week2000[12]={6,2,3,6,1,4,6,2,5,7,3,5};

//2000~2099年农历表
//数据来源:普中开发板店家提供的例程
unsigned char code LunarCalendar[300]={
/*数据含义

每年三个字节,
第一个字节:B7~B4表示闰月月份,值为0表示无闰月,B3~B0对应农历第1~4月的大小月情况,
第二个字节:B7-B0对应农历第5~12月的大小月情况,
第三个字节:B7表示农历第13个月的大小月情况(如果无闰月,则该位无意义),B6~B5表示春节的公历月份,B4~B0表示春节的公历日期
月份对应的位为1则表示此农历月为大月(30天),为0则表示小月(29天)

以2000年和2001年的数据为例

【2001年】
将三个字节展开为二进制格式:
0100 1101 0100 1010 1011 1000
二进制格式共24位,从左到右分别为第1位到第24位
第1位到第4位(0100):表示2001年闰四月
第5位到第17位(1101 0100 1010 1):表示13个农历月的大小月情况,1为大月30天,0为小月29天
第18位到第19位(01):表示春节在公历2001年的1月
第20位到第25位(1 1000):表示春节在公历2001年的(1月)24日

【2000年】
将三个字节展开为二进制格式
0000 1100 1001 0110 0100 0101
展开为二进制格式共24位,从左到右分别为第1位到第24位
第1位到第4位(0000):表示2000年无闰月
第5位到第17位(1100 1001 0110 0):表示12个农历月的大小月情况,1为大月30天,0为小月29天
(因2000年无闰月,则使用第5位到第17位的前12位(1100 1001 0110),第13位的“0”无意义)
第18位到第19位(10):表示春节在公历2000年的2月
第20位到第25位(0 0101):表示春节在公历2000年的(2月)5日
*/

0x0C,0x96,0x45,	//2000
0x4D,0x4A,0xB8,	//2001   
0x0D,0x4A,0x4C,	//2002
0x0D,0xA5,0x41,	//2003
0x25,0xAA,0xB6,	//2004 
0x05,0x6A,0x49,	//2005
0x7A,0xAD,0xBD,	//2006
0x02,0x5D,0x52,	//2007 
0x09,0x2D,0x47,	//2008
0x5C,0x95,0xBA,	//2009
0x0A,0x95,0x4E,	//2010 
0x0B,0x4A,0x43,	//2011
0x4B,0x55,0x37,	//2012
0x0A,0xD5,0x4A,	//2013 
0x95,0x5A,0xBF,	//2014
0x04,0xBA,0x53,	//2015
0x0A,0x5B,0x48,	//2016 
0x65,0x2B,0xBC,	//2017
0x05,0x2B,0x50,	//2018
0x0A,0x93,0x45,	//2019 
0x47,0x4A,0xB9,	//2020
0x06,0xAA,0x4C,	//2021
0x0A,0xD5,0x41,	//2022 
0x24,0xDA,0xB6,	//2023
0x04,0xB6,0x4A,	//2024
0x69,0x57,0x3D,	//2025 
0x0A,0x4E,0x51,	//2026
0x0D,0x26,0x46,	//2027
0x5E,0x93,0x3A,	//2028 
0x0D,0x53,0x4D,	//2029
0x05,0xAA,0x43,	//2030
0x36,0xB5,0x37,	//2031 
0x09,0x6D,0x4B,	//2032
0xB4,0xAE,0xBF,	//2033
0x04,0xAD,0x53,	//2034 
0x0A,0x4D,0x48,	//2035
0x6D,0x25,0xBC,	//2036
0x0D,0x25,0x4F,	//2037 
0x0D,0x52,0x44,	//2038
0x5D,0xAA,0x38,	//2039
0x0B,0x5A,0x4C,	//2040 
0x05,0x6D,0x41,	//2041
0x24,0xAD,0xB6,	//2042
0x04,0x9B,0x4A,	//2043 
0x7A,0x4B,0xBE,	//2044
0x0A,0x4B,0x51,	//2045
0x0A,0xA5,0x46,	//2046 
0x5B,0x52,0xBA,	//2047
0x06,0xD2,0x4E,	//2048
0x0A,0xDA,0x42,	//2049 
0x35,0x5B,0x37,	//2050
0x09,0x37,0x4B,	//2051
0x84,0x97,0xC1,	//2052 
0x04,0x97,0x53,	//2053
0x06,0x4B,0x48,	//2054
0x66,0xA5,0x3C,	//2055 
0x0E,0xA5,0x4F,	//2056
0x06,0xB2,0x44,	//2057
0x4A,0xB6,0x38,	//2058 
0x0A,0xAE,0x4C,	//2059
0x09,0x2E,0x42,	//2060
0x3C,0x97,0x35,	//2061 
0x0C,0x96,0x49,	//2062
0x7D,0x4A,0xBD,	//2063
0x0D,0x4A,0x51,	//2064 
0x0D,0xA5,0x45,	//2065
0x55,0xAA,0xBA,	//2066
0x05,0x6A,0x4E,	//2067 
0x0A,0x6D,0x43,	//2068
0x45,0x2E,0xB7,	//2069
0x05,0x2D,0x4B,	//2070 
0x8A,0x95,0xBF,	//2071
0x0A,0x95,0x53,	//2072
0x0B,0x4A,0x47,	//2073 
0x6B,0x55,0x3B,	//2074
0x0A,0xD5,0x4F,	//2075
0x05,0x5A,0x45,	//2076
0x4A,0x5D,0x38,	//2077
0x0A,0x5B,0x4C,	//2078
0x05,0x2B,0x42,	//2079 
0x3A,0x93,0xB6,	//2080
0x06,0x93,0x49,	//2081
0x77,0x29,0xBD,	//2082 
0x06,0xAA,0x51,	//2083
0x0A,0xD5,0x46,	//2084
0x54,0xDA,0xBA,	//2085 
0x04,0xB6,0x4E,	//2086
0x0A,0x57,0x43,	//2087
0x45,0x27,0x38,	//2088 
0x0D,0x26,0x4A,	//2089
0x8E,0x93,0x3E,	//2090
0x0D,0x52,0x52,	//2091 
0x0D,0xAA,0x47,	//2092
0x66,0xB5,0x3B,	//2093
0x05,0x6D,0x4F,	//2094 
0x04,0xAE,0x45,	//2095
0x4A,0x4E,0xB9,	//2096
0x0A,0x4D,0x4C,	//2097 
0x0D,0x15,0x41,	//2098
0x2D,0x92,0xB5,	//2099 
};


//2000~2099年节气表
//数据来源:https://blog.csdn.net/qq_46041930/article/details/108653836
unsigned char code The24SolarTerms[1200]={
/*数据含义

数据为二十四节气对应年的日期表
依次从1月开始,每月用一个字节存放,用15减去高四位数据即得到第一个节气对应日期
低四位数据加上15即得到第二个节气对应日期

以2000年第1个月的数据为例:0x96:
15-9=6:1月6日为小寒
15+6=21:1月21日为大寒
以2001年第1个月的数据为例:0xA5:
15-10=5:1月5日为小寒
15+5=20: 1月20日为大寒
*/
0x96,0xB4,0xA5,0xB5,0xA6,0xA6,0x87,0x88,0x88,0x78,0x87,0x86,	//2000
0xA5,0xB3,0xA5,0xA5,0xA6,0xA6,0x88,0x88,0x88,0x78,0x87,0x87,	//2001
0xA5,0xB4,0x96,0xA5,0x96,0x96,0x88,0x88,0x78,0x78,0x87,0x87,	//2002
0x95,0xB4,0x96,0xA5,0x96,0x97,0x88,0x78,0x78,0x69,0x78,0x87,	//2003
0x96,0xB4,0xA5,0xB5,0xA6,0xA6,0x87,0x88,0x88,0x78,0x87,0x86,	//2004
0xA5,0xB3,0xA5,0xA5,0xA6,0xA6,0x88,0x88,0x88,0x78,0x87,0x87,	//2005
0xA5,0xB4,0x96,0xA5,0xA6,0x96,0x88,0x88,0x78,0x78,0x87,0x87,	//2006
0x95,0xB4,0x96,0xA5,0x96,0x97,0x88,0x78,0x78,0x69,0x78,0x87,	//2007
0x96,0xB4,0xA5,0xB5,0xA6,0xA6,0x87,0x88,0x87,0x78,0x87,0x86,	//2008
0xA5,0xB3,0xA5,0xB5,0xA6,0xA6,0x88,0x88,0x88,0x78,0x87,0x87,	//2009
0xA5,0xB4,0x96,0xA5,0xA6,0x96,0x88,0x88,0x78,0x78,0x87,0x87,	//2010
0x95,0xB4,0x96,0xA5,0x96,0x97,0x88,0x78,0x78,0x79,0x78,0x87,	//2011
0x96,0xB4,0xA5,0xB5,0xA5,0xA6,0x87,0x88,0x87,0x78,0x87,0x86,	//2012
0xA5,0xB3,0xA5,0xB5,0xA6,0xA6,0x87,0x88,0x88,0x78,0x87,0x87,	//2013
0xA5,0xB4,0x96,0xA5,0xA6,0x96,0x88,0x88,0x78,0x78,0x87,0x87,	//2014
0x95,0xB4,0x96,0xA5,0x96,0x97,0x88,0x78,0x78,0x79,0x77,0x87,	//2015
0x95,0xB4,0xA5,0xB4,0xA5,0xA6,0x87,0x88,0x87,0x78,0x87,0x86,	//2016
0xA5,0xC3,0xA5,0xB5,0xA6,0xA6,0x87,0x88,0x88,0x78,0x87,0x87,	//2017
0xA5,0xB4,0xA6,0xA5,0xA6,0x96,0x88,0x88,0x78,0x78,0x87,0x87,	//2018
0xA5,0xB4,0x96,0xA5,0x96,0x96,0x88,0x78,0x78,0x79,0x77,0x87,	//2019
0x95,0xB4,0xA5,0xB4,0xA5,0xA6,0x97,0x87,0x87,0x78,0x87,0x86,	//2020
0xA5,0xC3,0xA5,0xB5,0xA6,0xA6,0x87,0x88,0x88,0x78,0x87,0x86,	//2021
0xA5,0xB4,0xA5,0xB5,0xA6,0x96,0x88,0x88,0x88,0x78,0x87,0x87,	//2022
0xA5,0xB4,0x96,0xA5,0x96,0x96,0x88,0x78,0x78,0x79,0x77,0x87,	//2023
0x95,0xB4,0xA5,0xB4,0xA5,0xA6,0x97,0x87,0x87,0x78,0x87,0x96,	//2024
0xA5,0xC3,0xA5,0xB5,0xA6,0xA6,0x87,0x88,0x88,0x78,0x87,0x86,	//2025
0xA5,0xB3,0xA5,0xA5,0xA6,0xA6,0x88,0x88,0x88,0x78,0x87,0x87,	//2026
0xA5,0xB4,0x96,0xA5,0x96,0x96,0x88,0x78,0x78,0x78,0x87,0x87,	//2027
0x95,0xB4,0xA5,0xB4,0xA5,0xA6,0x97,0x87,0x87,0x78,0x87,0x96,	//2028
0xA5,0xC3,0xA5,0xB5,0xA6,0xA6,0x87,0x88,0x88,0x78,0x87,0x86,	//2029
0xA5,0xB3,0xA5,0xA5,0xA6,0xA6,0x88,0x88,0x88,0x78,0x87,0x87,	//2030
0xA5,0xB4,0x96,0xA5,0x96,0x96,0x88,0x78,0x78,0x78,0x87,0x87,	//2031
0x95,0xB4,0xA5,0xB4,0xA5,0xA6,0x97,0x87,0x87,0x78,0x87,0x96,	//2032
0xA5,0xC3,0xA5,0xB5,0xA6,0xA6,0x87,0x88,0x88,0x78,0x87,0x86,	//2033
0xA5,0xB3,0xA5,0xA5,0xA6,0xA6,0x88,0x88,0x88,0x78,0x87,0x87,	//2034
0xA5,0xB4,0x96,0xA5,0xA6,0x96,0x88,0x88,0x78,0x78,0x87,0x87,	//2035
0x95,0xB4,0xA5,0xB4,0xA5,0xA6,0x97,0x87,0x87,0x78,0x87,0x96,	//2036
0xA5,0xC3,0xA5,0xB5,0xA6,0xA6,0x87,0x88,0x88,0x78,0x87,0x86,	//2037
0xA5,0xB3,0xA5,0xA5,0xA6,0xA6,0x88,0x88,0x88,0x78,0x87,0x87,	//2038
0xA5,0xB4,0x96,0xA5,0xA6,0x96,0x88,0x88,0x78,0x78,0x87,0x87,	//2039
0x95,0xB4,0xA5,0xB4,0xA5,0xA6,0x97,0x87,0x87,0x78,0x87,0x96,	//2040
0xA5,0xC3,0xA5,0xB5,0xA5,0xA6,0x87,0x88,0x87,0x78,0x87,0x86,	//2041
0xA5,0xB3,0xA5,0xB5,0xA6,0xA6,0x88,0x88,0x88,0x78,0x87,0x87,	//2042
0xA5,0xB4,0x96,0xA5,0xA6,0x96,0x88,0x88,0x78,0x78,0x87,0x87,	//2043
0x95,0xB4,0xA5,0xB4,0xA5,0xA6,0x97,0x87,0x87,0x88,0x87,0x96,	//2044
0xA5,0xC3,0xA5,0xB4,0xA5,0xA6,0x87,0x88,0x87,0x78,0x87,0x86,	//2045
0xA5,0xB3,0xA5,0xB5,0xA6,0xA6,0x87,0x88,0x88,0x78,0x87,0x87,	//2046
0xA5,0xB4,0x96,0xA5,0xA6,0x96,0x88,0x88,0x78,0x78,0x87,0x87,	//2047
0x95,0xB4,0xA5,0xB4,0xA5,0xA5,0x97,0x87,0x87,0x88,0x86,0x96,	//2048
0xA4,0xC3,0xA5,0xB4,0xA5,0xA6,0x97,0x87,0x87,0x78,0x87,0x86,	//2049
0xA5,0xC3,0xA5,0xB5,0xA6,0xA6,0x87,0x88,0x88,0x78,0x87,0x87,	//2050
0xA5,0xB4,0xA5,0xA5,0xA6,0x96,0x88,0x88,0x88,0x78,0x87,0x87,	//2051
0xA5,0xB4,0xA5,0xB4,0xA5,0xA5,0x97,0x87,0x97,0x88,0x86,0x96,	//2052
0xA4,0xC3,0xA5,0xB4,0xA5,0xA6,0x97,0x87,0x87,0x78,0x87,0x86,	//2053
0xA5,0xC3,0xA5,0xB5,0xA6,0xA6,0x87,0x88,0x88,0x78,0x87,0x87,	//2054
0xA5,0xB4,0xA5,0xA5,0xA6,0xA6,0x88,0x88,0x88,0x78,0x87,0x87,	//2055
0xA5,0xB4,0xA5,0xB4,0xA5,0xA5,0x97,0x87,0x87,0x88,0x86,0x96,	//2056
0xA4,0xC3,0xA5,0xB4,0xA5,0xA6,0x97,0x87,0x87,0x78,0x87,0x96,	//2057
0xA5,0xC3,0xA5,0xB5,0xA6,0xA6,0x87,0x88,0x88,0x78,0x87,0x86,	//2058
0xA5,0xB4,0xA5,0xA5,0xA6,0xA6,0x88,0x88,0x88,0x78,0x87,0x87,	//2059
0xA5,0xB4,0xA5,0xB4,0xA5,0xA5,0x97,0x87,0x87,0x87,0x96,0x96,	//2060
0xA4,0xC3,0xA5,0xB4,0xA5,0xA6,0x97,0x87,0x87,0x78,0x87,0x96,	//2061
0xA5,0xC3,0xA5,0xB5,0xA6,0xA6,0x87,0x88,0x88,0x78,0x87,0x86,	//2062
0xA5,0xB3,0xA5,0xA5,0xA6,0xA6,0x88,0x88,0x88,0x78,0x87,0x87,	//2063
0xA5,0xB4,0xA5,0xB4,0xA5,0xA5,0x97,0x87,0x87,0x87,0x96,0x96,	//2064
0xA4,0xC3,0xA5,0xB4,0xA5,0xA6,0x97,0x87,0x87,0x78,0x87,0x96,	//2065
0xA5,0xC3,0xA5,0xB5,0xA6,0xA6,0x87,0x88,0x88,0x78,0x87,0x86,	//2066
0xA5,0xB3,0xA5,0xA5,0xA6,0xA6,0x88,0x88,0x88,0x78,0x87,0x87,	//2067
0xA5,0xB4,0xA5,0xB4,0xB5,0xA5,0x97,0x97,0x87,0x87,0x96,0x96,	//2068
0xA4,0xC3,0xA5,0xB4,0xA5,0xA6,0x97,0x87,0x87,0x78,0x87,0x96,	//2069
0xA5,0xC3,0xA5,0xB5,0xA5,0xA6,0x87,0x88,0x87,0x78,0x87,0x86,	//2070
0xA5,0xB3,0xA5,0xA5,0xA6,0xA6,0x88,0x88,0x88,0x78,0x87,0x87,	//2071
0xA5,0xB4,0xA5,0xB4,0xB5,0xA5,0x97,0x97,0x87,0x87,0x96,0x96,	//2072
0xA4,0xC3,0xA5,0xB4,0xA5,0xA6,0x97,0x87,0x87,0x88,0x87,0x96,	//2073
0xA5,0xC3,0xA5,0xB5,0xA5,0xA6,0x87,0x88,0x87,0x78,0x87,0x86,	//2074
0xA5,0xB3,0xA5,0xB5,0xA6,0xA6,0x87,0x88,0x88,0x78,0x87,0x87,	//2075
0xA5,0xB4,0xA5,0xB4,0xB5,0xA5,0x97,0x97,0x87,0x87,0x96,0x96,	//2076
0xA4,0xC3,0xA5,0xB4,0xA5,0xA6,0x97,0x87,0x87,0x88,0x87,0x96,	//2077
0xA5,0xC3,0xA5,0xB4,0xA5,0xA6,0x97,0x88,0x87,0x78,0x87,0x86,	//2078
0xA5,0xB3,0xA5,0xB5,0xA6,0xA6,0x87,0x88,0x88,0x78,0x87,0x87,	//2079
0xA5,0xB4,0xA5,0xB4,0xB5,0xA5,0x97,0x97,0x87,0x87,0x96,0x96,	//2080
0xA4,0xC3,0xA5,0xB4,0xA5,0xA5,0x97,0x87,0x87,0x88,0x86,0x96,	//2081
0xA5,0xC3,0xA5,0xB4,0xA5,0xA6,0x97,0x87,0x87,0x78,0x87,0x86,	//2082
0xA5,0xC3,0xA5,0xB5,0xA6,0xA6,0x87,0x88,0x88,0x78,0x87,0x87,	//2083
0xA5,0xB4,0xB4,0xB4,0xB5,0xA5,0x97,0x97,0x97,0x87,0x96,0x96,	//2084
0xB4,0xC3,0xA5,0xB4,0xA5,0xA5,0x97,0x87,0x87,0x88,0x86,0x96,	//2085
0xA4,0xC3,0xA5,0xB4,0xA5,0xA6,0x97,0x87,0x87,0x78,0x87,0x86,	//2086
0xA5,0xC3,0xA5,0xB5,0xA6,0xA6,0x87,0x88,0x88,0x78,0x87,0x87,	//2087
0xA5,0xB4,0xB4,0xB4,0xB5,0xB5,0x97,0x97,0x97,0x87,0x96,0x96,	//2088
0xB4,0xC3,0xA5,0xB4,0xA5,0xA5,0x97,0x87,0x87,0x88,0x86,0x96,	//2089
0xA4,0xC3,0xA5,0xB4,0xA5,0xA6,0x97,0x87,0x87,0x78,0x87,0x96,	//2090
0xA5,0xC3,0xA5,0xB5,0xA6,0xA6,0x87,0x88,0x88,0x78,0x87,0x86,	//2091
0xA5,0xB4,0xB4,0xB4,0xB5,0xB5,0x97,0x97,0x97,0x87,0x96,0x96,	//2092
0xB4,0xC3,0xA5,0xB4,0xA5,0xA5,0x97,0x87,0x87,0x87,0x96,0x96,	//2093
0xA4,0xC3,0xA5,0xB4,0xA5,0xA6,0x97,0x87,0x87,0x78,0x87,0x96,	//2094
0xA5,0xC3,0xA5,0xB5,0xA6,0xA6,0x87,0x88,0x88,0x78,0x87,0x86,	//2095
0xA5,0xB3,0xB4,0xB4,0xB5,0xB5,0x97,0x97,0x97,0x87,0x96,0x96,	//2096
0xB4,0xC3,0xA5,0xB4,0xA5,0xA5,0x97,0x97,0x87,0x87,0x96,0x96,	//2097
0xA4,0xC3,0xA5,0xB4,0xA5,0xA6,0x97,0x87,0x87,0x78,0x87,0x96,	//2098
0xA5,0xC3,0xA5,0xB5,0xA6,0xA6,0x87,0x88,0x88,0x78,0x87,0x86,	//2099	
};

/**
  * @brief  判断是否为闰年
  * @param  Year  公历年(后两位)(2000~2099),范围:0~99
  * @retval 1表示闰年,0表示平年
  */
unsigned char IsLeapYear(unsigned char Year)
{
	unsigned int Temp;
	Temp=2000+Year;
	if( ( (Temp%4)==0) && ((Temp%100)!=0) || ((Temp%400)==0) )
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

/**
  * @brief  判断某年月日(公历)为星期几
  * @param  Year  公历年(后两位)(2000~2099),范围:0~99
  * @param  Month 公历月,范围:1~12
  * @param  Day   公历日,每个月份的日期范围不一样
  * @retval 星期的数据,范围:1~7,对应周一到周日
  */
unsigned char GetWeek(unsigned char Year,unsigned char Month,unsigned char Day)
{
	unsigned char Temp;
	unsigned char m,n;
	m=Year/4;
	n=Year%4;
	if(Month<3 && n!=0){Temp=( Week2000[Month-1] -1 + 5*m+n+1+(Day-1) )%7+1;}
	else{Temp=( Week2000[Month-1] -1 + 5*m+n+(Day-1) )%7+1;}
	return Temp;
}

/**
  * @brief  获取农历某月的天数
  * @param  LunarYear 要查询的年份(农历),范围:0~99
  * @param  LunarMonth 农历的第几个月,范围:1~13
  * @retval 无
  */
unsigned char GetLunarDays(unsigned char LunarYear,unsigned char LunarMonth)
{
	unsigned char Temp;
	switch(LunarMonth)
	{
		case 1:Temp=LunarCalendar[3*LunarYear]&0x08;break;
		case 2:Temp=LunarCalendar[3*LunarYear]&0x04;break;
		case 3:Temp=LunarCalendar[3*LunarYear]&0x02;break;
		case 4:Temp=LunarCalendar[3*LunarYear]&0x01;break;
		case 5:Temp=LunarCalendar[3*LunarYear+1]&0x80;break;
		case 6:Temp=LunarCalendar[3*LunarYear+1]&0x40;break;
		case 7:Temp=LunarCalendar[3*LunarYear+1]&0x20;break;
		case 8:Temp=LunarCalendar[3*LunarYear+1]&0x10;break;
		case 9:Temp=LunarCalendar[3*LunarYear+1]&0x08;break;
		case 10:Temp=LunarCalendar[3*LunarYear+1]&0x04;break;
		case 11:Temp=LunarCalendar[3*LunarYear+1]&0x02;break;
		case 12:Temp=LunarCalendar[3*LunarYear+1]&0x01;break;
		case 13:Temp=LunarCalendar[3*LunarYear+2]&0x80;break;
		default:break;
	}
	if(Temp==0)
	{
		return 29;
	}
	else
	{
		return 30;
	}
}

/**
  * @brief  获取闰月情况
  * @param  LunarYear 要查询的年份(农历),范围:0~99
  * @retval 所闰的月份,范围:0~12,0表示无闰月
  */
unsigned char GetLunarLeapMonth(unsigned char LunarYear)
{
	unsigned char Temp;
	Temp=(LunarCalendar[3*LunarYear]&0xF0)>>4;
	return Temp;
}

/**
  * @brief  公历转农历
  * @param  Year  公历年(后两位)(2000~2099),范围:0~99
  * @param  Month 公历月,范围:1~12
  * @param  Day   公历日,每个月份的日期范围不一样
  * @retval 无
  */
void ConvertSolarToLunar(unsigned char Year,unsigned char Month,unsigned char Day)
{
	unsigned char LunarNewYearMonth,LunarNewYearDay;	//春节公历月日
	unsigned int Temp1,Temp2;	//缓存变量

	LunarNewYearMonth=(LunarCalendar[3*Year+2]&0x60)>>5;	//春节所在公历的月数
	LunarNewYearDay=LunarCalendar[3*Year+2]&0x1F;	//春节所在公历的日数

	LunarLeapMonth=GetLunarLeapMonth(Year);  //获取当年闰月情况

	if(LunarNewYearMonth==1){Temp1=LunarNewYearDay-1;}   //计算春节离当年元旦的天数
	else{Temp1=31+LunarNewYearDay-1;}

	if(IsLeapYear(Year))	//判断此年是否为闰年
	{
		Temp2=AccumulatedDays2[Month-1]+Day-1;
	}
	else
	{
		Temp2=AccumulatedDays1[Month-1]+Day-1;
	}
	
	if(Temp2>=Temp1)	//如果此月日在春节后
	{
		LunarYear=Year;
		LunarMonth=1;
		Temp2=Temp2-Temp1;	//计算此月日离春节的天数
		Temp1=GetLunarDays(Year,LunarMonth);

		while(Temp2>=Temp1)
		{
			LunarMonth++;
			Temp2=Temp2-Temp1;
			Temp1=GetLunarDays(Year,LunarMonth); //计算当月天数
		}
		
		LunarDay=Temp2+1;
	}
	else	//如果此月日在春节前
	{
		if(Year==0)	//如果是农历2000年春节前
		{	//农历表中没有农历1999年冬月和腊月的数据,这里需要特殊处理一下
			LunarYear=99;	//农历1999年
			Temp1=Temp1-Temp2;	//计算此月日离春节的天数
			LunarMonth=12;
			Temp2=29;	//农历1999年12月有29天
			if(Temp1>=Temp2)
			{
				LunarMonth=11;
				Temp1=Temp1-Temp2;
				Temp2=30;	//农历1999年11月有30天
			}
		}
		else
		{
			LunarYear=Year-1;
			Temp1=Temp1-Temp2;	//计算此月日离春节的天数
			
			LunarLeapMonth=GetLunarLeapMonth(Year-1);
			if(LunarLeapMonth==0)   //若当年没有闰月
			{
				LunarMonth=12;
			}
			else
			{
				LunarMonth=13;
			}
			
			Temp2=GetLunarDays(Year-1,LunarMonth);
			while(Temp1>=Temp2)
			{
				LunarMonth--;
				Temp1=Temp1-Temp2;
				Temp2=GetLunarDays(Year-1,LunarMonth);
			}
		}
		LunarDay=Temp2-Temp1+1;
	}
}

/**
  * @brief  判断给定的公历年月日是否是春节
  * @param  Year  公历年(后两位)(2000~2099),范围:0~99
  * @param  Month 公历月,范围:1~12
  * @param  Day   公历日,每个月份的日期范围不一样
  * @retval 1:是春节,0:不是春节
  */
unsigned char IsLunarNewYear(unsigned char Year,unsigned char Month,unsigned char Day)
{
	unsigned char LunarNewYearMonth,LunarNewYearDay;	//春节公历月日
	unsigned char Temp1,Temp2;	//缓存变量

	LunarNewYearMonth=(LunarCalendar[3*Year+2]&0x60)>>5;	//春节所在公历的月数
	LunarNewYearDay=LunarCalendar[3*Year+2]&0x1F;	//春节所在公历的日数

	if(LunarNewYearMonth==1){Temp1=LunarNewYearDay-1;}   //计算春节离当年元旦的天数
	else{Temp1=31+LunarNewYearDay-1;}

	if(Month==1){Temp2=Day-1;}   //计算给定的公历年月日离当年元旦的天数
	else if(Month==2){Temp2=31+Day-1;}
	else{Temp2=0;}

	if(Temp1==Temp2){return 1;}
	else{return 0;}
}

/**
  * @brief  判断是否是二十四节气
  * @param  Year  公历年(后两位)(2000~2099),范围:0~99
  * @param  Month 公历月,范围:1~12
  * @param  Day   公历日,每个月份的日期范围不一样
  * @retval 是不是二十四节气,不是:返回0,是:返回1~24
  * @retval  1:立春, 2:雨水, 3:惊蛰, 4:春分, 5:清明, 6:谷雨  7:立夏, 8:小满, 9:芒种,10:夏至,11:小暑,12:大暑
  * @retval 13:立秋,14:处暑,15:白露,16:秋分,17:寒露,18:霜降 19:立冬,20:小雪,21:大雪,22:冬至,23:小寒,24:大寒
  */
unsigned char GetSolarTerms(unsigned char Year,unsigned char Month,unsigned char Day)
{
	unsigned char Temp=0;
	
	if( 15-(The24SolarTerms[12*Year+(Month-1)]/16)==Day )
	{
		Temp=(23-1+2*(Month-1))%24+1;
	}
	else if( 15+(The24SolarTerms[12*Year+(Month-1)]%16)==Day )
	{
		Temp=(24-1+2*(Month-1))%24+1;
	}
	
	return Temp;
}

/**
  * @brief  获取节气月份(用节气分开成12个月)
  * @param  Year  公历年(后两位)(2000~2099),范围:0~99
  * @param  Month 公历月,范围:1~12
  * @param  Day   公历日,每个月份的日期范围不一样
  * @retval 返回-2~10,-2=子,-1=丑,0=寅,1=卯,2=辰,3=巳,4=午,5=未,6=申,7=酉,8=戌,9=亥,10=子
  * @retval 寅月:立春~惊蛰,卯月:惊蛰~清明,辰月:清明~立夏,巳月:立夏~芒种,午月:芒种~小暑,未月:小暑~立秋
  * @retval 申月:立秋~白露,酉月:白露~寒露,戌月:寒露~立冬,亥月:立冬~大雪,子月:大雪~小寒,丑月:小寒~立春
  */
char GetSolarTermsMonth(unsigned char Year,unsigned char Month,unsigned char Day)
{
	char TempMonth;
	if( Day >= 15-(The24SolarTerms[12*Year+(Month-1)]/16) )
	{
		TempMonth=Month-2;
	}
	else
	{
		TempMonth=Month-3;
	}
	return TempMonth;
}

/**
  * @brief  获取节气月份的天干地支
  * @param  SolarTermsMonth  干支月(用节气分开成12个月),范围:-2~10
  * @retval 干支信息,高四位表示天干,低四位表示地支
  * @retval 高四位范围:0~9(甲乙丙丁戊己庚辛壬癸),低四位范围:0~11(子丑寅卯辰巳午未申酉戌亥)
  */
unsigned char GetMonthGanZhi(char SolarTermsMonth)
{
	unsigned char TempGanZhi=0;
	if(SolarTermsMonth>=0)	//如果是立春或立春之后,则农历年份跟公历年份相同
	{	//((Time[0]-4+10)%10%5)*2+2为寅月天干信息
		TempGanZhi=( (((Time[0]-4+10)%10%5)*2+2+SolarTermsMonth)%10 )*16;
	}
	else	//如果是立春之前,则农历年份=公历年份-1
	{
		TempGanZhi=( (((Time[0]-4+10-1)%10%5)*2+2+SolarTermsMonth+2)%10 )*16;
	}
	TempGanZhi+=(SolarTermsMonth+2)%12;
	return TempGanZhi;
}

/**
  * @brief  计算输入日期到2000年1月1日的天数
  * @param  Year  公历年(后两位)(2000~2099),范围:0~99
  * @param  Month 公历月,范围:1~12
  * @param  Day   公历日,每个月份的日期范围不一样
  * @retval 输入日期到2000年1月1日的天数
  */
unsigned int CalculateDays(unsigned char Year,unsigned char Month,unsigned char Day)
{
	unsigned char i;
	unsigned int TempDays=0;
	for(i=0;i<Year;i++)
	{
		if(IsLeapYear(i)){TempDays+=366;}
		else{TempDays+=365;}
	}
	MonthDays[1]=28;
	if(IsLeapYear(Year)){MonthDays[1]=29;}
	for(i=0;i<Month-1;i++)
	{
		TempDays+=MonthDays[i];
	}
	TempDays+=Day-1;
	return TempDays;
}

5、OLED12864显示屏

h文件

#ifndef _OLED_H_
#define _OLED_H_

#include "OLED_Data.h"

/*参数宏定义*******/

/*FontSize参数取值*/
/*此参数值不仅用于判断,而且用于计算横向字符偏移,默认值为字体像素宽度*/
#define OLED_8X16		8
#define OLED_6X8		6

/*IsFilled参数数值*/
#define OLED_UNFILLED	0
#define OLED_FILLED		1

/*******参数宏定义*/

/*函数声明*******/

/*初始化函数*/
void OLED_Init(void);

/*更新函数*/
void OLED_Update(void);

/*显存控制函数*/
void OLED_Clear(void);
void OLED_ClearArea(int X,int Y,unsigned char Width,unsigned char Height);

/*显示函数*/
void OLED_ShowImage(int X,int Y,unsigned char Width,unsigned char Height,unsigned char *Image);
void OLED_ShowChar(int X,int Y,char Char,unsigned char FontSize);
void OLED_ShowString(int X,int Y,char *String,unsigned char FontSize);
void OLED_ShowNum(int X,int Y,unsigned long Number,unsigned char Length,unsigned char FontSize);

/*******函数声明*/

#endif

/*****************江协科技|版权所有****************/
/*****************jiangxiekeji.com*****************/

c文件

/**代码说明
  *
  *根据江协科技开源共享的代码修改
  *
  *程序名称:			0.96寸OLED显示屏驱动程序(4针脚I2C接口)
  *程序创建时间:		2023.10.24
  *当前程序版本:		V2.0
  *当前版本发布时间:	2024.10.20
  *
  *江协科技官方网站:		jiangxiekeji.com
  *江协科技官方淘宝店:	jiangxiekeji.taobao.com
  *程序介绍及更新动态:	jiangxiekeji.com/tutorial/oled.html
  *
  */

/**数据存储格式
  *
  *纵向8点,高位在下,先从左到右,再从上到下
  *每一个Bit对应一个像素点
  * 
  *     B0 B0                  B0 B0
  *     B1 B1                  B1 B1
  *     B2 B2                  B2 B2
  *     B3 B3  ------------->  B3 B3 --
  *     B4 B4                  B4 B4  |
  *     B5 B5                  B5 B5  |
  *     B6 B6                  B6 B6  |
  *     B7 B7                  B7 B7  |
  * 								  |
  * -----------------------------------
  * |   
  * |   B0 B0                  B0 B0
  * |   B1 B1                  B1 B1
  * |   B2 B2                  B2 B2
  * --> B3 B3  ------------->  B3 B3
  *     B4 B4                  B4 B4
  *     B5 B5                  B5 B5
  *     B6 B6                  B6 B6
  *     B7 B7                  B7 B7
  * 
  *坐标轴定义:
  *左上角为(0, 0)点
  *横向向右为X轴,取值范围:0~127
  *纵向向下为Y轴,取值范围:0~63
  *     
  * 	 0             X轴           127 
  *     .------------------------------->
  *   0 |
  *     |
  *     |
  *     |
  * Y轴 |
  *     |
  *     |
  *     |
  *  63 |
  *     v
  * 
  */

#include <STC32G.H>
#include "OLED.h"
#include <string.h>
#include <INTRINS.H>

/*引脚配置*******/

sbit OLED_SCL=P2^6;
sbit OLED_SDA=P2^7;

/*******引脚配置*/

/*全局变量*******/

/**
  * OLED显存数组
  * 所有的显示函数,都只是对此显存数组进行读写
  * 随后调用OLED_Update函数或OLED_UpdateArea函数
  * 才会将显存数组的数据发送到OLED硬件,进行显示
  * xdata:变量存储在片外的RAM空间
  */
unsigned char xdata OLED_DisplayBuffer[8][128];

/*******全局变量*/

/*延时函数*******/

/**
  * 函    数:OLED私有延时函数
  * 参    数:无
  * 返 回 值:无
  */
void OLED_Delay(void)	//@30.0000MHz
{
	unsigned long edata i;
	i=2UL;
	while(i){i--;}
}

/*******延时函数*/

/*通信协议*******/

/**
  * 函    数:OLED引脚初始化
  * 参    数:无
  * 返 回 值:无
  * 说    明:当上层函数需要初始化时,此函数会被调用,用户需要释放引脚
  */
void OLED_I2C_Init(void)
{
	OLED_SCL=1;
	OLED_SDA=1;
}

/**
  * 函    数:I2C起始
  * 参    数:无
  * 返 回 值:无
  */
void OLED_I2C_Start(void)
{
	OLED_SDA=1;	//释放SDA,确保SDA为高电平
	OLED_Delay();
	OLED_SCL=1;	//释放SCL,确保SCL为高电平
	OLED_Delay();
	OLED_SDA=0;	//在SCL高电平期间,拉低SDA,产生起始信号
	OLED_Delay();
	OLED_SCL=0;	//起始后把SCL也拉低,即为了占用总线,也为了方便总线时序的拼接
	OLED_Delay();
}

/**
  * 函    数:I2C终止
  * 参    数:无
  * 返 回 值:无
  */
void OLED_I2C_Stop(void)
{
	OLED_SDA=0;	//拉低SDA,确保SDA为低电平
	OLED_Delay();
	OLED_SCL=1;	//释放SCL,使SCL呈现高电平
	OLED_Delay();
	OLED_SDA=1;	//在SCL高电平期间,释放SDA,产生终止信号
	OLED_Delay();
}

/**
  * 函    数:I2C发送一个字节
  * 参    数:Byte 要发送的一个字节数据,范围:0x00~0xFF
  * 返 回 值:无
  */
void OLED_I2C_SendByte(unsigned char Byte)
{
	unsigned char i;

	/*循环8次,主机依次发送数据的每一位*/
	for(i=0;i<8;i++)
	{
		OLED_SDA=Byte&(0x80>>i);
	OLED_Delay();
		OLED_SCL=1;	//释放SCL,从机在SCL高电平期间读取SDA
	OLED_Delay();
		OLED_SCL=0;	//拉低SCL,主机开始发送下一位数据
	OLED_Delay();
	}

	OLED_SCL=1;	//额外的一个时钟,不处理应答信号
	OLED_Delay();
	OLED_SCL=0;
	OLED_Delay();
}

/**
  * 函    数:OLED写命令
  * 参    数:Command 要写入的命令值,范围:0x00~0xFF
  * 返 回 值:无
  */
void OLED_WriteCommand(unsigned char Command)
{
	OLED_I2C_Start();			//I2C起始
	OLED_I2C_SendByte(0x78);	//发送OLED的I2C从机地址
	OLED_I2C_SendByte(0x00);	//控制字节,给0x00,表示即将写命令
	OLED_I2C_SendByte(Command); //写入指定的命令
	OLED_I2C_Stop();            //I2C终止
}

/**
  * 函    数:OLED写数据
  * 参    数:Data 要写入数据的起始地址
  * 参    数:Count 要写入数据的数量
  * 返 回 值:无
  */
void OLED_WriteData(unsigned char *Data,unsigned char Count)
{
	unsigned char i;
	
	OLED_I2C_Start();				//I2C起始
	OLED_I2C_SendByte(0x78);		//发送OLED的I2C从机地址
	OLED_I2C_SendByte(0x40);		//控制字节,给0x40,表示即将写数据
	
	/*循环Count次,进行连续的数据写入*/
	for(i=0;i<Count;i++)
	{
		OLED_I2C_SendByte(Data[i]);	//依次发送Data的每一个数据
	}

	OLED_I2C_Stop();				//I2C终止
}

/*******通信协议*/

/*硬件配置*******/

/**
  * 函    数:OLED初始化
  * 参    数:无
  * 返 回 值:无
  * 说    明:使用前,需要调用此初始化函数
  */
void OLED_Init(void)
{
	unsigned char i,j;
	for(i=0;i<255;i++)
	{
		for(j=0;j<255;j++);
	}
	
	OLED_I2C_Init();			//先调用底层的端口初始化
	
	/*写入一系列的命令,对OLED进行初始化配置*/
	OLED_WriteCommand(0xAE);	//设置显示开启/关闭,0xAE关闭,0xAF开启
	
	OLED_WriteCommand(0xD5);	//设置显示时钟分频比/振荡器频率
	OLED_WriteCommand(0x80);	//0x00~0xFF
	
	OLED_WriteCommand(0xA8);	//设置多路复用率
	OLED_WriteCommand(0x3F);	//0x0E~0x3F
	
	OLED_WriteCommand(0xD3);	//设置显示偏移
	OLED_WriteCommand(0x00);	//0x00~0x7F
	
	OLED_WriteCommand(0x40);	//设置显示开始行,0x40~0x7F
	
	OLED_WriteCommand(0xA1);	//设置左右方向,0xA1正常,0xA0左右反置
	
	OLED_WriteCommand(0xC8);	//设置上下方向,0xC8正常,0xC0上下反置

	OLED_WriteCommand(0xDA);	//设置COM引脚硬件配置
	OLED_WriteCommand(0x12);
	
	OLED_WriteCommand(0x81);	//设置对比度
	OLED_WriteCommand(0xCF);	//0x00~0xFF

	OLED_WriteCommand(0xD9);	//设置预充电周期
	OLED_WriteCommand(0xF1);

	OLED_WriteCommand(0xDB);	//设置VCOMH取消选择级别
	OLED_WriteCommand(0x30);

	OLED_WriteCommand(0xA4);	//设置整个显示打开/关闭

	OLED_WriteCommand(0xA6);	//设置正常/反色显示,0xA6正常,0xA7反色

	OLED_WriteCommand(0x8D);	//设置充电泵
	OLED_WriteCommand(0x14);

	OLED_WriteCommand(0xAF);	//开启显示
	
	OLED_Clear();				//清空显存数组
	OLED_Update();				//更新显示,清屏,防止初始化后未显示内容时花屏
}

/**
  * 函    数:OLED设置显示光标位置
  * 参    数:Page 指定光标所在的页,范围:0~7
  * 参    数:X 指定光标所在的X轴坐标,范围:0~127
  * 返 回 值:无
  * 说    明:OLED默认的Y轴,只能8个Bit为一组写入,即1页等于8个Y轴坐标
  */
void OLED_SetCursor(unsigned char Page, unsigned char X)
{
	/*如果使用此程序驱动1.3寸的OLED显示屏,则需要解除此注释*/
	/*因为1.3寸的OLED驱动芯片(SH1106)有132列*/
	/*屏幕的起始列接在了第2列,而不是第0列*/
	/*所以需要将X加2,才能正常显示*/
//	X += 2;
	
	/*通过指令设置页地址和列地址*/
	OLED_WriteCommand(0xB0|Page);			//设置页位置
	OLED_WriteCommand(0x10|((X&0xF0)>>4));	//设置X位置高4位
	OLED_WriteCommand(0x00|(X&0x0F));		//设置X位置低4位
}

/*******硬件配置*/

/*工具函数*******/

/*工具函数仅供内部部分函数使用*/

/**
  * 函    数:次方函数
  * 参    数:X 底数
  * 参    数:Y 指数
  * 返 回 值:等于X的Y次方
  */
unsigned long OLED_Pow(unsigned long X,unsigned long Y)
{
	unsigned long Result=1;	//结果默认为1
	while(Y--)				//累乘Y次
	{
		Result*=X;			//每次把X累乘到结果上
	}
	return Result;
}

/*******工具函数*/

/*功能函数*******/

/**
  * 函    数:将OLED显存数组更新到OLED屏幕
  * 参    数:无
  * 返 回 值:无
  * 说    明:所有的显示函数,都只是对OLED显存数组进行读写
  *           随后调用OLED_Update函数或OLED_UpdateArea函数
  *           才会将显存数组的数据发送到OLED硬件,进行显示
  *           故调用显示函数后,要想真正地呈现在屏幕上,还需调用更新函数
  */
void OLED_Update(void)
{
	unsigned char j;
	/*遍历每一页*/
	for(j=0;j<8;j++)
	{
		/*设置光标位置为每一页的第一列*/
		OLED_SetCursor(j,0);
		/*连续写入128个数据,将显存数组的数据写入到OLED硬件*/
		OLED_WriteData(OLED_DisplayBuffer[j],128);
	}
}

/**
  * 函    数:将OLED显存数组全部清零
  * 参    数:无
  * 返 回 值:无
  * 说    明:调用此函数后,要想真正地呈现在屏幕上,还需调用更新函数
  */
void OLED_Clear(void)
{
	unsigned char i,j;
	for(j=0;j<8;j++)						//遍历8页
	{
		for(i=0;i<128;i++)					//遍历128列
		{
			OLED_DisplayBuffer[j][i]=0x00;	//将显存数组数据全部清零
		}
	}
}

/**
  * 函    数:将OLED显存数组部分清零
  * 参    数:X 指定区域左上角的横坐标,范围:-32768~32767,屏幕区域:0~127
  * 参    数:Y 指定区域左上角的纵坐标,范围:-32768~32767,屏幕区域:0~63
  * 参    数:Width 指定区域的宽度,范围:0~128
  * 参    数:Height 指定区域的高度,范围:0~64
  * 返 回 值:无
  * 说    明:调用此函数后,要想真正地呈现在屏幕上,还需调用更新函数
  */
void OLED_ClearArea(int X,int Y,unsigned char Width,unsigned char Height)
{
	int i,j;
	
	for(j=Y;j<Y+Height;j++)		//遍历指定页
	{
		for(i=X;i<X+Width;i++)	//遍历指定列
		{
			if(i>=0 && i<=127 && j>=0 && j<=63)					//超出屏幕的内容不显示
			{
				OLED_DisplayBuffer[j/8][i] &= ~(0x01<<(j%8));	//将显存数组指定数据清零
			}
		}
	}
}

/**
  * 函    数:OLED显示图像
  * 参    数:X 指定图像左上角的横坐标,范围:-32768~32767,屏幕区域:0~127
  * 参    数:Y 指定图像左上角的纵坐标,范围:-32768~32767,屏幕区域:0~63
  * 参    数:Width 指定图像的宽度,范围:0~128
  * 参    数:Height 指定图像的高度,范围:0~64
  * 参    数:Image 指定要显示的图像
  * 返 回 值:无
  * 说    明:调用此函数后,要想真正地呈现在屏幕上,还需调用更新函数
  */
void OLED_ShowImage(int X,int Y,unsigned char Width,unsigned char Height,unsigned char *Image)
{
	unsigned char i=0,j=0;
	int Page,Shift;
	
	/*将图像所在区域清空*/
	OLED_ClearArea(X,Y,Width,Height);
	
	/*遍历指定图像涉及的相关页*/
	/*(Height-1)/8+1的目的是Height/8并向上取整*/
	for(j=0;j<(Height-1)/8+1;j++)
	{
		/*遍历指定图像涉及的相关列*/
		for(i=0;i<Width;i++)
		{
			if(X+i>=0&&X+i<=127)	//超出屏幕的内容不显示
			{
				/*负数坐标在计算页地址和移位时需要加一个偏移*/
				Page=Y/8;
				Shift=Y%8;
				if(Y<0)
				{
					Page-=1;
					Shift+=8;
				}
				
				if(Page+j>=0 && Page+j<=7)		//超出屏幕的内容不显示
				{
					/*显示图像在当前页的内容*/
					OLED_DisplayBuffer[Page+j][X+i] |= Image[j*Width+i]<<(Shift);
				}
				
				if (Page+j+1>=0 && Page+j+1<=7)		//超出屏幕的内容不显示
				{					
					/*显示图像在下一页的内容*/
					OLED_DisplayBuffer[Page+j+1][X+i] |= Image[j*Width+i]>>(8-Shift);
				}
			}
		}
	}
}

/**
  * 函    数:OLED显示一个字符
  * 参    数:X 指定字符左上角的横坐标,范围:-32768~32767,屏幕区域:0~127
  * 参    数:Y 指定字符左上角的纵坐标,范围:-32768~32767,屏幕区域:0~63
  * 参    数:Char 指定要显示的字符,范围:ASCII码可见字符
  * 参    数:FontSize 指定字体大小
  *           范围:OLED_8X16		宽8像素,高16像素
  *                 OLED_6X8		宽6像素,高8像素
  * 返 回 值:无
  * 说    明:调用此函数后,要想真正地呈现在屏幕上,还需调用更新函数
  */
void OLED_ShowChar(int X,int Y,char Char,unsigned char FontSize)
{
	if(FontSize==OLED_8X16)		//字体为宽8像素,高16像素
	{
		/*将ASCII字模库OLED_F8x16的指定数据以8*16的图像格式显示*/
		OLED_ShowImage(X,Y,8,16,OLED_F8x16[Char-' ']);
	}
	else if(FontSize==OLED_6X8)	//字体为宽6像素,高8像素
	{
		/*将ASCII字模库OLED_F6x8的指定数据以6*8的图像格式显示*/
		OLED_ShowImage(X,Y,6,8,OLED_F6x8[Char-' ']);
	}
}

/**
  * 函    数:OLED显示字符串(支持ASCII码和中文混合写入)
  * 参    数:X 指定字符串左上角的横坐标,范围:-32768~32767,屏幕区域:0~127
  * 参    数:Y 指定字符串左上角的纵坐标,范围:-32768~32767,屏幕区域:0~63
  * 参    数:String 指定要显示的字符串,范围:ASCII码可见字符或中文字符组成的字符串
  * 参    数:FontSize 指定字体大小
  *           范围:OLED_8X16		宽8像素,高16像素
  *                 OLED_6X8		宽6像素,高8像素
  * 返 回 值:无
  * 说    明:显示的中文字符需要在OLED_Data.c里的OLED_CF16x16数组定义
  *           未找到指定中文字符时,会显示默认图形(一个方框,内部一个问号)
  *           当字体大小为OLED_8X16时,中文字符以16*16点阵正常显示
  *           当字体大小为OLED_6X8时,中文字符以6*8点阵显示'?'
  * 说    明:调用此函数后,要想真正地呈现在屏幕上,还需调用更新函数
  */
void OLED_ShowString(int X,int Y,char *String,unsigned char FontSize)
{
	unsigned int i=0;
	char SingleChar[5];
	unsigned char CharLength=0;
	unsigned int XOffset=0;
	unsigned int pIndex;
	
	while (String[i] != '\0')	//遍历字符串
	{

		/*此段代码的目的是,提取UTF8字符串中的一个字符,转存到SingleChar子字符串中*/
		/*判断UTF8编码第一个字节的标志位*/
		if ((String[i]&0x80)==0x00)			//第一个字节为0xxxxxxx
		{
			CharLength=1;					//字符为1字节
			SingleChar[0]=String[i++];		//将第一个字节写入SingleChar第0个位置,随后i指向下一个字节
			SingleChar[1]='\0';				//为SingleChar添加字符串结束标志位
		}
		else if ((String[i]&0xE0)==0xC0)	//第一个字节为110xxxxx
		{
			CharLength=2;					//字符为2字节
			SingleChar[0]=String[i++];		//将第一个字节写入SingleChar第0个位置,随后i指向下一个字节
			if (String[i]=='\0'){break;}	//意外情况,跳出循环,结束显示
			SingleChar[1]=String[i++];		//将第二个字节写入SingleChar第1个位置,随后i指向下一个字节
			SingleChar[2]='\0';				//为SingleChar添加字符串结束标志位
		}
		else if ((String[i]&0xF0)==0xE0)	//第一个字节为1110xxxx
		{
			CharLength=3;					//字符为3字节
			SingleChar[0]=String[i++];
			if (String[i]=='\0'){break;}
			SingleChar[1]=String[i++];
			if (String[i]=='\0'){break;}
			SingleChar[2]=String[i++];
			SingleChar[3]='\0';
		}
		else if ((String[i]&0xF8)==0xF0)	//第一个字节为11110xxx
		{
			CharLength=4;					//字符为4字节
			SingleChar[0]=String[i++];
			if (String[i]=='\0'){break;}
			SingleChar[1]=String[i++];
			if (String[i]=='\0'){break;}
			SingleChar[2]=String[i++];
			if (String[i]=='\0'){break;}
			SingleChar[3]=String[i++];
			SingleChar[4]='\0';
		}
		else
		{
			i++;	//意外情况,i指向下一个字节,忽略此字节,继续判断下一个字节
			continue;
		}
		
		/*显示上述代码提取到的SingleChar*/
		if(CharLength==1)	//如果是单字节字符
		{
			/*使用OLED_ShowChar显示此字符*/
			OLED_ShowChar(X+XOffset,Y,SingleChar[0],FontSize);
			XOffset+=FontSize;
		}
		else	//否则,即多字节字符
		{
			/*遍历整个字模库,从字模库中寻找此字符的数据*/
			/*如果找到最后一个字符(定义为空字符串),则表示字符未在字模库定义,停止寻找*/
			for(pIndex=0;strcmp(OLED_CF16x16[pIndex].Index,"")!=0;pIndex++)
			{
				/*找到匹配的字符*/
				if(strcmp(OLED_CF16x16[pIndex].Index,SingleChar)==0)
				{
					break;	//跳出循环,此时pIndex的值为指定字符的索引
				}
			}
			if(FontSize==OLED_8X16)	//给定字体为8*16点阵
			{
				/*将字模库OLED_CF16x16的指定数据以16*16的图像格式显示*/
				OLED_ShowImage(X+XOffset,Y,16,16,OLED_CF16x16[pIndex].Data);
				XOffset+=16;
			}
			else if(FontSize==OLED_6X8)	//给定字体为6*8点阵
			{
				/*空间不足,此位置显示'?'*/
				OLED_ShowChar(X+XOffset,Y,'?',OLED_6X8);
				XOffset+=OLED_6X8;
			}
		}
	}
}

/**
  * 函    数:OLED显示数字(十进制,正整数)
  * 参    数:X 指定数字左上角的横坐标,范围:-32768~32767,屏幕区域:0~127
  * 参    数:Y 指定数字左上角的纵坐标,范围:-32768~32767,屏幕区域:0~63
  * 参    数:Number 指定要显示的数字,范围:0~4294967295
  * 参    数:Length 指定数字的长度,范围:0~10
  * 参    数:FontSize 指定字体大小
  *           范围:OLED_8X16		宽8像素,高16像素
  *                 OLED_6X8		宽6像素,高8像素
  * 返 回 值:无
  * 说    明:调用此函数后,要想真正地呈现在屏幕上,还需调用更新函数
  */
void OLED_ShowNum(int X,int Y,unsigned long Number,unsigned char Length,unsigned char FontSize)
{
	unsigned char i;
	for(i=0;i<Length;i++)		//遍历数字的每一位							
	{
		/*调用OLED_ShowChar函数,依次显示每个数字*/
		/*Number / OLED_Pow(10, Length - i - 1) % 10 可以十进制提取数字的每一位*/
		/*+ '0' 可将数字转换为字符格式*/
		OLED_ShowChar(X+i*FontSize,Y,Number/OLED_Pow(10,Length-i-1)%10+'0',FontSize);
	}
}

/*******功能函数*/

6、OLED12864字模数据

h文件

#ifndef __OLED_DATA_H
#define __OLED_DATA_H

/*字模基本单元*/
typedef struct 
{
	char Index[5];			//汉字索引,空间为5字节
	unsigned char Data[32];	//字模数据
}ChineseCell;

/*ASCII字模数据声明*/
extern unsigned char code OLED_F8x16[][16];
extern unsigned char code OLED_F6x8[][6];

/*汉字字模数据声明*/
extern ChineseCell code OLED_CF16x16[];

/*图像数据声明*/
extern unsigned char code Diode[];
/*按照上面的格式,在这个位置加入新的图像数据声明*/
extern unsigned char code SheShiDu[];


#endif

/*****************江协科技|版权所有****************/
/*****************jiangxiekeji.com*****************/

c文件

//略(太多了),详看工程文件

7、定时器0

h文件

#ifndef __TIMER0_H__
#define __TIMER0_H__

void Timer0_Init(void);

#endif

c文件

#include <STC32G.H>

/**
  * @brief	定时器0初始化
  * @param  无
  * @retval 无
  */
void Timer0_Init(void)
{
	AUXR|=0x80;	//定时器时钟1T模式
	TMOD&=0xF0;	//设置定时器模式(16位不自动重载)
	TMOD|=0x01;	//设置定时器模式(16位不自动重载)
	TL0=0xA0;	//设置定时初值,定时2ms,1T@30.0000MHz
	TH0=0x15;	//设置定时初值,定时2ms,1T@30.0000MHz
	TF0=0;	//清除TF0标志
	TR0=1;	//定时器0开始计时
	ET0=1;	//打开定时器0中断允许
	EA=1;	//打开总中断
	PT0=0;	//当PT0=0时,定时器0为低优先级,当PT0=1时,定时器0为高优先级
}

/*定时器中断函数模板
void Timer0_Routine() interrupt 1	//定时器0中断函数
{
	static unsigned int T0Count;	//定义静态变量
	TL0=0xA0;	//设置定时初值,定时2ms,1T@30.0000MHz
	TH0=0x15;	//设置定时初值,定时2ms,1T@30.0000MHz
	T0Count++;
	if(T0Count>=100)
	{
		T0Count=0;
		
	}
}
*/

四、主函数

main.c

/*说明
by甘腾胜@20250313
【效果展示】可以在B站搜索“甘腾胜”或“gantengsheng”查看
【接线】编程环境:Keil C251
【Keil设置】
CPU Mode:251 native
Memory Model:Xsmall
Code Rom Size:Large
HEX Format:HEX-386
Encoding:UTF-8
【单片机】STC32G12K128
【频率】1T@30.0000MHz
【外设】OLED12864、DS3231、独立按键
【接线】
(1)独立按键:K1接P34,K2接P35,K3接P36,K4接P37
(2)DS3231:SDA接P24,SCL接P25
(3)OLED12864:SCL接P26,SDA接P27
【操作】
	K1	K2	K3	K4	
一、正常走时模式:
K1:切换为调整时间模式
K2:切换为显示更多界面(超过8个字的节日、年月日时的干支)
二、调整时间模式:
K1:切换为正常走时模式
K2:切换选择要设置的时间(年、月、日、时、分、秒)
K3:减,短按减1,长按连续减小(设置秒的时候,清零)
K4:增,短按加1,长按连续增加
三、显示更多界面:
K2:切换为调整时间模式
*/

#include <STC32G.H>
#include "Delay.h"
#include "OLED.h"
#include "DS3231.h"
#include "Timer0.h"
#include "LunarTime.h"
#include "KeyScan.h"

unsigned char KeyNum;	//存储获得的键码值
unsigned char Mode;	//时间模式,0:正常走时模式,1:设置时间模式,2:显示更多信息界面
unsigned char AllowChangeModeFlag=1;	//允许更改模式的标志,用来控制模式的切换,1:允许更改,0:不允许更改
unsigned char TimeSelect;	//设置时间时的时间选择变量,0:年,1:月,2:日,3:时,4:分,5:秒
unsigned char FlashFlag;	//设置时间时闪烁的标志,1:不显示,0:显示
unsigned int T0Count0,T0Count1,T0Count2,T0Count3,T0Count4;	//定时器计数全局变量
unsigned char ReadTimeFlag;	//读取时间的标志,1:读取,0:不读取
unsigned char ReadTempFlag;	//读取温度的标志,1:读取,0:不读取
float T;	//存储温度数据的变量
unsigned char Offset;	//Offset为偏移量,用于正常显示有闰月时闰月后面的月份
unsigned char SolarTerm;	//节气,0:不是节气,1~24:立春、雨水...大寒
unsigned char Holiday;	//公历节日,1:有节日,0:没有节日
unsigned char Festival;	//农历节日,0:没有节日,不为0则数值代表农历节日的顺序号
unsigned char LastYear;	//上一次读出的年,用来控制LCD12864最后一行的显示
unsigned char LastMonth;	//上一次读出的月,用来控制LCD12864最后一行的显示
unsigned char LastDay;	//上一次读出的日,用来控制LCD12864最后一行的显示
unsigned char LastHour;	//上一次读出的时
unsigned char LastMinute;	//上一次读出的分
unsigned char LastSecond;	//上一次读出的秒
unsigned char DateChangedFlag=1;	//日期有改变的标志,初始值为1,1:有改变,0:无改变
unsigned char TooMore;	//同一天有多个节日时,用来控制切换显示,0:表示当日只有一个节日,不为零则数值代表当月的日期
unsigned char TooLong;	//节日太长(超过八个字)时,用来控制在另一个界面显示,0:表示节日少于或等于8个字,不为零则数值代表当月的日期
unsigned char Order1;	//显示内容的序号,0:显示星期,1:显示节气
unsigned char Sum1=1;	//决定是否要显示节气,1:只显示星期,2:轮流显示星期和节气
unsigned char Order2;	//显示内容的序号,0:显示温度,1:显示农历节日
unsigned char Sum2=1;	//决定是否要显示农历节日,1:只显示温度,2:轮流显示温度和农历节日
unsigned char Order3;	//要显示内容的序号
unsigned char Sum3=1;	//第四行显示内容的总数量
unsigned char Overlap;	//节日重叠的标志,0:不重叠(如果有第X个星期X这种节日),不为零则数值表示该月重叠节日的序号
unsigned char NoOverlap;	//节日不重叠的标志,0:重叠(如果有第X个星期X这种节日),不为零则数值表示该月第X个星期X这种节日的序号
unsigned char MonthGanZhi;	//月份干支,高四位范围:0~9(甲乙丙丁戊己庚辛壬癸),低四位范围:0~11(子丑寅卯辰巳午未申酉戌亥)
unsigned int TotalDays;	//离2000年1月1日的总天数

/**
  * 函    数:检查时间,防止越界
  * 参    数:无
  * 返 回 值:无
  */
void CheckTime(void)	//时间越界判断,防止向时钟芯片写入错误数据
{
	if(Time[0]<0){Time[0]=99;}	//年越界判断,范围:0~99
	if(Time[0]>99){Time[0]=0;}
	if(Time[1]<1){Time[1]=12;}	//月越界判断,,范围:1~12
	if(Time[1]>12){Time[1]=1;}
	if(Time[1]==1 || Time[1]==3 || Time[1]==5 || Time[1]==7 || 
		Time[1]==8 || Time[1]==10 || Time[1]==12)	//日越界判断,区分大小月、闰年2月、平年2月
	{
		if(Time[2]<1){Time[2]=31;}	//大月
		if(Time[2]>31){Time[2]=1;}
	}
	else if(Time[1]==4 || Time[1]==6 || Time[1]==9 || Time[1]==11)
	{
		if(Time[2]<1){Time[2]=30;}	//小月
		if(Time[2]>30){Time[2]=1;}
	}
	else if(Time[1]==2)
	{
		if(Time[0]%4==0)	//年份范围是2000~2099,2000年是闰年
		{
			if(Time[2]<1){Time[2]=29;}	//闰年2月
			if(Time[2]>29){Time[2]=1;}
		}
		else
		{
			if(Time[2]<1){Time[2]=28;}	//平年2月
			if(Time[2]>28){Time[2]=1;}
		}
	}
	if(Time[3]<0){Time[3]=23;}	//时越界判断,范围:0~23
	if(Time[3]>23){Time[3]=0;}
	if(Time[4]<0){Time[4]=59;}	//分越界判断,范围:0~59
	if(Time[4]>59){Time[4]=0;}	
	if(Time[5]>59){Time[5]=0;}	//秒越界判断,范围:0~59
	if(Time[5]<0){Time[5]=59;}	//秒越界判断,范围:0~59
	Time[6]=GetWeek(Time[0],Time[1],Time[2]);	//根据年月日计算出星期
}


/**
  * 函    数:更新显示时间
  * 参    数:无
  * 返 回 值:无
  */
void ShowTime(void)
{
	//判断年月日是否有改变
	if(LastDay!=Time[2] || LastMonth!=Time[1] || LastYear!=Time[0]){DateChangedFlag=1;}
	LastDay=Time[2];LastMonth=Time[1];LastYear=Time[0];

	//年月日
	OLED_ShowString(0,0,"20",8);
	OLED_ShowChar(4*8,0,'-',8);
	OLED_ShowChar(7*8,0,'-',8);
	if(Mode==1 && FlashFlag==1 && TimeSelect==0){OLED_ShowString(2*8,0,"  ",8);}
	else{OLED_ShowNum(2*8,0,Time[0],2,8);}
	if(Mode==1 && FlashFlag==1 && TimeSelect==1){OLED_ShowString(5*8,0,"  ",8);}
	else{OLED_ShowNum(5*8,0,Time[1],2,8);}
	if(Mode==1 && FlashFlag==1 && TimeSelect==2){OLED_ShowString(8*8,0,"  ",8);}
	else{OLED_ShowNum(8*8,0,Time[2],2,8);}

	//时分秒
	OLED_ShowChar(2*8,16,':',8);
	OLED_ShowChar(5*8,16,':',8);
	if(Mode==1 && FlashFlag==1 && TimeSelect==3){OLED_ShowString(0,16,"  ",8);}
	else{OLED_ShowNum(0,16,Time[3],2,8);}
	if(Mode==1 && FlashFlag==1 && TimeSelect==4){OLED_ShowString(3*8,16,"  ",8);}
	else{OLED_ShowNum(3*8,16,Time[4],2,8);}
	if(Mode==1 && FlashFlag==1 && TimeSelect==5){OLED_ShowString(6*8,16,"  ",8);}
	else{OLED_ShowNum(6*8,16,Time[5],2,8);}

	if(DateChangedFlag)	//如果日期有改变
	{
		DateChangedFlag=0;

		//如果日或月或年改变,则第四行清空显示
		OLED_ShowString(0,3*16,"                ",8);

		//判断是否是二十四节气,来决定是否让星期和节气轮流显示
		SolarTerm=GetSolarTerms(Time[0],Time[1],Time[2]);
		if(SolarTerm){Sum1=2;Order1=1;T0Count4=0;}	//如果是节气,则立刻显示节气,并且定时器的计数清零
		else{Sum1=1;Order1=0;T0Count4=0;}

		//判断是否是农历节日,来决定是否让温度和农历节日轮流显示
		Festival=0;
		if(LunarLeapMonth==0 || LunarMonth<=LunarLeapMonth)
		{
			if(LunarMonth== 1 && LunarDay== 1){Festival= 1;}	//春节
			if(LunarMonth== 1 && LunarDay==15){Festival= 2;}	//元宵节
			if(LunarMonth== 2 && LunarDay== 2){Festival= 3;}	//龙抬头
			if(LunarMonth== 5 && LunarDay== 5){Festival= 4;}	//端午节
			if(LunarMonth== 7 && LunarDay== 7){Festival= 5;}	//七夕节
			if(LunarMonth== 7 && LunarDay==15){Festival= 6;}	//中元节
			if(LunarMonth== 8 && LunarDay== 5){Festival= 7;}	//中秋节
			if(LunarMonth== 9 && LunarDay== 9){Festival= 8;}	//重阳节
			if(LunarMonth==10 && LunarDay== 1){Festival= 9;}	//寒衣节
			if(LunarMonth==12 && LunarDay== 8){Festival=10;}	//腊八节
		}
		if(LunarLeapMonth!=0 && LunarMonth>LunarLeapMonth+1)
		{
			if(LunarMonth-1== 1 && LunarDay== 1){Festival= 1;}	//春节
			if(LunarMonth-1== 1 && LunarDay==15){Festival= 2;}	//元宵节
			if(LunarMonth-1== 2 && LunarDay== 2){Festival= 3;}	//龙抬头
			if(LunarMonth-1== 5 && LunarDay== 5){Festival= 4;}	//端午节
			if(LunarMonth-1== 7 && LunarDay== 7){Festival= 5;}	//七夕节
			if(LunarMonth-1== 7 && LunarDay==15){Festival= 6;}	//中元节
			if(LunarMonth-1== 8 && LunarDay==15){Festival= 7;}	//中秋节
			if(LunarMonth-1== 9 && LunarDay== 9){Festival= 8;}	//重阳节
			if(LunarMonth-1==10 && LunarDay== 1){Festival= 9;}	//寒衣节
			if(LunarMonth-1==12 && LunarDay== 8){Festival=10;}	//腊八节
		}
		if(Time[1]==1 || Time[1]==2)	//春节的时间在公历1月21日至2月20日之间变动
		{	//判断第二天是否是春节,如果是,则当天是除夕
			if(Time[2]==31)	//如果是1月31日
			{	//则判断当年2月1日时否是春节
				if(IsLunarNewYear(Time[0],2,1)){Festival=11;}	//除夕
			}
			else if(IsLunarNewYear(Time[0],Time[1],Time[2]+1)){Festival=11;}
		}
		if(Festival){Sum2=2;Order2=1;T0Count4=0;}
		else{Sum2=1;Order2=0;T0Count4=0;}

		//年干支(年的天干地支)
		if(Time[0]==0 && LunarYear==99)	//农历1999年(公历2000年2月5日前,即2000年春节之前),需要特殊处理一下
		{
			OLED_ShowString(0,2*16,"己卯",8);
		}
		else
		{
			switch(LunarYear%10)	//年干
			{
				case 4:OLED_ShowString(0,2*16,"甲",8);break;
				case 5:OLED_ShowString(0,2*16,"乙",8);break;
				case 6:OLED_ShowString(0,2*16,"丙",8);break;
				case 7:OLED_ShowString(0,2*16,"丁",8);break;
				case 8:OLED_ShowString(0,2*16,"戊",8);break;
				case 9:OLED_ShowString(0,2*16,"己",8);break;
				case 0:OLED_ShowString(0,2*16,"庚",8);break;
				case 1:OLED_ShowString(0,2*16,"辛",8);break;
				case 2:OLED_ShowString(0,2*16,"壬",8);break;
				case 3:OLED_ShowString(0,2*16,"癸",8);break;
				default:break;
			}
			switch(LunarYear%12)	//年支
			{
				case  8:OLED_ShowString(1*16,2*16,"子",8);break;
				case  9:OLED_ShowString(1*16,2*16,"丑",8);break;
				case 10:OLED_ShowString(1*16,2*16,"寅",8);break;
				case 11:OLED_ShowString(1*16,2*16,"卯",8);break;
				case  0:OLED_ShowString(1*16,2*16,"辰",8);break;
				case  1:OLED_ShowString(1*16,2*16,"巳",8);break;
				case  2:OLED_ShowString(1*16,2*16,"午",8);break;
				case  3:OLED_ShowString(1*16,2*16,"未",8);break;
				case  4:OLED_ShowString(1*16,2*16,"申",8);break;
				case  5:OLED_ShowString(1*16,2*16,"酉",8);break;
				case  6:OLED_ShowString(1*16,2*16,"戌",8);break;
				case  7:OLED_ShowString(1*16,2*16,"亥",8);break;
				default:break;
			}
		}

		//生肖
		if(Time[0]==0 && LunarYear==99)	//农历1999年,需要特殊处理一下
		{
			OLED_ShowString(2*16,2*16,"兔年",8);
		}
		else
		{
			switch(LunarYear%12)
			{
				case  8:OLED_ShowString(2*16,2*16,"鼠",8);break;
				case  9:OLED_ShowString(2*16,2*16,"牛",8);break;
				case 10:OLED_ShowString(2*16,2*16,"虎",8);break;
				case 11:OLED_ShowString(2*16,2*16,"兔",8);break;
				case  0:OLED_ShowString(2*16,2*16,"龙",8);break;
				case  1:OLED_ShowString(2*16,2*16,"蛇",8);break;
				case  2:OLED_ShowString(2*16,2*16,"马",8);break;
				case  3:OLED_ShowString(2*16,2*16,"羊",8);break;
				case  4:OLED_ShowString(2*16,2*16,"猴",8);break;
				case  5:OLED_ShowString(2*16,2*16,"鸡",8);break;
				case  6:OLED_ShowString(2*16,2*16,"狗",8);break;
				case  7:OLED_ShowString(2*16,2*16,"猪",8);break;
				default:break;
			}
			OLED_ShowString(3*16,2*16,"年",8);
		}

		//农历月
		if(LunarLeapMonth==0 || LunarMonth<=LunarLeapMonth || LunarMonth>LunarLeapMonth+1)
		{	//如果无闰月,或农历月小于闰月,或农历月大于闰月+1
			if( (LunarMonth>LunarLeapMonth+1) && (LunarLeapMonth!=0) ){Offset=1;}
			else{Offset=0;}	//Offset为偏移量,用于正常显示有闰月时闰月后面的月份
			switch(LunarMonth-Offset)
			{
				case  1:OLED_ShowString(4*16,2*16,"正",8);break;
				case  2:OLED_ShowString(4*16,2*16,"二",8);break;
				case  3:OLED_ShowString(4*16,2*16,"三",8);break;
				case  4:OLED_ShowString(4*16,2*16,"四",8);break;
				case  5:OLED_ShowString(4*16,2*16,"五",8);break;
				case  6:OLED_ShowString(4*16,2*16,"六",8);break;
				case  7:OLED_ShowString(4*16,2*16,"七",8);break;
				case  8:OLED_ShowString(4*16,2*16,"八",8);break;
				case  9:OLED_ShowString(4*16,2*16,"九",8);break;
				case 10:OLED_ShowString(4*16,2*16,"十",8);break;
				case 11:OLED_ShowString(4*16,2*16,"冬",8);break;
				case 12:OLED_ShowString(4*16,2*16,"腊",8);break;
				default:break;
			}
			OLED_ShowString(5*16,2*16,"月",8);
		}
		else	//如果是闰月
		{
			switch(LunarLeapMonth)
			{
				case  1:OLED_ShowString(4*16,2*16,"闰正",8);break;	//其实2000~2099年之间没有闰正月
				case  2:OLED_ShowString(4*16,2*16,"闰二",8);break;
				case  3:OLED_ShowString(4*16,2*16,"闰三",8);break;
				case  4:OLED_ShowString(4*16,2*16,"闰四",8);break;
				case  5:OLED_ShowString(4*16,2*16,"闰五",8);break;
				case  6:OLED_ShowString(4*16,2*16,"闰六",8);break;
				case  7:OLED_ShowString(4*16,2*16,"闰七",8);break;
				case  8:OLED_ShowString(4*16,2*16,"闰八",8);break;
				case  9:OLED_ShowString(4*16,2*16,"闰九",8);break;
				case 10:OLED_ShowString(4*16,2*16,"闰十",8);break;
				case 11:OLED_ShowString(4*16,2*16,"闰冬",8);break;
				case 12:OLED_ShowString(4*16,2*16,"闰腊",8);break;
				default:break;
			}
		}

		//农历日
		switch(LunarDay)
		{
			case  1:OLED_ShowString(6*16,2*16,"初一",8);break;
			case  2:OLED_ShowString(6*16,2*16,"初二",8);break;
			case  3:OLED_ShowString(6*16,2*16,"初三",8);break;
			case  4:OLED_ShowString(6*16,2*16,"初四",8);break;
			case  5:OLED_ShowString(6*16,2*16,"初五",8);break;
			case  6:OLED_ShowString(6*16,2*16,"初六",8);break;
			case  7:OLED_ShowString(6*16,2*16,"初七",8);break;
			case  8:OLED_ShowString(6*16,2*16,"初八",8);break;
			case  9:OLED_ShowString(6*16,2*16,"初九",8);break;
			case 10:OLED_ShowString(6*16,2*16,"初十",8);break;
			case 11:OLED_ShowString(6*16,2*16,"十一",8);break;
			case 12:OLED_ShowString(6*16,2*16,"十二",8);break;
			case 13:OLED_ShowString(6*16,2*16,"十三",8);break;
			case 14:OLED_ShowString(6*16,2*16,"十四",8);break;
			case 15:OLED_ShowString(6*16,2*16,"十五",8);break;
			case 16:OLED_ShowString(6*16,2*16,"十六",8);break;
			case 17:OLED_ShowString(6*16,2*16,"十七",8);break;
			case 18:OLED_ShowString(6*16,2*16,"十八",8);break;
			case 19:OLED_ShowString(6*16,2*16,"十九",8);break;
			case 20:OLED_ShowString(6*16,2*16,"二十",8);break;
			case 21:OLED_ShowString(6*16,2*16,"廿一",8);break;
			case 22:OLED_ShowString(6*16,2*16,"廿二",8);break;
			case 23:OLED_ShowString(6*16,2*16,"廿三",8);break;
			case 24:OLED_ShowString(6*16,2*16,"廿四",8);break;
			case 25:OLED_ShowString(6*16,2*16,"廿五",8);break;
			case 26:OLED_ShowString(6*16,2*16,"廿六",8);break;
			case 27:OLED_ShowString(6*16,2*16,"廿七",8);break;
			case 28:OLED_ShowString(6*16,2*16,"廿八",8);break;
			case 29:OLED_ShowString(6*16,2*16,"廿九",8);break;
			case 30:OLED_ShowString(6*16,2*16,"三十",8);break;
			default:break;
		}

		//公历节日
		Holiday=1;	//有节日的标志置1
		TooLong=0;	//节日汉字太多的标志清零
		Overlap=0;	//节日重叠的标志清零
		NoOverlap=0;	//节日不重叠的标志清零
		Sum3=1;Order3=0;T0Count4=0;	//重置这三个变量的值
		if(Time[1]==1)	//1月
		{
			switch(Time[2])
			{
				case  1:break;	//元旦(1月1日)
				case  5:break;	//哈尔滨国际冰雪节
				case 10:break;	//中国人民警察节
				case 21:break;	//国际拥抱日
				case 26:break;	//国际海关日
				case 27:TooLong=27;Holiday=0;break;	//缅怀大屠杀受难者国际纪念日(文字太多,在ShowMore函数中显示,即在显示更多的界面显示)
				default:Holiday=0;break;	//如果不是固定日期的节日,则Holiday为0
			}
			if((GetWeek(Time[0],1,31)%7+Time[2])==31)	//一月最后一个星期日(范围:1月25日~1月31日)
			{
				if(Holiday){Sum3++;Overlap=1;}	//国际麻风节(如果跟固定日期的节日有重叠)
				else{NoOverlap=1;}
			}
		}
		else if(Time[1]==2)	//2月
		{
			switch(Time[2])
			{
				case  2:break;	//世界湿地日
				case  4:break;	//世界抗癌症日
				case 10:break;	//国际气象节
				case 14:break;	//情人节
				case 20:break;	//世界社会公正日
				case 21:break;	//国际母语日
				default:Holiday=0;break;
			}
		}
		else if(Time[1]==3)	//3月
		{
			switch(Time[2])
			{
				case  1:Sum3=2;break;	//国际海豹日、国际民防日
				case  3:Sum3=2;break;	//全国爱耳日、世界野生动植物日
				case  5:break;	//学雷锋纪念日
				case  6:break;	//世界青光眼日
				case  7:break;	//女生节
				case  8:break;	//国际妇女节
				case 12:break;	//中国植树节
				case 15:break;	//国际消费者权益日
				case 20:Sum3=2;break;	//世界无肉日、国际幸福日
				case 21:Sum3=3;TooLong=21;break;	//世界森林日、世界睡眠日、世界儿歌日、国际消除种族歧视日
				case 22:break;	//世界水日
				case 23:break;	//世界气象日
				case 24:break;	//世界防止结核病日
				case 27:break;	//世界戏剧日
				default:Holiday=0;break;
			}
			if( ((GetWeek(Time[0],3,1)-1+3)%7+1+Time[2])==15 )	//三月第二个星期四(范围:3月8日~3月14日)
			{
				if(Holiday){Sum3++;Overlap=1;}	//世界肾脏节
				else{NoOverlap=1;}
			}
			if( ((GetWeek(Time[0],3,1)-1+5)%7+1+Time[2])==22 )	//三月第三个星期二(范围:3月15日~3月21日)
			{
				if(Holiday){Sum3++;Overlap=2;}	//世界社会工作日
				else{NoOverlap=2;}
			}
			if( ( ((GetWeek(Time[0],3,31)-1+6)%7+1)%7+Time[2] ) ==31 )	//三月最后一个星期一(范围:3月25日~3月31日)
			{	//全国中小学生安全教育日
				TooLong=33;	//文字太多,在ShowMore函数中显示(随便设一个不是21的数)
			}

		}
		else if(Time[1]==4)	//4月
		{
			switch(Time[2])
			{
				case  1:Sum3=2;break;	//愚人节、国际爱鸟日
				case  2:Sum3=2;break;	//国际儿童图书日、世界自闭症日
				case  7:break;	//世界卫生日
				case  8:TooLong=8;Holiday=0;break;	//国际珍稀动物保护日
				case 11:break;	//世界帕金森病日
				case 12:break;	//世界航天日
				case 15:break;	//国家安全教育日
				case 16:break;	//世界噪音日
				case 17:break;	//世界血友病日
				case 20:break;	//联合国中文日
				case 22:Sum3=2;break;	//世界地球日、世界法律日
				case 23:break;	//世界读书日
				case 24:break;	//中国航天日
				case 25:break;	//世界防治疟疾日
				case 26:Sum3=2;break;	//世界知识产权日、中国疟疾日
				case 28:break;
				default:Holiday=0;break;
			}
			if( ( ((GetWeek(Time[0],4,30)-1+4)%7+1)%7+Time[2] ) ==30 )	//四月最后一个星期三(范围:4月24日~4月30日)
			{
				if(Holiday){Sum3++;Overlap=1;}	//国际行政专员日
				else{NoOverlap=1;}
			}
		}
		else if(Time[1]==5)	//5月
		{
			switch(Time[2])
			{
				case  1:break;	//国际劳动节
				case  4:break;	//中国五四青年节
				case  8:break;	//世界红十字日
				case 10:break;	//中国品牌日
				case 11:break;	//防治肥胖日
				case 12:Sum3=2;break;	//国际护士节、全国防灾减灾日
				case 15:Sum3=2;break;	//国际家庭日、全国碘缺乏病日
				case 17:break;	//世界电信日
				case 18:break;	//国际博物馆日
				case 19:break;	//中国旅游日
				case 20:Sum3=2;TooLong=20;break;	//中国网络情人节、中国学生营养日、全国母乳喂养宣传日
				case 22:break;	//国际生物多样性日
				case 25:break;	//国际爱肤日
				case 30:break;	//全国科技工作者日
				case 31:break;	//世界无烟日
				default:Holiday=0;break;
			}
			if( ((GetWeek(Time[0],5,1)-1+5)%7+1+Time[2])==8 )	//五月第一个星期二(范围:5月1日~5月7日)
			{
				if(Holiday){Sum3++;Overlap=1;}	//世界防治哮喘日
				else{NoOverlap=1;}
			}
			if((GetWeek(Time[0],5,1)+Time[2]==15))	//五月第二个星期日(范围:5月8日~5月14日)
			{
				if(Holiday){Sum3++;Overlap=2;}	//母亲节
				else{NoOverlap=2;}
			}
			if((GetWeek(Time[0],5,1)+Time[2]==22))	//五月第三个星期日(范围:5月15日~5月21日)
			{
				if(Holiday){Sum3++;Overlap=3;}	//全国助残日
				else{NoOverlap=3;}
			}
		}
		else if(Time[1]==6)	//6月
		{
			switch(Time[2])
			{
				case  1:break;	//国际儿童节
				case  5:break;	//世界环境日
				case  6:break;	//全国爱眼日
				case  7:break;	//世界食品安全日
				case  9:break;	//世界认可日
				case 23:break;	//国际奥林匹克日
				case 25:break;	//全国土地日
				case 26:break;	//国际禁毒日
				default:Holiday=0;break;
			}
			if( ((GetWeek(Time[0],6,1)-1+1)%7+1+Time[2])==15 )	//六月第二个星期六(范围:6月8日~6月14日)
			{
				if(Holiday){Sum3++;Overlap=1;}	//文化和自然遗产日
				else{NoOverlap=1;}
			}
			if((GetWeek(Time[0],6,1)+Time[2]==22))	//六月第三个星期日(范围:6月15日~6月21日)
			{
				if(Holiday){Sum3++;Overlap=2;}	//父亲节
				else{NoOverlap=2;}
			}
		}
		else if(Time[1]==7)	//7月
		{
			switch(Time[2])
			{
				case  1:Sum3=2;break;	//建党节、香港回归日
				case  7:break;	//七七抗战纪念日
				case 11:Sum3=2;break;	//世界人口日、中国航海日
				case 30:break;	//国际友谊日
				default:Holiday=0;break;
			}
		}
		else if(Time[1]==8)	//8月
		{
			switch(Time[2])
			{
				case  1:break;	//建军节
				case  8:break;	//全民健身日
				case 12:break;	//国际青年节
				case 13:break;	//国际左撇子日
				case 15:Sum3=2;break;	//全国生态日、日本无条件投降日
				case 19:break;	//中国医师节
				case 25:break;	//全国残疾预防日
				case 29:break;	//全国测绘法宣传日
				default:Holiday=0;break;
			}
		}
		else if(Time[1]==9)	//9月
		{
			switch(Time[2])
			{
				case  3:TooLong=3;Holiday=0;break;	//中国人民抗日战争胜利纪念日
				case  5:break;	//中华慈善日
				case 10:break;	//教师节
				case 12:TooLong=12;Holiday=0;break;	//中国预防出生缺陷日
				case 16:break;	//国际臭氧层保护日
				case 18:break;	//九一八纪念日
				case 20:Sum3=2;break;	//全国爱牙日、公民道德宣传日
				case 21:break;	//国际和平日
				case 27:break;	//世界旅游日
				case 30:break;	//烈士纪念日
				default:Holiday=0;break;
			}
			if( ((GetWeek(Time[0],9,1)-1+1)%7+1+Time[2])==22 )	//九月第三个星期六(范围:9月15日~9月21日)
			{
				TooLong=33;	//全民国防教育日,在显示更多的界面显示
				if(Holiday){Sum3++;Overlap=1;}	//全国科普日,九月第三周双休日(周六)
				else{NoOverlap=1;}
			}
			if((GetWeek(Time[0],9,1)%7+Time[2])==22)	//九月第三周双休日(周日)(范围:9月15日~9月21日)
			{
				if(Holiday){Sum3++;Overlap=2;}	//全国科普日
				else{NoOverlap=2;}
			}
			if((GetWeek(Time[0],9,1)+Time[2])==29)	//九月第四个星期日(范围:9月22日~9月28日)
			{
				if(Holiday){Sum3++;Overlap=3;}	//国际聋人节
				else{NoOverlap=3;}
			}
			if(SolarTerm==16)	//秋分(范围:9月22日~9月24日)
			{
				TooLong=34;	//中国农民丰收节
			}
		}
		else if(Time[1]==10)	//10月
		{
			switch(Time[2])
			{
				case  1:Sum3=2;break;	//国庆节、国际音乐节
				case  4:break;	//世界动物日
				case  5:break;	//世界教师日
				case  7:break;	//国际住房日
				case  9:break;	//世界邮政日
				case 10:break;	//世界精神卫生日
				case 13:TooLong=13;break;	//世界保健日、国际减轻自然灾害日
				case 15:Sum3=2;break;	//国际盲人节、全球洗手日
				case 16:break;	//世界粮食节
				case 17:Sum3=2;break;	//世界消除贫困日、国家扶贫日
				case 24:Sum3=2;break;	//联合国日、程序员节
				case 29:break;	//世界银屑病日
				default:Holiday=0;break;
			}
			if( ((GetWeek(Time[0],10,1)-1+6)%7+1+Time[2])==8 )	//十月第一个星期一(范围:10月1日~10月7日)
			{
				if(Holiday){Sum3++;Overlap=1;}	//国际建筑日
				else{NoOverlap=1;}
			}
			if( ((GetWeek(Time[0],10,1)-1+3)%7+1+Time[2])==15 )	//十月第二个星期四(范围:10月8日~10月14日)
			{
				if(Holiday){Sum3++;Overlap=2;}	//世界视力日
				else{NoOverlap=2;}
			}
		}
		else if(Time[1]==11)	//11月
		{
			switch(Time[2])
			{
				case  1:break;	//万圣节
				case  8:break;	//中国记者日
				case  9:break;	//消防宣传日
				case 14:break;	//世界糖尿病日
				case 16:break;	//国际宽容日
				case 17:break;	//国际大学生节
				case 25:TooLong=25;Holiday=0;break;	//国际消除家庭暴力日
				default:Holiday=0;break;
			}
			if( ((GetWeek(Time[0],11,1)-1+3)%7+1+Time[2])==29 )	//十一月第四个星期四(范围:11月22日~11月28日)
			{
				if(Holiday){Sum3++;Overlap=1;}	//感恩节
				else{NoOverlap=1;}
			}
		}
		else if(Time[1]==12)	//12月
		{
			switch(Time[2])
			{
				case  1:break;	//世界艾滋病日
				case  2:break;	//全国交通安全日
				case  3:break;	//世界残疾人日
				case  4:Sum3=2;break;	//国家宪法日、全国法制宣传日
				case  5:break;	//国际志愿者日
				case  9:break;	//世界足球日
				case 13:TooLong=13;Holiday=0;break;	//南京大屠杀死难者国家公祭日
				case 20:break;	//澳门回归纪念日
				case 21:break;	//国际篮球日
				case 24:break;	//平安夜
				case 25:break;	//圣诞节
				default:Holiday=0;break;
			}
		}

		if(TooLong)	//如果节日超过8个字,则在第1行第6列显示一个“*”号,表示有当天有超过8个字的节日,正常走时模式按K2可以查看
		{
			if(Time[1]==1)
			{
				if(TooLong==27)	//缅怀大屠杀受难者国际纪念日
				{
					OLED_ShowChar(5*16,0,'*',8);
				}
			}
			else if(Time[1]==3)
			{
				if(TooLong==21)	//国际消除种族歧视日
				{
					OLED_ShowChar(5*16,0,'*',8);
				}
				if(TooLong==33)	//三月最后一个星期一(范围:3月25日~3月31日)
				{	//全国中小学生安全教育日
					OLED_ShowChar(5*16,0,'*',8);
				}
			}
			else if(Time[1]==4)
			{
				if(TooLong==8)	//国际珍稀动物保护日
				{
					OLED_ShowChar(5*16,0,'*',8);
				}
			}
			else if(Time[1]==5)
			{
				if(TooLong==20)	//全国母乳喂养宣传日
				{
					OLED_ShowChar(5*16,0,'*',8);
				}
			}
			else if(Time[1]==9)
			{
				if(TooLong==3)	//中国人民抗日战争胜利纪念日
				{
					OLED_ShowChar(5*16,0,'*',8);
				}
				if(TooLong==12)	//中国预防出生缺陷日
				{
					OLED_ShowChar(5*16,0,'*',8);
				}
				if(TooLong==33)	//全民国防教育日
				{
					OLED_ShowChar(5*16,0,'*',8);
				}
				if(TooLong==34)	//中国农民丰收节
				{
					OLED_ShowChar(5*16,0,'*',8);
				}
			}
			else if(Time[1]==10)
			{
				if(TooLong==13)	//国际减轻自然灾害日
				{
					OLED_ShowChar(5*16,0,'*',8);
				}
			}
			else if(Time[1]==11)
			{
				if(TooLong==25)	//国际消除家庭暴力日
				{
					OLED_ShowChar(5*16,0,'*',8);
				}
			}
			else if(Time[1]==12)
			{
				if(TooLong==13)	//南京大屠杀死难者国家公祭日
				{
					OLED_ShowChar(5*16,0,'*',8);
				}
			}
		}
		else	//如果没有文字超过8个字的节日,则不显示“*”号
		{
			OLED_ShowChar(5*16,0,' ',8);
		}

	}

	//星期
	if(Order1==0)
	{
		switch(Time[6])
		{
			case 1:OLED_ShowString(6*16,0,"Mon ",8);break;
			case 2:OLED_ShowString(6*16,0,"Tue ",8);break;
			case 3:OLED_ShowString(6*16,0,"Wen ",8);break;
			case 4:OLED_ShowString(6*16,0,"Thu ",8);break;
			case 5:OLED_ShowString(6*16,0,"Fri ",8);break;
			case 6:OLED_ShowString(6*16,0,"Sat ",8);break;
			case 7:OLED_ShowString(6*16,0,"Sun ",8);break;
			default:break;
		}
	}
	//二十四节气
	else if(Order1==1)
	{
		switch(SolarTerm)
		{
			case  1:OLED_ShowString(6*16,0,"立春",8);break;
			case  2:OLED_ShowString(6*16,0,"雨水",8);break;
			case  3:OLED_ShowString(6*16,0,"惊蛰",8);break;
			case  4:OLED_ShowString(6*16,0,"春分",8);break;
			case  5:OLED_ShowString(6*16,0,"清明",8);break;
			case  6:OLED_ShowString(6*16,0,"谷雨",8);break;
			case  7:OLED_ShowString(6*16,0,"立夏",8);break;
			case  8:OLED_ShowString(6*16,0,"小满",8);break;
			case  9:OLED_ShowString(6*16,0,"芒种",8);break;
			case 10:OLED_ShowString(6*16,0,"夏至",8);break;
			case 11:OLED_ShowString(6*16,0,"小暑",8);break;
			case 12:OLED_ShowString(6*16,0,"大暑",8);break;
			case 13:OLED_ShowString(6*16,0,"立秋",8);break;
			case 14:OLED_ShowString(6*16,0,"处暑",8);break;
			case 15:OLED_ShowString(6*16,0,"白露",8);break;
			case 16:OLED_ShowString(6*16,0,"秋分",8);break;
			case 17:OLED_ShowString(6*16,0,"寒露",8);break;
			case 18:OLED_ShowString(6*16,0,"霜降",8);break;
			case 19:OLED_ShowString(6*16,0,"立冬",8);break;
			case 20:OLED_ShowString(6*16,0,"小雪",8);break;
			case 21:OLED_ShowString(6*16,0,"大雪",8);break;
			case 22:OLED_ShowString(6*16,0,"冬至",8);break;
			case 23:OLED_ShowString(6*16,0,"小寒",8);break;
			case 24:OLED_ShowString(6*16,0,"大寒",8);break;
			default:break;
		}
	}

	//温度
	if(Order2==0)
	{
		if(T<0)	//如果温度小于0
		{
			OLED_ShowChar(9*8,1*16,'-',8);	//显示负号
			T=-T;	//将温度变为正数
		}
		else	//如果温度大于等于0
		{
			OLED_ShowChar(9*8,1*16,'+',8);	//显示正号
		}
		OLED_ShowNum(10*8,1*16,T,2,8);
		OLED_ShowChar(12*8,1*16,'.',8);
		OLED_ShowNum(13*8,1*16,(unsigned long)(T*10)%10,1,8);	//显示温度小数部分,显示1位小数
		OLED_ShowImage(14*8,1*16,16,16,SheShiDu);
	}
	//农历节日
	else if(Order2==1)
	{
		switch(Festival)
		{
			case  1:OLED_ShowString(4*16,1*16,"    春节",8);break;
			case  2:OLED_ShowString(4*16,1*16,"  元宵节",8);break;
			case  3:OLED_ShowString(4*16,1*16,"  龙抬头",8);break;
			case  4:OLED_ShowString(4*16,1*16,"  端午节",8);break;
			case  5:OLED_ShowString(4*16,1*16,"  七夕节",8);break;
			case  6:OLED_ShowString(4*16,1*16,"  中元节",8);break;
			case  7:OLED_ShowString(4*16,1*16,"  中秋节",8);break;
			case  8:OLED_ShowString(4*16,1*16,"  重阳节",8);break;
			case  9:OLED_ShowString(4*16,1*16,"  寒衣节",8);break;
			case 10:OLED_ShowString(4*16,1*16,"  腊八节",8);break;
			case 11:OLED_ShowString(4*16,1*16,"    除夕",8);break;
			default:break;
		}
	}

	//公历节日
	if(Order3==0)	//同一天的第一个节日
	{
		if(Time[1]==1)
		{
			switch(Time[2])
			{
				case  1:OLED_ShowString(0,3*16,"元旦",8);break;
				case  5:OLED_ShowString(0,3*16,"哈尔滨国际冰雪节",8);break;
				case 10:OLED_ShowString(0,3*16,"中国人民警察节",8);break;
				case 21:OLED_ShowString(0,3*16,"国际拥抱日",8);break;
				case 26:OLED_ShowString(0,3*16,"国际海关日      ",8);break;
				default:break;
			}
			if(NoOverlap==1)	//一月最后一个星期日(范围:1月25日~1月31日)
			{
				OLED_ShowString(0,3*16,"国际麻风节",8);
			}
		}
		else if(Time[1]==2)
		{
			switch(Time[2])
			{
				case  2:OLED_ShowString(0,3*16,"世界湿地日",8);break;
				case  4:OLED_ShowString(0,3*16,"世界抗癌症日",8);break;
				case 10:OLED_ShowString(0,3*16,"国际气象节",8);break;
				case 14:OLED_ShowString(0,3*16,"情人节",8);break;
				case 20:OLED_ShowString(0,3*16,"世界社会公正\xfd日",8);break;
				case 21:OLED_ShowString(0,3*16,"国际母语日",8);break;
				default:break;
			}
			if(Time[0]%4!=0 && Time[2]==28){OLED_ShowString(0,3*16,"国际罕见病日",8);NoOverlap=1;}
			if(Time[0]%4==0 && Time[2]==29){OLED_ShowString(0,3*16,"国际罕见病日",8);NoOverlap=1;}
		}
		else if(Time[1]==3)
		{
			switch(Time[2])
			{
				case  1:OLED_ShowString(0,3*16,"国际海豹日",8);break;
				case  3:OLED_ShowString(0,3*16,"全国爱耳日      ",8);break;
				case  5:OLED_ShowString(0,3*16,"学雷锋纪念日",8);break;
				case  6:OLED_ShowString(0,3*16,"世界青光眼日",8);break;
				case  7:OLED_ShowString(0,3*16,"女生节",8);break;
				case  8:OLED_ShowString(0,3*16,"国际妇女节      ",8);break;
				case 12:OLED_ShowString(0,3*16,"中国植树节      ",8);break;
				case 15:OLED_ShowString(0,3*16,"国际消费者权益日",8);break;
				case 20:OLED_ShowString(0,3*16,"世界无肉日      ",8);break;
				case 21:OLED_ShowString(0,3*16,"世界森林日      ",8);break;
				case 22:OLED_ShowString(0,3*16,"世界水日",8);break;
				case 23:OLED_ShowString(0,3*16,"世界气象日",8);break;
				case 24:OLED_ShowString(0,3*16,"世界防止结核病日",8);break;
				case 27:OLED_ShowString(0,3*16,"世界戏剧日",8);break;
				default:break;
			}
			if(NoOverlap==1)	//三月第二个星期四(范围:3月8日~3月14日)
			{
				OLED_ShowString(0,3*16,"世界肾脏日",8);
			}
			if(NoOverlap==2)	//三月第三个星期二(范围:3月15日~3月21日)
			{
				OLED_ShowString(0,3*16,"世界社会工作日",8);
			}
		}
		else if(Time[1]==4)
		{
			switch(Time[2])
			{
				case  1:OLED_ShowString(0,3*16,"愚人节    ",8);break;
				case  2:OLED_ShowString(0,3*16,"国际儿童图书日",8);break;
				case  7:OLED_ShowString(0,3*16,"世界卫生日",8);break;
				case 11:OLED_ShowString(0,3*16,"世界帕金森病日",8);break;
				case 12:OLED_ShowString(0,3*16,"世界航天日",8);break;
				case 15:OLED_ShowString(0,3*16,"国家安全教育\xfd日",8);break;
				case 16:OLED_ShowString(0,3*16,"世界噪音日",8);break;
				case 17:OLED_ShowString(0,3*16,"世界血友病日",8);break;
				case 20:OLED_ShowString(0,3*16,"联合国中文日",8);break;
				case 22:OLED_ShowString(0,3*16,"世界地球日",8);break;
				case 23:OLED_ShowString(0,3*16,"世界读书日",8);break;
				case 24:OLED_ShowString(0,3*16,"中国航天日      ",8);break;
				case 25:OLED_ShowString(0,3*16,"世界防治疟疾日  ",8);break;
				case 26:OLED_ShowString(0,3*16,"世界知识产权日  ",8);break;
				case 28:OLED_ShowString(0,3*16,"安全生产与健康日",8);break;
				default:break;
			}
			if(NoOverlap==1)	//四月最后一个星期三(范围:4月24日~4月30日)
			{
				OLED_ShowString(0,3*16,"国际行政专员日",8);
			}
		}
		else if(Time[1]==5)
		{
			switch(Time[2])
			{
				case  1:OLED_ShowString(0,3*16,"国际劳动节      ",8);break;
				case  4:OLED_ShowString(0,3*16,"中国五四青年节  ",8);break;
				case  8:OLED_ShowString(0,3*16,"世界红十字日    ",8);break;
				case 10:OLED_ShowString(0,3*16,"中国品牌日      ",8);break;
				case 11:OLED_ShowString(0,3*16,"防治肥胖日      ",8);break;
				case 12:OLED_ShowString(0,3*16,"国际护士节      ",8);break;
				case 15:OLED_ShowString(0,3*16,"国际家庭日      ",8);break;
				case 17:OLED_ShowString(0,3*16,"世界电信日      ",8);break;
				case 18:OLED_ShowString(0,3*16,"国际博物馆日    ",8);break;
				case 19:OLED_ShowString(0,3*16,"中国旅游日      ",8);break;
				case 20:OLED_ShowString(0,3*16,"中国网络情人节  ",8);break;
				case 22:OLED_ShowString(0,3*16,"国际生物多样性日",8);break;
				case 25:OLED_ShowString(0,3*16,"国际爱肤日",8);break;
				case 30:OLED_ShowString(0,3*16,"全国科技工作者日",8);break;
				case 31:OLED_ShowString(0,3*16,"世界无烟日",8);break;
				default:break;
			}
			if(NoOverlap==1)	//五月第一个星期二(范围:5月1日~5月7日)
			{
				OLED_ShowString(0,3*16,"世界防治哮喘日",8);
			}
			if(NoOverlap==2)	//五月第二个星期日(范围:5月8日~5月14日)
			{
				OLED_ShowString(0,3*16,"母亲节",8);
			}
			if(NoOverlap==3)	//五月第三个星期日(范围:5月15日~5月21日)
			{
				OLED_ShowString(0,3*16,"全国助残日",8);
			}
		}
		else if(Time[1]==6)
		{
			switch(Time[2])
			{
				case  1:OLED_ShowString(0,3*16,"国际儿童节",8);break;
				case  5:OLED_ShowString(0,3*16,"世界环境日",8);break;
				case  6:OLED_ShowString(0,3*16,"全国爱眼日",8);break;
				case  7:OLED_ShowString(0,3*16,"世界食品安全日",8);break;
				case  9:OLED_ShowString(0,3*16,"世界认可日      ",8);break;
				case 23:OLED_ShowString(0,3*16,"国际奥林匹克日",8);break;
				case 25:OLED_ShowString(0,3*16,"全国土地日",8);break;
				case 26:OLED_ShowString(0,3*16,"国际禁毒日",8);break;
				default:break;
			}
			if(NoOverlap==1)	//六月第二个星期六(范围:6月8日~6月14日)
			{
				OLED_ShowString(0,3*16,"文化和自然遗产日",8);
			}
			if(NoOverlap==2)	//六月第三个星期日(范围:6月15日~6月21日)
			{
				OLED_ShowString(0,3*16,"父亲节",8);
			}
		}
		else if(Time[1]==7)
		{
			switch(Time[2])
			{
				case  1:OLED_ShowString(0,3*16,"建党节    ",8);break;
				case  7:OLED_ShowString(0,3*16,"七七抗战纪念日",8);break;
				case 11:OLED_ShowString(0,3*16,"世界人口日",8);break;
				case 30:OLED_ShowString(0,3*16,"国际友谊日",8);break;
				default:break;
			}
		}
		else if(Time[1]==8)
		{
			switch(Time[2])
			{
				case  1:OLED_ShowString(0,3*16,"建军节",8);break;
				case  8:OLED_ShowString(0,3*16,"全民健身日",8);break;
				case 12:OLED_ShowString(0,3*16,"国际青年节",8);break;
				case 13:OLED_ShowString(0,3*16,"国际左撇子日",8);break;
				case 15:OLED_ShowString(0,3*16,"全国生态日      ",8);break;
				case 19:OLED_ShowString(0,3*16,"中国医师节",8);break;
				case 25:OLED_ShowString(0,3*16,"全国残疾预防日",8);break;
				case 29:OLED_ShowString(0,3*16,"全国测绘法宣传日",8);break;
				default:break;
			}
		}
		else if(Time[1]==9)
		{
			switch(Time[2])
			{
				case  5:OLED_ShowString(0,3*16,"中华慈善日",8);break;
				case 10:OLED_ShowString(0,3*16,"教师节",8);break;
				case 16:OLED_ShowString(0,3*16,"国际臭氧层保护日",8);break;
				case 18:OLED_ShowString(0,3*16,"九一八纪念日    ",8);break;
				case 20:OLED_ShowString(0,3*16,"全国爱牙日      ",8);break;
				case 21:OLED_ShowString(0,3*16,"国际和平日      ",8);break;
				case 27:OLED_ShowString(0,3*16,"世界旅游日",8);break;
				case 30:OLED_ShowString(0,3*16,"烈士纪念日",8);break;
				default:break;
			}
			if(NoOverlap==1)	//九月第三周双休日(周六)(范围:9月15日~9月21日)
			{
				OLED_ShowString(0,3*16,"全国科普日",8);
			}
			if(NoOverlap==2)	//九月第三周双休日(周日)(范围:9月15日~9月21日)
			{
				OLED_ShowString(0,3*16,"全国科普日",8);
			}
			if(NoOverlap==3)	//九月第四个星期日(范围:9月15日~9月21日)
			{
				OLED_ShowString(0,3*16,"国际聋人节",8);
			}
			if(NoOverlap==4)	//秋分(范围:9月22日~9月24日)
			{
				OLED_ShowString(0,3*16,"中国农民丰收节",8);
			}
		}
		else if(Time[1]==10)
		{
			switch(Time[2])
			{
				case  1:OLED_ShowString(0,3*16,"国庆节          ",8);break;
				case  4:OLED_ShowString(0,3*16,"世界动物日      ",8);break;
				case  5:OLED_ShowString(0,3*16,"世界教师日      ",8);break;
				case  7:OLED_ShowString(0,3*16,"国际住房日      ",8);break;
				case  9:OLED_ShowString(0,3*16,"世界邮政日      ",8);break;
				case 10:OLED_ShowString(0,3*16,"世界精神卫生日  ",8);break;
				case 13:OLED_ShowString(0,3*16,"世界保健日      ",8);break;
				case 15:OLED_ShowString(0,3*16,"国际盲人节",8);break;
				case 16:OLED_ShowString(0,3*16,"世界粮食节",8);break;
				case 17:OLED_ShowString(0,3*16,"世界消除\xfd贫困日",8);break;
				case 24:OLED_ShowString(0,3*16,"联合国日",8);break;
				case 29:OLED_ShowString(0,3*16,"世界银屑病日",8);break;
				default:break;
			}
			if(NoOverlap==1)	//十月第一个星期一(范围:10月1日~10月7日)
			{
				OLED_ShowString(0,3*16,"国际建筑日",8);
			}
			if(NoOverlap==2)	//十月第二个星期四(范围:10月8日~10月14日)
			{
				OLED_ShowString(0,3*16,"世界视力日",8);
			}
		}
		else if(Time[1]==11)
		{
			switch(Time[2])
			{
				case  1:OLED_ShowString(0,3*16,"万圣节",8);break;
				case  8:OLED_ShowString(0,3*16,"中国记者日",8);break;
				case  9:OLED_ShowString(0,3*16,"消防宣传日",8);break;
				case 14:OLED_ShowString(0,3*16,"世界糖尿病日",8);break;
				case 16:OLED_ShowString(0,3*16,"国际宽容日",8);break;
				case 17:OLED_ShowString(0,3*16,"国际大学生节",8);break;
				default:break;
			}
			if(NoOverlap==1)	//十一月第四个星期四(范围:11月22日~11月28日)
			{
				OLED_ShowString(0,3*16,"感恩节",8);
			}
		}
		else if(Time[1]==12)
		{
			switch(Time[2])
			{
				case  1:OLED_ShowString(0,3*16,"世界艾滋病日",8);break;
				case  2:OLED_ShowString(0,3*16,"全国交通安全日",8);break;
				case  3:OLED_ShowString(0,3*16,"世界残疾人日",8);break;
				case  4:OLED_ShowString(0,3*16,"国家宪法日    ",8);break;
				case  5:OLED_ShowString(0,3*16,"国际志愿者日",8);break;
				case  9:OLED_ShowString(0,3*16,"世界足球日",8);break;
				case 20:OLED_ShowString(0,3*16,"澳门回归纪念日",8);break;
				case 21:OLED_ShowString(0,3*16,"国际篮球日",8);break;
				case 24:OLED_ShowString(0,3*16,"平安夜",8);break;
				case 25:OLED_ShowString(0,3*16,"圣诞节",8);break;
				default:break;
			}
		}

	}
	else if(Order3==1)	//同一天的第二个节日
	{
		if(Time[1]==3)
		{
			switch(Time[2])
			{
				case  1:OLED_ShowString(0,3*16,"国际民防日",8);break;
				case  3:OLED_ShowString(0,3*16,"世界野生动植物日",8);break;
				case 20:OLED_ShowString(0,3*16,"国际幸福日      ",8);break;
				case 21:OLED_ShowString(0,3*16,"世界睡眠日      ",8);break;
				default:break;
			}
		}
		else if(Time[1]==4)
		{
			switch(Time[2])
			{
				case  1:OLED_ShowString(0,3*16,"国际爱鸟日",8);break;
				case  2:OLED_ShowString(0,3*16,"世界自闭症日  ",8);break;
				case 22:OLED_ShowString(0,3*16,"世界法律日",8);break;
				case 26:OLED_ShowString(0,3*16,"中国疟疾日    ",8);break;
				default:break;
			}
		}
		else if(Time[1]==5)
		{
			switch(Time[2])
			{
				case 12:OLED_ShowString(0,3*16,"全国防灾减灾日",8);break;
				case 15:OLED_ShowString(0,3*16,"全国碘缺乏病日",8);break;
				case 20:OLED_ShowString(0,3*16,"中国学生营养日",8);break;
				default:break;
			}
		}
		else if(Time[1]==7)
		{
			switch(Time[2])
			{
				case  1:OLED_ShowString(0,3*16,"香港回归日",8);break;
				case 11:OLED_ShowString(0,3*16,"中国航海日",8);break;
				default:break;
			}
		}
		else if(Time[1]==8)
		{
			switch(Time[2])
			{
				case 15:OLED_ShowString(0,3*16,"日本无条件投降日",8);break;
				default:break;
			}
		}
		else if(Time[1]==9)
		{
			switch(Time[2])
			{
				case 20:OLED_ShowString(0,3*16,"公民道德宣传日",8);break;
				default:break;
			}
		}
		else if(Time[1]==10)
		{
			switch(Time[2])
			{
				case  1:OLED_ShowString(0,3*16,"国际音乐节",8);break;
				case 15:OLED_ShowString(0,3*16,"全球洗手日",8);break;
				case 17:OLED_ShowString(0,3*16,"国家扶贫日    ",8);break;
				case 24:OLED_ShowString(0,3*16,"程序员节",8);break;
				default:break;
			}
		}
		else if(Time[1]==11)
		{
			switch(Time[2])
			{
				case  1:OLED_ShowString(0,3*16,"万圣节",8);break;
				case  8:OLED_ShowString(0,3*16,"中国记者日",8);break;
				case  9:OLED_ShowString(0,3*16,"消防宣传日",8);break;
				case 14:OLED_ShowString(0,3*16,"世界糖尿病日",8);break;
				case 16:OLED_ShowString(0,3*16,"国际宽容日",8);break;
				case 17:OLED_ShowString(0,3*16,"国际大学生节",8);break;
				default:break;
			}
		}
		else if(Time[1]==12)
		{
			switch(Time[2])
			{
				case  4:OLED_ShowString(0,3*16,"全国法制宣传日",8);break;
				default:break;
			}
		}
	}
	else if(Order3==2)	//同一天的第三个节日
	{
		if(Time[1]==3)
		{
			switch(Time[2])
			{
				case 21:OLED_ShowString(0,3*16,"世界儿歌日      ",8);break;
				default:break;
			}
		}
		else if(Time[1]==5)
		{
			switch(Time[2])
			{
				case 20:OLED_ShowString(0,3*16,"中国学生营养日",8);break;
				default:break;
			}
		}
	}
	if(Overlap)	//如果X月的X个星期X的节日与固定日期的节日有重叠
	{
		if(Time[1]==1)
		{
			if(Overlap==1 && Order3==Sum3-1){OLED_ShowString(0,3*16,"国际麻风节      ",8);}	//一月最后一个星期日(范围:1月25日~1月31日)
		}
		else if(Time[1]==3)
		{
			if(Overlap==1 && Order3==Sum3-1){OLED_ShowString(0,3*16,"世界肾脏日      ",8);}	//三月第二个星期四(范围:3月8日~3月14日)
			if(Overlap==2 && Order3==Sum3-1){OLED_ShowString(0,3*16,"世界社会工作日  ",8);}	//三月第三个星期二(范围:3月15日~3月21日)
		}

		else if(Time[1]==4)
		{
			if(Overlap==1 && Order3==Sum3-1){OLED_ShowString(0,3*16,"国际行政专员日  ",8);}	//四月最后一个星期三(范围:4月24日~4月30日)
		}
		else if(Time[1]==5)	//5月
		{
			if(Overlap==1 && Order3==Sum3-1){OLED_ShowString(0,3*16,"世界防治哮喘日  ",8);}	//五月第一个星期二(范围:5月1日~5月7日)
			if(Overlap==2 && Order3==Sum3-1){OLED_ShowString(0,3*16,"母亲节          ",8);}	//五月第二个星期日(范围:5月8日~5月14日)
			if(Overlap==3 && Order3==Sum3-1){OLED_ShowString(0,3*16,"全国助残日      ",8);}	//五月第三个星期日(范围:5月15日~5月21日)
		}
		else if(Time[1]==6)	//6月
		{
			if(Overlap==1 && Order3==Sum3-1){OLED_ShowString(0,3*16,"文化和自然遗产日",8);}	//六月第二个星期六(范围:6月8日~6月14日)
			if(Overlap==2 && Order3==Sum3-1){OLED_ShowString(0,3*16,"父亲节          ",8);}	//六月第三个星期日(范围:6月15日~6月21日)
		}
		else if(Time[1]==9)	//9月
		{
			if(Overlap==1 && Order3==Sum3-1){OLED_ShowString(0,3*16,"全国科普日      ",8);}	//九月第三个星期六(范围:9月15日~9月21日)
			if(Overlap==2 && Order3==Sum3-1){OLED_ShowString(0,3*16,"全国科普日      ",8);}	//九月第三周双休日(范围:9月15日~9月21日)
			if(Overlap==3 && Order3==Sum3-1){OLED_ShowString(0,3*16,"国际聋人节      ",8);}	//九月第四个星期日(范围:9月15日~9月21日)
		}
		else if(Time[1]==10)	//10月
		{
			if(Overlap==1 && Order3==Sum3-1){OLED_ShowString(0,3*16,"国际建筑日      ",8);}	//十月第一个星期一(范围:10月1日~10月7日)
			if(Overlap==2 && Order3==Sum3-1){OLED_ShowString(0,3*16,"世界视力日      ",8);}	//十月第二个星期四(范围:10月8日~10月14日)
		}
		else if(Time[1]==11)	//11月
		{
			if(Overlap==1 && Order3==Sum3-1){OLED_ShowString(0,3*16,"感恩节          ",8);}	//十一月第四个星期四(范围:11月22日~11月28日)
		}
	}

	//如果没有节日,第四行就显示月日时的干支
	if(Holiday==0 && NoOverlap==0)
	{
		//月干支
		MonthGanZhi=GetMonthGanZhi(GetSolarTermsMonth(Time[0],Time[1],Time[2]));
		switch(MonthGanZhi/16)	//月干
		{
			case  0:OLED_ShowString(0,3*16,"甲",8);break;
			case  1:OLED_ShowString(0,3*16,"乙",8);break;
			case  2:OLED_ShowString(0,3*16,"丙",8);break;
			case  3:OLED_ShowString(0,3*16,"丁",8);break;
			case  4:OLED_ShowString(0,3*16,"戊",8);break;
			case  5:OLED_ShowString(0,3*16,"己",8);break;
			case  6:OLED_ShowString(0,3*16,"庚",8);break;
			case  7:OLED_ShowString(0,3*16,"辛",8);break;
			case  8:OLED_ShowString(0,3*16,"壬",8);break;
			case  9:OLED_ShowString(0,3*16,"癸",8);break;
			default:break;
		}
		switch(MonthGanZhi%16)	//月支
		{
			case  0:OLED_ShowString(1*16,3*16,"子",8);break;
			case  1:OLED_ShowString(1*16,3*16,"丑",8);break;
			case  2:OLED_ShowString(1*16,3*16,"寅",8);break;
			case  3:OLED_ShowString(1*16,3*16,"卯",8);break;
			case  4:OLED_ShowString(1*16,3*16,"辰",8);break;
			case  5:OLED_ShowString(1*16,3*16,"巳",8);break;
			case  6:OLED_ShowString(1*16,3*16,"午",8);break;
			case  7:OLED_ShowString(1*16,3*16,"未",8);break;
			case  8:OLED_ShowString(1*16,3*16,"申",8);break;
			case  9:OLED_ShowString(1*16,3*16,"酉",8);break;
			case 10:OLED_ShowString(1*16,3*16,"戌",8);break;
			case 11:OLED_ShowString(1*16,3*16,"亥",8);break;
			default:break;
		}

		//日干支(2000年1月1日为戊午日,以此为基准)
		TotalDays=CalculateDays(Time[0],Time[1],Time[2]);	
		switch(TotalDays%10)	//日干
		{
			case  6:OLED_ShowString(3*16,3*16,"甲",8);break;
			case  7:OLED_ShowString(3*16,3*16,"乙",8);break;
			case  8:OLED_ShowString(3*16,3*16,"丙",8);break;
			case  9:OLED_ShowString(3*16,3*16,"丁",8);break;
			case  0:OLED_ShowString(3*16,3*16,"戊",8);break;
			case  1:OLED_ShowString(3*16,3*16,"己",8);break;
			case  2:OLED_ShowString(3*16,3*16,"庚",8);break;
			case  3:OLED_ShowString(3*16,3*16,"辛",8);break;
			case  4:OLED_ShowString(3*16,3*16,"壬",8);break;
			case  5:OLED_ShowString(3*16,3*16,"癸",8);break;
			default:break;
		}
		switch(TotalDays%12)	//日支
		{
			case  6:OLED_ShowString(4*16,3*16,"子",8);break;
			case  7:OLED_ShowString(4*16,3*16,"丑",8);break;
			case  8:OLED_ShowString(4*16,3*16,"寅",8);break;
			case  9:OLED_ShowString(4*16,3*16,"卯",8);break;
			case 10:OLED_ShowString(4*16,3*16,"辰",8);break;
			case 11:OLED_ShowString(4*16,3*16,"巳",8);break;
			case  0:OLED_ShowString(4*16,3*16,"午",8);break;
			case  1:OLED_ShowString(4*16,3*16,"未",8);break;
			case  2:OLED_ShowString(4*16,3*16,"申",8);break;
			case  3:OLED_ShowString(4*16,3*16,"酉",8);break;
			case  4:OLED_ShowString(4*16,3*16,"戌",8);break;
			case  5:OLED_ShowString(4*16,3*16,"亥",8);break;
			default:break;
		}
		//时干支
		switch((((TotalDays+Time[3]/23)%10+4)%10%5*2+(Time[3]+1)%24/2)%10)	//时干
		{// Time[3]/23:   23时后属于后一天
			case  0:OLED_ShowString(6*16,3*16,"甲",8);break;
			case  1:OLED_ShowString(6*16,3*16,"乙",8);break;
			case  2:OLED_ShowString(6*16,3*16,"丙",8);break;
			case  3:OLED_ShowString(6*16,3*16,"丁",8);break;
			case  4:OLED_ShowString(6*16,3*16,"戊",8);break;
			case  5:OLED_ShowString(6*16,3*16,"己",8);break;
			case  6:OLED_ShowString(6*16,3*16,"庚",8);break;
			case  7:OLED_ShowString(6*16,3*16,"辛",8);break;
			case  8:OLED_ShowString(6*16,3*16,"壬",8);break;
			case  9:OLED_ShowString(6*16,3*16,"癸",8);break;
			default:break;
		}
		if(Time[3]>=23 || Time[3]< 1){OLED_ShowString(7*16,3*16,"子",8);}	//时支
		if(Time[3]>= 1 && Time[3]< 3){OLED_ShowString(7*16,3*16,"丑",8);}
		if(Time[3]>= 3 && Time[3]< 5){OLED_ShowString(7*16,3*16,"寅",8);}
		if(Time[3]>= 5 && Time[3]< 7){OLED_ShowString(7*16,3*16,"卯",8);}
		if(Time[3]>= 7 && Time[3]< 9){OLED_ShowString(7*16,3*16,"辰",8);}
		if(Time[3]>= 9 && Time[3]<11){OLED_ShowString(7*16,3*16,"巳",8);}
		if(Time[3]>=11 && Time[3]<13){OLED_ShowString(7*16,3*16,"午",8);}
		if(Time[3]>=13 && Time[3]<15){OLED_ShowString(7*16,3*16,"未",8);}
		if(Time[3]>=15 && Time[3]<17){OLED_ShowString(7*16,3*16,"申",8);}
		if(Time[3]>=17 && Time[3]<19){OLED_ShowString(7*16,3*16,"酉",8);}
		if(Time[3]>=19 && Time[3]<21){OLED_ShowString(7*16,3*16,"戌",8);}
		if(Time[3]>=21 && Time[3]<23){OLED_ShowString(7*16,3*16,"亥",8);}
	}

	OLED_Update();
}

/**
  * 函    数:显示更多信息
  * 参    数:无
  * 返 回 值:无
  * 说    明:显示超过8个字的节日和年月日时的天干地支
  */
void ShowMore(void)
{
	if(TooLong)	//如果是汉字太多(超过8个汉字)的节日
	{
		if(Time[1]==1)
		{
			if(TooLong==27)	//缅怀大屠杀受难者国际纪念日
			{
				OLED_ShowString(0,0,"缅怀大屠杀受难者",8);
				OLED_ShowString(0,1*16,"国际纪念日",8);
			}
		}
		else if(Time[1]==3)
		{
			if(TooLong==21)	//国际消除种族歧视日
			{
				OLED_ShowString(0,0,"国际消除\xfd种族歧视",8);
				OLED_ShowString(0,1*16,"日",8);
			}
			if(TooLong==33)	//三月最后一个星期一(范围:3月25日~3月31日)
			{	//全国中小学生安全教育日
				OLED_ShowString(0,0,"全国中小学生安全",8);
				OLED_ShowString(0,1*16,"教育\xfd日",8);
			}
		}
		else if(Time[1]==4)
		{
			if(TooLong==8)	//国际珍稀动物保护日
			{
				OLED_ShowString(0,0,"国际珍稀动物保护",8);
				OLED_ShowString(0,1*16,"日",8);
			}
		}
		else if(Time[1]==5)
		{
			if(TooLong==20)	//全国母乳喂养宣传日
			{
				OLED_ShowString(0,0,"全国母乳喂养宣传",8);
				OLED_ShowString(0,1*16,"日",8);
			}
		}
		else if(Time[1]==9)
		{
			if(TooLong==3)	//中国人民抗日战争胜利纪念日
			{
				OLED_ShowString(0,0,"中国人民抗日战争",8);
				OLED_ShowString(0,1*16,"胜利纪念日",8);
			}
			if(TooLong==12)	//中国预防出生缺陷日
			{
				OLED_ShowString(0,0,"中国预防出生缺陷",8);
				OLED_ShowString(0,1*16,"日",8);
			}
			if(TooLong==33)	//全民国防教育日
			{
				OLED_ShowString(0,0,"全民国防教育\xfd日",8);
			}
			if(TooLong==34)	//中国农民丰收节
			{
				OLED_ShowString(0,0,"中国农民丰收节",8);
			}
		}
		else if(Time[1]==10)
		{
			if(TooLong==13)	//国际减轻自然灾害日
			{
				OLED_ShowString(0,0,"国际减轻自然灾害",8);
				OLED_ShowString(0,1*16,"日",8);
			}
		}
		else if(Time[1]==11)
		{
			if(TooLong==25)	//国际消除家庭暴力日
			{
				OLED_ShowString(0,0,"国际消除\xfd家庭暴力",8);
				OLED_ShowString(0,1*16,"日",8);
			}
		}
		else if(Time[1]==12)
		{
			if(TooLong==13)	//南京大屠杀死难者国家公祭日
			{
				OLED_ShowString(0,0,"南京大屠杀死难者",8);
				OLED_ShowString(0,1*16,"国家公祭日",8);
			}
		}
	}

	//年干支
	if(Time[0]==0 && LunarYear==99)	//农历1999年(公历2000年2月5日前,即2000年春节之前),需要特殊处理一下
	{
		OLED_ShowString(0,2*16,"己卯",8);
	}
	else
	{
		switch(LunarYear%10)	//年干
		{
			case 4:OLED_ShowString(0,2*16,"甲",8);break;	//甲
			case 5:OLED_ShowString(0,2*16,"乙",8);break;	//乙
			case 6:OLED_ShowString(0,2*16,"丙",8);break;	//丙
			case 7:OLED_ShowString(0,2*16,"丁",8);break;	//丁
			case 8:OLED_ShowString(0,2*16,"戊",8);break;	//戊
			case 9:OLED_ShowString(0,2*16,"己",8);break;	//己
			case 0:OLED_ShowString(0,2*16,"庚",8);break;	//庚
			case 1:OLED_ShowString(0,2*16,"辛",8);break;	//辛
			case 2:OLED_ShowString(0,2*16,"壬",8);break;	//壬
			case 3:OLED_ShowString(0,2*16,"癸",8);break;	//癸
			default:break;
		}
		switch(LunarYear%12)	//年支
		{
			case  8:OLED_ShowString(1*16,2*16,"子",8);break;
			case  9:OLED_ShowString(1*16,2*16,"丑",8);break;
			case 10:OLED_ShowString(1*16,2*16,"寅",8);break;
			case 11:OLED_ShowString(1*16,2*16,"卯",8);break;
			case  0:OLED_ShowString(1*16,2*16,"辰",8);break;
			case  1:OLED_ShowString(1*16,2*16,"巳",8);break;
			case  2:OLED_ShowString(1*16,2*16,"午",8);break;
			case  3:OLED_ShowString(1*16,2*16,"未",8);break;
			case  4:OLED_ShowString(1*16,2*16,"申",8);break;
			case  5:OLED_ShowString(1*16,2*16,"酉",8);break;
			case  6:OLED_ShowString(1*16,2*16,"戌",8);break;
			case  7:OLED_ShowString(1*16,2*16,"亥",8);break;
			default:break;
		}
	}
	OLED_ShowString(2*16,2*16,"年",8);
	//月干支
	MonthGanZhi=GetMonthGanZhi(GetSolarTermsMonth(Time[0],Time[1],Time[2]));
	switch(MonthGanZhi/16)	//月干
	{
		case  0:OLED_ShowString(4*16,2*16,"甲",8);break;
		case  1:OLED_ShowString(4*16,2*16,"乙",8);break;
		case  2:OLED_ShowString(4*16,2*16,"丙",8);break;
		case  3:OLED_ShowString(4*16,2*16,"丁",8);break;
		case  4:OLED_ShowString(4*16,2*16,"戊",8);break;
		case  5:OLED_ShowString(4*16,2*16,"己",8);break;
		case  6:OLED_ShowString(4*16,2*16,"庚",8);break;
		case  7:OLED_ShowString(4*16,2*16,"辛",8);break;
		case  8:OLED_ShowString(4*16,2*16,"壬",8);break;
		case  9:OLED_ShowString(4*16,2*16,"癸",8);break;
		default:break;
	}
	switch(MonthGanZhi%16)	//月支
	{
		case  0:OLED_ShowString(5*16,2*16,"子",8);break;
		case  1:OLED_ShowString(5*16,2*16,"丑",8);break;
		case  2:OLED_ShowString(5*16,2*16,"寅",8);break;
		case  3:OLED_ShowString(5*16,2*16,"卯",8);break;
		case  4:OLED_ShowString(5*16,2*16,"辰",8);break;
		case  5:OLED_ShowString(5*16,2*16,"巳",8);break;
		case  6:OLED_ShowString(5*16,2*16,"午",8);break;
		case  7:OLED_ShowString(5*16,2*16,"未",8);break;
		case  8:OLED_ShowString(5*16,2*16,"申",8);break;
		case  9:OLED_ShowString(5*16,2*16,"酉",8);break;
		case 10:OLED_ShowString(5*16,2*16,"戌",8);break;
		case 11:OLED_ShowString(5*16,2*16,"亥",8);break;
		default:break;
	}
	OLED_ShowString(6*16,2*16,"月",8);
	//日干支(2000年1月1日为戊午日,以此为基准)
	TotalDays=CalculateDays(Time[0],Time[1],Time[2]);	
	switch(TotalDays%10)	//日干
	{
		case  6:OLED_ShowString(0,3*16,"甲",8);break;
		case  7:OLED_ShowString(0,3*16,"乙",8);break;
		case  8:OLED_ShowString(0,3*16,"丙",8);break;
		case  9:OLED_ShowString(0,3*16,"丁",8);break;
		case  0:OLED_ShowString(0,3*16,"戊",8);break;
		case  1:OLED_ShowString(0,3*16,"己",8);break;
		case  2:OLED_ShowString(0,3*16,"庚",8);break;
		case  3:OLED_ShowString(0,3*16,"辛",8);break;
		case  4:OLED_ShowString(0,3*16,"壬",8);break;
		case  5:OLED_ShowString(0,3*16,"癸",8);break;
		default:break;
	}
	switch(TotalDays%12)	//日支
	{
		case  6:OLED_ShowString(1*16,3*16,"子",8);break;
		case  7:OLED_ShowString(1*16,3*16,"丑",8);break;
		case  8:OLED_ShowString(1*16,3*16,"寅",8);break;
		case  9:OLED_ShowString(1*16,3*16,"卯",8);break;
		case 10:OLED_ShowString(1*16,3*16,"辰",8);break;
		case 11:OLED_ShowString(1*16,3*16,"巳",8);break;
		case  0:OLED_ShowString(1*16,3*16,"午",8);break;
		case  1:OLED_ShowString(1*16,3*16,"未",8);break;
		case  2:OLED_ShowString(1*16,3*16,"申",8);break;
		case  3:OLED_ShowString(1*16,3*16,"酉",8);break;
		case  4:OLED_ShowString(1*16,3*16,"戌",8);break;
		case  5:OLED_ShowString(1*16,3*16,"亥",8);break;
		default:break;
	}
	OLED_ShowString(2*16,3*16,"日",8);

	//时干支
	switch((((TotalDays+Time[3]/23)%10+4)%10%5*2+(Time[3]+1)%24/2)%10)	//时干
	{//Time[3]/23:23时后属于后一天
		case  0:OLED_ShowString(4*16,3*16,"甲",8);break;
		case  1:OLED_ShowString(4*16,3*16,"乙",8);break;
		case  2:OLED_ShowString(4*16,3*16,"丙",8);break;
		case  3:OLED_ShowString(4*16,3*16,"丁",8);break;
		case  4:OLED_ShowString(4*16,3*16,"戊",8);break;
		case  5:OLED_ShowString(4*16,3*16,"己",8);break;
		case  6:OLED_ShowString(4*16,3*16,"庚",8);break;
		case  7:OLED_ShowString(4*16,3*16,"辛",8);break;
		case  8:OLED_ShowString(4*16,3*16,"壬",8);break;
		case  9:OLED_ShowString(4*16,3*16,"癸",8);break;
		default:break;
	}
	if(Time[3]>=23 || Time[3]< 1){OLED_ShowString(5*16,3*16,"子",8);}	//时支
	if(Time[3]>= 1 && Time[3]< 3){OLED_ShowString(5*16,3*16,"丑",8);}
	if(Time[3]>= 3 && Time[3]< 5){OLED_ShowString(5*16,3*16,"寅",8);}
	if(Time[3]>= 5 && Time[3]< 7){OLED_ShowString(5*16,3*16,"卯",8);}
	if(Time[3]>= 7 && Time[3]< 9){OLED_ShowString(5*16,3*16,"辰",8);}
	if(Time[3]>= 9 && Time[3]<11){OLED_ShowString(5*16,3*16,"巳",8);}
	if(Time[3]>=11 && Time[3]<13){OLED_ShowString(5*16,3*16,"午",8);}
	if(Time[3]>=13 && Time[3]<15){OLED_ShowString(5*16,3*16,"未",8);}
	if(Time[3]>=15 && Time[3]<17){OLED_ShowString(5*16,3*16,"申",8);}
	if(Time[3]>=17 && Time[3]<19){OLED_ShowString(5*16,3*16,"酉",8);}
	if(Time[3]>=19 && Time[3]<21){OLED_ShowString(5*16,3*16,"戌",8);}
	if(Time[3]>=21 && Time[3]<23){OLED_ShowString(5*16,3*16,"亥",8);}
	OLED_ShowString(6*16,3*16,"时",8);

	OLED_Update();
}

/**
  * 函    数:IO口初始化,全部设置为上拉模式
  * 参    数:无
  * 返 回 值:无
  */
void GPIO_Init(void)
{
	P0M1=0;P0M0=0;
	P1M1=0;P1M0=0;
	P2M1=0;P2M0=0;
	P3M1=0;P3M0=0;
	P4M1=0;P4M0=0;
	P5M1=0;P5M0=0;
	P6M1=0;P6M0=0;
	P7M1=0;P7M0=0;
}

/**
  * 函    数:主函数
  * 参    数:无
  * 返 回 值:无
  * 说    明:main函数是程序执行的起点,负责执行整个程序的主要逻辑‌
  */
void main()
{	
    WTST=0;	//不加这行,则延时不准确
	GPIO_Init();	//IO口初始化
	DS3231_ConvertT();	//转换温度
	OLED_Init();	//OLED12864初始化
	Timer0_Init();	//定时器0初始化
	DS3231_ReadTime();	//上电先读取一次时间
	if(Time[0]<0 || Time[0]>99 || Time[1]<1 || Time[1]>12 || Time[3]<0 ||
		Time[3]>23 || Time[4]<0 || Time[4]>59 || Time[5]>59 || Time[5]<0)	//如果年月日时分秒越界
	{
		CheckTime();	//就对时间进行调整
		DS3231_SetTime();	//再将调整后的时间写入时钟芯片
	}
	while(1)
	{
		KeyNum=Key();
		
		if(KeyNum)	//如果有按键按下
		{
			if(KeyNum==9)	//如果K1按下(松手瞬间)
			{
				if(AllowChangeModeFlag && Mode==0)	//切换模式
				{
					AllowChangeModeFlag=0;
					Mode=1;
					TimeSelect=0;
				}
				if(AllowChangeModeFlag && Mode==1)
				{
					AllowChangeModeFlag=0;
					Mode=0;
				}
				AllowChangeModeFlag=1;
			}
			
			if(KeyNum==10)	//如果K2按下(松手瞬间)
			{
				if(AllowChangeModeFlag && Mode==0)	//切换模式
				{
					AllowChangeModeFlag=0;
					Mode=2;
					OLED_Clear();	//清屏
				}
				if(AllowChangeModeFlag && Mode==2)
				{
					AllowChangeModeFlag=0;
					Mode=0;
					OLED_Clear();	//清屏
					DateChangedFlag=1;
				}
				AllowChangeModeFlag=1;
				if(Mode==1)
				{
					TimeSelect++;	//时间选择变量自增
					TimeSelect%=6;	//可以设置年、月、日、时、分、秒(星期不用设置,通过代码计算得出)
				}
			}
	
			if(KeyNum==3)	//如果K3短按
			{
				if(Mode==1)	//如果是设置时间模式
				{
					switch(TimeSelect)	//时间数值减小
					{
						case 0:Time[0]--;break;	//年
						case 1:Time[1]--;break; //月
						case 2:Time[2]--;break; //日
						case 3:Time[3]--;break; //时
						case 4:Time[4]--;break; //分
						case 5:Time[5]=0;break;	//秒(按下按键3,秒的数值清零)
						default:break;
					}
					CheckTime();	//检查时间值是否越界
					ConvertSolarToLunar(Time[0],Time[1],Time[2]);
					FlashFlag=0;	//调节时间后暂不闪烁
					T0Count3=0;
					ShowTime();	//更新显示
					Delay(333);
				}
			}

			if(KeyNum==4)	//如果K4短按
			{
				if(Mode==1)
				{
					switch(TimeSelect)	//时间数值增加
					{
						case 0:Time[0]++;break;
						case 1:Time[1]++;break;
						case 2:Time[2]++;break;
						case 3:Time[3]++;break;
						case 4:Time[4]++;break;
						case 5:Time[5]++;break;
						default:break;
					}
					CheckTime();	//检查时间值是否越界
					ConvertSolarToLunar(Time[0],Time[1],Time[2]);
					FlashFlag=0;	//调节时间后暂不闪烁
					T0Count3=0;
					ShowTime();	//更新显示
					Delay(333);
				}
			}

			if(KeyNum==7)	//如果K3长按
			{
				if(Mode==1)
				{
					switch(TimeSelect)	//时间数值连续减小
					{
						case 0:Time[0]--;break;
						case 1:Time[1]--;break;
						case 2:Time[2]--;break;
						case 3:Time[3]--;break;
						case 4:Time[4]--;break;
						case 5:Time[5]=0;break;
						default:break;
					}
					CheckTime();	//检查时间值是否越界
					ConvertSolarToLunar(Time[0],Time[1],Time[2]);
					FlashFlag=0;	//调节时间后暂不闪烁
					T0Count3=0;
					ShowTime();	//更新显示
					Delay(50);	//防止数值变化过快
				}
			}

			if(KeyNum==8)	//如果K4长按
			{
				if(Mode==1)
				{
					switch(TimeSelect)	//时间数值连续增加
					{
						case 0:Time[0]++;break;
						case 1:Time[1]++;break;
						case 2:Time[2]++;break;
						case 3:Time[3]++;break;
						case 4:Time[4]++;break;
						case 5:Time[5]++;break;
					}
					CheckTime();	//检查时间值是否越界
					ConvertSolarToLunar(Time[0],Time[1],Time[2]);
					FlashFlag=0;	//调节时间后暂不闪烁
					T0Count3=0;
					ShowTime();	//更新显示
					Delay(50);	//防止数值变化过快
				}
			}

			if(KeyNum==11 || KeyNum==12)	//如果K3或K4松开(松开瞬间)
			{
				if(Mode==1)
				{
					DS3231_SetTime();	//将修改后的时间写入时钟芯片
				}
			}
		}
		
		if(Mode==0 || Mode==1)
		{
			if(ReadTimeFlag && !KeyNum)	//如果读取时间的标志为1
			{	//有按键按下时不进入此if,防止调整后的时间还没写入时钟芯片就又从时钟芯片中读取数据
				ReadTimeFlag=0;	//读取时间的标志清零
				DS3231_ReadTime();
				ConvertSolarToLunar(Time[0],Time[1],Time[2]);
				ShowTime();
			}

			if(ReadTempFlag)	//如果读取温度的标志为1
			{	//在ShowTime函数中显示温度
				ReadTempFlag=0;	//读取温度的标志清零
				if(DS3231_CheckBusy()==0)
				{
					T=DS3231_ReadT();
					DS3231_ConvertT();
				}					
			}
		}
		else if(Mode==2)	//显示更多信息
		{
			ShowMore();
		}

	}
}

void Timer0_Routine() interrupt 1	//定时器0中断函数
{
	TL0=0xA0;	//设置定时初值,定时2ms,1T@30.0000MHz
	TH0=0x15;	//设置定时初值,定时2ms,1T@30.0000MHz
	T0Count0++;
	T0Count1++;
	T0Count2++;
	T0Count3++;
	T0Count4++;
	if(T0Count0>=10)	//每隔20ms检测一次按键
	{
		T0Count0=0;
		Key_Tick();
	}
	if(T0Count1>=50)	//每隔100ms读取一次时间
	{
		T0Count1=0;
		ReadTimeFlag=1;
	}
	if(T0Count2>=165)	//每隔330ms读取一次温度
	{
		T0Count2=0;
		ReadTempFlag=1;
	}
	if(T0Count3>=250)	//设置时间时每隔500ms翻转一次FlashFlag的值,即以1s的周期闪烁
	{
		T0Count3=0;
		FlashFlag=!FlashFlag;
	}
	if(T0Count4>=1000)	//每隔2s切换节日/温度/节气/星期的显示(如果有农历节日或者是二十四节气之一或者有多个节日的话)
	{
		T0Count4=0;
		Order1++;
		Order2++;
		Order3++;
		Order1%=Sum1;
		Order2%=Sum2;
		Order3%=Sum3;
	}
}

/*公历节日
【一月】
1月1日:元旦
1月5日:哈尔滨国际冰雪节
1月10日:中国人民警察节
1月21日:国际拥抱日
1月26日:国际海关日
1月27日:缅怀大屠杀受难者国际纪念日
一月最后一个星期日:国际麻风节
【二月】
2月2日:世界湿地日
2月4日:世界抗癌症日
2月10日:国际气象节
2月14日:情人节
2月20日:世界社会公正日
2月21日:国际母语日
二月最后一日:国际罕见病日
【三月】
3月1日:国际海豹日
3月1日:国际民防日
3月3日:全国爱耳日
3月3日:世界野生动植物日
3月5日:学雷锋纪念日
3月6日:世界青光眼日
3月7日:女生节
3月8日:国际妇女节
3月12日:中国植树节
3月15日:国际消费者权益日
3月20日:世界无肉日
3月20日:国际幸福日
3月21日:世界森林日
3月21日:世界睡眠日
3月21日:世界儿歌日
3月21日:国际消除种族歧视日
3月22日:世界水日
3月23日:世界气象日
3月24日:世界防止结核病日
3月27日:世界戏剧日
三月第二个星期四:世界肾脏日
三月第三个星期二:世界社会工作日
三月最后一个星期一:全国中小学生安全教育日
【四月】
4月1日:愚人节
4月1日:国际爱鸟日
4月2日:国际儿童图书日
4月2日:世界自闭症日
4月4日:寒食节
4月7日:世界卫生日
4月8日:国际珍稀动物保护日
4月11日:世界帕金森病日
4月12日:世界航天日
4月15日:国家安全教育日
4月16日:世界噪音日
4月17日:世界血友病日
4月20日:联合国中文日
4月22日:世界地球日
4月22日:世界法律日
4月23日:世界读书日
4月24日:中国航天日
4月25日:世界防治疟疾日
4月26日:世界知识产权日
4月26日:中国疟疾日
4月28日:安全生产与健康日
四月最后一个星期三:国际行政专员日
【五月】
5月1日:国际劳动节
5月4日:中国五四青年节
5月8日:世界红十字日
5月10日:中国品牌日
5月11日:防治肥胖日
5月12日:国际护士节
5月12日:全国防灾减灾日
5月15日:国际家庭日
5月15日:全国碘缺乏病日
5月17日:世界电信日
5月18日:国际博物馆日
5月19日:中国旅游日
5月20日:中国网络情人节
5月20日:全国母乳喂养宣传日
5月20日:中国学生营养日
5月22日:国际生物多样性日
5月25日:国际爱肤日
5月30日:全国科技工作者日
5月31日:世界无烟日
五月第二个星期日:母亲节
五月第一个星期二:世界防治哮喘日
五月第三个星期日:全国助残日
【六月】
6月1日:国际儿童节
6月5日:世界环境日
6月6日:全国爱眼日
6月7日:世界食品安全日
6月9日:世界认可日
6月23日:国际奥林匹克日
6月25日:全国土地日
6月26日:国际禁毒日
六月第三个星期日:父亲节
六月第二个星期六:文化和自然遗产日
【七月】
7月1日:建党节
7月1日:香港回归日
7月7日:七七抗战纪念日
7月11日:世界人口日
7月11日:中国航海日
7月30日:国际友谊日
【八月】
8月1日:建军节
8月8日:全民健身日
8月12日:国际青年节
8月13日:国际左撇子日
8月15日:全国生态日
8月15日:日本无条件投降日
8月19日:中国医师节
8月25日:全国残疾预防日
8月29日:全国测绘法宣传日
【九月】
9月3日:中国人民抗日战争胜利纪念日
9月5日:中华慈善日
9月10日:教师节
9月12日:中国预防出生缺陷日
9月16日:国际臭氧层保护日
9月18日:九一八纪念日
9月20日:全国爱牙日
9月20日:公民道德宣传日
9月21日:国际和平日
9月27日:世界旅游日
9月30日:烈士纪念日
九月第三个星期六:全民国防教育日
九月第三周公休日:全国科普日
九月第四个星期日:国际聋人节
秋分:中国农民丰收节
【十月】
10月1日:国庆节
10月1日:国际音乐节
10月4日:世界动物日
10月5日:世界教师日
10月7日:国际住房日
10月9日:世界邮政日
10月10日:世界精神卫生日
10月13日:国际减轻自然灾害日
10月13日:世界保健日
10月15日:国际盲人节
10月15日:全球洗手日
10月16日:世界粮食节
10月17日:世界消除贫困日
10月17日:国家扶贫日
10月24日:联合国日
10月24日:程序员节
10月29日:世界银屑病日
十月第一个星期一:国际建筑日
十月第二个星期四:世界视力日
【十一月】
11月1日:万圣节
11月8日:中国记者日
11月9日:消防宣传日
11月14日:世界糖尿病日
11月16日:国际宽容日
11月17日:国际大学生节
11月25日:国际消除家庭暴力日
十一月第四个星期四:感恩节
【十二月】
12月1日:世界艾滋病日
12月2日:全国交通安全日
12月3日:世界残疾人日
12月4日:国家宪法日
12月4日:全国法制宣传日
12月5日:国际志愿者日
12月9日:世界足球日
12月13日:南京大屠杀死难者国家公祭日
12月20日:澳门回归纪念日
12月21日:国际篮球日
12月24日:平安夜
12月25日:圣诞节
*/

总结

开始时STC32G12K128也是用12.0000MHz的频率,准备先测试一下能不能正常运行,结果是OLED12864屏幕能正常显示,但是不能从DS3231时钟芯片中读取时间。按理说这两款单片机都是1T单片机,频率也都是12.0000MHz,应该都能正常运行才对呀。也想过会不会是通信速度超过了DS3231的I2C的极限,在通信协议那块加了几个“nop();”函数,发现还是不行,就想着会不会是C251和C51有些地方不兼容,试了很多都找不到原因。后来专门给DS3231做了一个延时函数,降低I2C通信速率,就可以了,估计是用几个“nop();”函数延时的时间不够。正常后再将STC32G12K128的频率改为30.0000MHz,显示就很流畅了,秒的显示不再有卡顿的情况了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值