数码之家

 找回密码
 立即注册
搜索
查看: 4466|回复: 10

[Arduino] 浅谈编程菜鸟***【三】ESP8266驱动DS3231网络校时代码分享

[复制链接]
发表于 2021-8-26 10:56:50 | 显示全部楼层 |阅读模式

爱科技、爱创意、爱折腾、爱极致,我们都是技术控

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 慕名而来 于 2021-8-27 18:03 编辑

接上篇:浅谈编程菜鸟与arduino-esp8266之间的那些事【二】https://www.mydigit.cn/thread-272594-1-1.html(出处: 数码之家)
尾篇——我的esp8266校时时钟方案
前一篇已经分析了网上常见的校时时钟方案,但是我总是感觉除了本坛朋友发的几个LED数码或点阵屏的时钟(天气)有实用性以外,其他很多都是用于演示的,关于网络校时时钟是否需要含有RTC时钟芯片有各种说法,但是我认为还是加一片RTC好些,对于点阵屏显示或者是TFT彩屏显示的时钟,其耗电量都不适合电池供电,通过适配器供电的设备难免遇有停电或断网,因此我觉得电路中加一片RTC会稳妥些,更为主要的是因为不是做商品设计需要斤斤计较、自己玩耍硬件加几元钱成本也无可厚非,我的方案如下:

方案图示.JPG

方案中我的显示屏为5”TFT彩屏、16位并口总线,用esp8266直接驱动16位并口总线至少我是弄不了的,所以我外加了一片STC8A8K64S4A12-LQFP44单片机来驱动TFT。
方案中因为使用RTC芯片来传递数据,使原有的MCU控制程序不用任何变动,而arduino的编程也变得非常简单,所以,我的方案非常适合为已有时钟添加wifi校时功能并且只需要MCU提供一个I/O口用于启动校时即可,如下图所示:

控制图.JPG
代码须知:
1.代码用于esp8266+DS3231的控制,需要时请通过arduino ide编译下载到esp8266之中,以下代码用于串口演示,如果你的esp8266已经连接了DS3231并且已经供电,那么,代码下载完成后打开串口监视器并调整波特率为9600,应该可以看到时间显示,并且每按动一次8266的复位键可以显示一次时间(也包含wifi配置信息)。
2.本程序应用时有一个重要的问题需要注意!!!,你的esp8266模块在下载本程序之前如果曾经正常连接过你的wifi,那么就可以直接工作了,如果没有连接过wifi则需要在你的手机中找到名字为
esp8266(密码:esp@wifi)的热点AP这是本程序生成的wifi配置界面,可以根据程序中的名称、密码进行登陆,登陆成功后可以在手机上配置并保存配置信息,如果手机中总是不能出现这个热点,就请查找其他原因吧,这方面我真的知之甚少无法提供帮助,而我的代码在我应用的时候经过一次配置后也就不再出现需要登陆的情况所以我也就没有再行测试。
3.本程序应用需要有WiFiManagerESP8266HTTPClient库文件,如果缺少可以在arduino ide内下载安装。
4.esp8266的I2C引脚连接详见程序内的标注提示。
5.如果不是做串口演示而用于实际控制时,可以注释掉主函数中的所有相关串口输出的代码,而DS3231_ESP中用不到的函数及函数声明也可以注释掉。
6.代码中的D6、D7端口功能可以根据自己的需要可用可不用,不用的时候与其相关的代码可以删除。


