IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 用ESP32+TM1638实验NTP网络校时闹钟的ARDUINO代码 -> 正文阅读

[嵌入式]用ESP32+TM1638实验NTP网络校时闹钟的ARDUINO代码

资源地址: ESP32+TM1638网络校时闹钟ARDUINO代码

? ? ? ? 之前买了块TM1638驱动的LED数码管显示模块,加上手头有块ESP32最小系统板,找根五芯线连接起来,趁这几天天气炎热,窝在家没事做,搞个带NTP网络校时功能的简单闹钟,就当没事练练手。

一、硬件配置。

? ? ? ? 下面先上图,左图是硬件连接和实验效果,除电源外,TM1638的三根信号线STB、CLK、DIO分别连接ESP32模块的GPIO14、GPIO26、GPIO32。右图则展示了功能设计方案。

???????

二、功能设计。

1、首先,本实验最重要的是时钟计时功能。要求在网络断开情况下可以正常计时,自由调校。而在网络连接情况下,可以通过NTP时间服务器进行校准。

2、充分利用TM1638显示模块上的资源,提供日期、时间、星期显示功能和时间、闹钟设置功能。

? ? ? ? 最上边的LED分别指示星期日到星期六,最后一只(右边)LED作为闹钟指示;8只数码管可以分时显示日期和时间;最下边的8个按键为功能键。

? ? ? ? 按“模式”键,8只数码管分别显示日期或时间;按“设置”键(与“模式”键配合),可以分别调整时间的“时”、“分”、“秒”或者调整日期的“年”、“月”、“日”(调整项会闪烁);“减键”和“加键”分别对调整的项目进行加减操作,并支持长按快速调整模式。“定闹”按键可以对当前时间设置/取消闹钟,而“清闹”按键会清除全部闹钟设置。按“配网”键,ESP32板载LED将闪烁,此时需打开微信公众号“安信可科技”进行配网,WIFI连接成功,ESP32板载LED将常亮(失败将熄灭)。按“同步”键,将自动连接NTP服务器进行时间校准。

3、关于闹钟,是本实验的一个附属功能,因为只是实验目的,功能相对简单。程序里用一个字符串保存闹钟数据(对定闹次数没有限制),但没有设计断电保存功能。定闹数据只保存“小时”和“分种”数据,不保存“秒钟”数据,故每个闹钟输出时长为一分钟,而输出也只是简单地通过一只LED进行显示,没有更进一步的音乐或电器控制设计,以避免系统复杂化。

三、软件环境。

? ? ? ? 本实验使用ARDUINO集成开发环境,相关软件及ESP32编译环境请自行百度。这里提供一个比较实用的资源:ARDUINO编译ESP32开发环境文件(注意只是开发环境,不包括ARDUINO软件,主要解决无法下载的问题)。

? ? ? ? 下面是本实验的全部代码资源:ESP32+TM1638网络校时闹钟ARDUINO代码

四、程序说明。

? ? ? ? 本程序使用ARDUINO软件编程,采用模块化设计,共四个文件:TM1638.C为显示驱动模块,提供LED灯珠、数码管、按键处理功能。TIMERS.C是时钟处理模块,用于设置和读取ESP32内部RTC时钟源,以及时区设置,NTP校时功能。ESP32OBJ.C则提供配网及WIFI连接功能。主程序NTP_TIME.INO整合各模块,进行初始化,并负责实现各设计功能。

? ? ? ? 下面贴出主程序NTP_TIME.INO代码:

#include <Arduino.h>
#include <WiFi.h>
#include "ESP32OBJ.C"
#include "TM1638.C"
#include "TIMERS.C"
ESP32OBJ esp32;
TM1638 tm1638;
USER_TIMERS timers;
uint8_t days[12]={31,28,31,30,31,30,31,31,30,31,30,31};
String dingShi="";//形如:"0000,1200,1530,2300";/*四个数字字符,前两个表示时,后两个表示分,定时之间用逗号隔开,默认没有定时*/
struct tm info;/*时间结构体*/
uint32_t keyUpTime=0;/*按键释放时间*/
uint32_t keyDownTime=0;/*按键按下时间*/
uint8_t dispMode=0;/*显示模式(0--显示时间;1--显示日期;2--显示星期)*/
uint8_t setMode=0;/*调整模式(0--正常状态;1--低位调整状态;2--中位调整状态;3--高位调整状态)*/
void setup ()
{
  Serial.begin(115200);
  esp32.begin();
  timers.begin();
  tm1638.begin(14,26,32);/*显示模块引脚设置*/
 }
