【合宙ESP32C3 Arduino开发】第四篇:TFT_eSPI 驱动 合宙Air101 ST7735 LCD 显示普通时钟,模块化编程

忘记过去,超越自己

  • ❤️ 博客主页 单片机菜鸟哥,一个野生非专业硬件IOT爱好者 ❤️
  • ❤️ 本篇创建时间 2024-03-02❤️
  • ❤️ 本篇更新时间 2024-03-02❤️
  • 🎉 欢迎关注 🔎点赞 👍收藏 ⭐️留言📝
  • 🙏 此博客均由博主单独编写,不存在任何商业团队运营,如发现错误,请留言轰炸哦!及时修正!感谢支持!

快速导读

    • 1. 前言
      • 1.1 模块步骤
      • 1.2 代码结构
    • 2. 详细介绍
      • 2.1 主工程 —— CLOCK
      • 2.2 模块化细节
        • 2.2.1 m_wifi —— 管理联网过程
        • 2.2.2 m_ntp —— ntp网络时间同步
        • 2.2.3 m_display —— 显示联网过程
        • 2.2.4 m_display_default —— 时间刷新显示
    • 3.成果
      • 3.1 串口调试
      • 3.2 实物效果

合宙ESP32C3 Arduino开发付费专栏群 689271933,不喜勿加,凭借付费专栏订单号加入

1. 前言

在前篇中,我们学习了 TFT_eSPI 驱动 合宙Air101 ST7735 LCD,这一节我们来学习一下基于它基础上做一个简单时钟,并且开始接触模块化编程思想。

【合宙ESP32C3 Arduino开发】第三篇:TFT_eSPI 驱动 合宙Air101 ST7735 LCD

1.1 模块步骤

第一步:联网,显示联网过程
第二步:通过ntp同步最新网络时间
第三步:时间同步到单片机中,每隔秒级进行刷新。

1.2 代码结构

为了区分模块化,博主拆开了主工程和功能模块。
在这里插入图片描述

2. 详细介绍

2.1 主工程 —— CLOCK

#include <Arduino.h>
#include <ArduinoJson.h>
#include <TimeLib.h>
#include <WiFi.h>
#include <WiFiUdp.h>
#include <HTTPClient.h>
#include <TFT_eSPI.h>
#include <SPI.h>
#include <TJpg_Decoder.h>// 当前版本
#define Version  "CL V1.0"/* ******************************************************************  字库、图片库* *****************************************************************/
#include "number.h"
#include "font/ZdyLwFont_20.h"
#include "font/fangzheng/fangzheng20.h"
#include "font/hanyi/hanyi20.h"
#define TEXT_FONT  ZdyLwFont_20// 设备启动打印信息
const char projectInfo[] PROGMEM = R"rawliteral(
/* ****************************************************************** 基于ESP32C3 160x80 TFT屏 时钟* 当前固件版本:V1.3* 创 建 日 期:2024.02.27* 最后更改日期:2024.02.27** *****************************************************************/
)rawliteral";/* ******************************************************************  字库、图片库* *****************************************************************/
// 屏幕区域
#define  TFT_WIDTH      80
#define  TFT_HEIGHT     160TFT_eSPI tft = TFT_eSPI();              // 引脚请自行配置tft_eSpi库中的 User_Setup.h文件
TFT_eSprite clk = TFT_eSprite(&tft);
time_t time_old = 0; //上次时间刷新时间
time_t time_now = 0; //当前秒Number      dig;uint16_t bgColor = TFT_BLACK;   // 黑色背景色
uint16_t txtColor = TFT_WHITE;  // 字体颜色
uint32_t targetTime = 0;void setup() {Serial.begin(115200);Serial.println(projectInfo);tft_init(); //屏幕初始化// 连接wifiwhile(!wifi_connect());ntp_init(); //ntp服务初始化tft_display_layout();             // 绘制屏幕布局
}void loop(){time_now = now();//刷新时间信息,每秒刷新if (time_now != time_old){time_old = time_now;tft_display_time();}
}

主工程就管理整个代码运行过程。

  1. 初始化tft屏幕,并且进行网络连接,这里会展示联网界面
  2. ntp服务初始化,然后持续绘制显示时间

