数码之家

 找回密码
 立即注册
搜索
查看: 6426|回复: 5

[Arduino] [开源]用Esp01-m(esp8285、esp8266兼容)做一个简单实用的NTP同步时钟

[复制链接]
发表于 2020-6-1 10:48:26 | 显示全部楼层 |阅读模式
本帖最后由 jjbboox 于 2020-6-1 12:03 编辑

功能:       
       开机先显示一段数码管自检小动画
       然后自动连接无线网络(数码管显示[c---]),秒点闪烁
       如果是首次连接或者15秒内无法连接到上次使用的网络则进入自动配网状态,数码管显示[s---],此时可以用手机微信的安信可小程序配网
       配网成功后显示[done],连接成功后自动通过NTP服务器同步时间,同步成功后开始时间显示。
       配网成功后可以记住ssid和密码,下次开机除非无法连接,否则无需重新配网。
       NTP服务器和同步间隔时间可以自己设置,代码中为8小时,可按自己需求修改,除非使用局域网中NTP服务器,否则不建议将时间间隔设置得过小。
       只要把钟放在家里能连接到无线网络的地方,插上USB线就可以用。常年分秒不差。(Esp8266系列仅支持2.4G网络,5G的WiFi网络是连不上的)

硬件:
       Esp8266或者Esp8285(没用到什么特殊的端口,我用的是安信可的Esp-01M,主要是因为体积小,加上扩展板双列直插,方便上洞洞板罢了)
       TM1650(数码管驱动芯片)
       共阴4位时钟专用数码管(自带秒点)      
       引脚连接请参考/doc/Pin_Map.txt
       USB口使用的是淘宝买的micro USB小板,然后用1117-3.3降压以后给电路供电。
       使用TM1650驱动数码管,无需使用限流电阻,亮度可调,发色均匀。

开源代码:
       https://github.com/jjbboox/NTPClock_Esp8285

如果你还在使用老掉牙的Arduino IDE,请将main.cpp改名为NTPClock_Esp8285.ino,并将其他的*.h文件和*.cpp保存到ino相同的目录中即可

需要添加的Arduino库:
      NTPClient
      TM1650

正面:


背面(跳线比较乱):


视频连接
ESP8285(Esp8266) NTP时钟


为了方便不愿意点外链的朋友,下面把所有的源码贴出

main.cpp(NTPClock_Esp8285.ino)
  1. #include <NTPClient.h>
  2. #include <ESP8266WiFi.h>
  3. #include <WiFiUdp.h>
  4. #include <Wire.h>
  5. #include <TM1650.h>
  6. #include "air_kiss_connect.h"

  7. WiFiUDP ntpUDP;


  8. #define NTP_SERVER_ADDR   "ntp.sjtu.edu.cn" // NTP服务器地址,可自行修改
  9. #define NTP_UPDATE_SECS   (8*60*60)         // 8小时同步一次时间

  10. // NTP服务器地址和同步间隔时间
  11. NTPClient timeClient(ntpUDP, NTP_SERVER_ADDR, NTP_UPDATE_SECS);

  12. // 驱动数码管的TM1650的I2C总线端口
  13. #define TM1650_SDA  9
  14. #define TM1650_SCL  10

  15. // 数码管小数点和冒号的数组下标
  16. // 使用4位共阴带冒号的时钟数码管
  17. // 不同型号的数码管点位不同,控制方式也会有所不同
  18. #define TM1650_DOT_POS        0
  19. #define TM1650_SEMICOLON_POS  1

  20. // 数码管对象实例
  21. TM1650  NixieTube(4);

  22. // AirKissConnect的状态回调函数
  23. void def_tick_fun(String str) {
  24.   static bool dot;
  25.   if(str.equalsIgnoreCase("START")) {
  26.     NixieTube.clear();
  27.     NixieTube.displayString("c---");
  28.   }
  29.   else if(str.equalsIgnoreCase("SMART")) {
  30.     NixieTube.clear();
  31.     NixieTube.displayString("s---");
  32.   }
  33.   else if(str.equalsIgnoreCase("Success")) {
  34.     NixieTube.clear();
  35.     NixieTube.displayString("done");
  36.   }
  37.   else if(str.equalsIgnoreCase(".")) {
  38.     dot = !dot;
  39.     NixieTube.setDot(TM1650_SEMICOLON_POS, dot);
  40.   }
  41. }

  42. void I2C_init(uint8_t sda_pin, uint8_t scl_pin) {
  43.   // TM1650 I2C总线设置为上拉
  44.   pinMode(sda_pin, INPUT_PULLUP);
  45.   pinMode(scl_pin, INPUT_PULLUP);
  46.   
  47.   // 初始化并启动I2C总线
  48.   Wire.begin(sda_pin, scl_pin);
  49. }

  50. // 数码管显示剩余时间
  51. void show_timer(NTPClient &ntp_time) {
  52.   // 显示缓存
  53.   char str[5];
  54.   // 打印显示字符串
  55.   sprintf(str, "%02d%02d", ntp_time.getHours(), ntp_time.getMinutes());
  56.   // 根据秒数的奇偶来切换":"显示
  57.   
  58.   str[TM1650_SEMICOLON_POS] |= (ntp_time.getSeconds()%2)?0x80:0x00;
  59.   // 显示
  60.   NixieTube.displayString(str);
  61. }

  62. void show_start() {
  63.   uint8_t v = 0x01;
  64.   for(int d = 0; d < 4; d++) {
  65.     v = 1;
  66.     NixieTube.clear();
  67.     for(int i = 0; i < 7; i++) {
  68.       NixieTube.setPosition(d, v);
  69.       v <<= 1;
  70.       delay(50);
  71.     }
  72.   }
  73. }

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

  76.   Serial.println("Serial Init Ok!");
  77.   
  78.   // 初始化I2C总线
  79.   I2C_init(TM1650_SDA, TM1650_SCL);
  80.   
  81.   Serial.println("I2C init ok.");
  82.   // 初始化数码管
  83.   NixieTube.init();
  84.   Serial.println("NixieTube init ok.");
  85.   // 设置数码管亮度
  86.   NixieTube.setBrightness(3);
  87.   
  88.   show_start();
  89.   
  90.   Serial.println("Air kiss connect start.");
  91.   // 调用AirKissConnect配置无线网络,回调函数用来处理返回内容
  92.   air_kiss_connect(def_tick_fun);

  93.   // Wait for connection
  94.   if(WiFi.status() != WL_CONNECTED) {
  95.     Serial.println("Can not connect to WIFI!");
  96.     NixieTube.displayString("Err ");
  97.   }
  98.   else {
  99.     Serial.println("");
  100.     Serial.print("Connected to ");
  101.     Serial.println(WiFi.SSID());
  102.     Serial.print("IP address: ");
  103.     Serial.println(WiFi.localIP());
  104.   }
  105.   
  106.   // 启动NTP连接获取同步时间
  107.   timeClient.begin();  
  108. }

  109. void clock_loop() {
  110.   static uint32_t time_out = 0; // 刷新时间控制
  111.   uint32_t now_mill = millis(); // 当前的系统时间
  112.   
  113.   // 如果系统计时器溢出
  114.   if(now_mill >= time_out) {
  115.     // 设定下次刷新的时间点(1s以后再次刷新)
  116.     time_out = now_mill + 1000;
  117.     // 更新TNP时间
  118.     timeClient.update();

  119.     Serial.println(timeClient.getFormattedTime());
  120.     // 显示时间
  121.     show_timer(timeClient);
  122.   }
  123. }

  124. void loop() {
  125.   clock_loop();
  126. }
