| 
 | 
 
 
 本帖最后由 慕名而来 于 2021-8-27 18:03 编辑  
 
接上篇:浅谈编程菜鸟与arduino-esp8266之间的那些事【二】https://www.mydigit.cn/thread-272594-1-1.html(出处: 数码之家) 
尾篇——我的esp8266校时时钟方案 
前一篇已经分析了网上常见的校时时钟方案,但是我总是感觉除了本坛朋友发的几个LED数码或点阵屏的时钟(天气)有实用性以外,其他很多都是用于演示的,关于网络校时时钟是否需要含有RTC时钟芯片有各种说法,但是我认为还是加一片RTC好些,对于点阵屏显示或者是TFT彩屏显示的时钟,其耗电量都不适合电池供电,通过适配器供电的设备难免遇有停电或断网,因此我觉得电路中加一片RTC会稳妥些,更为主要的是因为不是做商品设计需要斤斤计较、自己玩耍硬件加几元钱成本也无可厚非,我的方案如下: 
 
 
 
方案中我的显示屏为5”TFT彩屏、16位并口总线,用esp8266直接驱动16位并口总线至少我是弄不了的,所以我外加了一片STC8A8K64S4A12-LQFP44单片机来驱动TFT。 
方案中因为使用RTC芯片来传递数据,使原有的MCU控制程序不用任何变动,而arduino的编程也变得非常简单,所以,我的方案非常适合为已有时钟添加wifi校时功能并且只需要MCU提供一个I/O口用于启动校时即可,如下图所示: 
 
 
代码须知: 
1.代码用于esp8266+DS3231的控制,需要时请通过arduino ide编译下载到esp8266之中,以下代码用于串口演示,如果你的esp8266已经连接了DS3231并且已经供电,那么,代码下载完成后打开串口监视器并调整波特率为9600,应该可以看到时间显示,并且每按动一次8266的复位键可以显示一次时间(也包含wifi配置信息)。 
2.本程序应用时有一个重要的问题需要注意!!!,你的esp8266模块在下载本程序之前如果曾经正常连接过你的wifi,那么就可以直接工作了,如果没有连接过wifi则需要在你的手机中找到名字为esp8266(密码:esp@wifi)的热点AP这是本程序生成的wifi配置界面,可以根据程序中的名称、密码进行登陆,登陆成功后可以在手机上配置并保存配置信息,如果手机中总是不能出现这个热点,就请查找其他原因吧,这方面我真的知之甚少无法提供帮助,而我的代码在我应用的时候经过一次配置后也就不再出现需要登陆的情况所以我也就没有再行测试。 
3.本程序应用需要有WiFiManager 和ESP8266HTTPClient库文件,如果缺少可以在arduino ide内下载安装。 
4.esp8266的I2C引脚连接详见程序内的标注提示。 
5.如果不是做串口演示而用于实际控制时,可以注释掉主函数中的所有相关串口输出的代码,而DS3231_ESP中用不到的函数及函数声明也可以注释掉。 
6.代码中的D6、D7端口功能可以根据自己的需要可用可不用,不用的时候与其相关的代码可以删除。 
 
代码如下: 
 
- /**
 
 -  * 代码原创:wannenggong
 
 -  * 代码仅用于演示
 
 -  * 未经同意请勿转载
 
 -  * 使用代码请注明出处
 
 - **/
 
 - #include <ESP8266WiFi.h>
 
 - #include <ESP8266HTTPClient.h>
 
 - #include <WiFiManager.h>
 
 - #include "DS3231_ESP.h"
 
  
- #define URL "http://quan.suning.com/getSysTime.do"//苏宁的时间api
 
 - extern unsigned char time_dat[];
 
 - extern unsigned char timeBcd[];
 
  
- unsigned char error_count = 0; //失败次数
 
 - String acquire;
 
  
