一个简单的ESP8266WiFi时钟

首先,上效果图


你可能需要的准备


连线&安装NTPClient库

安装NTPClient库

这次我们选择NTPClient库,联网获取ntp时间。

项目地址

#获取UNIX时间戳
getEpochTime();

#获取当前时间
getFormattedTime();

#获取星期,0是星期日
getDay();


连线

  • D1 --- SDA
  • D2 --- SCL
  • 3V --- VCC
  • G --- GND

2089953529.png2089953529.png


代码

#include <Arduino.h>
#include <U8g2lib.h>
#include <time.h>
#include <SPI.h>
#include <Wire.h>
#include <NTPClient.h>
// change next line to use with another board/shield
#include <ESP8266WiFi.h>
//#include <WiFi.h> // for WiFi shield
//#include <WiFi101.h> // for WiFi 101 shield or MKR1000
#include <WiFiUdp.h>

#define SDA 05 //ESP8266 D1 PIN 05
#define SCL 04 //ESP8266 D2 PIN 04



const char *ssid     = "360 N7 Pro";
const char *password = "123456780";
char *week = "";


//SSD1306,128x64,全屏缓冲模式,模拟I2C,I2C,u8g2(旋转0度,时钟,数据,重置)
U8G2_SSD1306_128X64_NONAME_1_SW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE); 

WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "ntp1.aliyun.com",60*60*8, 30*60*1000);//设置访问的ntp服务器

void setup(){
  Serial.begin(115200);
  WiFi.begin(ssid, password);

  while ( WiFi.status() != WL_CONNECTED ) {
    delay ( 500 );
    Serial.print ( "." );
  }

  timeClient.begin();
  u8g2.begin();
  u8g2.enableUTF8Print();
}

void loop() {
  timeClient.update();
  u8g2.setFont(u8g2_font_unifont_t_chinese2);
  u8g2.firstPage();  
  do {
    u8g2.setCursor(0, 15);
    u8g2.print("北京时间:="); 
    u8g2.setCursor(0, 35);
    u8g2.print(timeClient.getFormattedTime()); 
    u8g2.setCursor(75, 35);
    switch(timeClient.getDay();){
      case 0:
            week = "Sun.";
            break;
      case 1:
            week = "Mon.";
            break;
      case 2:
            week = "Tues.";
            break;
      case 3:
            week = "Wed.";
            break;
      case 4:
            week = "Thur.";
            break;
      case 5:
            week = "Fri.";
            break;
      case 6:
            week = "Sat.";
            break;    
      }
    u8g2.print(week);  
    u8g2.setCursor(0, 55);
    time_t t;  
    struct tm *p;  
    t=timeClient.getEpochTime();  
    p=gmtime(&t);  
    char s[100];  
    //strftime(s, sizeof(s), "%Y-%m-%d %H:%M:%S", p);  
    strftime(s, sizeof(s), "%Y年%m月%d日", p);  
    u8g2.print(s);  
  } while ( u8g2.nextPage() );
  Serial.println(timeClient.getEpochTime());
  delay(1000);
}

ESP8266使用I2C连接OLDE屏幕

首先,上效果图

2019-12-29_122548.png2019-12-29_122548.png


你可能需要的前期准备


连线&安装OLED驱动库

1. 安装OLED驱动库

这次我们选择U8G2库,来驱动OLED屏幕。

项目地址 | wiki | 如何安装支持库

2. 连线

  • D1 --- SDA(数据)
  • D2 --- SCL(时钟)
  • 3V --- VCC
  • G --- GND

2089953529.png2089953529.png


代码

#include <Arduino.h>
#include <U8g2lib.h>
#include <SPI.h>
#include <Wire.h>


#define SDA 05 //ESP8266 D1 PIN 05
#define SCL 04 //ESP8266 D2 PIN 04

//SSD1306,128x64,全屏缓冲模式,模拟I2C,I2C,u8g2(旋转0度,时钟,数据,重置)
U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE);


void setup(void) {
  u8g2.begin();
  u8g2.enableUTF8Print();// 为 Arduino print() 函数启用UTF8支持
}

void loop(void) {  
  u8g2.clearBuffer();//清除当前Buffer内的像素
  u8g2.setFont(u8g2_font_ncenB08_tr);// 英文字库
  u8g2.setCursor(0, 10);
  u8g2.print("Hello World!");// 英文 "Hello World" 
  u8g2.setFont(u8g2_font_unifont_t_chinese2);// 中文支持 chinese2: Lerning Level 1-6
  u8g2.setCursor(0, 35);
  u8g2.print("你好世界!");// 中文 "Hello World" 
  u8g2.setFont(u8g2_font_b10_t_japanese2);// 日文支持 japanese1: Lerning Level 1-6
  u8g2.setCursor(0, 55);
  u8g2.print("こんにちは世界!");// 日语 "Hello World" 
  u8g2.setFont(u8g2_font_unifont_t_symbols);
  u8g2.drawUTF8(75, 35, "☀ ☁ ☂");
  u8g2.sendBuffer();//发送Buffer内容到屏上
  delay(1000); 
}

