esp8266做led时钟 (用esp8266做离线时钟)

之前带大家用ESP8266制作了wifi遥控屏幕和wifi遥控小车,大家觉得怎么样呢?

好多朋友都说想要看网络时钟的制作教程。那我们今天就来用ESP8266和MAX7219来制作支持炫酷动画效果的网络时钟吧~

人人都能学会的人工智能ai实操课,esp8266可以当时钟芯片吗

接电后,自动联网获取最新的时间,并且还会实时更新时间,分秒不差~

人人都能学会的人工智能ai实操课,esp8266可以当时钟芯片吗

每过一段时间会滚动显示日期~

一、所需材料

  • ESP8266 NodeMCU开发板,售价低廉,性能强大
  • MAX7219 LED点阵显示屏模块
  • 随点阵屏模块赠送的杜邦线等附件

ESP8266: ESP8266是一个非常适合用于 物联网和家庭智能项目 的wifi模块。它的售价非常低廉,在某宝上一块 ESP8266开发板只要10几块钱

ESP8266的介绍和入门指南可以参见我上次写的这篇文章:十块钱入门物联网!ESP8266新手指南

人人都能学会的人工智能ai实操课,esp8266可以当时钟芯片吗

MAX7219:MAX7219是一种集成化的串行输入/输出显示驱动器,用它可以在LED点阵屏幕方便地显示你想要的内容。我买到的是4合1的MAX7219点阵模块,也只需十来块

MAX7219的介绍和入门指南可以参见我上次写的这篇文章:手把手教你用wifi控制显示屏!ESP8266实践指南(一)

人人都能学会的人工智能ai实操课,esp8266可以当时钟芯片吗

二、配置开发环境

首先参照我上次写的ESP8266新手指南,设置好基本环境:

手把手教你用wifi控制显示屏!ESP8266实践指南(一)

这里简单概括一下:

  • 安装串口芯片驱动(CH340或者CP2102)
  • 安装Arduino IDE
  • 安装用于Arduino IDE的ESP8266插件
  • 设置开发板型号并选择正确的COM口

三、接线

根据线路图,连接好ESP8266 NodeMCU模块和MAX7219点阵:

  • 3v3 接 VCC
  • GND 接 GND
  • D5 接 CLK
  • D7 接 DIN
  • D8 接 CS

人人都能学会的人工智能ai实操课,esp8266可以当时钟芯片吗

ESP8266与MAX7219接线图, 原图来自于etechpath

实际接线效果如图:

人人都能学会的人工智能ai实操课,esp8266可以当时钟芯片吗

ESP8266与MAX7219接线实物图

四、上传代码

将以下代码贴入Arduino IDE, 并修改wifi名词和密码:

人人都能学会的人工智能ai实操课,esp8266可以当时钟芯片吗

// source code modified from John Rogers @ https://github.com/K1WIZ/ESP8266-8x32-Matrix-clock
// copyright@OrangeZero 零度橙子 2020, all rights reserved
#include "Arduino.h"
#include <ESP8266WiFi.h>

WiFiClient client;

int day, month, year, dayOfWeek;
int summerTime = 0;
String date;

#define NUM_MAX 4

#define DIN_PIN D7
#define CS_PIN  D8
#define CLK_PIN D5

#include "max7219.h"
#include "fonts.h"
#define HOSTNAME "ESP-Clock"

// =======================================================================
// CHANGE YOUR CONFIG HERE:
// 在此处修改你的wifi名称和密码,注意ESP8266只支持2.4Gwifi!
// =======================================================================
const char* ssid     = "ssid";     // wifi名称,只支持2.4g
const char* password = "password";   // wifi密码

void setup() 
{
  Serial.begin(115200);
  initMAX7219();
  sendCmdAll(CMD_SHUTDOWN,1);
  sendCmdAll(CMD_INTENSITY,5);
  Serial.print("Connecting WiFi ");

  WiFi.begin(ssid, password);
  
  printStringWithShift("Connecting",15);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.print("MyIP: "); Serial.println(WiFi.localIP());
  printStringWithShift((String("  MyIP: ")+WiFi.localIP().toString()).c_str(), 15);
  delay(1500);
}