代码如下:

  1. /**
  2. * 代码原创:wannenggong
  3. * 代码仅用于演示
  4. * 未经同意请勿转载
  5. * 使用代码请注明出处
  6. **/
  7. #include <ESP8266WiFi.h>
  8. #include <ESP8266HTTPClient.h>
  9. #include <WiFiManager.h>
  10. #include "DS3231_ESP.h"

  11. #define URL "http://quan.suning.com/getSysTime.do"//苏宁的时间api
  12. extern unsigned char time_dat[];
  13. extern unsigned char timeBcd[];

  14. unsigned char error_count = 0; //失败次数
  15. String acquire;

  16. //--------------------------------
  17. //网络时间获取与DS3231时间寄存器更新函数
  18. void get_time()
  19. {
  20.   int httpcode;//状态码
  21.     HTTPClient httpclient;
  22.     httpclient.setTimeout(1000);//超时时间
  23.     while (1)
  24.     {
  25.       httpclient.begin(URL);//开始连接
  26.       httpcode = httpclient.GET();//获取状态码
  27.       if (httpcode == 200)  //如果成功
  28.       {
  29.       delay(100);
  30.       //获取网络时间
  31.       /**报文格式:{"sysTime2":"2021-08-17 20:17:48","sysTime1":"20210817201748"}**/
  32.       acquire = httpclient.getString();
  33.       //拆分提取年、月、日、时、分、秒的char数据
  34.       //分别提取十位、个位的数值并组合两位数
  35.       //组合后的数据转换成ascⅡ数值
  36.       time_dat[6] =(DecToBcd((acquire.charAt(15)-0x30)*10+(acquire.charAt(16)-0x30)));//年
  37.       time_dat[5] =(DecToBcd((acquire.charAt(18)-0x30)*10+(acquire.charAt(19)-0x30)));//月
  38.       time_dat[4] =(DecToBcd((acquire.charAt(21)-0x30)*10+(acquire.charAt(22)-0x30)));//日
  39.       time_dat[3]=3;//报文中没有星期数据,这里预置任意值由MCU的C51程序予以更正
  40.       time_dat[2] =(DecToBcd((acquire.charAt(24)-0x30)*10+(acquire.charAt(25)-0x30)));//时
  41.       time_dat[1] =(DecToBcd((acquire.charAt(27)-0x30)*10+(acquire.charAt(28)-0x30)));//分
  42.       time_dat[0] =(DecToBcd((acquire.charAt(30)-0x30)*10+(acquire.charAt(31)-0x30)));//秒
  43.   
  44.       write_DS3231();//更新DS3231时间寄存器、校准时间
  45.       delay(1000);
  46.       read_DS3231();//读出DS3231时间数据用于演示
  47.       delay(1000);
  48.       usart_out();//串口输出演示效果、按一次复位键更新一次显示时间      
  49.       delay(1000);
  50.       digitalWrite(D6, HIGH);//校时成功时清除两个端口的提示状态
  51.       digitalWrite(D7, HIGH);
  52.       httpclient.end();//断开连接(一定要断开,否则会出问题)
  53.       WiFi.forceSleepBegin();//开始wifi睡眠
  54.       delay(5000);
  55.       ESP.deepSleep(0);//开始esp8266深度睡眠(由复位键唤醒)      
  56.       break;
  57.       }
  58.       else
  59.       {     
  60.       httpclient.end();//断开连接
  61.       delay(100);
  62.       error_count++;
  63.         if(error_count>50)
  64.         {
  65.         error_count=0;
  66.         digitalWrite(D6,LOW);//D6口低电平提示读取时间失败等待下一次校时
  67.         delay(5000);        
  68.         ESP.deepSleep(0);//经过50次操作后仍然不能联网获取时间则放弃校时使模块休眠
  69.         }
  70.       }
  71.     }
  72. }
  73. //--------------------------------------------------------
  74. //wifi连接函数
  75. void wifi_connect()
  76. {
  77.     unsigned char f=0;
  78.     delay(10);
  79.     WiFiManager wifiManager;//建立一个对象
  80.     if(WiFi.status() == WL_CONNECTED)//wifi连接成功时会由autoConnect()返回标志
  81.     {
  82.       f=1;
  83.     }
  84.     if(f!=1)//如果wifi连接不成功则标志维持初始0状态不变
  85.     {
  86.       digitalWrite(D7, LOW);//D7口低电平提示wifi连接失败   
  87.       Serial.println("WiFi connected_fail");//连接失败
  88.       wifiManager.autoConnect("esp8266","esp@wifi");//建立无线AP
  89.       if(WiFi.status() == WL_CONNECTED)//判断连接状态、如果成功则置位标志
  90.       f=1;
  91.     }
  92.     if(f==1)
  93.     {
  94.       Serial.println("WiFi connected_ok");//串口显示wifi连接成功
  95.       get_time();
  96.     }
  97. }
  98. //-------------------------------------------------------
  99. //串口输出函数(用于演示)
  100. void usart_out()
  101. {
  102.     Serial.print(timeBcd[6], HEX);
  103.     Serial.print("/");
  104.     Serial.print(timeBcd[5], HEX);
  105.     Serial.print("/");
  106.     Serial.print(timeBcd[4], HEX);
  107.     Serial.print("/");
  108.     Serial.print(timeBcd[3]);
  109.     Serial.print(" ");
  110.     Serial.print(timeBcd[2], HEX);
  111.     Serial.print(":");
  112.     Serial.print(timeBcd[1], HEX);
  113.     Serial.print(":");
  114.     Serial.println(timeBcd[0], HEX);//此处换行
  115.     delay(1000);
  116. }
  117. //------------------------------------------------------
  118. void setup()
  119. {
  120.   Serial.begin(9600);
  121.   Wire.begin();//使能I2C总线(默认SCL=GPIO05(D1)、SDA=GPIO04(D2))
  122.   delay(10);
  123.   pinMode(D6, OUTPUT);//状态输出此声明只能放在启动函数内
  124.   pinMode(D6, OUTPUT);
  125.   digitalWrite(D6, HIGH);
  126.   digitalWrite(D7, HIGH);
  127. }

  128. void loop()
  129. {
  130.    wifi_connect();

  131. }
