打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
用Arduino和DS1302时钟模块做个简易电子钟

今天更个ARDUINO从入门到创客带师第⑤弹 自制WIFI时钟 的简单番外,以前在实验室的时候刚入门的小白经常喜欢玩的用DS1302 DS1307+ATMEL332做外部时钟同步时间的简单教程

当然,还是基于ARDUINO

首先,关于ARDUINO咱就不用多说了吧,相信各位都懂是什么东西了,比51单片机先进,编程理念前卫,有封装好的库,小白非常容易上手搞制作之类的……

DS1302 芯片介绍

一个时钟芯片,可以设置和获取当前时间。 可以自动处理月份、闰年等信息。支持双电源,可以同时使用外接电源和电池同时供电。系统会自动选用电压较高的电源供电。一般模块接一个3v的纽扣电池, 联机使用接开发板上的外接电源,当外界电源断电后,就会使用纽扣电池供电。(然而模块不应该使用开发板上的5V电源,电压太高时钟会走的过快)

引脚定义

VCC1 和VCC2 ,双供电电源。 X1 和X2 接32768Hz晶振 SCLK和IO和RST共同完成通讯过程。 SCLK为通讯的时钟信号。当RST为高电平时,开始通讯。

写入逻辑

写入时间需要转换很多次的电平

读取也差不多少,总之是非常麻烦了

因此,ARDUINO环境带有了DS1302库 ,可以自动的来完成这种复杂重复的操作

#include <Wire.h>

#include <DS1302.h>

DS1302 rtc(2, 3, 4); // RST, DAT, CLK

void getdatetime()

{

Serial.println(rtc.getDateStr(FORMAT_LONG, FORMAT_LITTLEENDIAN, '/'));

Serial.print(rtc.getDOWStr());

Serial.print(" ");

Serial.println(rtc.getTimeStr());

}

void setup()

{

Serial.begin(9600);

// 设置时间后, 需要注释掉设置时间的代码,并重新烧录一次. 以免掉电重新执行setup中的时间设置函数.

rtc.halt(false);

rtc.writeProtect(false);

rtc.setDOW(SATURDAY);

rtc.setTime(17, 22, 30);

rtc.setDate(31, 12, 2016);

rtc.writeProtect(true);

}

void loop()

{

getdatetime();

delay(1000);

}

接线图

1602可以无视了,在这个项目中我们可以用串口监视器来读取时钟数据,老式1602显示屏现在哪还有人用了,上期我们都用12864显示日期时间了好吗

虽然ARDUINO也有对1602显示屏的库就是了

作为一个番外我们并不需要太长的篇幅,简单介绍一下就完事

简单编译上传成功之后我们打开串口监视器

emmmmmmm,看来这个代码定义的时钟的时间停在了2016年

简单改一下

rtc.writeProtect(false);

rtc.setDOW(TUESDAY);

rtc.setTime(21, 05, 30);

rtc.setDate(28, 1, 2020);

rtc.writeProtect(true);

PS:英语的星期月份:星期一 Monday 缩写:Mon. 星期二 Tuesday 缩写:Tues. 星期三 Wednesday 缩写:Wed. 星期四 Thursday 缩写:Thur./Thurs. 星期五 Friday 缩写:Fri. 星期六 Saturday 缩写:Sat. 星期日 Sunday 缩写:Sun. (2)月份: 第一栏为英语月份的缩写。 一月 Jan. January 二月 Feb. February 三月 Mar. March 四月 Apr. April 五月 May. May 六月 Jun. June 七月 Jul. July 八月 Aug. August 九月 Sept. September 十月 Oct. October 十一月 Nov. November 十二月 Dec. December

总之改好之后再上传一次

这次没问题了

记得把设置时间的代码注释之后再上传一次,不然每次单片机开发板重新上电都会把时钟模块的时间设置为代码上写死的时间

那么它有什么用呢?当然有用了,现在这个1307模块就有了相对准确的时间,可以执行现在我们需要的记录时间的功能了。当我们把电脑关机,单片机开发板断电的时候,1307时钟模块的时间还是准的,而且因为内置了纽扣电池,所以它的时间虽然可能走的不精确,但是续航非常长,因此作为早期小白娱乐向项目还是有点实用意义的。

上期改进后代码:

/* 作者:flyAkari 会飞的阿卡林 bilibili UID:751219

 * 本代码适用于ESP8266 NodeMCU + 12864显示屏

 * 7pin SPI引脚,正面看,从左到右依次为GND、VCC、D0、D1、RES、DC、CS

 *    ESP8266 ---  OLED

 *      3V    ---  VCC

 *      G     ---  GND

 *      D7    ---  D1

 *      D5    ---  D0

 *      D2orD8---  CS

 *      D1    ---  DC

 *      RST   ---  RES

 * 4pin IIC引脚,正面看,从左到右依次为GND、VCC、SCL、SDA

 *      ESP8266  ---  OLED

 *      3.3V     ---  VCC

 *      G (GND)  ---  GND

 *      D1(GPIO5)---  SCL

 *      D2(GPIO4)---  SDA

 */