// =============================DEFINE VARS==============================
#define MAX_DIGITS 20
byte dig[MAX_DIGITS]={0};
byte digold[MAX_DIGITS]={0};
byte digtrans[MAX_DIGITS]={0};
int updCnt = 0;
int dots = 0;
long dotTime = 0;
long clkTime = 0;
int dx=0;
int dy=0;
byte del=0;
int h,m,s;
float utcOffset = +8;  // 时区,中国是东八区,保持原样即可。如果你在海外,需要改成正确的时区。
long localEpoc = 0;
long localMillisAtUpdate = 0;
// =======================================================================
void loop()
{
  if(updCnt<=0) { // every 10 scrolls, ~450s=7.5m
    updCnt = 60;
    Serial.println("Getting data ...");
    printStringWithShift("   Setting Time...",15);
    getTime();
    Serial.println("Data loaded");
    clkTime = millis();
  }
 
  if(millis()-clkTime > 60000 && !del && dots) { // clock for 30s, then scrolls for about 30s
    printStringWithShift(date.c_str(),40);
    delay(2000);
    updCnt--;
    clkTime = millis();
  }
  if(millis()-dotTime > 500) {
    dotTime = millis();
    dots = !dots;
  }
  updateTime();
  showAnimClock();
}

// =======================================================================

void showSimpleClock()
{
  dx=dy=0;
  clr();
  showDigit(h/10,  0, dig6x8);
  showDigit(h%10,  8, dig6x8);
  showDigit(m/10, 17, dig6x8);
  showDigit(m%10, 25, dig6x8);
  showDigit(s/10, 34, dig6x8);
  showDigit(s%10, 42, dig6x8);
  setCol(15,dots ? B00100100 : 0);
  setCol(32,dots ? B00100100 : 0);
  refreshAll();
}

// =======================================================================

void showAnimClock()
{
  byte digPos[6]={0,8,17,25,34,42};
  int digHt = 12;
  int num = 6; 
  int i;
  if(del==0) {
    del = digHt;
    for(i=0; i<num; i++) digold[i] = dig[i];
    dig[0] = h/10 ? h/10 : 10;
    dig[1] = h%10;
    dig[2] = m/10;
    dig[3] = m%10;
    dig[4] = s/10;
    dig[5] = s%10;
    for(i=0; i<num; i++)  digtrans[i] = (dig[i]==digold[i]) ? 0 : digHt;
  } else
    del--;
  
  clr();
  for(i=0; i<num; i++) {
    if(digtrans[i]==0) {
      dy=0;
      showDigit(dig[i], digPos[i], dig6x8);
    } else {
      dy = digHt-digtrans[i];
      showDigit(digold[i], digPos[i], dig6x8);
      dy = -digtrans[i];
      showDigit(dig[i], digPos[i], dig6x8);
      digtrans[i]--;
    }
  }
  dy=0;
  setCol(15,dots ? B00100100 : 0);
  setCol(32,dots ? B00100100 : 0);
  refreshAll();
  delay(30);
}

// =======================================================================

void showDigit(char ch, int col, const uint8_t *data)
{
  if(dy<-8 | dy>8) return;
  int len = pgm_read_byte(data);
  int w = pgm_read_byte(data + 1 + ch * len);
  col += dx;
  for (int i = 0; i < w; i++)
    if(col+i>=0 && col+i<8*NUM_MAX) {
      byte v = pgm_read_byte(data + 1 + ch * len + 1 + i);
      if(!dy) scr[col + i] = v; else scr[col + i] |= dy>0 ? v>>dy : v<<-dy;
    }
}

// =======================================================================

void setCol(int col, byte v)
{
  if(dy<-8 | dy>8) return;
  col += dx;
  if(col>=0 && col<8*NUM_MAX)
    if(!dy) scr[col] = v; else scr[col] |= dy>0 ? v>>dy : v<<-dy;
}

// =======================================================================

int showChar(char ch, const uint8_t *data)
{
  int len = pgm_read_byte(data);
  int i,w = pgm_read_byte(data + 1 + ch * len);
  for (i = 0; i < w; i++)
    scr[NUM_MAX*8 + i] = pgm_read_byte(data + 1 + ch * len + 1 + i);
  scr[NUM_MAX*8 + i] = 0;
  return w;
}

// =======================================================================
int dualChar = 0;