- //--------------------------------
 
 - //网络时间获取与DS3231时间寄存器更新函数
 
 - void get_time() 
 
 - {
 
 -   int httpcode;//状态码
 
 -     HTTPClient httpclient;
 
 -     httpclient.setTimeout(1000);//超时时间
 
 -     while (1) 
 
 -     {
 
 -       httpclient.begin(URL);//开始连接
 
 -       httpcode = httpclient.GET();//获取状态码
 
 -       if (httpcode == 200)  //如果成功
 
 -       {
 
 -       delay(100);
 
 -       //获取网络时间
 
 -       /**报文格式:{"sysTime2":"2021-08-17 20:17:48","sysTime1":"20210817201748"}**/
 
 -       acquire = httpclient.getString();
 
 -       //拆分提取年、月、日、时、分、秒的char数据
 
 -       //分别提取十位、个位的数值并组合两位数
 
 -       //组合后的数据转换成ascⅡ数值
 
 -       time_dat[6] =(DecToBcd((acquire.charAt(15)-0x30)*10+(acquire.charAt(16)-0x30)));//年
 
 -       time_dat[5] =(DecToBcd((acquire.charAt(18)-0x30)*10+(acquire.charAt(19)-0x30)));//月
 
 -       time_dat[4] =(DecToBcd((acquire.charAt(21)-0x30)*10+(acquire.charAt(22)-0x30)));//日
 
 -       time_dat[3]=3;//报文中没有星期数据,这里预置任意值由MCU的C51程序予以更正
 
 -       time_dat[2] =(DecToBcd((acquire.charAt(24)-0x30)*10+(acquire.charAt(25)-0x30)));//时
 
 -       time_dat[1] =(DecToBcd((acquire.charAt(27)-0x30)*10+(acquire.charAt(28)-0x30)));//分
 
 -       time_dat[0] =(DecToBcd((acquire.charAt(30)-0x30)*10+(acquire.charAt(31)-0x30)));//秒
 
 -   
 
 -       write_DS3231();//更新DS3231时间寄存器、校准时间
 
 -       delay(1000);
 
 -       read_DS3231();//读出DS3231时间数据用于演示
 
 -       delay(1000);
 
 -       usart_out();//串口输出演示效果、按一次复位键更新一次显示时间      
 
 -       delay(1000);
 
 -       digitalWrite(D6, HIGH);//校时成功时清除两个端口的提示状态
 
 -       digitalWrite(D7, HIGH);
 
 -       httpclient.end();//断开连接(一定要断开,否则会出问题)
 
 -       WiFi.forceSleepBegin();//开始wifi睡眠
 
 -       delay(5000);
 
 -       ESP.deepSleep(0);//开始esp8266深度睡眠(由复位键唤醒)      
 
 -       break;
 
 -       } 
 
 -       else 
 
 -       {     
 
 -       httpclient.end();//断开连接
 
 -       delay(100);
 
 -       error_count++;
 
 -         if(error_count>50)
 
 -         {
 
 -         error_count=0;
 
 -         digitalWrite(D6,LOW);//D6口低电平提示读取时间失败等待下一次校时
 
 -         delay(5000);        
 
 -         ESP.deepSleep(0);//经过50次操作后仍然不能联网获取时间则放弃校时使模块休眠 
 
 -         }
 
 -       }
 
 -     }
 
 - }
 
 - //--------------------------------------------------------
 
 - //wifi连接函数
 
 - void wifi_connect()
 
 - {
 
 -     unsigned char f=0;
 
 -     delay(10);
 
 -     WiFiManager wifiManager;//建立一个对象
 
 -     if(WiFi.status() == WL_CONNECTED)//wifi连接成功时会由autoConnect()返回标志
 
 -     {
 
 -       f=1;
 
 -     }
 
 -     if(f!=1)//如果wifi连接不成功则标志维持初始0状态不变
 
 -     {
 
 -       digitalWrite(D7, LOW);//D7口低电平提示wifi连接失败   
 
 -       Serial.println("WiFi connected_fail");//连接失败
 
 -       wifiManager.autoConnect("esp8266","esp@wifi");//建立无线AP
 
 -       if(WiFi.status() == WL_CONNECTED)//判断连接状态、如果成功则置位标志
 
 -       f=1;
 
 -     }
 
 -     if(f==1)
 
 -     {
 
 -       Serial.println("WiFi connected_ok");//串口显示wifi连接成功 
 
 -       get_time();
 
 -     }
 
 - }
 
 - //-------------------------------------------------------
 
 - //串口输出函数(用于演示)
 
 - void usart_out()
 
 - {
 
 -     Serial.print(timeBcd[6], HEX); 
 
 -     Serial.print("/");
 
 -     Serial.print(timeBcd[5], HEX); 
 
 -     Serial.print("/"); 
 
 -     Serial.print(timeBcd[4], HEX);
 
 -     Serial.print("/");
 
 -     Serial.print(timeBcd[3]);
 
 -     Serial.print(" ");
 
 -     Serial.print(timeBcd[2], HEX); 
 
 -     Serial.print(":");
 
 -     Serial.print(timeBcd[1], HEX); 
 
 -     Serial.print(":");
 
 -     Serial.println(timeBcd[0], HEX);//此处换行 
 
 -     delay(1000);
 
 - }
 
 - //------------------------------------------------------
 
 - void setup()
 
 - {
 
 -   Serial.begin(9600);
 
 -   Wire.begin();//使能I2C总线(默认SCL=GPIO05(D1)、SDA=GPIO04(D2))
 
 -   delay(10);
 
 -   pinMode(D6, OUTPUT);//状态输出此声明只能放在启动函数内
 
 -   pinMode(D6, OUTPUT);
 
 -   digitalWrite(D6, HIGH);
 
 -   digitalWrite(D7, HIGH);
 
 - }
 
  