#include <TimeLib.h>

#include <ESP8266WiFi.h>

#include <WiFiUdp.h>

#include <SPI.h>

#include <DYWiFiConfig.h>

#include <U8g2lib.h>

//U8G2_SSD1306_128X64_NONAME_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/4, /* dc=*/5, /* reset=*/3);

U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ 4, /* data=*/ 5);

DYWiFiConfig wificonfig;

ESP8266WebServer webserver(80);

#define DEF_WIFI_SSID     "D1"

#define DEF_WIWI_PASSWORD "01234567890"

#define AP_NAME "flyAkari" //dev

void wificb(int c)

{

  Serial.print("=-=-=-=-");

  Serial.println(c);

}

static const char ntpServerName[] = "ntp1.aliyun.com"; //NTP服务器,阿里云

const int timeZone = 8;                                //时区,北京时间为+8

WiFiUDP Udp;

unsigned int localPort = 8888; // 用于侦听UDP数据包的本地端口

time_t getNtpTime();

void sendNTPpacket(IPAddress& address);

void oledClockDisplay();

void sendCommand(int command, int value);

void initdisplay();

boolean isNTPConnected = false;

const unsigned char xing[] U8X8_PROGMEM = {

  0x00, 0x00, 0xF8, 0x0F, 0x08, 0x08, 0xF8, 0x0F, 0x08, 0x08, 0xF8, 0x0F, 0x80, 0x00, 0x88, 0x00,

  0xF8, 0x1F, 0x84, 0x00, 0x82, 0x00, 0xF8, 0x0F, 0x80, 0x00, 0x80, 0x00, 0xFE, 0x3F, 0x00, 0x00

};  /*星*/

const unsigned char liu[] U8X8_PROGMEM = { 

  0x40, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00,

  0x20, 0x02, 0x20, 0x04, 0x10, 0x08, 0x10, 0x10, 0x08, 0x10, 0x04, 0x20, 0x02, 0x20, 0x00, 0x00

};  /*六*/

void setup()

{

  Serial.begin(115200);

  while (!Serial)

    continue;

  Serial.println("NTP Clock oled version v1.1");

  Serial.println("Designed by flyAkari");

  initdisplay();

  u8g2.clearBuffer();

  u8g2.setFont(u8g2_font_unifont_t_chinese2);

  u8g2.setCursor(0, 14);

  u8g2.print("Waiting for WiFi");

  u8g2.setCursor(0, 30);

  u8g2.print("connection...");

  u8g2.setCursor(0, 47);

  u8g2.print("flyAkari");

  u8g2.setCursor(0, 64);

  u8g2.print("192.168.4.1");

  u8g2.sendBuffer();

  Serial.println("OLED Ready");

  Serial.print("Connecting WiFi...");

  wificonfig.begin(&webserver, "/");

  DYWIFICONFIG_STRUCT defaultConfig = wificonfig.createConfig();

  strcpy(defaultConfig.SSID, DEF_WIFI_SSID);

  strcpy(defaultConfig.SSID_PASSWORD, DEF_WIWI_PASSWORD);

  strcpy(defaultConfig.HOSTNAME, AP_NAME);

  strcpy(defaultConfig.APNAME, AP_NAME);

  wificonfig.setDefaultConfig(defaultConfig);

  wificonfig.enableAP();

  while (WiFi.status() != WL_CONNECTED)

  {

    wificonfig.handle();

    //Serial.println("Waiting for Connection...");

  }

  Serial.println("");

  Serial.println("WiFi connected");

  Serial.println("IP address: ");

  Serial.println(WiFi.localIP());

  Serial.println("Starting UDP");

  Udp.begin(localPort);

  Serial.print("Local port: ");

  Serial.println(Udp.localPort());

  Serial.println("waiting for sync");

  setSyncProvider(getNtpTime);

  setSyncInterval(30); //每300秒同步一次时间

  isNTPConnected = true;

}

time_t prevDisplay = 0;   //当时钟已经显示

void loop()

{

  if (timeStatus() != timeNotSet)

  {

    if (now() != prevDisplay)

    { //时间改变时更新显示

      prevDisplay = now();

      oledClockDisplay();

    }

  }

  wificonfig.handle();

}

void initdisplay()

{

  u8g2.begin();

  u8g2.enableUTF8Print();

}

void oledClockDisplay()

