普中51-单核-A2
STC89C52
Keil uVision V5.29.0.0
PK51 Prof.Developers Kit Version:9.60.0.0
stdint.h见【51单片机快速入门指南】1:基础知识和工程创建
I2C版OLED驱动程序见【51单片机快速入门指南】4.2: SSD1306 OLED屏(0.96寸、1.3寸)的I2C控制详解
SPI版OLED驱动程序见SPI驱动0.96/1.3寸 OLED屏幕,易修改为DMA控制
软件I2C程序见【51单片机快速入门指南】4: 软件 I2C
软件SPI程序见【51单片机快速入门指南】5:软件SPI
calendar.c
#include "./I2C_OLED/oled.h"
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#define DAYS_PER_WEEK 7
#define MONTHS 12
#define is_leap_year(year) ((year % 400 == 0) || (year % 4 == 0 && year % 100 != 0)) //返回当前年份是否为闰年
#define Date_Distance 16
//存储平年每月的天数
code uint8_t month_days[MONTHS] =
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
code uint8_t Month_Str[12][10] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
code uint8_t Week_Str[] = "MoTuWeThFrSaSu";
code uint8_t F4X6[][4] =
{
{ 0x00, 0x1F, 0x11, 0x1F },/*0*/
{ 0x00, 0x00, 0x00, 0x1F },/*1*/
{ 0x00, 0x1D, 0x15, 0x17 },/*2*/
{ 0x00, 0x15, 0x15, 0x1F },/*3*/
{ 0x00, 0x07, 0x04, 0x1F },/*4*/
{ 0x00, 0x17, 0x15, 0x1D },/*5*/
{ 0x00, 0x1F, 0x15, 0x1D },/*6*/
{ 0x00, 0x01, 0x01, 0x1F },/*7*/
{ 0x00, 0x1F, 0x15, 0x1F },/*8*/
{ 0x00, 0x17, 0x15, 0x1F }, /*9*/
};
void OLED_Showsmallnum(uint8_t x, uint8_t y, uint8_t chr)
{
uint8_t i = 0;
OLED_Set_Pos(x, y);
for (i = 0; i < 4; i++)
OLED_WR_Byte(F4X6[chr][i], OLED_DATA);
}
//返还某年某月有几天
uint8_t days_of_month(uint16_t year, uint8_t month)
{
if (2 == month && is_leap_year(year))
return 29; // 如果是闰年2月,返回29天
else
return month_days[month - 1]; //正常返回
}
//返回某年某月某日是当前年份第几天
uint16_t days_of_year(uint16_t year, uint8_t month, uint8_t day)
{
uint8_t i;
uint16_t days = 0;
for (i = 1; i < month; i++)
{
days += days_of_month(year, i);
}
return days + day;
}
//返回从公元元年算起,某年某月某日是第几天,用这个数字算星期几
uint32_t get_days(uint16_t year, uint8_t month, uint8_t day)
{
uint16_t days = days_of_year(year, month, day);
uint16_t temp = year - 1;
return (uint32_t)temp * 365 + temp / 4 - temp / 100 + temp / 400 + days;
}
//返回某年某月某日是星期几,星期天返回0
uint8_t day_of_week(uint16_t year, uint8_t month, uint8_t day)
{
return get_days(year, month, day) % DAYS_PER_WEEK;
}
void printfsm(uint8_t x, uint8_t y, uint8_t num)
{
if (num < 10)
OLED_Showsmallnum(x, y, num);
else
{
OLED_Showsmallnum(x - 4, y, num / 10);
OLED_Showsmallnum(x, y, num % 10);
}
}
//输出某年某个月的日历
void print_date_of_month(uint16_t year, uint8_t month)
{
uint8_t first, days, i, h = 2;
int16_t x;
uint8_t year_month_str[14] = {0};
//先求出这个月第一天星期几
first = day_of_week(year, month, 1);
//求出这个月一共有几天
days = days_of_month(year, month);
if(first)
{
x = first * Date_Distance;
}
else
{
x = 7 * Date_Distance;
}
for (i = 0; i < days; ++i)
{
printfsm(x + Date_Distance * i, h, i + 1);
if ((first + i) % 7 == 0)
{
h++;
x = -Date_Distance * i;
}
}
OLED_ShowNum(64 - 4 * (strlen(Month_Str[month - 1]) + 5), 0, year, 4, 6, 0);
OLED_ShowString(64 - 4 * strlen(Month_Str[month - 1] + 5) + 4, 0, Month_Str[month - 1], 6, 0);
OLED_ShowString(64 - 4 * strlen(Week_Str), 1, Week_Str, 6, 0);
}
测试程序
#include <STC89C5xRC.H>
#include "intrins.h"
#include "stdint.h"
#include "./I2C_OLED/oled.h"
void print_date_of_month(int year, int month);
void main(void)
{
OLED_Init();
OLED_Clear();
OLED_Display_On();
print_date_of_month(2022, 1);
OLED_Refresh_Gram();
while(1)
{
}
}
效果