- void loop()
 
 - {
 
 -    wifi_connect();
 
  
- }
 
 
  复制代码 
下面代码是DS3231_ESP.cpp 
 
 
- #include "DS3231_ESP.h"
 
  
 
- unsigned char time_dat[7] = {0,30,8,3,11,8,21};//重上电显示的时间
 
 - unsigned char timeBcd[7] = {0, 0, 0, 0, 0, 0, 0};
 
 - //--------------------------------------------------------- 
 
 - unsigned char DecToBcd(unsigned char val)
 
 - {
 
 -     return (((val/10)<<4) | (val%10));
 
 - }
 
 - //--------------------------------------------------------
 
 - //BCD码转10进制数据
 
 - unsigned char BcdToDec(unsigned char val)
 
 - {
 
 -     return ((val >> 4)*10 + (val & 0x0F));
 
 - }
 
 - //-------------------------------------------------------
 
 - void write_DS3231()
 
 - {
 
 -     int i;
 
 -     //set the time
 
 -     Wire.beginTransmission(ADDRESS_DS3231);
 
 -     Wire.write(0x00);//从DS3231的寄存器0开始至寄存器6分别写入7个时间参数
 
 -     for (i = 0; i < 7; i++)
 
 -     {
 
 -         Wire.write(time_dat[i]);
 
 -     }
 
 -     Wire.endTransmission();  
 
 -  }
 
 - //-------------------------------------------------------
 
 - void read_DS3231()
 
 - {
 
 -     Wire.beginTransmission(ADDRESS_DS3231);//挂载与address器件通讯的I2C总线
 
 -     Wire.write(0x00);//发送起始地址
 
 -     Wire.endTransmission();//完成发送操作释放总线
 
 -     Wire.requestFrom(ADDRESS_DS3231, 7);//启动接收操作读取从寄存器0开始的7个寄存器数据、结束后释放总线
 
 -     if (Wire.available() >= 7)//如果返回数据达到了7个就将数据分别读出并存入数组当中
 
 -     {
 
 -         for (int i = 0; i < 7; i++)
 
 -         {
 
 -             timeBcd[i] = Wire.read();
 
 -         }
 
 -     }  
 
 - }
 
 
  复制代码 
下面代码是DS3231_ESP.h 
 
- #ifndef __DS3231_ESP_h__
 
 - #define __DS3231_ESP_h__
 
 - #include <Wire.h>
 
  
- #define ADDRESS_DS3231 0x68
 
  
- unsigned char DecToBcd(unsigned char val);
 
 - unsigned char BcdToDec(unsigned char val);
 
 - void write_DS3231();
 
 - void read_DS3231();
 
  
 
- #endif
 
 
  复制代码 
我的演示: 
 
 
 
我的实用: 
原有的时钟系统添加了wifi校时后,在C51单片机的程序中增加了一个用于复位esp8266的函数如下: 
 
- //====校时启动函数=====================================
 
 - //P1.0口模拟输出一个下跳脉冲
 
 - void calibration_start()
 
 - {
 
 - P1M0=0x01;//P1.0为推挽输出
 
 - P1M1=0x00;
 
 - calibration=1;
 
 - delay_ms(20);
 
 - calibration=0;
 
 - delay_ms(20);
 
 - calibration=1;
 
 - }
 
  复制代码 
设定为每天0点校准一次时间,C51单片机程序中仅仅加入一句代码就可以了,如下图: 
 
 
显示效果:如果想要验证校时效果,可以在半夜0点以前将时钟调整为错误时间,待到显示的0点后就可以看到正确时间了。 
 
 
 
我的用于调试arduino程序及演示应用的模块: 
 
 
 
文字到此结束,啰嗦了好多只是浅谈一下这些天玩这个模块的过程,随着帖子的结篇我对于arduino-esp8266的应用也将到此结束,除非发现自己感兴趣的玩法就不再继续弄了,毕竟第一次弄这东西,难免疏漏诚信请这方面的高手把关指正,以免误人子弟得不偿失,有兴趣的朋友如果有问题可以跟帖家交流。 
 
 
 
 
 
 |   
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册 
 
 
 
 
x
 
 
打赏
- 
查看全部打赏
 
 
 
 
 
 |