Arduino实验五:电子时钟
本文最后更新于 627 天前,其中的信息可能已经有所发展或是发生改变。
  • 实验目的:设计实现一个电子时钟,具备动态屏保显示/修改时间的功能。
  • 实验器材
  • mini遥控器一个
  • Irrecv 红外接收模块
  • 1602液晶显示屏
  • 蜂鸣器
  • Arduino Uno主板
  • Xbee传感器拓展板

接线示意图

实验现象:

  • 液晶显示屏以”年/月/日 时:分:秒 星期”的格式分两行显示时间
  • 遥控器
  •      1)电源键按下,显示屏熄屏/亮屏
  •      2)按下1,进入修改时间模式;再按1,显示修改后时间
  •      3)按下2,进入设定闹钟模式;再按2;保存闹钟并显示之前时间
  • 进入修改时间或设定闹钟模式时
  •     1)按vol+键可循环增加光标闪烁数位的值
  •     2)按左、右快进键可向左向右移动闪烁光标的位置
  • 当时间到达设定闹钟值,蜂鸣器开始闹铃
  • 温馨提示:请使用质量较好的遥控器以及红外接受器

功能实现分析:

首先是把整个过程分为三个部分:

  • 时钟显示和递增
  • 时间修改
  • 闹钟功能
  • 时间显示和递增

大致流程是时间变量的定义及初始化→显示屏打印时间变量→时间变量递增

后两步一直循环

关键点:变量递增的时候要考虑实际是否存在,以及进位。在每次打印后可以使用delay(1000)的方式来实现延迟一秒递增。

  • 时间修改

这个模块的实现大概要考虑这几个功能:

  • 信号接受的判断
  • 开启与关闭时间修改功能
  • 修改值(此处可以设计为仅仅使用vol+/-)

为了达到开关的效果,代码中会考虑用到bool变量来实现,并且设计为当bool变量为真时,在接受到对应的合理信号时才会变动

关键点:如何判断该调整哪一个数字?如何判断修改后的值是否合理?前者可以考虑用一个数组来描述坐标,后者自己加油吧!

  • 闹钟功能

其实在前两个模块写完之后,这个模块就显得比较简单了。可以考虑设置两组时间变量,一组是用来存储在进入闹钟模块前的时间,一组是用来存储闹钟的时间。

关键点:闹钟模块开启的时候应该顺带开启时间修改功能,从而把两个模块一起利用,减少代码量也提高效率。

  • 实验结果展示
  • 时间显示
  • 闹钟功能
  • 实验参考源码(写的比较垃圾的那种)
#include<LiquidCrystal_I2C.h>
#include <IRremote.hpp>
LiquidCrystal_I2C lcd(0x20,16,2);   //初始化lcd屏
#define IR_RECEIVE_PIN 10           //定义红外接受的接口

bool alarm_flag=false;
bool modify_flag=false;
bool light=false;  
int Y1,Y2,Y3,Y4;      //定义年份的四个数字变量
int alarm_pin=7;
int year;
int M1,M2;            //定义月
int D1,D2;            //定义日
int H1,H2;            //定义时
int MI1,MI2;          //定义分
int S1,S2;            //定义秒
int Date;             //定义周
int x,y;
int modifyIndex=0;
int pos[]={3,4,5,6,8,9,11,12,
           13,14,16,17,19,20,22};
int tY1,tY2,tY3,tY4,tM1,tM2,tD1,tD2,tH1,tH2,tMI1,tMI2,tS1,tS2;  //定义临时变量
int aY1,aY2,aY3,aY4,aM1,aM2,aD1,aD2,aH1,aH2,aMI1,aMI2,aS1,aS2;  //定义闹钟变量
void xblink(){
  lcd.setCursor(x,y);
  lcd.blink();
}

void xNoblink()
{
  lcd.noBlink();
}

