arduino教程——贪睡数字闹钟

5.UNO闹钟

点击此处alarm-clock.ino - Wokwi Arduino and ESP32 Simulator开始在线仿真
arduino教程——贪睡数字闹钟_第1张图片

该数字闹钟在4位7段显示屏上显示时间。它具有以下特点:

  • 两个按钮用于设置当前时间(小时/分钟)
  • 具有贪睡功能的可编程警报
  • 报警声音可以在代码中轻松自定义,甚至可以播放旋律
  • 冒号闪烁以指示秒数
  • 可选RTC,使时钟更精确
  • 断电恢复:当前时间和报警设置存储在RTC中

如何使用时钟

要设置时间,请按分钟/小时按钮。

按下警报按钮可启用/禁用警报。屏幕将通过显示单词"打开"或"关闭"来显示警报状态。

启用报警后,当前报警时间将显示几秒钟。您可以使用分钟/小时按钮来调整闹钟时间。要完成操作,请再次按"闹钟"按钮,或等待几秒钟。

当闹钟响起时,短按闹钟按钮可将其暂停 9 分钟。屏幕将显示四个圆圈,让您知道闹钟已打盹。

要停止闹钟,请按住闹钟按钮一秒钟或更长时间。

项目结构

该代码分为几个模块:

  1. config.h - 时钟的配置选项:是否使用RTC芯片,贪睡时间等。当程序中有多个模块时,使用配置文件是一种常见的做法。
  2. alarm-clock.ino - 主程序代码。它管理用户界面:7段显示器和按钮。
  3. 时钟 - 类管理当前时间和警报状态机。它使用RTClib库与RTC芯片通信并跟踪时间。Clock
  4. 闹钟铃声 - 班级播放闹钟声音。您可以更改数组的值,并自定义闹钟并播放不同的音调和旋律。AlarmTone``TONES``TONE_TIME``TONE_SPACING

硬件

项目 数量 笔记
Arduino Uno R3 1
4 位 7 段 4 通用阳极,14 引脚
220Ω 电阻器 8 连接到 7 段段引脚
PNP 晶体管 4 可选,推荐
4.7kΩ 电阻器 4 如果您使用PNP晶体管
12 毫米按钮 3
压电蜂鸣器 1 用于报警
DS1307 RTC 1 自选
  • 您还可以使用共阴极7段显示器,只需在config.h中调整常数,然后切换到NPN晶体管。DISPLAY_TYPE

为了将时钟硬件保持在最低限度,Arduino使用SevSeg库直接控制7段显示。但是,这种方法有一个缺点:它使用12个GPIO引脚!

如果要节省Arduino引脚,可以使用74HC595移位寄存器将引脚使用量减少到6个,甚至可以使用带有集成控制器芯片的7段显示器,例如TM1637HT16K33MAX7219。在这种情况下,您需要更改代码以使用不同的显示库(SevSeg 不支持这种情况),但这超出了本项目的范围。

引脚连接

Arduino Uno Pin Device Device Pin
2 7-Segment 14 (Dig 1)
3 7-Segment 11 (Dig 2)
4 7-Segment 10 (Dig 3)
5 7-Segment 6 (Dig 4)
6 7-Segment 13 (A)
7 7-Segment 9 (B)
8 7-Segment 4 ©
9 7-Segment 2 (D)
10 7-Segment 1 (E)
11 7-Segment 12 (F)
12 7-Segment 5 (G)
13 7-Segment 8 (Colon)
A0 Hour Button -
A1 Minute Button -
A2 Alarm Button -
A3 Buzzer / Speaker -
A4 DS1307 RTC SDA
A5 DS1307 RTC SCL
  • The pin numbers for your 7-segment display may differ. Please consult the datasheet relevant to your device to find out the relevant pin numbers.

代码

/**
   Arduino Digital Alarm Clock

   Copyright (C) 2020, Uri Shaked.
   Released under the MIT License.

*/

#include //数码管函数库
#include "Button.h"
#include "AlarmTone.h"
#include "Clock.h"
#include "config.h"

const int COLON_PIN = 13;
const int SPEAKER_PIN = A3;

Button hourButton(A0);
Button minuteButton(A1);
Button alarmButton(A2);

AlarmTone alarmTone;//闹钟音
Clock clock;//
SevSeg sevseg;//

enum DisplayState {//枚举显示时钟,时间等参数
  DisplayClock,
  DisplayAlarmStatus,
  DisplayAlarmTime,
  DisplayAlarmActive,
  DisplaySnooze,
};

DisplayState displayState = DisplayClock;
long lastStateChange = 0;