unsigned char convertPolish(unsigned char _c)
{
  unsigned char c = _c;
  if(c==196 || c==197 || c==195) {
    dualChar = c;
    return 0;
  }
  if(dualChar) {
    switch(_c) {
      case 133: c = 1+'~'; break; // 'ą'
      case 135: c = 2+'~'; break; // 'ć'
      case 153: c = 3+'~'; break; // 'ę'
      case 130: c = 4+'~'; break; // 'ł'
      case 132: c = dualChar==197 ? 5+'~' : 10+'~'; break; // 'ń' and 'Ą'
      case 179: c = 6+'~'; break; // 'ó'
      case 155: c = 7+'~'; break; // 'ś'
      case 186: c = 8+'~'; break; // 'ź'
      case 188: c = 9+'~'; break; // 'ż'
      //case 132: c = 10+'~'; break; // 'Ą'
      case 134: c = 11+'~'; break; // 'Ć'
      case 152: c = 12+'~'; break; // 'Ę'
      case 129: c = 13+'~'; break; // 'Ł'
      case 131: c = 14+'~'; break; // 'Ń'
      case 147: c = 15+'~'; break; // 'Ó'
      case 154: c = 16+'~'; break; // 'Ś'
      case 185: c = 17+'~'; break; // 'Ź'
      case 187: c = 18+'~'; break; // 'Ż'
      default:  break;
    }
    dualChar = 0;
    return c;
  }    
  switch(_c) {
    case 185: c = 1+'~'; break;
    case 230: c = 2+'~'; break;
    case 234: c = 3+'~'; break;
    case 179: c = 4+'~'; break;
    case 241: c = 5+'~'; break;
    case 243: c = 6+'~'; break;
    case 156: c = 7+'~'; break;
    case 159: c = 8+'~'; break;
    case 191: c = 9+'~'; break;
    case 165: c = 10+'~'; break;
    case 198: c = 11+'~'; break;
    case 202: c = 12+'~'; break;
    case 163: c = 13+'~'; break;
    case 209: c = 14+'~'; break;
    case 211: c = 15+'~'; break;
    case 140: c = 16+'~'; break;
    case 143: c = 17+'~'; break;
    case 175: c = 18+'~'; break;
    default:  break;
  }
  return c;
}

// =======================================================================

void printCharWithShift(unsigned char c, int shiftDelay) {
  c = convertPolish(c);
  if (c < ' ' || c > '~'+25) return;
  c -= 32;
  int w = showChar(c, font);
  for (int i=0; i<w+1; i++) {
    delay(shiftDelay);
    scrollLeft();
    refreshAll();
  }
}

// =======================================================================

void printStringWithShift(const char* s, int shiftDelay){
  while (*s) {
    printCharWithShift(*s, shiftDelay);
    s++;
  }
}
// =======================================================================

void getTime()
{
  WiFiClient client;
  if (!client.connect("www.baidu.com", 80)) {
    Serial.println("connection to baidu failed");
    return;
  }

  client.print(String("GET / HTTP/1.1\r\n") +
               String("Host: www.baidu.com\r\n") +
               String("Connection: close\r\n\r\n"));
  int repeatCounter = 0;
  while (!client.available() && repeatCounter < 10) {
    delay(500);
    //Serial.println(".");
    repeatCounter++;
  }

  String line;
  client.setNoDelay(false);
  while(client.connected() && client.available()) {
    line = client.readStringUntil('\n');
    line.toUpperCase();
    if (line.startsWith("DATE: ")) {
      date = "     "+line.substring(6, 22);
      date.toUpperCase();
//      decodeDate(date);
      h = line.substring(23, 25).toInt();
      m = line.substring(26, 28).toInt();
      s = line.substring(29, 31).toInt();
      summerTime = checkSummerTime();
        if(h+utcOffset+summerTime>23) {
          if(++day>31) { day=1; month++; };  // needs better patch
          if(++dayOfWeek>7) dayOfWeek=1; 
        }
      localMillisAtUpdate = millis();
      localEpoc = (h * 60 * 60 + m * 60 + s);
    }
  }
  client.stop();
}

// =======================================================================

int checkSummerTime()
{
  if(month>3 && month<10) return 1;
  if(month==3 && day>=31-(((5*year/4)+4)%7) ) return 1;
  if(month==10 && day<31-(((5*year/4)+1)%7) ) return 1;
  return 0;
}
// =======================================================================

// =======================================================================

void updateTime()
{
  long curEpoch = localEpoc + ((millis() - localMillisAtUpdate) / 1000);
  long epoch = int( curEpoch + 3600 * ( utcOffset + summerTime ) + 86400L ) % 86400L;
  h = ((epoch  % 86400L) / 3600) % 24;
  m = (epoch % 3600) / 60;
  s = epoch % 60;
}

// =======================================================================

点击按钮,上传代码到ESP8266:

人人都能学会的人工智能ai实操课,esp8266可以当时钟芯片吗

稍等片刻,上传完成,屏幕开始显示信息,待时间获取成功后,我们的网络时钟就完成啦~

只要用USB线接上一个充电宝,就可以把他放在任意位置当一个真正的时钟啦~

默认显示时间,每隔一小会儿,会滚动显示日期。在时间变幻的时候,还有翻页效果~

人人都能学会的人工智能ai实操课,esp8266可以当时钟芯片吗

大家有没有觉得一点都不难,而且成就感满满呢~

大家有什么还有什么想要做的物联网或者智能家居项目呢?在下面留言告诉我吧~

我是零度橙子,科技达人,谷歌认证云计算架构师,AWS认证devops专家,大家可以关注我,了解有用有趣的科技知识~