void Show(){
  lcd.setCursor(3,0);
  lcd.print(Y1);
  lcd.print(Y2);
  lcd.print(Y3);
  lcd.print(Y4);
  lcd.print("/");
  lcd.print(M1);
  lcd.print(M2);
  lcd.print("/");
  lcd.print(D1);
  lcd.print(D2);
  lcd.setCursor(1,1);
  lcd.print(H1);
  lcd.print(H2);
  lcd.print(":");
  lcd.print(MI1);
  lcd.print(MI2);
  lcd.print(":");
  lcd.print(S1);
  lcd.print(S2);
  lcd.setCursor(10,1);
  switch(Date){
    case 1:lcd.print("Mon");
    break;
    case 2:lcd.print("Tue");
    break;
    case 3:lcd.print("Wes");
    break;
    case 4:lcd.print("Thu");
    break;
    case 5:lcd.print("Fri");
    break;
    case 6:lcd.print("Sat");
    break;
    case 7:lcd.print("Sun");
    break;
    default:lcd.print("Error");
  }
}

void tita(){
  S2++;
  if(S2==10){
    S1++;
    S2-=10;
  }
  if(S1==6){
    MI2++;
    S1-=6;
  }
  if(MI2==10){
    MI1++;
    MI2-=10;
  }
  if(MI1==6){
    H2++;
    MI1-=6;
  }
  if(H1<2&&H2==10){
    H1++;
    H2-=10;
  }
  if(H1==2&&H2==4){
    H1=0;
    H2=0;
    D2++;
    Date++;
  }
  if(Date==8)
  Date=1;
  if(M1==0)
  {
    if(M2==1||M2==3||M2==5||M2==7||M2==8)
    {
      if(D1<3&&D2==10)
      {
        D2++;
        D1=0;
      }
      if(D1==3&&D2==2)
      {
        D1=0;
        D2=1;
        M2++;
      }
    }
    if(M2==4||M2==6||M2==9)
    {
      if(D1<3&&D2==10)
      {
        D1++;
        D2=0;
      }
      if(D1==3&&D2==1)
      {
        D1=0;
        D2=1;
        M2++;
      }
    }
    if(M2==2)
    {
      if(runnian())
      {
        if(D1<3&&D2==10)
        {
          D1++;
          D2=0;
        }
        if(D1==3&&D2==0)
        {
          D1=0;
          D2=1;
          M2++;
        }
      }
      else
      {
        if(D1<2&&D2==10)
        {
          D1++;
          D2=0;
        }
        if(D1==2&&D2==9)
        {
          D1=0;
          D2=1;
          M2++;
        }
      }
    }
  }
  else if(M1==1)
  {
    if(M2==1)
    {
      if(D1<3&&D2==10)
      {
        D1++;
        D2=0;
      }
      if(D1==3&&D2==1)
      {
        D1=0;
        D2=1;
        M2++;
      }
    }
    if(M2==0)
    {
      if(D1<3&&D2==10)
      {
        D1++;
        D2=0;
      }
      if(D1==3&&D2==2)
      {
        D1=0;
        D2=1;
        M2++;
      }
    }
    if(M2==2)
    {
      if(D1<3&&D2==10)
      {
        D1++;
        D2=0;
      }
      if(D1==3&&D2==2)
      {
        D1=0;
        D2=1;
        M1=0;
        M2=1;
        Y4++;
      }
    }
  }
  if(Y4==10)
  {
    Y4=0;
    Y3++;
  }
  if(Y3==10)
  {
    Y3=0;
    Y2++;
  }
  if(Y2==10)
  {
    Y2=0;
    Y1++;
  }
  if(Y1==10)
  {
    Y1=0;
  }
}

void onoff(){
  if(light)
  {
    light=false;
    lcd.noBacklight();
  }
  else
  {
    light=true;
    lcd.backlight();
  }
}

void setup() {
  // put your setup code here, to run once:
  pinMode(alarm_pin,OUTPUT);             //设置蜂鸣器为输出
  lcd.init();                            // lcd 初始化,无参
  lcd.backlight();                       // lcd 背景灯常亮
  light=true;
  Serial.begin(9600);                    // 设置串口波特率
  IrReceiver.begin(IR_RECEIVE_PIN, ENABLE_LED_FEEDBACK);
  Y1=2,Y2=0,Y3=2,Y4=3;
  M1=1,M2=1;
  D1=2,D2=1;
  H1=0,H2=9;
  MI1=1,MI2=4;
  S1=0,S2=1;
  Date=2;
}
void alarm()    
{
  if(aY1==Y1&&aY2==Y2&&aY3==Y3&&aY4==Y4&&aM1==M1&&aM2==M2&&aD1==D1&&aD2==D2)
  { 
    if(aH1==H1&&aH2==H2&&aMI1==MI1&&aMI2==MI2&&aS1==S1&&aS2==S2)
    {
      tone(alarm_pin,300);
      delay(2500);
      noTone(alarm_pin);
    }
  }
}       //分两次判断可以减少运算量