复制代码

下面代码是DS3231_ESP.cpp


  1. #include "DS3231_ESP.h"


  2. unsigned char time_dat[7] = {0,30,8,3,11,8,21};//重上电显示的时间
  3. unsigned char timeBcd[7] = {0, 0, 0, 0, 0, 0, 0};
  4. //---------------------------------------------------------
  5. unsigned char DecToBcd(unsigned char val)
  6. {
  7.     return (((val/10)<<4) | (val%10));
  8. }
  9. //--------------------------------------------------------
  10. //BCD码转10进制数据
  11. unsigned char BcdToDec(unsigned char val)
  12. {
  13.     return ((val >> 4)*10 + (val & 0x0F));
  14. }
  15. //-------------------------------------------------------
  16. void write_DS3231()
  17. {
  18.     int i;
  19.     //set the time
  20.     Wire.beginTransmission(ADDRESS_DS3231);
  21.     Wire.write(0x00);//从DS3231的寄存器0开始至寄存器6分别写入7个时间参数
  22.     for (i = 0; i < 7; i++)
  23.     {
  24.         Wire.write(time_dat[i]);
  25.     }
  26.     Wire.endTransmission();  
  27. }
  28. //-------------------------------------------------------
  29. void read_DS3231()
  30. {
  31.     Wire.beginTransmission(ADDRESS_DS3231);//挂载与address器件通讯的I2C总线
  32.     Wire.write(0x00);//发送起始地址
  33.     Wire.endTransmission();//完成发送操作释放总线
  34.     Wire.requestFrom(ADDRESS_DS3231, 7);//启动接收操作读取从寄存器0开始的7个寄存器数据、结束后释放总线
  35.     if (Wire.available() >= 7)//如果返回数据达到了7个就将数据分别读出并存入数组当中
  36.     {
  37.         for (int i = 0; i < 7; i++)
  38.         {
  39.             timeBcd[i] = Wire.read();
  40.         }
  41.     }  
  42. }
复制代码

下面代码是DS3231_ESP.h

  1. #ifndef __DS3231_ESP_h__
  2. #define __DS3231_ESP_h__
  3. #include <Wire.h>

  4. #define ADDRESS_DS3231 0x68

  5. unsigned char DecToBcd(unsigned char val);
  6. unsigned char BcdToDec(unsigned char val);
  7. void write_DS3231();
  8. void read_DS3231();


  9. #endif
复制代码

我的演示:

wifi校时效果.jpg

我的实用:
原有的时钟系统添加了wifi校时后,在C51单片机的程序中增加了一个用于复位esp8266的函数如下:

  1. //====校时启动函数=====================================
  2. //P1.0口模拟输出一个下跳脉冲
  3. void calibration_start()
  4. {
  5. P1M0=0x01;//P1.0为推挽输出
  6. P1M1=0x00;
  7. calibration=1;
  8. delay_ms(20);
  9. calibration=0;
  10. delay_ms(20);
  11. calibration=1;
  12. }
复制代码