void changeDisplayState(DisplayState newValue) {
  displayState = newValue;
  lastStateChange = millis();
}//改变显示时间

long millisSinceStateChange() {
  return millis() - lastStateChange;
}

void setColon(bool value) {
  digitalWrite(COLON_PIN, value ? LOW : HIGH);
}//设置冒号

void displayTime() {
  DateTime now = clock.now();
  bool blinkState = now.second() % 2 == 0;
  sevseg.setNumber(now.hour() * 100 + now.minute());
  setColon(blinkState);
}

void clockState() {
  displayTime();

  if (alarmButton.read() == Button::RELEASED && clock.alarmActive()) {
    //读取alarmButton has_changed()以清除其状态
    alarmButton.has_changed();
    changeDisplayState(DisplayAlarmActive);
    return;
  }

  if (hourButton.pressed()) {
    clock.incrementHour();
  }//按键按下增加小时
  if (minuteButton.pressed()) {
    clock.incrementMinute();
  }
  if (alarmButton.pressed()) {
    clock.toggleAlarm();
    changeDisplayState(DisplayAlarmStatus);
  }
}

void alarmStatusState() {
  setColon(false);
  sevseg.setChars(clock.alarmEnabled() ? " on" : " off");
  if (millisSinceStateChange() > ALARM_STATUS_DISPLAY_TIME) {
    changeDisplayState(clock.alarmEnabled() ? DisplayAlarmTime : DisplayClock);
    return;
  }
}//闹钟开关

void alarmTimeState() {
  DateTime alarm = clock.alarmTime();
  sevseg.setNumber(alarm.hour() * 100 + alarm.minute(), -1);

  if (millisSinceStateChange() > ALARM_HOUR_DISPLAY_TIME || alarmButton.pressed()) {
    changeDisplayState(DisplayClock);
    return;
  }

  if (hourButton.pressed()) {
    clock.incrementAlarmHour();
    lastStateChange = millis();
  }
  if (minuteButton.pressed()) {
    clock.incrementAlarmMinute();
    lastStateChange = millis();
  }
  if (alarmButton.pressed()) {
    changeDisplayState(DisplayClock);
  }
}

void alarmState() {
  displayTime();//显示时间

  if (alarmButton.read() == Button::RELEASED) {
    alarmTone.play();//启动报警
  }
  if (alarmButton.pressed()) {
    alarmTone.stop();//按键按下报警结束
  }
  if (alarmButton.released()) {
    alarmTone.stop();//按键释放报警结束
    bool longPress = alarmButton.repeat_count() > 0;
    if (longPress) {//长按
      clock.stopAlarm();
      changeDisplayState(DisplayClock);
    } else {
      clock.snooze();//小盹模式
      changeDisplayState(DisplaySnooze);
    }
  }
}

void snoozeState() {//小盹模式
  sevseg.setChars("****");
  if (millisSinceStateChange() > SNOOZE_DISPLAY_TIME) {
    changeDisplayState(DisplayClock);
    return;
  }
}

void setup() {
  Serial.begin(115200);

  clock.begin();

  hourButton.begin();
  hourButton.set_repeat(500, 200);

  minuteButton.begin();
  minuteButton.set_repeat(500, 200);

  alarmButton.begin();
  alarmButton.set_repeat(1000, -1);

  alarmTone.begin(SPEAKER_PIN);

  pinMode(COLON_PIN, OUTPUT);

  byte digits = 4;
  byte digitPins[] = {2, 3, 4, 5};
  byte segmentPins[] = {6, 7, 8, 9, 10, 11, 12};
  bool resistorsOnSegments = false;
  bool updateWithDelays = false;
  bool leadingZeros = true;
  bool disableDecPoint = true;
  sevseg.begin(DISPLAY_TYPE, digits, digitPins, segmentPins, resistorsOnSegments,
               updateWithDelays, leadingZeros, disableDecPoint);
  sevseg.setBrightness(90);
}

void loop() {
  sevseg.refreshDisplay();

  switch (displayState) {
    case DisplayClock:
      clockState();
      break;

    case DisplayAlarmStatus:
      alarmStatusState();
      break;

    case DisplayAlarmTime:
      alarmTimeState();
      break;

    case DisplayAlarmActive:
      alarmState();
      break;

    case DisplaySnooze:
      snoozeState();
      break;
  }
}

结束

知命者不怨天,知己者不怨人。 – 淮南子 《淮南子》
arduino教程——贪睡数字闹钟_第2张图片

你可能感兴趣的:(单片机仿真,单片机,c语言,arduino)