{

  int years, months, days, hours, minutes, seconds, weekdays;

  years = year();

  months = month();

  days = day();

  hours = hour();

  minutes = minute();

  seconds = second();

  weekdays = weekday();

  Serial.printf("%d/%d/%d %d:%d:%d Weekday:%d\n", years, months, days, hours, minutes, seconds, weekdays);

  u8g2.clearBuffer();

  u8g2.setFont(u8g2_font_unifont_t_chinese2);

  u8g2.setCursor(0, 14);

  if (isNTPConnected)

    u8g2.print("当前时间 (UTC+8)");

  else

    u8g2.print("无网络!"); //如果上次对时失败,则会显示无网络

  String currentTime = "";

  if (hours < 10)

    currentTime += 0;

  currentTime += hours;

  currentTime += ":";

  if (minutes < 10)

    currentTime += 0;

  currentTime += minutes;

  currentTime += ":";

  if (seconds < 10)

    currentTime += 0;

  currentTime += seconds;

  String currentDay = "";

  currentDay += years;

  currentDay += "/";

  if (months < 10)

    currentDay += 0;

  currentDay += months;

  currentDay += "/";

  if (days < 10)

    currentDay += 0;

  currentDay += days;

  u8g2.setFont(u8g2_font_logisoso24_tr);

  u8g2.setCursor(0, 44);

  u8g2.print(currentTime);

  u8g2.setCursor(0, 61);

  u8g2.setFont(u8g2_font_unifont_t_chinese2);

  u8g2.print(currentDay);

  u8g2.drawXBM(80, 48, 16, 16, xing);

  u8g2.setCursor(95, 62);

  u8g2.print("期");

  if (weekdays == 1)

    u8g2.print("日");

  else if (weekdays == 2)

    u8g2.print("一");

  else if (weekdays == 3)

    u8g2.print("二");

  else if (weekdays == 4)

    u8g2.print("三");

  else if (weekdays == 5)

    u8g2.print("四");

  else if (weekdays == 6)

    u8g2.print("五");

  else if (weekdays == 7)

    u8g2.drawXBM(111, 49, 16, 16, liu);

  u8g2.sendBuffer();

}

/*-------- NTP 代码 ----------*/

const int NTP_PACKET_SIZE = 48;     // NTP时间在消息的前48个字节里

byte packetBuffer[NTP_PACKET_SIZE]; // 输入输出包的缓冲区

time_t getNtpTime()

{

  IPAddress ntpServerIP;          // NTP服务器的地址

  while (Udp.parsePacket() > 0);  // 丢弃以前接收的任何数据包

  Serial.println("Transmit NTP Request");

  // 从池中获取随机服务器

  WiFi.hostByName(ntpServerName, ntpServerIP);

  Serial.print(ntpServerName);

  Serial.print(": ");

  Serial.println(ntpServerIP);

  sendNTPpacket(ntpServerIP);

  uint32_t beginWait = millis();

  while (millis() - beginWait < 1500)

  {

    int size = Udp.parsePacket();

    if (size >= NTP_PACKET_SIZE)

    {

      Serial.println("Receive NTP Response");

      isNTPConnected = true;

      Udp.read(packetBuffer, NTP_PACKET_SIZE); // 将数据包读取到缓冲区

      unsigned long secsSince1900;

      // 将从位置40开始的四个字节转换为长整型,只取前32位整数部分

      secsSince1900 = (unsigned long)packetBuffer[40] << 24;

      secsSince1900 |= (unsigned long)packetBuffer[41] << 16;

      secsSince1900 |= (unsigned long)packetBuffer[42] << 8;

      secsSince1900 |= (unsigned long)packetBuffer[43];

      Serial.println(secsSince1900);

      Serial.println(secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR);

      return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR;

    }

  }

  Serial.println("No NTP Response :-("); //无NTP响应

  isNTPConnected = false;

  return 0; //如果未得到时间则返回0

}

// 向给定地址的时间服务器发送NTP请求

void sendNTPpacket(IPAddress& address)

{

  memset(packetBuffer, 0, NTP_PACKET_SIZE);

  packetBuffer[0] = 0b11100011; // LI, Version, Mode

  packetBuffer[1] = 0;          // Stratum, or type of clock

  packetBuffer[2] = 6;          // Polling Interval

  packetBuffer[3] = 0xEC;       // Peer Clock Precision

  // 8 bytes of zero for Root Delay & Root Dispersion

  packetBuffer[12] = 49;

  packetBuffer[13] = 0x4E;

  packetBuffer[14] = 49;

  packetBuffer[15] = 52;

  Udp.beginPacket(address, 123); //NTP需要使用的UDP端口号为123

  Udp.write(packetBuffer, NTP_PACKET_SIZE);

  Udp.endPacket();

}

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
arduino+w5100获取网络时间采用12864液晶显示
深入学习 RTC时钟库 DS3231
OCROBOT ESP8266 WIFI模块之重新定义
制作一个Tello无人机的WiFi无线遥控器(ESP8266+Shield).源码分析上
基于arduino的心率检测仪
HC05蓝牙模块的使用
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服