设定为每天0点校准一次时间,C51单片机程序中仅仅加入一句代码就可以了,如下图:
99999.JPG

显示效果:如果想要验证校时效果,可以在半夜0点以前将时钟调整为错误时间,待到显示的0点后就可以看到正确时间了。

0100.jpg

我的用于调试arduino程序及演示应用的模块:

0101.jpg

文字到此结束,啰嗦了好多只是浅谈一下这些天玩这个模块的过程,随着帖子的结篇我对于arduino-esp8266的应用也将到此结束,除非发现自己感兴趣的玩法就不再继续弄了,毕竟第一次弄这东西,难免疏漏诚信请这方面的高手把关指正,以免误人子弟得不偿失,有兴趣的朋友如果有问题可以跟帖家交流。





打赏

参与人数 2家元 +30 收起 理由
jpdd521 + 10 已经非常厉害了,很优秀了。
飞向狙沙 + 20 謝謝分享

查看全部打赏

发表于 2021-8-26 11:32:37 | 显示全部楼层
已经非常厉害了,很优秀了。
回复 支持 反对

使用道具 举报

发表于 2021-8-26 14:58:19 | 显示全部楼层
我也弄了两片8266板子在玩,现在还是只会用别人的程序的阶段,向楼主学习。
回复 支持 反对

使用道具 举报

发表于 2021-8-26 15:50:17 | 显示全部楼层
image.png 时间字体好小,不是彩屏的:lol::lol::lol::lol:
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-8-26 21:20:14 | 显示全部楼层
hbliwww 发表于 2021-8-26 14:58
我也弄了两片8266板子在玩,现在还是只会用别人的程序的阶段,向楼主学习。 ...

我也是刚刚弄,也是要用别人的程序的,慢慢修改的过程中逐渐明白的多了就可以写自己的了。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-8-26 21:34:44 | 显示全部楼层
本帖最后由 慕名而来 于 2021-8-26 21:38 编辑
long2012 发表于 2021-8-26 15:50
时间字体好小,不是彩屏的

彩屏分辨率高且没有矢量字库的话显示大的字符挺费事的,做万年历最好用低分辨率的屏,一般5寸用到480*270最好(可惜我玩坏了两个),而这个5寸屏的分辨率为800*480,现在显示时间的字模是数组的96*96点阵字形,而且是自己顶格画的字符,其他文字、字符是用W25Q**自建字库是48*48的标准点阵字符,另外,经过试验时间数字再大了就与布局不协调了,另外还有一个问题至今我也没明白,蓝色背景显示黄色字符的效果咋看都是蓝底白字,其实现在显示的文字真的是黄色的。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-8-26 21:46:05 | 显示全部楼层
long2012 发表于 2021-8-26 15:50
时间字体好小,不是彩屏的

ttt_副本.jpg
回复 支持 反对

使用道具 举报

发表于 2021-8-27 08:29:02 | 显示全部楼层
楼主,利害利害:lol::lol::lol:
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-8-31 09:45:35 | 显示全部楼层

只是简单的玩玩彩屏,弄的都是入门级的东西没啥技术含量。
回复 支持 反对

使用道具 举报

发表于 2021-8-31 12:46:19 | 显示全部楼层
向楼主致敬!我只是找别人现成的东西做最简单的时钟,已经没有学习上进的动力了。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-9-1 08:45:09 | 显示全部楼层
hzw6834 发表于 2021-8-31 12:46
向楼主致敬!我只是找别人现成的东西做最简单的时钟,已经没有学习上进的动力了。 ...

多谢支持,我玩这些是为了消磨时间,喜欢动手焊东西也喜欢和代码较劲,虽然程序都是东拼西凑的代码但是总要想办法剔除多余的并按照自己的思路来编排,经常感觉有些例程经过大家抄来抄去,越弄弯路越多、越弄代码越多、越难以理解,本贴中我改编的代码我觉得可以算是此类代码中最简化的了。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

APP|手机版|小黑屋|关于我们|联系我们|法律条款|技术知识分享平台

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2024-3-30 00:00 , Processed in 0.140400 second(s), 13 queries , Redis On.

Powered by Discuz!

© 2006-2023 smzj.net

快速回复 返回顶部 返回列表