| #include <reg51.h> #include <intrins.h>
 
 sbit LCD_RS = P2^0; // LCD_RS引脚
 sbit LCD_RW = P2^1; // LCD_RW引脚
 sbit LCD_E = P2^2; // LCD_E引脚
 sbit SDA = P1^1; // I2C数据线
 sbit SCL = P1^0; // I2C时钟线
 sbit KEY_UP = P3^2; // 上键
 sbit KEY_DOWN = P3^3; // 下键
 sbit KEY_SET = P3^4; // 设置键
 
 typedef unsigned char uint8_t; // 无符号8位整型数据类型
 typedef unsigned int uint16_t; // 无符号16位整型数据类型
 
 void Delay(uint16_t i); // 延时函数
 void WriteCmd(uint8_t cmd); // 写指令到LCD函数
 void WriteData(uint8_t dat); // 写数据到LCD函数
 void LCD_Init(); // LCD初始化函数
 void LCD_ShowString(uint8_t x, uint8_t y, uint8_t* str); // LCD显示字符串函数
 void LCD_ShowTime(); // LCD显示时间函数
 void LCD_ShowDate(); // LCD显示日期函数
 void PCF8563_Write(uint8_t addr, uint8_t dat); // 写PCF8563芯片寄存器函数
 uint8_t PCF8563_Read(uint8_t addr); // 读PCF8563芯片寄存器函数
 void ReadTime(); // 读取当前时间函数
 void SetTime(); // 设置时间函数
 uint8_t Key_Scan(); // 按键扫描函数
 void AdjustTime(); // 调整时间函数
 
 uint8_t sec, min, hour, day, week, month, year; // 时间变量定义
 
 void main()
 {
 LCD_Init(); // LCD初始化
 while(1){
 ReadTime(); // 读取当前时间
 LCD_ShowTime(); // 显示时间
 LCD_ShowDate(); // 显示日期
 Delay(1000); // 延时1s
 }
 }
 
 void Delay(uint16_t i) // 延时函数
 {
 while(i--);
 }
 
 void WriteCmd(uint8_t cmd) // 写指令到LCD函数
 {
 LCD_RS = 0; // 设置LCD_RS引脚为0,表示传输的是指令
 LCD_RW = 0; // 设置LCD_RW引脚为0,表示写操作
 P0 = cmd; // 设置P0口输出值为指令
 LCD_E = 1; // 设置LCD_E引脚为1,表示开始传输数据
 _nop_(); // 等待一段时间
 _nop_();
 LCD_E = 0; // 设置LCD_E引脚为0,表示数据传输结束
 }
 
 void WriteData(uint8_t dat) // 写数据到LCD函数
 {
 LCD_RS = 1; // 设置LCD_RS引脚为1,表示传输的是数据
 LCD_RW = 0; // 设置LCD_RW引脚为0,表示写操作
 P0 = dat; // 设置P0口输出值为数据
 LCD_E = 1; // 设置LCD_E引脚为1,表示开始传输数据
 _nop_(); // 等待一段时间
 _nop_();
 LCD_E = 0; // 设置LCD_E引脚为0,表示数据传输结束
 }
 
 void LCD_Init() // LCD初始化函数
 {
 Delay(1000); // 延时等待LCD初始化完成
 WriteCmd(0x38); // 初始化LCD显示模式
 WriteCmd(0x0c); // 开启LCD显示,并设置光标不可见
 WriteCmd(0x06); // 光标右移,字符不动
 WriteCmd(0x01); // 清屏
 }
 
 void LCD_ShowString(uint8_t x, uint8_t y, uint8_t* str) // LCD显示字符串函数
 {
 uint8_t i;
 if(y == 0) WriteCmd(0x80 + x); // 如果y为0,则设置光标在第一行的第x个位置
 else WriteCmd(0xc0 + x); // 如果y为1,则设置光标在第二行的第x个位置
 for(i=0; str!='\0'; i++){ // 逐个字符显示到LCD上
 WriteData(str);
 }
 }
 
 void LCD_ShowTime() // LCD显示时间函数
 {
 LCD_ShowString(0, 0, "Time: "); // 在第一行第一个字符显示"Time: "
 WriteData(hour/10+'0'); // 显示小时十位数
 WriteData(hour%10+'0'); // 显示小时个位数
 WriteData(':'); // 显示冒号
 WriteData(min/10+'0'); // 显示分钟十位数
 WriteData(min%10+'0'); // 显示分钟个位数
 WriteData(':'); // 显示冒号
 WriteData(sec/10+'0'); // 显示秒钟十位数
 WriteData(sec%10+'0'); // 显示秒钟个位数
 }
 
 void LCD_ShowDate() // LCD显示日期函数
 {
 uint8_t buf[16];
 sprintf(buf, "%04d-%02d-%02d", year+2000, month, day); // 将年、月、日格式化为字符串
 LCD_ShowString(0, 1, buf); // 在第二行显示日期
 }
 
 void PCF8563_Write(uint8_t addr, uint8_t dat) // 写PCF8563芯片寄存器函数
 {
 Start_I2C(); // 启动I2C总线
 Write_I2C(0xa2); // 发送写地址
 Write_I2C(addr); // 发送寄存器地址
 Write_I2C(dat); // 发送数据
 Stop_I2C(); // 停止I2C总线
 }
 
 uint8_t PCF8563_Read(uint8_t addr) // 读PCF8563芯片寄存器函数
 {
 uint8_t dat;
 Start_I2C(); // 启动I2C总线
 Write_I2C(0xa2); // 发送写地址
 Write_I2C(addr); // 发送寄存器地址
 Start_I2C(); // 启动I2C总线
 Write_I2C(0xa3); // 发送读地址
 dat = Read_I2C(); // 读取数据
 NoAck_I2C(); // 发送非应答信号
 Stop_I2C(); // 停止I2C总线
 return dat; // 返回读到的数据
 }
 
 void ReadTime() // 读取当前时间函数
 {
 sec = bcd2hex(PCF8563_Read(0x02) & 0x7f); // 读取秒,并将转换后的十进制数赋值给sec变量
 min = bcd2hex(PCF8563_Read(0x03) & 0x7f); // 读取分,并将转换后的十进制数赋值给min变量
 hour = bcd2hex(PCF8563_Read(0x04) & 0x3f); // 读取小时,并将转换后的十进制数赋值给hour变量
 day = bcd2hex(PCF8563_Read(0x05) & 0x3f); // 读取日,并将转换后的十进制数赋值给day变量
 week = bcd2hex(PCF8563_Read(0x06) & 0x07); // 读取周,并将转换后的十进制数赋值给week变量
 month = bcd2hex(PCF8563_Read(0x07) & 0x1f); // 读取月,并将转换后的十进制数赋值给month变量
 year = bcd2hex(PCF8563_Read(0x08)); // 读取年,并将转换后的十进制数赋值给year变量
 }
 
 void SetTime() // 设置时间函数
 {
 PCF8563_Write(0x02, hex2bcd(sec)); // 写入秒
 PCF8563_Write(0x03, hex2bcd(min)); // 写入分
 PCF8563_Write(0x04, hex2bcd(hour)); // 写入小时
 PCF8563_Write(0x05, hex2bcd(day)); // 写入日
 PCF8563_Write(0x06, hex2bcd(week)); // 写入周
 PCF8563_Write(0x07, hex2bcd(month)); // 写入月
 PCF8563_Write(0x08, hex2bcd(year)); // 写入年
 }
 
 uint8_t Key_Scan() // 按键扫描函数
 {
 uint8_t key = 0xff; // 初始化按键值为无效值
 if(KEY_UP == 0){ // 如果检测到上键按下
 Delay(10); // 延时一段时间
 if(KEY_UP == 0) key = KEY_UP; // 如果还是检测到上键按下,则将按键值设置为KEY_UP
 }
 if(KEY_DOWN == 0){ // 如果检测到下键按下
 Delay(10); // 延时一段时间
 if(KEY_DOWN == 0) key = KEY_DOWN; // 如果还是检测到下键按下,则将按键值设置为KEY_DOWN
 }
 if(KEY_SET == 0){ // 如果检测到设置键
 
 |