U8g2初始化(如何选择oled构造函数)

注意:U8g2不支持“无控制器”屏幕

U8g2驱动库构造函数

U8g2驱动库构造函数格式如下:

U8G2_ 屏幕控制器型号 _ 分辨率 _ 显示名称 _ 缓冲模式(1,2,F) _ 通讯方式 u8g2( 参数 );


例如:

//SSD1306,128x64,全屏缓冲模式,模拟I2C,I2C,u8g2(旋转0度,时钟,数据,重置)
U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE);

你可以点击这里查看已支持的显示控制器构造函数

标识符命名规则(C语言)

C语言标识符分三种:

  • 保留字(关键字)
  • 预定义标识符
  • 用户标识符

保留字(关键字)

C语言保留关键字(C99):

  • char 字符型
  • short 短整型
  • int 整形
  • unsigned 无符号整形
  • long 长整形
  • float 单精度浮点数
  • double 双精度浮点数
  • struct 结构体
  • union 共用体
  • void 字面意思是“无类型”,void *则为“无类型指针”,void *可以指向任何类型的数据。
  • enum 枚举类型
  • signed 有符号整形,默认省略。
  • const 限定一个变量不允许被改变,产生静态作用。
  • volatile 是一个特征修饰符,作用是作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值。
  • typedef 在计算机编程语言中用来为复杂的声明定义简单的别名,它与宏定义有些差异。它本身是一种存储类的关键字,与auto、extern、mutable、static、register等关键字不能出现在同一个表达式中。
  • auto 是一个C/C++语言存储类型,仅在语句块内部使用,初始化可为任何表达式,其特点是当执行流程进入该语句块的时候初始化可为任何表达式。
  • register 暗示编译程序相应的变量将被频繁地使用,如果可能的话,应将其保存在CPU的寄存器中,以加快其存储速度。
  • static 定义一个内部函数(关键字“static”,译成中文就是“静态的”,所以内部函数又称静态函数),函数的作用域仅局限于本文件,与面向对象的编程语言不同作用!
  • extern 可置于变量或者函数前,以表示变量或者函数的定义在别的文件中。提示编译器遇到此变量或函数时,在其它模块中寻找其定义。
  • break 其作用大多情况下是终止所在层的循环。在 C语言 的 switch(开关语句)中,break 语句还可用来在执行完一个 case(分支)后立即跳出当前 switch 结构。
  • switch 经常跟case一起使用,是一个判断选择代码。其功能就是控制流程流转的。
  • case 见上条
  • default 在c语言中与switch语句配套使用。
  • continue 表示结束本次循环,而不终止整个循环的执行。而是结束本次循环,进行下一次循环。
  • do 开始一层循环,需要和while配合使用。
  • if 分支结构的一种。
  • else 需要和if配合使用。
  • for 用于循环处理的语句。
  • goto 跳转到指定标号,其中标号需要申请,在对应的过程的申请的位置写label <标号>;其中,标号必须为byte型整数。
  • return 函数的返回值。
  • while 一种基本循环模式。当满足条件时进入循环,进入循环后,当条件不满足时,跳出循环。
  • sizeof 判断数据类型或者表达式长度的运算符。对 sizeof() 的处理都是在编译阶段进行。
  • _Bool 布尔类型
  • _Complex 复数类型,C99提供了三种复数类型:float_Complexdouble_Complexlong double_Complex
  • _Imaginary 虚数类型,C99提供了三种虚数类型:float_Imaginarydouble_Imaginary,以及 long double_Imaginary。虚数类型只有虚部,没有实部。
  • inline 内联函数,作用是将函数展开,把函数的源代码复制到每一个调用它的地方。在程序运行过程中可以直接执行函数代码,而不发生跳转、压栈等一般性函数操作。可以节省时间,也会提高程序的执行速度。注意:gcc编译器对其定义不同!
  • restrict 类型限定符,用于告诉编译器,对象已经被指针所引用,不能通过除该指针外所有其他直接或间接的方式修改该对象的内容。

预定义标识符

预定义标识符是C语言中有特定意义的标识符。预定义标识符也可以作为用户标识符使用,但是会导致原有功能丧失。非常不建议占用预定义标识符!

  • 一些常用函数,例如: printfscanfsin
  • 编译预处理命令名,例如: defineinclude

用户标识符

用户标识符一般是:

  • 自定义的变量
  • 自定义的函数名

用户标识符命名规则:

  1. 必须使用字母(A-Z和a-z)、数字(0-9)和下划线(_
  2. 不能以数字作为开头,但字母和下划线可以
  3. 不能是保留字(关键字)
  4. 大小写敏感,严格区分大小写