#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){ // 如果检测到设置键
|