复制代码

air_kiss.cpp
  1. #include <Arduino.h>
  2. #ifdef ESP32
  3. #include <WiFi.h>
  4. #else
  5. #include <ESP8266WiFi.h>
  6. #endif

  7. #ifdef _USER_SSID_
  8. const String ssid = "my_ssid_xxxx";
  9. const String pwd = "my_wifi_password";
  10. #endif

  11. void air_kiss_connect(void (*tick_fun)(String))
  12. {
  13.     int cnt = 0;

  14.     WiFi.mode(WIFI_STA);

  15. #ifdef _USER_SSID_
  16.     WiFi.begin(ssid, pwd);
  17. #else
  18.     WiFi.begin();
  19. #endif
  20.     tick_fun("START");
  21.     while (WiFi.status() != WL_CONNECTED)
  22.     {
  23.         delay(500);
  24.         tick_fun(".");
  25.         if (cnt++ >= 30)
  26.         {
  27.             tick_fun("SMART");
  28.             WiFi.beginSmartConfig();
  29.             while (true)
  30.             {
  31.                 delay(1000);
  32.                 if (WiFi.smartConfigDone())
  33.                 {
  34.                     tick_fun("Success");
  35.                     // Serial.println("SmartConfig Success");
  36.                     while (WiFi.status() != WL_CONNECTED);
  37.                     break;
  38.                 }
  39.             }
  40.         }
  41.     }
  42. }
复制代码


air_kiss_connect.h
  1. #ifndef _AIR_KISS_CONNECT_H_
  2. #define _AIR_KISS_CONNECT_H_

  3. void air_kiss_connect(void (*tick_fun)(String));

  4. #endif
复制代码







本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

打赏

参与人数 3家元 +33 收起 理由
sunnyquan + 10
zidian + 8 电路图也上传一下吧
人艰不拆了 + 15

查看全部打赏

发表于 2020-6-1 10:59:36 | 显示全部楼层
收藏,感谢,有时间也来折腾个!:praise:
回复 支持 反对

使用道具 举报

发表于 2020-6-1 11:36:43 | 显示全部楼层
年纪大了,折腾代码有力不从心的感觉,,学了东忘记西。。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-6-1 11:37:29 | 显示全部楼层
TO:zidian

电路太简单了,没有事先画电路图,其实只要知道I2C的两个脚怎么接就可以了,其他连线都没什么歧义,有芯片的引脚定义就行了。
那我就随便画一个吧。
用excel简单画了一个电路图已添加到GitHub上了
/doc/电路图.xlsx
回复 支持 反对

使用道具 举报

发表于 2020-6-1 13:13:43 | 显示全部楼层
手上有D1 mini  TM1637数码管模块,改天有空试下
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-6-1 14:33:17 | 显示全部楼层
sunnyquan 发表于 2020-6-1 13:13
手上有D1 mini  TM1637数码管模块,改天有空试下

一样的,大不了把tm1650的库改成适用的tm1637就行了。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

APP|手机版|小黑屋|关于我们|联系我们|法律条款|技术知识分享平台

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2025-5-28 01:16 , Processed in 0.592801 second(s), 14 queries , Redis On.

Powered by Discuz!

© 2006-2025 MyDigit.Net

快速回复 返回顶部 返回列表