【合宙ESP32C3 Arduino开发】第五篇:TFT_eSPI 驱动 合宙Air101 ST7735 LCD 显示猫系字体时钟,模块化编程

本文主要是介绍【合宙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_cat —— 时间刷新显示
    • 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 "font/cat/font_cat20.h"
#include "font/cat/font_cat30.h"
#include "font/cat/font_cat72.h"
#define TEXT_FONT  font_cat20// 设备启动打印信息
const char projectInfo[] PROGMEM = R"rawliteral(
/* ****************************************************************** 基于ESP32C3 160x80 TFT屏 猫系时钟* 当前固件版本:V1.0* 创 建 日 期: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; //当前秒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_cat —— 时间刷新显示
// 定义使用什么字体
#define HOUR_FONT   font_cat30
#define MINUTE_FONT font_cat30
#define SECOND_FONT font_cat30// 刷新时间显示
extern void tft_display_time(void){int timeY = 0;// 记录上一次时间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;static unsigned int hourW = 0;static unsigned int hourH = 74;static unsigned int minuteW = 0;static unsigned int minuteH = 74;static unsigned int secondW = 0;static unsigned int secondH = 0;String hourMinute_now = hourMinute();clk.setColorDepth(8);//--------------------中间时间区显示开始--------------------// 时分if(hourMinute_now != hourMinute_old){hourMinute_old = hourMinute_now;// 小时刷新if(hour()!= Hour_old){clk.loadFont(HOUR_FONT);  // 加载字体hourW = clk.textWidth(num2str(hour()), 1);
//       hourH = clk.fontHeight(1);
//       Serial.printf("hourW:%d,hourH:%d\n",hourW,hourH);clk.createSprite(hourW, hourH);clk.setTextWrap(false);clk.setTextDatum(CC_DATUM);clk.setTextColor(txtColor, bgColor);clk.drawString(num2str(hour()),hourW/2,hourH/2);clk.pushSprite(20,timeY);clk.deleteSprite();clk.unloadFont(); //释放字库文件,节省资源Hour_old = hour();}// 分钟刷新if(minute()!= Minute_old){clk.loadFont(MINUTE_FONT);  // 加载字体minuteW = clk.textWidth(num2str(minute()), 1);
//       minuteH = clk.fontHeight(1);
//       Serial.printf("minuteW:%d,minuteH:%d\n",minuteW,minuteH);clk.createSprite(minuteW, minuteH);clk.setTextWrap(false);clk.setTextDatum(CC_DATUM);clk.setTextColor(txtColor, bgColor);clk.drawString(num2str(minute()),minuteW/2,minuteH/2);clk.pushSprite(20 + hourW + 1,timeY);clk.deleteSprite();clk.unloadFont(); //释放字库文件,节省资源Minute_old = minute();}}// 秒if(second()!= Second_old){clk.loadFont(SECOND_FONT);  // 加载汉字字体secondW = clk.textWidth(num2str(second()), 1);clk.createSprite(secondW, minuteH);clk.fillSprite(bgColor);clk.setTextDatum(CC_DATUM);clk.setTextColor(txtColor, bgColor);clk.drawString(num2str(second()),secondW/2,minuteH/2);clk.pushSprite(20 + hourW + 1 + minuteW + 1,timeY);clk.deleteSprite();clk.unloadFont(); //释放字库文件,节省资源Second_old = second();}//--------------------中间时间区显示结束--------------------
}

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

3.成果

3.1 串口调试

在这里插入图片描述

3.2 实物效果

  • wifi联网过程
    在这里插入图片描述

  • 时钟显示效果在这里插入图片描述

这篇关于【合宙ESP32C3 Arduino开发】第五篇:TFT_eSPI 驱动 合宙Air101 ST7735 LCD 显示猫系字体时钟,模块化编程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/767701

相关文章

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

第10章 中断和动态时钟显示

第10章 中断和动态时钟显示 从本章开始,按照书籍的划分,第10章开始就进入保护模式(Protected Mode)部分了,感觉从这里开始难度突然就增加了。 书中介绍了为什么有中断(Interrupt)的设计,中断的几种方式:外部硬件中断、内部中断和软中断。通过中断做了一个会走的时钟和屏幕上输入字符的程序。 我自己理解中断的一些作用: 为了更好的利用处理器的性能。协同快速和慢速设备一起工作

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

OpenHarmony鸿蒙开发( Beta5.0)无感配网详解

1、简介 无感配网是指在设备联网过程中无需输入热点相关账号信息,即可快速实现设备配网,是一种兼顾高效性、可靠性和安全性的配网方式。 2、配网原理 2.1 通信原理 手机和智能设备之间的信息传递,利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家应用和设备之间的发现。在完成设备间的认证和响应后,即可发送相关配网数据。同时还支持与常规Sof

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

安卓链接正常显示,ios#符被转义%23导致链接访问404

原因分析: url中含有特殊字符 中文未编码 都有可能导致URL转换失败,所以需要对url编码处理  如下: guard let allowUrl = webUrl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {return} 后面发现当url中有#号时,会被误伤转义为%23,导致链接无法访问

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount