目录
- calendar.c
- 测试程序
- 效果
普中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天elsereturn 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){}
}
效果