数码之家
标题:
[开源]用Esp01-m(esp8285、esp8266兼容)做一个简单实用的NTP同步时钟
[打印本页]
作者:
jjbboox
时间:
2020-6-1 10:48
标题:
[开源]用Esp01-m(esp8285、esp8266兼容)做一个简单实用的NTP同步时钟
本帖最后由 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
正面:
[attach]769451[/attach]
背面(跳线比较乱):
[attach]769450[/attach]
视频连接
ESP8285(Esp8266) NTP时钟
为了方便不愿意点外链的朋友,下面把所有的源码贴出
main.cpp(NTPClock_Esp8285.ino)
#include <NTPClient.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <Wire.h>
#include <TM1650.h>
#include "air_kiss_connect.h"
WiFiUDP ntpUDP;
#define NTP_SERVER_ADDR "ntp.sjtu.edu.cn" // NTP服务器地址,可自行修改
#define NTP_UPDATE_SECS (8*60*60) // 8小时同步一次时间
// NTP服务器地址和同步间隔时间
NTPClient timeClient(ntpUDP, NTP_SERVER_ADDR, NTP_UPDATE_SECS);
// 驱动数码管的TM1650的I2C总线端口
#define TM1650_SDA 9
#define TM1650_SCL 10
// 数码管小数点和冒号的数组下标
// 使用4位共阴带冒号的时钟数码管
// 不同型号的数码管点位不同,控制方式也会有所不同
#define TM1650_DOT_POS 0
#define TM1650_SEMICOLON_POS 1
// 数码管对象实例
TM1650 NixieTube(4);
// AirKissConnect的状态回调函数
void def_tick_fun(String str) {
static bool dot;
if(str.equalsIgnoreCase("START")) {
NixieTube.clear();
NixieTube.displayString("c---");
}
else if(str.equalsIgnoreCase("SMART")) {
NixieTube.clear();
NixieTube.displayString("s---");
}
else if(str.equalsIgnoreCase("Success")) {
NixieTube.clear();
NixieTube.displayString("done");
}
else if(str.equalsIgnoreCase(".")) {
dot = !dot;
NixieTube.setDot(TM1650_SEMICOLON_POS, dot);
}
}
void I2C_init(uint8_t sda_pin, uint8_t scl_pin) {
// TM1650 I2C总线设置为上拉
pinMode(sda_pin, INPUT_PULLUP);
pinMode(scl_pin, INPUT_PULLUP);
// 初始化并启动I2C总线
Wire.begin(sda_pin, scl_pin);
}
// 数码管显示剩余时间
void show_timer(NTPClient &ntp_time) {
// 显示缓存
char str[5];
// 打印显示字符串
sprintf(str, "%02d%02d", ntp_time.getHours(), ntp_time.getMinutes());
// 根据秒数的奇偶来切换":"显示
str[TM1650_SEMICOLON_POS] |= (ntp_time.getSeconds()%2)?0x80:0x00;
// 显示
NixieTube.displayString(str);
}
void show_start() {
uint8_t v = 0x01;
for(int d = 0; d < 4; d++) {
v = 1;
NixieTube.clear();
for(int i = 0; i < 7; i++) {
NixieTube.setPosition(d, v);
v <<= 1;
delay(50);
}
}
}
void setup(){
Serial.begin(115200);
Serial.println("Serial Init Ok!");
// 初始化I2C总线
I2C_init(TM1650_SDA, TM1650_SCL);
Serial.println("I2C init ok.");
// 初始化数码管
NixieTube.init();
Serial.println("NixieTube init ok.");
// 设置数码管亮度
NixieTube.setBrightness(3);
show_start();
Serial.println("Air kiss connect start.");
// 调用AirKissConnect配置无线网络,回调函数用来处理返回内容
air_kiss_connect(def_tick_fun);
// Wait for connection
if(WiFi.status() != WL_CONNECTED) {
Serial.println("Can not connect to WIFI!");
NixieTube.displayString("Err ");
}
else {
Serial.println("");
Serial.print("Connected to ");
Serial.println(WiFi.SSID());
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
// 启动NTP连接获取同步时间
timeClient.begin();
}
void clock_loop() {
static uint32_t time_out = 0; // 刷新时间控制
uint32_t now_mill = millis(); // 当前的系统时间
// 如果系统计时器溢出
if(now_mill >= time_out) {
// 设定下次刷新的时间点(1s以后再次刷新)
time_out = now_mill + 1000;
// 更新TNP时间
timeClient.update();
Serial.println(timeClient.getFormattedTime());
// 显示时间
show_timer(timeClient);
}
}
void loop() {
clock_loop();
}
复制代码
air_kiss.cpp
#include <Arduino.h>
#ifdef ESP32
#include <WiFi.h>
#else
#include <ESP8266WiFi.h>
#endif
#ifdef _USER_SSID_
const String ssid = "my_ssid_xxxx";
const String pwd = "my_wifi_password";
#endif
void air_kiss_connect(void (*tick_fun)(String))
{
int cnt = 0;
WiFi.mode(WIFI_STA);
#ifdef _USER_SSID_
WiFi.begin(ssid, pwd);
#else
WiFi.begin();
#endif
tick_fun("START");
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
tick_fun(".");
if (cnt++ >= 30)
{
tick_fun("SMART");
WiFi.beginSmartConfig();
while (true)
{
delay(1000);
if (WiFi.smartConfigDone())
{
tick_fun("Success");
// Serial.println("SmartConfig Success");
while (WiFi.status() != WL_CONNECTED);
break;
}
}
}
}
}
复制代码
air_kiss_connect.h
#ifndef _AIR_KISS_CONNECT_H_
#define _AIR_KISS_CONNECT_H_
void air_kiss_connect(void (*tick_fun)(String));
#endif
复制代码
作者:
worldlyguest
时间:
2020-6-1 10:59
收藏,感谢,有时间也来折腾个!:praise:
作者:
sunnyquan
时间:
2020-6-1 11:36
年纪大了,折腾代码有力不从心的感觉,,学了东忘记西。。
作者:
jjbboox
时间:
2020-6-1 11:37
TO:zidian
电路太简单了,没有事先画电路图,其实只要知道I2C的两个脚怎么接就可以了,其他连线都没什么歧义,有芯片的引脚定义就行了。
那我就随便画一个吧。
用excel简单画了一个电路图已添加到GitHub上了
/doc/电路图.xlsx
作者:
sunnyquan
时间:
2020-6-1 13:13
手上有D1 mini TM1637数码管模块,改天有空试下
作者:
jjbboox
时间:
2020-6-1 14:33
sunnyquan 发表于 2020-6-1 13:13
手上有D1 mini TM1637数码管模块,改天有空试下
一样的,大不了把tm1650的库改成适用的tm1637就行了。
欢迎光临 数码之家 (https://www.mydigit.cn/)
Powered by Discuz! X3.4