int runnian(){
  year=Y1*1000+Y2*100+Y3*10+Y4;
  if(year%4==0&&year%100!=0)
  return 1;
  if(year%400==0)
  return 1;
  return 0;
}

void addtime(){
  if(y==0)            //光标在第一行時
  {
    switch(x)
    {
      case 3:         //修改年
      {
        Y1++;
        if(Y1>=10)
        Y1=0;
      }
      break;
      case 4:
      {
        Y2++;
        if(Y2>=10)
        Y2=0;
      }
      break;
      case 5: 
      {
        Y3++;
        if(Y3>=10)
        Y3=0;
      }
      break;
      case 6:
      {
        Y4++;
        if(Y4>=10)
        Y4=0;
      }
      break;
      case 8:           //修改月
      {
        M1++;
        if(M1>=2)
        M1=0;
      }
      break;
      case 9:
      {
        M2++;
        if(M1==1&&M2>=3)
        M2=0;
        if(M1==0&&M2>=10)
        M2=0;
      }
      break;
      case 11:      //修改第一个日
      {
        D1++;
        switch(M1*10+M2)
        {
          case 1:;
          case 3:;
          case 5:;
          case 7:;
          case 8:;
          case 10:;
          case 12:
          {
            if(D1>3)      //大月的情况
            D1=0;
            if(D1==3&&D2>1)
            D1=0;
          }
          break;
          case 4:;
          case 6:;
          case 9:
          case 11:              //小月的情况
          { 
            if(D1>3)
            D1=0;
            if(D1==3&&D2>0)
            D1=0;
          }
          break;
          case 2:
          {
            if(D1>2)
            D1=0;
            if(runnian())
            ;
            else
            {
              if(D1==2&&D2==9)
              D1=0;
            }
          }
          break;
        }
      }
      break;
      case 12:        //修改第二个日
      {
        D2++;
        switch(M1*10+M2)
        {
          case 1:;
          case 3:;
          case 5:;
          case 7:;
          case 8:;
          case 10:;
          case 12:
          {
            if(D1>=3)
            {
              if(D2>=2)
              D2=0;
            }
            else
            {
              if(D2>=10)
              D2=0;
            }
          }
          break;
          case 4:;
          case 6:;
          case 9:;
          case 11:
          {
            if(D1>=3)
            {
              if(D2>=1)
              D2=0;
            }
            else
            {
              if(D2>=10)
              D2=0;
            }
          }
          break;
          case 2:
          {
            if(runnian())
            {
              if(D2>=10)
              D2=0;
            }
            else
            {
              if(D1==2)
              {
                if(D2>=9)
                D2=0;
              }
              else
              {
                if(D2>=10)
                D2=0;
              }
            }
          }
          break;
        }
      }
      default:break;
    }
  }
  else if(y==1)              //光标在第二行時
  {
    switch(x)
    {
      case 1:       //修改時
      {
        H1++;
        if(H2>=5&&H1>=2)
        H1=0;
        if(H1>=3)
        H1=0;
      }
      break;
      case 2:
      {
        H2++;
        if(H1==2)
        {
          if(H2>=4)
          H2=0;
        }
        else
        {
          if(H2>=10)
          H2=0;
        }
      }
      
      break;
      case 4:       //修改分
      {
        MI1++;
        if(MI1>=6)
        MI1=0;
      }
      break;
      case 5:
      {
        MI2++;
        if(MI2>=10)
        MI2=0;
      }
      break;
      case 7:     //修改秒
      {
        S1=(S1+1)%6;
      }
      break;
      case 8:
      {
        S2++;
        if(S2>=10)
        S2=0;
      }
      break;
      case 10:
      {
        Date++;
        if(Date>=8)
        Date=1;
      }
      default:break;
    }
  }
  if(M1==0&&M2==0)
  M2=1;
  if(D1==0&&D2==0)
  D2=1;
  if(H1==0&&H2==0)
  H2=1;
  if(MI1==0&&MI2==0)
  MI2=1;
  if(S1==0&&S2==0)
  S2=1;
}

