#include <reg52.h>
#include <intrins.h>
#include <string.h>
// 引脚定义
sbit K1 = P3^0; // 状态切换
sbit K2 = P3^1; // 增加/长按确认
sbit K3 = P3^2; // 移位/复位
sbit K4 = P3^3; // 低功耗模式
sbit BEEP = P1^0; // 蜂鸣器
sbit LED = P1^1; // 低功耗指示灯
// LCD1602引脚定义
sbit RS = P2^0;
sbit RW = P2^1;
sbit EN = P2^2;
#define LCD_DATA P0
// DS1302引脚定义
sbit RST = P1^5;
sbit IO = P1^6;
sbit SCLK = P1^7;
// DS18B20引脚定义
sbit DQ = P3^7;
// 全局变量
unsigned char display_state = 0; // 0:日期 1:时间 2:温度 3:闹钟 4:倒计时
unsigned char setting_pos = 0; // 设置位置
bit setting_mode = 0; // 设置模式标志
bit low_power = 0; // 低功耗模式标志
bit alarm_on = 0; // 报警标志
unsigned int timer_minutes = 10; // 倒计时值(分钟)
unsigned char alarm_h = 7, alarm_m = 0, alarm_s = 0; // 闹钟时间
bit blink = 0; // 闪烁控制变量
unsigned int power_off_timer = 0; // 低功耗计时器
unsigned int beep_counter = 0; // 蜂鸣器计数器
unsigned char beep_freq = 10; // 蜂鸣器频率
unsigned int no_reset_counter = 0; // 未复位计数器
unsigned char key_state[4] = {0}; // 按键状态数组
unsigned int key_press_time = 0; // 按键按下时间计数器
// 时间结构体
struct Time {
unsigned char year, month, day;
unsigned char hour, minute, second;
} current_time;
// LCD1602基础函数
void LCD_Delay(unsigned int t) {
while(t--);
}
void LCD_WriteCmd(unsigned char cmd) {
RS = 0; // 命令模式
RW = 0; // 写操作
LCD_DATA = cmd;
EN = 1; // 使能高电平
_nop_(); // 短暂延时
_nop_();
_nop_();
EN = 0; // 使能下降沿触发
LCD_Delay(100); // 延时确保命令执行完成
}
void LCD_WriteData(unsigned char dat) {
RS = 1; // 数据模式
RW = 0; // 写操作
LCD_DATA = dat;
EN = 1; // 使能高电平
_nop_();
_nop_();
_nop_();
EN = 0; // 使能下降沿触发
LCD_Delay(50); // 延时确保数据写入
}
void LCD_Init() {
// 上电后延时确保LCD稳定
LCD_Delay(20000);
// 初始化序列 - 确保8位模式
LCD_WriteCmd(0x30); // 尝试设置为8位
LCD_Delay(5000);
LCD_WriteCmd(0x30); // 再次发送
LCD_Delay(200);
LCD_WriteCmd(0x30); // 第三次发送
LCD_Delay(200);
// 正式设置
LCD_WriteCmd(0x38); // 8位数据,双行显示,5x8点阵
LCD_WriteCmd(0x0C); // 开显示,关光标
LCD_WriteCmd(0x06); // 增量不移位
LCD_WriteCmd(0x01); // 清屏
LCD_Delay(2000); // 清屏需要较长时间
}
void LCD_ShowStr(unsigned char x, unsigned char y, char *str) {
if (y == 0)
LCD_WriteCmd(0x80 + x);
else
LCD_WriteCmd(0xC0 + x);
while (*str) {
LCD_WriteData(*str++);
}
}
// 显示两位数字
void LCD_Show2Digit(unsigned char x, unsigned char y, unsigned char num) {
if (y == 0) LCD_WriteCmd(0x80 + x);
else LCD_WriteCmd(0xC0 + x);
LCD_WriteData('0' + num / 10); // 十位
LCD_WriteData('0' + num % 10); // 个位
}
// 显示三位数字
void LCD_Show3Digit(unsigned char x, unsigned char y, unsigned int num) {
if (y == 0) LCD_WriteCmd(0x80 + x);
else LCD_WriteCmd(0xC0 + x);
LCD_WriteData('0' + num / 100); // 百位
LCD_WriteData('0' + (num / 10) % 10); // 十位
LCD_WriteData('0' + num % 10); // 个位
}
// 显示温度值
void LCD_ShowTemp(unsigned char x, unsigned char y, float temp) {
if (y == 0) LCD_WriteCmd(0x80 + x);
else LCD_WriteCmd(0xC0 + x);
if (temp < -50) {
LCD_ShowStr(x, y, "--.-- C");
return;
}
unsigned int temp_int = (unsigned int)temp;
unsigned int temp_frac = (unsigned int)((temp - temp_int) * 100);
// 显示整数部分
if (temp_int < 10) {
LCD_WriteData(' ');
LCD_WriteData('0' + temp_int);
} else {
LCD_WriteData('0' + temp_int / 10);
LCD_WriteData('0' + temp_int % 10);
}
LCD_WriteData('.');
LCD_WriteData('0' + temp_frac / 10);
LCD_WriteData('0' + temp_frac % 10);
LCD_WriteData(' ');
LCD_WriteData('C');
}
// DS1302基础函数
void DS1302_WriteByte(unsigned char dat) {
unsigned char i;
for(i=0; i<8; i++) {
IO = dat & 0x01;
dat >>= 1;
SCLK = 1;
_nop_();
SCLK = 0;
_nop_();
}
}
unsigned char DS1302_ReadByte() {
unsigned char i, dat = 0;
for(i=0; i<8; i++) {
dat >>= 1;
if(IO) dat |= 0x80;
SCLK = 1;
_nop_();
SCLK = 0;
_nop_();
}
return dat;
}
void DS1302_WriteReg(unsigned char addr, unsigned char dat) {
RST = 0; _nop_();
SCLK = 0; _nop_();
RST = 1; _nop_();
DS1302_WriteByte(addr);
DS1302_WriteByte(dat);
SCLK = 1; _nop_();
RST = 0; _nop_();
}
unsigned char DS1302_ReadReg(unsigned char addr) {
unsigned char dat;
RST = 0; _nop_();
SCLK = 0; _nop_();
RST = 1; _nop_();
DS1302_WriteByte(addr | 0x01);
dat = DS1302_ReadByte();
SCLK = 1; _nop_();
RST = 0; _nop_();
return dat;
}
// BCD转十进制
unsigned char BCD2Dec(unsigned char bcd) {
return (bcd >> 4) * 10 + (bcd & 0x0F);
}
// 十进制转BCD
unsigned char Dec2BCD(unsigned char dec) {
return ((dec / 10) << 4) | (dec % 10);
}
void DS1302_GetTime(struct Time *t) {
t->second = BCD2Dec(DS1302_ReadReg(0x81));
t->minute = BCD2Dec(DS1302_ReadReg(0x83));
t->hour = BCD2Dec(DS1302_ReadReg(0x85));
t->day = BCD2Dec(DS1302_ReadReg(0x87));
t->month = BCD2Dec(DS1302_ReadReg(0x89));
t->year = BCD2Dec(DS1302_ReadReg(0x8D));
}
// DS18B20基础函数
void DS18B20_Delay(unsigned int t) {
while(t--);
}
bit DS18B20_Init() {
bit ack;
DQ = 1; DS18B20_Delay(8);
DQ = 0; DS18B20_Delay(80);
DQ = 1; DS18B20_Delay(14);
ack = DQ;
DS18B20_Delay(20);
return ack;
}
void DS18B20_WriteByte(unsigned char dat) {
unsigned char i;
for(i=0; i<8; i++) {
DQ = 0;
_nop_();
DQ = dat & 0x01;
DS18B20_Delay(5);
DQ = 1;
dat >>= 1;
}
DS18B20_Delay(5);
}
unsigned char DS18B20_ReadByte() {
unsigned char i, dat = 0;
for(i=0; i<8; i++) {
dat >>= 1;
DQ = 0;
_nop_();
DQ = 1;
_nop_();
if(DQ) dat |= 0x80;
DS18B20_Delay(5);
}
return dat;
}
// DS18B20温度读取函数
float DS18B20_GetTemp() {
unsigned char LSB, MSB;
int temp;
float f_temp;
unsigned int timeout; // 将timeout声明放在函数开头
if(!DS18B20_Init()) return -99.9; // 初始化失败
DS18B20_WriteByte(0xCC); // Skip ROM
DS18B20_WriteByte(0x44); // Convert
// 等待转换完成 (750ms)
timeout = 750;
while(timeout > 0) { // 修复timeout未定义问题
DS18B20_Delay(1000);
if(!DQ) break; // 转换完成DQ变低
timeout--;
}
if(!DS18B20_Init()) return -99.9; // 初始化失败
DS18B20_WriteByte(0xCC);
DS18B20_WriteByte(0xBE); // Read Scratchpad
LSB = DS18B20_ReadByte();
MSB = DS18B20_ReadByte();
temp = (MSB << 8) | LSB;
f_temp = temp * 0.0625;
return f_temp;
}
// 按键处理函数 (非阻塞式)
void Key_Process() {
// K1处理 - 状态切换 (功能4)
if(!K1) {
if(key_state[0] == 0) { // K1首次按下
key_state[0] = 1;
display_state = (display_state + 1) % 5;
setting_mode = (display_state == 3 || display_state == 4);
if(setting_mode) setting_pos = 0; // 进入设置模式时重置位置
LCD_WriteCmd(0x01); // 清屏
}
} else {
key_state[0] = 0;
}
// K2处理 - 增加/长按确认 (功能4)
if(!K2) {
if(key_state[1] == 0) { // K2首次按下
key_state[1] = 1;
key_press_time = 0;
} else {
key_press_time++;
// 长按超过3秒
if(key_press_time > 300) { // 假设10ms中断,3000ms
setting_mode = 0;
display_state = 0; // 返回日期模式
LCD_WriteCmd(0x01);
key_state[1] = 0;
key_press_time = 0;
}
}
// 短按处理 (仅在设置模式) (功能4)
if(key_state[1] == 1 && setting_mode) {
if(display_state == 3) { // 闹钟设置
switch(setting_pos) {
case 0: alarm_h = (alarm_h + 1) % 24; break;
case 1: alarm_m = (alarm_m + 1) % 60; break;
case 2: alarm_s = (alarm_s + 1) % 60; break;
}
} else if(display_state == 4) { // 倒计时设置
if(setting_pos == 0) timer_minutes = (timer_minutes + 1) % 1000;
}
}
} else {
key_state[1] = 0;
}
// K3处理 - 移位/复位 (功能5)
if(!K3) {
if(key_state[2] == 0) { // K3首次按下
key_state[2] = 1;
if(setting_mode) {
setting_pos = (setting_pos + 1) % 3; // 循环移位
} else if(alarm_on) {
alarm_on = 0; // 清除报警
BEEP = 0; // 关闭蜂鸣器
beep_freq = 10; // 重置频率
no_reset_counter = 0; // 复位未响应计数器
}
}
} else {
key_state[2] = 0;
}
// K4处理 - 低功耗模式 (功能6)
if(!K4) {
if(key_state[3] == 0) { // K4首次按下
key_state[3] = 1;
low_power = !low_power;
LED = low_power; // LED指示状态
power_off_timer = 0;
if(!low_power) {
LCD_WriteCmd(0x0C); // 恢复显示
}
}
} else {
key_state[3] = 0;
}
}
// 显示处理函数 (功能3)
void Display_Process() {
switch(display_state) {
case 0: // 日期信息
LCD_ShowStr(0, 0, "Date:20");
LCD_Show2Digit(7, 0, current_time.year);
LCD_WriteData('-');
LCD_Show2Digit(10, 0, current_time.month);
LCD_WriteData('-');
LCD_Show2Digit(13, 0, current_time.day);
break;
case 1: // 时间信息
LCD_ShowStr(0, 0, "Time: ");
LCD_Show2Digit(6, 0, current_time.hour);
LCD_WriteData(':');
LCD_Show2Digit(9, 0, current_time.minute);
LCD_WriteData(':');
LCD_Show2Digit(12, 0, current_time.second);
break;
case 2: // 温度信息
LCD_ShowStr(0, 0, "Temp: ");
LCD_ShowTemp(6, 0, DS18B20_GetTemp());
break;
case 3: // 闹钟设置
LCD_ShowStr(0, 0, "Alarm:");
if (setting_mode && blink) {
// 闪烁状态 - 当前设置位置显示空格
switch(setting_pos) {
case 0: // 小时闪烁
LCD_WriteData(' ');
LCD_WriteData(' ');
LCD_WriteData(':');
LCD_Show2Digit(10, 0, alarm_m);
LCD_WriteData(':');
LCD_Show2Digit(13, 0, alarm_s);
break;
case 1: // 分钟闪烁
LCD_Show2Digit(7, 0, alarm_h);
LCD_WriteData(':');
LCD_WriteData(' ');
LCD_WriteData(' ');
LCD_WriteData(':');
LCD_Show2Digit(13, 0, alarm_s);
break;
case 2: // 秒钟闪烁
LCD_Show2Digit(7, 0, alarm_h);
LCD_WriteData(':');
LCD_Show2Digit(10, 0, alarm_m);
LCD_WriteData(':');
LCD_WriteData(' ');
LCD_WriteData(' ');
break;
}
} else {
// 正常显示
LCD_Show2Digit(7, 0, alarm_h);
LCD_WriteData(':');
LCD_Show2Digit(10, 0, alarm_m);
LCD_WriteData(':');
LCD_Show2Digit(13, 0, alarm_s);
}
break;
case 4: // 倒计时设置
LCD_ShowStr(0, 0, "Timer:");
if (setting_mode && blink) {
// 闪烁状态
LCD_ShowStr(7, 0, "--- min");
} else {
// 正常显示
LCD_Show3Digit(7, 0, timer_minutes);
LCD_ShowStr(10, 0, " min");
}
break;
}
}
// 报警处理 (功能7)
void Alarm_Process() {
if(alarm_on) {
beep_counter++;
// 基础报警
if(beep_counter % (500/beep_freq) == 0) {
BEEP = !BEEP;
}
// 5秒内未按下K3则增加频率 (功能7)
if(no_reset_counter++ > 500) { // 5秒
no_reset_counter = 0;
if(beep_freq < 50) beep_freq += 5; // 增加频率
}
} else {
BEEP = 0; // 关闭蜂鸣器
}
}
// 低功耗处理 (功能6)
void LowPower_Process() {
static unsigned char blink_count = 0;
if(low_power) {
power_off_timer++;
// 10秒后闪烁息屏
if(power_off_timer > 1000) { // 10秒
// 闪烁3次后息屏
if(blink_count < 3) {
LCD_WriteCmd(0x08); // 关显示
LCD_Delay(50000);
LCD_WriteCmd(0x0C); // 开显示
blink_count++;
} else if(blink_count == 3) {
LCD_WriteCmd(0x08); // 息屏
blink_count++;
}
}
} else {
blink_count = 0;
}
}
// 倒计时处理
void Timer_Process() {
static unsigned int second_counter = 0;
static unsigned int seconds_remaining = 0; // 将声明移到函数开头
if(timer_minutes > 0 && !alarm_on) {
if(++second_counter >= 100) { // 1秒
second_counter = 0;
if(seconds_remaining == 0) {
timer_minutes--;
seconds_remaining = 59;
if(timer_minutes == 0) {
alarm_on = 1; // 触发报警
no_reset_counter = 0; // 重置未响应计数器
}
} else {
seconds_remaining--;
}
}
}
}
// 主函数
void main() {
// 初始化
LCD_Init();
DS1302_WriteReg(0x8E, 0x00); // 允许写操作
// 设置初始时间 (2023-12-25 08:30:00)
DS1302_WriteReg(0x8C, Dec2BCD(23)); // 2023年
DS1302_WriteReg(0x88, Dec2BCD(12)); // 12月
DS1302_WriteReg(0x86, Dec2BCD(25)); // 25日
DS1302_WriteReg(0x84, Dec2BCD(8)); // 08时
DS1302_WriteReg(0x82, Dec2BCD(30)); // 30分
DS1302_WriteReg(0x80, Dec2BCD(0)); // 00秒
DS1302_WriteReg(0x8E, 0x80); // 写保护
// 定时器0初始化 (10ms中断)
TMOD = 0x01;
TH0 = 0xDC;
TL0 = 0x00;
ET0 = 1;
EA = 1;
TR0 = 1;
// 初始显示
LCD_ShowStr(0, 0, "Multifunction");
LCD_ShowStr(0, 1, "Clock Ready");
LCD_Delay(200000);
LCD_WriteCmd(0x01); // 清屏
while(1) {
Key_Process();
Display_Process();
Alarm_Process();
LowPower_Process();
Timer_Process();
}
}
// 定时器0中断服务程序 (10ms)
void Timer0_ISR() interrupt 1 {
static unsigned int ms_count = 0;
static unsigned int blink_count = 0;
static unsigned int temp_update = 0;
// 重装定时器
TH0 = 0xDC;
TL0 = 0x00;
// 闪烁控制 (0.5秒周期) (功能4)
if(++blink_count >= 50) {
blink_count = 0;
blink = !blink;
}
// 时间更新 (每秒)
if(++ms_count >= 100) { // 1秒
ms_count = 0;
DS1302_GetTime(¤t_time);
// 检查闹钟 (功能1)
if(current_time.hour == alarm_h &&
current_time.minute == alarm_m &&
current_time.second == alarm_s) {
alarm_on = 1;
no_reset_counter = 0; // 重置未响应计数器
}
// 温度更新 (每5秒)
if(++temp_update >= 5) {
temp_update = 0;
// 温度在显示函数中读取
}
}
}
请将这段简易多功能时钟程序变得更加简洁,删去不必要的程序
最新发布