【合宙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.pswp.cn/news/714831.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/714831.shtml
英文地址,請注明出處:http://en.pswp.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類就可以了。有三個方法。分別是初始化、繪制、釋放。 這里把官方源碼的例子扒出來給大家看一下。源碼在我以前發布的單組件里面。地址在前面的界面總結博文里面。 …