通过使用定时器模块来实现按键可调的闹钟功能。具体操作如下:
定义一个变量alarm_time用于存储用户设置的闹钟时间戳;
当按下闹钟键时,启动定时器并设置定时器的计时时间为alarm_time;
每次定时器中断发生时,判断是否已经超过设定的时间点,如果超过了则响铃提示;
如果没有超过设定的时间点,则重新设置定时器的计时时间为当前时刻加上一段延时时间,以便下次定时器中断时再次响铃提示。
另外还需要添加一个按钮来停止闹钟。当按下该按钮时,终止定时器循环并将alarm_time置为-1表示取消闹钟。
同时需要添加一些显示界面来让用户可以查看当前的闹钟状态以及修改闹钟时间等操作。
具体的代码实现可以参考下面的示例:
// 定义一个变量保存用户设置的闹钟时间戳
unsigned int alarm_time = -1; // 初始值为未设闹钟
void timer() {
if (alarm_time != -1) { // 若设置了闹钟,则响铃提示
if ((int)(millis()) > alarm_time) { // 已到设定的时间点
beep(); // 响铃提示
alarm_time = -1; // 清空闹钟时间戳
} else {
delay(ALARM_INTERVAL); // 延时一定时间后再次响铃提醒
}
}
}
void setup() {
pinMode(BUTTON, INPUT); // 配置按扭传感器引脚为输入模式
attachInterrupt(digitalPinToInterruptNumber(BUTTON), buttonPressed, FALLING); // 注册按键触发的中断函数
setAlarmTime(-1); // 初始化闹钟时间戳为未设闹钟
}
void loop() {
while (!buttonPressed()); // 直到按下按钮才跳出循环体
clearButtonPressedFlag(); // 释放按键触发的中断标志位
setAlarmTime(userInputGetCurrentDateTime()); // 根据用户的选择设置新的闹钟时间
startTimer(); // 开启定时器循环
displaySetText(""); // 清除显示屏上的内容
displayClearDisplay(); // 清除显示屏上所有的字符
displayPrintf("%d", userInputGetCurrentDateTime().hour);
displayPrintf(":%d", userInputGetCurrentDateTime().minute);
displayPrintf(":%d", userInputGetCurrentDateTime().second);
displayPrintf(" ");
displayPrintf("%s", "Alarm Time");
displayPrintf(" %d ", getAlarmTime());
displayUpdateScreen(); // 刷新显示屏的内容
stopTimer(); // 关闭定时器循环
}
void buttonPressed() {
return !digitalRead(BUTTON); // 按扭传感器输出高电平即为按下按钮
}
void setAlarmTime(uint8_t time) {
uint8_t old_value = alarm_time;
alarm_time = time;
if (old_value == -1 && alarm_time != -1) { // 从未设闹钟变为设了闹钟
startTimer(); // 打开定时器循环
} else if (old_value != -1 && alarm_time == -1) { // 从有闹钟变成无闹钟
stopTimer(); // 关闭定时器循环
}
}
void startTimer() {
noInterrupts();
TCNT0 = (F_CPU / ALARM_CLOCK)/PRESCALE;
ICR1 |= _BV(ICIE1);
interrupts();
}
void stopTimer() {
noInterrupts();
IC1R &= ~(_BV(ICEN1));
interrupts();
}
以上是使用ATmega328p单片机的示例代码,其他型号的单片机也可以根据自己的实际情况进行相应的调整
|