2.2 模块化细节

2.2.1 m_wifi —— 管理联网过程
String WifiSSID = "xxxxx";  // 填写自己的wifi账号,只支持2.4G
String WifiPassword = "xxxx";  // 填写自己的wifi密码,只支持2.4G
int animate_refresh_Time = 0;
int animate_key = -1; //初始化图标显示帧数// 连接wifi
extern bool wifi_connect(void){bool conn_result = false;if (WifiSSID.length() == 0){return conn_result;}WiFi.mode(WIFI_STA);WiFi.disconnect();WiFi.setTxPower(WIFI_POWER_5dBm);WiFi.begin(WifiSSID.c_str(), WifiPassword.c_str());const uint8_t *animate_value;       // 指向关键帧的指针uint32_t animate_size;        // 指向关键帧大小的指针uint32_t index = 0;while (true){if (millis() - animate_refresh_Time > 30){index++;Serial.print(".");animate_refresh_Time = millis();tft_display_loading(50); //每50毫秒检测一次,刷新一次进度条// 查询连接结果int status = WiFi.status();if (status == WL_CONNECT_FAILED ||status == WL_NO_SSID_AVAIL ||status == WL_CONNECTION_LOST){conn_result = false;Serial.println("【m_wifi】连接失败");break;} else if (status == WL_CONNECTED){conn_result = true;Serial.print("【m_wifi】wifi连接成功,当前IP地址:");Serial.println(WiFi.localIP());tft_display_loading_complete();   // 将进度条刷到100%Serial.println("【m_wifi】结束loading");break;}// 超过当做连接失败if (index > 300){// 连接超时WiFi.disconnect();break;}}}if (WiFi.status() != WL_CONNECTED){return false;}return true;
}

wifi_connect中,进行begin网络连接后,开始间隔一段时间进行刷新联网进度 tft_display_loading
当网络连接成功后,还需要把进度涨到100% tft_display_loading_complete。当然,总不能一直在联网,会有一个错误时间,这里超过300次就表示连接失败。

2.2.2 m_ntp —— ntp网络时间同步
//NTP服务器
WiFiUDP Udp;
const char ntpServerName[] = "ntp6.aliyun.com";
const int timeZone = 8;     //东八区
unsigned int localPort = 8000;
const int NTP_PACKET_SIZE = 48; // NTP时间在消息的前48字节中
byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packetsstatic time_t getNtpTime()
{IPAddress ntpServerIP; // NTP server's ip addresswhile (Udp.parsePacket() > 0) ; // discard any previously received packets//Serial.println("Transmit NTP Request");// get a random server from the poolWiFi.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");Udp.read(packetBuffer, NTP_PACKET_SIZE);  // read packet into the bufferunsigned long secsSince1900;// convert four bytes starting at location 40 to a long integersecsSince1900 =  (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 - 2208988800UL + timeZone * SECS_PER_HOUR);return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR;}}Serial.println("【m_ntp】ntp服务器无响应");return 0; // 无法获取时间时返回0
}// 向NTP服务器发送请求
static void sendNTPpacket(IPAddress &address)
{// set all bytes in the buffer to 0memset(packetBuffer, 0, NTP_PACKET_SIZE);// Initialize values needed to form NTP request// (see URL above for details on the packets)packetBuffer[0] = 0b11100011;   // LI, Version, ModepacketBuffer[1] = 0;     // Stratum, or type of clockpacketBuffer[2] = 6;     // Polling IntervalpacketBuffer[3] = 0xEC;  // Peer Clock Precision// 8 bytes of zero for Root Delay & Root DispersionpacketBuffer[12] = 49;packetBuffer[13] = 0x4E;packetBuffer[14] = 49;packetBuffer[15] = 52;// all NTP fields have been given values, now// you can send a packet requesting a timestamp:Udp.beginPacket(address, 123); //NTP requests are to port 123Udp.write(packetBuffer, NTP_PACKET_SIZE);Udp.endPacket();
}extern void ntp_init(void)
{Udp.begin(localPort);setSyncProvider(getNtpTime);setSyncInterval(60 * 60); // 1小时同步一次
}