void loop(){
  uint8_t key;uint8_t nowKey;
  if(millis()-keyUpTime>10000){dispMode=0;setMode=0;}/*10秒未操作自动转入时间显示状态,并取消调整状态。*/
  key=tm1638.key();
  if(key!=8){keyDownTime=millis();}/*如按下按键则记录按键时的系统时间*/
  if(dispMode!=0||setMode!=1){info=timers.getTime();}/*获取时间信息(校秒时不刷新)*/
  keySet(key);
  ScreenDisplay(false);
  while(key!=8){
    keyUpTime=millis();
    nowKey=tm1638.key();
    if(nowKey==8&&(key==1||setMode>0&&key>1&&key<4)){timers.setTime(info);break;}else{key=nowKey;}/*与调整有关的按键释放时更新时间,写入RTC*/
    if(keyUpTime-keyDownTime>1500){delay(100);if(key==2||key==3){keySet(key);}}/*按键1.5秒未释放,则进行长按键(只支持"加键"和"减键")连续处理)*/
    if(setMode==0){info=timers.getTime();}/*非调校状态即使按键未释放也会刷新时间*/
    ScreenDisplay(true);/*按键未释放状态不会闪烁*/
    ;
  }/*按键阻塞*/
}
void keySet(uint8_t key){
  /*按键处理函数*/
  switch(key){
    case 0:/*模式键*/
      dispMode=(dispMode+1)%2;
      setMode=0;
      break;  
    case 1:/*调整键*/
      if(dispMode<2){setMode=(setMode+1)%4;}
      break;
    case 2:/*减号键*/
      switch(setMode){
        case 1:/*调整低位*/
          switch(dispMode){
            case 0:/*秒减一*/
              if(info.tm_sec>0){info.tm_sec--;}else{info.tm_sec=59;}break;
            case 1:/*日减一*/
              if(info.tm_mday>1){info.tm_mday--;}else{info.tm_mday=days[info.tm_mon-1];if(info.tm_mon==2&&info.tm_year%4==0){info.tm_mday++;}}break;
          }break;
        case 2:/*调整中位*/
          switch(dispMode){
            case 0:/*分减一*/
              if(info.tm_min>0){info.tm_min--;}else{info.tm_min=59;}break;
            case 1:/*月减一*/
              if(info.tm_mon>1){info.tm_mon--;}else{info.tm_mon=12;}if(info.tm_mday>days[info.tm_mon-1]){info.tm_mday=days[info.tm_mon-1];if(info.tm_mon==2&&info.tm_year%4==0){info.tm_mday++;}}break;
          }break;
        case 3:/*调整高位*/
          switch(dispMode){
            case 0:/*时减一*/
              if(info.tm_hour>0){info.tm_hour--;}else{info.tm_hour=23;}break;
            case 1:/*年减一*/
              if(info.tm_year>1970){info.tm_year--;if(info.tm_year%4!=0&&info.tm_mon==2&&info.tm_mday>days[info.tm_mon-1]){info.tm_mday=days[info.tm_mon-1];}}break;
          }break;
      }
      break;  
    case 3:/*加号键*/
      switch(setMode){
        case 1:/*调整低位*/
          switch(dispMode){
            case 0:/*秒加1*/
              info.tm_sec=(info.tm_sec+1)%60;break;
            case 1:/*日加1*/
              info.tm_mday++;if(info.tm_mday>days[info.tm_mon-1]&&(info.tm_mon!=2||info.tm_year%4!=0||info.tm_mday>29)){info.tm_mday=1;}break;
          }break;
        case 2:/*调整中位*/
          switch(dispMode){
            case 0:/*分加一*/
              info.tm_min=(info.tm_min+1)%60;break;
            case 1:/*月加一*/
              info.tm_mon=info.tm_mon%12+1;if(info.tm_mday>days[info.tm_mon-1]){info.tm_mday=days[info.tm_mon-1];if(info.tm_mon==2&&info.tm_year%4==0){info.tm_mday++;}}break;
          }break;
        case 3:/*调整高位*/
          switch(dispMode){
            case 0:/*时加一*/
              info.tm_hour=(info.tm_hour+1)%24;break;
           case 1:/*年加一*/
              if(info.tm_year<2037){info.tm_year++;}if(info.tm_mon==2&&info.tm_year%4!=0&&info.tm_mday>days[info.tm_mon-1]){info.tm_mday=days[info.tm_mon-1];}break;
          }break;
      }
      break;  
    case 4:/*响铃设置*/alarmClock(info.tm_hour,info.tm_min,1);break;
    case 5:/*响铃清空*/dingShi="";break;
    case 6:/*配网键*/esp32.smartConfig();break;
    case 7:/*校时键*/timers.ntpUpdate();dispMode=0;setMode=0;break;
    default:/*默认操作*/break;  
  }
}
void ScreenDisplay(boolean mode){
  /*显示处理函数*/
  uint16_t tem;uint8_t i;uint16_t temtime;
  temtime=millis()%1000;
  switch(dispMode){
    case 1:/*显示日期*/
      tem=info.tm_year;
      for(i=0;i<4;i++){
        if(setMode!=3||temtime<500||mode){tm1638.display(3-i,tem%10);tem=tem/10;}else{tm1638.display(3-i,-1);tem=tem/10;}
      }
      tem=info.tm_mon;
      for(i=0;i<2;i++){
        if(setMode!=2||temtime<500||mode){tm1638.display(5-i,tem%10);tem=tem/10;}else{tm1638.display(5-i,-1);tem=tem/10;}
      }
      tem=info.tm_mday;
      for(i=0;i<2;i++){
        if(setMode!=1||temtime<500||mode){ tm1638.display(7-i,tem%10);tem=tem/10;}else{tm1638.display(7-i,-1);tem=tem/10;}
      }
      break;
    default:/*显示时间*/
      tm1638.display(2,16);tm1638.display(5,16);/*显示横线.*/
      tem=info.tm_hour;
      if(setMode!=3||temtime<500||mode){tm1638.display(0,tem/10);tm1638.display(1,tem%10);}else{tm1638.display(0,-1);tm1638.display(1,-1);}
      tem=info.tm_min;
      if(setMode!=2||temtime<500||mode){tm1638.display(3,tem/10);tm1638.display(4,tem%10);}else{tm1638.display(3,-1);tm1638.display(4,-1);}
      tem=info.tm_sec;
      if(setMode!=1||temtime<500||mode){tm1638.display(6,tem/10);tm1638.display(7,tem%10);}else{tm1638.display(6,-1);tm1638.display(7,-1);}
      break;
  }
  /*使用独立LED提示星期几,第一个LED表示星期日*/
  for(i=0;i<7;i++){
    if(info.tm_wday==i){tm1638.led(i,1);}else{tm1638.led(i,0);}
  }
  alarmClock(info.tm_hour,info.tm_min,0);
}
void alarmClock(uint16_t in_hour,uint16_t in_min,uint8_t in_mode){
  //根据小时和分钟数判断是否打开闹铃(每次响铃一分钟).
  //由于使用字符串保存定时数据,实际使用场景基本不用考虑定时控制的数量限制问题(可以使用24*60=1440个定时,字符串最长可达1440*5=7200个字节.).
  //由于没有使用闪存保存,所以断电或重启后定时数据将丢失.
  String temStr="";int i;
  temStr=temStr+char(in_hour/10+48)+char(in_hour%10+48)+char(in_min/10+48)+char(in_min%10+48);/*四个字符代表一个定时时间*/
  switch(in_mode){
    case 0:/*响铃判断*/
      if(dingShi.indexOf(temStr)==-1){tm1638.led(7,0);}else{tm1638.led(7,1);}/*这里可以更改定时控制方式,示例以最后一个LED亮灭为标志*/
      break;
    case 1:/*响铃设置*/
      i=dingShi.indexOf(temStr);
      if(i!=-1){
        /*已有此定时则删除*/
        if(i==0){
          if(dingShi==temStr){
            dingShi="";
          }else{
            dingShi=dingShi.substring(5);
          }
        }else{
          if(i==dingShi.length()-4){
            dingShi=dingShi.substring(0,dingShi.length()-5);
          }else{
            dingShi=dingShi.substring(0,i-1)+dingShi.substring(i+4);
          }
        }
      }else{
        /*没有此定时则添加*/
        if(dingShi==""){dingShi=temStr;}else{dingShi=dingShi+","+temStr;}
      }
      break;
  }
}

? ? ? ? 主要位置都作了中文注释,故不再对程序作进一步说明,请各位下载资源实验便可。这里要特别提醒大家的是,TIMERS.C中关于日期数据增加了修正,年号+1900自动调整为通常的表现形式,而月号也是加了1,时区修正使用的是configTime函数,第一个参数8*3600表示修正为北京时间(东八区)。整个程序只依赖ESP32基础库,不涉及第三方库引用。所有模块都是ARDUINO标准C语言程序,可以随意修改,增删功能。一切都由你自己掌控。

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-07-20 19:03:54  更:2022-07-20 19:04:29 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/18 15:23:33-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码