void loop() {
  // put your main code here, to run repeatedly:
  if(IrReceiver.decode())     //判断是否接收到信号
  {                
    Serial.println(IrReceiver.decodedIRData.decodedRawData, HEX);  //打印接收的红外信号到串口监视器
    if(IrReceiver.decodedIRData.decodedRawData==0xFF00BF00)       //接受电源信号;
    onoff();
    else if(IrReceiver.decodedIRData.decodedRawData==0xEF10BF00)    //接受到1信号
    {
      modifyIndex=0;                              //初始化数组索引
      modify_flag=!modify_flag;                   //取反,类似开关;
      if(modify_flag)
      {
        xblink();                                 //开始闪烁
        Serial.print("接受到1信号,进入修改时间模式");
      }
      else
      {
        xNoblink();                               //关闭闪烁
        modifyIndex=0;                            //初始化数组索引
      }
    }           
    else if(IrReceiver.decodedIRData.decodedRawData==0xFB04BF00)      //接受到左移
    {
      if(modify_flag)
      {
        xNoblink();
        modifyIndex=(modifyIndex+14)%15;    //坐标-1;
        x=pos[modifyIndex];
        if(x>12)        //如果横坐标到了逻辑上的第二行,则减去12的偏移,并设置纵坐标为1
        {
          x=x-12;
          y=1;
        }
        else
        {
          y=0;
        }
        xblink();
      }
    }             
    else if(IrReceiver.decodedIRData.decodedRawData==0xF906BF00)
    {
      if(modify_flag)   //接受到右移
      {
        xNoblink();
        modifyIndex=(modifyIndex+16)%15;    //坐标+1;
        x=pos[modifyIndex];
        if(x>12)
        {
          x=x-12;
          y=1;
        }
        else
        {
          y=0;
        }
        xblink();
      }
    }             
    else if(IrReceiver.decodedIRData.decodedRawData==0xFE01BF00) //接受到vol+
    {
      if(modify_flag)
      {
      addtime();
      Show();
      lcd.setCursor(x,y);
      }
    }             
    else if(IrReceiver.decodedIRData.decodedRawData==0xEE11BF00)      //接受到2信号
    {
      modifyIndex=0;                              //初始化数组索引
      alarm_flag=!alarm_flag;                   //取反,类似开关;
      if(alarm_flag)
      {
        xblink();                                 //开始闪烁
        Serial.print("接受到2信号,进入闹钟设置");
        modify_flag=true;
        tS1=S1;                                     //将时间存储至临时时间
        tS2=S2;
        tMI1=MI1;
        tMI2=MI2;
        tH1=H1;
        tH2=H2;
        tD1=D1;
        tD2=D2;
        tM1=M1;
        tM2=M2;
        tY1=Y1;
        tY2=Y2;
        tY3=Y3;
        tY4=Y4;
      }
      else
      {
        modify_flag=false;
        aS1=S1;                                     //将时间存储到闹钟
        aS2=S2;
        aMI1=MI1;
        aMI2=MI2;
        aH1=H1;
        aH2=H2;
        aD1=D1;
        aD2=D2;
        aM1=M1;
        aM2=M2;
        aY1=Y1;
        aY2=Y2;
        aY3=Y3;
        aY4=Y4;
        Y4=tY4;
        Y3=tY3;
        Y2=tY2;
        Y1=tY1;
        M1=tM1;
        M2=tM2;
        D1=tD1;
        D2=tD2;
        H1=tH1;
        H2=tH2;
        MI1=tMI1;
        MI2=tMI2;
        S1=tS1;
        S2=tS2;
        xNoblink();                               //关闭闪烁
        modifyIndex=0;                            //初始化数组索引
      }
    }
    IrReceiver.resume();
  }
  if(modify_flag);
  else
  {
  Show();           //打印时间
  delay(1000);      //延时1s
  tita();           //变量递增
  alarm();          //判断闹钟
  }
}
  • 实验反思
  • 能否在更改时间的时候时间继续走呢?
  • 能否实现多个闹钟设置存储呢?(考虑用数组)
  • 每次时间增加前延时设置为1000ms,真的合理吗?(考虑一下单片机的能力)
  • 就目前的器材,能否提高红外的灵敏呢?
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