这里我们设置了1小时同步一次时间。

关于ntp深入学习可以,参考

ESP8266开发之旅 网络篇⑰ NTP——时间服务

2.2.3 m_display —— 显示联网过程
//初始化屏幕
extern void tft_init(void){tft.begin();           // TFT初始化tft.setRotation(3);    // 旋转角度0-3tft.setTextColor(TFT_BLACK, TFT_WHITE); //设置字体颜色tft.fillScreen(TFT_BLACK); // 清屏TJpgDec.setJpgScale(1);       // 设置放大倍数TJpgDec.setSwapBytes(true);   // 它的作用是设置TFT液晶屏的像素字节序。在某些情况下,像素字节序可能需要被交换,以确保图像正确显示。这段代码中的true表示需要交换字节序,而false则表示不需要交换字节序。TJpgDec.setCallback(tft_output);  // 回调函数
}extern bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t *bitmap) {if (y >= tft.height())return 0;// 这句代码是将一个位图(bitmap)显示在TFT屏幕上,其中x和y是位图左上角的坐标,w和h是位图的宽度和高度。具体来说,它将位图的像素数据推送到TFT屏幕上,从而在指定的位置显示出来。tft.pushImage(x, y, w, h, bitmap);return 1;
}// 进度条
byte loadNum = 6;
extern void tft_display_loading(byte delayTime){clk.setColorDepth(8);                                // 设置TFT屏幕的颜色深度为8位。TFT屏幕的颜色深度指的是每个像素点可以显示的颜色数量,8位颜色深度可以显示256种颜色。clk.createSprite(160, 50);                           // 创建Spriteclk.fillSprite(TFT_BLACK);                           // 填充颜色:黑色clk.drawRoundRect(0, 0, 160, 16, 8, TFT_WHITE);      // 画一个圆角矩形框,白色clk.fillRoundRect(3, 3, loadNum, 10, 5, TFT_WHITE);  // 画一个填充的圆角矩形,白色clk.setTextDatum(CC_DATUM);                          // 设置文本显示基准为居中对齐clk.setTextColor(TFT_WHITE, TFT_BLACK);              // 设置文本的前景色和背景色clk.drawString("Connecting to WiFi", 80, 40, 2);    // 显示“Connecting to WiFi”这个字符串,位置为(80,40),字体大小为2。clk.pushSprite(0, 10);                             // Sprite中内容一次推向屏幕clk.deleteSprite();                                  // 删除SpriteloadNum += 1;if (loadNum >= 154){loadNum = 154;}delay(delayTime);
}// 将进度条刷到100%
extern void tft_display_loading_complete(void){while (loadNum < 154) { //让动画走完tft_display_loading(1);}
} // 绘制屏幕布局
extern void tft_display_layout(void){tft.setRotation(3);tft.fillScreen(bgColor);                                   //清屏
}
2.2.4 m_display_default —— 时间刷新显示
// 刷新时间显示
extern void tft_display_time(void){int timeY = 20;// 记录上一次时间static String hourMinute_old = "";static String second_old = "";static unsigned char Hour_old   = 60;static unsigned char Minute_old = 60;static unsigned char Second_old = 60;String hourMinute_now = hourMinute();//--------------------中间时间区显示开始--------------------// 时分if(hourMinute_now != hourMinute_old){hourMinute_old = hourMinute_now;// 小时刷新if(hour()!= Hour_old){dig.printfW1830(10, timeY, hour()/10);dig.printfW1830(30, timeY, hour()%10);Hour_old = hour();}// 分钟刷新if(minute()!= Minute_old ){dig.printfW1830(60, timeY, minute()/10);dig.printfW1830(80, timeY, minute()%10);Minute_old = minute();}}// 秒if(second()!= Second_old){dig.printfW1830(120, timeY, second()/10);dig.printfW1830(140, timeY, second()%10);Second_old = second();}//--------------------中间时间区显示结束--------------------
}

为了做到性能优化,做了新旧数据对比,只有数据变化了才会去刷新。

3.成果

3.1 串口调试

在这里插入图片描述

3.2 实物效果

  • wifi联网过程
    在这里插入图片描述
  • 时钟显示效果在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/714831.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

白话大模型② | 如何提升AI分析的准确性?

白话大模型系列共六篇文章&#xff0c;将通俗易懂的解读大模型相关的专业术语。本文为第二篇&#xff1a;如何提升AI分析的准确性&#xff1f; 作者&#xff1a;星环科技 人工智能产品部 面对AI分析落地时的数量化、准确性、泛化性等问题&#xff0c;让我们稍微深入了解下当前…

pycharm专业版本的安装

一 、到官网下载对应的pycharm安装包 也可以把安装软件&#xff08;用物理机下载到共享文件夹&#xff09; 然后进入Ubuntu系统把下载大的安装包剪贴到目标路径 1 在ubuntu中创建一个用来存放pycharm安装包的文件夹 rootzmq-virtual-machine:/home/zmq/Desktop# mkdir pycha…

京东云硬钢阿里云:承诺再低10%

关注卢松松&#xff0c;会经常给你分享一些我的经验和观点。 阿里云刚刚宣布史上最大规模的全线产品降价20%&#xff0c;这热度还没过&#xff0c;京东云当晚就喊话&#xff1a;“随便降、比到底!&#xff0c;全网比价&#xff0c;击穿低价&#xff0c;再低10%”&#xff0c;并…

[技巧]Arcgis之图斑四至范围批量计算

ArcGIS图层&#xff08;点、线、面三类图形&#xff09;四至范围计算 例外一篇介绍&#xff1a;[技巧]Arcgis之图斑四至点批量计算 说明&#xff1a;如下图画出来的框&#xff08;范围标记不是很准&#xff09; &#xff0c;图斑的x最大和x最小&#xff0c;y最大&#xff0c;…

专为大模型训练优化,百度集合通信库 BCCL 万卡集群快速定位故障

1 集合通信对分布式训练至关重要 在分布式训练中&#xff0c;每一块 GPU 只负责处理部分模型或者数据。集群中不同 GPU 之间通过集合通信的方式&#xff0c;完成梯度同步和参数更新等操作&#xff0c;使得所有 GPU 能够作为一个整体加速模型训练。 如果有一块 GPU 在集合通…

C++调用PyTorch模型教程

在人工智能的世界中&#xff0c;PyTorch已经成为了研究人员和工程师们广泛使用的深度学习框架之一。它以其灵活性和动态计算图而闻名&#xff0c;非常适合快速原型设计和实验。然而&#xff0c;当我们想要将训练好的模型部署到生产环境中时&#xff0c;我们可能会倾向于使用C这…

老卫带你学---leetcode刷题(172. 阶乘后的零)

172. 阶乘后的零 问题 给定一个整数 n &#xff0c;返回 n! 结果中尾随零的数量。 提示 n! n * (n - 1) * (n - 2) * … * 3 * 2 * 1 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;0 解释&#xff1a;3! 6 &#xff0c;不含尾随 0 示例 2&#xff1a; 输入…

Java Web之网页开发基础复习

tomcat之网页开发基础复习 **声明** :HTML标准规范 </!doctype> <html> : 根标签 <head>: 头部标签 内含<title><meta><link><style> <body>: 主体 <body></body> html标签 单标签: <标签名 \> 双标…

Python线性代数数字图像和小波分析之二

要点 数学方程&#xff1a;数字信号和傅里叶分析&#xff0c;离散时间滤波器&#xff0c;小波分析Python代码实现及应用变换过程&#xff1a; 读取音频和处理音频波&#xff0c;使用Karplus-强算法制作吉他音频离散傅里叶计算功能和绘制图示结果计算波形傅里叶系数正向和反向&…

1_SQL

文章目录 前端复习SQL数据库的分类关系型数据库非关系型数据库&#xff08;NoSQL&#xff09; 数据库的构成软件架构MySQL内部数据组织方式 SQL语言登录数据库数据库操作查看库创建库删除库修改库 数据库中表的操作选择数据库创建表删除表查看表修改表 数据库中数据的操作添加数…

性别和年龄的视频实时监测项目

注意&#xff1a;本文引用自专业人工智能社区Venus AI 更多AI知识请参考原站 &#xff08;[www.aideeplearning.cn]&#xff09; 性别和年龄检测 Python 项目 首先介绍性别和年龄检测的高级Python项目中使用的专业术语 什么是计算机视觉&#xff1f; 计算机视觉是使计算机能…

基于Camunda实现bpmn 2.0各种类型的任务

基于Camunda实现bpmn中各种类型任务 ​ Camunda Modeler -为流程设置器&#xff08;建模工具&#xff09;&#xff0c;用来构建我们的流程模型。Camunda Modeler流程绘图工具&#xff0c;支持三种协议类型流程文件分别为&#xff1a;BPMN、DMN、Form。 ​ Camunda Modeler下载…

笨办法:基于后端Matplotlib生成图片, 前端绘制报表

很久很久以前, 做过一个项目, 因为前端基础差, echarts捣鼓不来, 然后就折腾出来一套比较奇葩的技术方案, 就是前端需要什么图表, 后端先绘制好, 然后前端需要什么图表, 再从后端拉取后端之前响应的图片路径, 再去做渲染。 其实基于后端使用 Matplotlib 绘制图表,前端…

DangZero:通过直接页表访问的高效UAF检测(摘要及介绍及背景翻译)

先通过翻译过一遍文章&#xff0c;然后再对每个章节进行总结 摘要 Use-after-free vulnerabilities remain difficult to detect and mitigate, making them a popular source of exploitation. Existing solutions in- cur impractical performance/memory overhead, requir…

powershell界面中,dir命令的效果

常用参数 -path D:\111\111_2。读取指定路径。 -Name。只输出文件名 -Include *.txt。指定后缀的文件 -Recurse。搜索目录及其子目录。 -Force。显示具有 h 模式的隐藏文件。 >1dir.txt。将结果入指定文件 各参数使用效果 dir PS D:\111\111_2> dir 目录: D:\111…

初中孩子最近不愿意上学怎么办?有什么好方法可以解决?

这个年龄段属于叛逆期&#xff0c;这个时候孩子出现厌学问题很正常&#xff0c;家长应该多些耐心和时间&#xff0c;不要一味地责骂&#xff0c;会更加排斥和反感&#xff0c;叛逆的。可以跟孩子好好谈谈聊聊&#xff0c;学会倾听他的心声&#xff0c;愿意听你说话在教育和引导…

配置MySQL与登录模块

使用技术 MySQL&#xff0c;Mybatis-plus&#xff0c;spring-security&#xff0c;jwt验证&#xff0c;vue 1. 配置Mysql 1.1 下载 MySQL :: Download MySQL Installer 1.2 安装 其他页面全选默认即可 1.3 配置环境变量 将C:\Program Files\MySQL\MySQL Server 8.0\bin…

10个常见的Java面试问题及其答案

问题&#xff1a; Java的主要特性是什么&#xff1f; 答案&#xff1a; Java的主要特性包括面向对象、平台无关、自动内存管理、安全性、多线程支持、丰富的API和强大的社区支持。 问题&#xff1a; 什么是Java的垃圾回收机制&#xff1f; 答案&#xff1a; Java的垃圾回收机…

【Spring Boot 源码学习】BootstrapRegistry 初始化器实现

《Spring Boot 源码学习系列》 BootstrapRegistry 初始化器实现 一、引言二、往期内容三、主要内容3.1 BootstrapRegistry3.2 BootstrapRegistryInitializer3.3 BootstrapRegistry 初始化器实现3.3.1 定义 DemoBootstrapper3.3.2 添加 DemoBootstrapper 四、总结 一、引言 前面…

Avalonia学习(二十八)-OpenGL

Avalonia已经继承了opengl&#xff0c;详细的大家可以自己查阅。Avalonia里面启用opengl继承OpenGlControlBase类就可以了。有三个方法。分别是初始化、绘制、释放。 这里把官方源码的例子扒出来给大家看一下。源码在我以前发布的单组件里面。地址在前面的界面总结博文里面。 …