深圳晶彩智能3.5寸彩色屏PlatformIO本地气象站时钟和播放GIF-Arduino中文社区 - Powered by Discuz! Archiver

topdog 发表于 2022-9-10 20:55

深圳晶彩智能3.5寸彩色屏PlatformIO本地气象站时钟和播放GIF

本帖最后由 topdog 于 2022-9-11 08:06 编辑

深圳晶彩智能3.5寸彩色屏采用分辨率480x320彩色液晶屏,驱动芯片是ST7796,板载乐鑫公司出品ESP-WROOM-32,Flash 4M。本示例外接一块Bosch BME280 I2C测量本地的温湿度、大气压等做气象站,通过WIFI校时显示北京时间,为了增加趣味性播放一段小黄人的GIF。使用PlatformIO编译速度非常快捷,为了节约时间所以推荐采用此方法。
1,自定义核心
PlatformIO IDE允许自定义核心的,Windows 10系统依C:\Users\用户名\.platformio\platforms\espressif32\boards路径,用记事本或者nodepad++把以下文字保存为JCZN_WROOM_4M.json ,这样在Boards中就能找到自定义名称板子了,设置核心为ESP-WROOM-32 ,外接闪存设置成了4M。

{
"build": {
    "arduino":{
      "ldscript": "esp32_out.ld"   
    },
    "core": "esp32",
    "extra_flags": "-DARDUINO_ESP32_DEV",
    "f_cpu": "240000000L",
    "f_flash": "40000000L",
    "flash_mode": "qio",
    "mcu": "esp32",
    "variant": "esp32"
},
"connectivity": [
    "wifi",
    "bluetooth",
    "ethernet",
    "can"
],
"debug": {
    "openocd_board": "esp-wroom-32.cfg"
},
"frameworks": [
    "arduino",
    "espidf"
],
"name": "JCZN WROOM 4M",
"upload": {
    "flash_size": "4MB",
    "maximum_ram_size":327680,
    "maximum_size": 4194304,
    "require_upload_port": true,
    "speed":460800
},
"url": "http://www.jczn1688.com/sy",
"vendor": "JCZN"
}
2,示例项目文件结构:
A:项目要用到TFT_eSPI 、ESP32Time库,直接用pio home安装,其他的TJpg_Decoder 、SparkFun_BME280就需要安装到lib文件夹里面,点击New Terminal输入以下命令:
cd lib
git clone https://github.com/Bodmer/TJpg_Decoder.git
git clone https://github.com/sparkfun/SparkFun_BME280_Arduino_Library.git

B:录一段小黄人的视频或者下载GIF,在线编辑 https://ezgif.com/修改成你需要的大小,然后切片放入data文件夹里面。不要超过flash的容量呦。

C:特色字体库的制作,参见《合宙ESP32C3使用TFT_eSPI库操作ST7735s屏幕 (中)》,自定义字库放入include文件夹,特别强调注意vlw文件转C的网站地址:https://tomeko.net/online_tools/file_to_hex.php?lang=en   



3,深圳晶彩智能3.5寸彩色屏,针对TFT_eSPI 学习而设计制作,能够非常完美地实现触碰所有功能。这里没用用到触碰功能所以没有设置,不用的字库也没有引用。对应的platformio.ini 做如下修改:

platform = espressif32
board = JCZN_WROOM_4M
framework = arduino
upload_speed = 921600
board_build.f_flash = 80000000L
board_build.flash_mode = qio
monitor_speed = 115200
upload_port = COM9
board_build.mcu = esp32
upload_protocol = esptool
board_build.f_cpu = 240000000L
lib_ldf_mode = deep
board_build.partitions = huge_app.csv

platform_packages =
      platformio/framework-arduinoespressif32@^3.20004.0

build_flags = -DCORE_DEBUG_LEVEL=3
      -DBOARD_HAS_PSRAM
      -mfix-esp32-psram-cache-issue
      -DUSER_SETUP_LOADED=1
      -DDEBUG=1
      -DST7796_DRIVER=1
      -DTFT_RGB_ORDER=TFT_BGR
      -DTFT_WIDTH=320
      -DTFT_HEIGHT=480
      -DTFT_BACKLIGHT_ON=HIGH
      -DTFT_BACKLIGHT_OFF=LOW
      -DTFT_MISO=12
      -DTFT_MOSI=13
      -DTFT_SCLK=14
      -DTFT_CS=15
      -DTFT_DC=2
      -DTFT_RST=-1
      -DTFT_BL=27      
      -DLOAD_FONT4=1      
      -DSMOOTH_FONT=1
      -DSPI_FREQUENCY=65000000
      -DSPI_READ_FREQUENCY=20000000
      -DSPI_TOUCH_FREQUENCY=2500000
      -DUSE_HSPI_PORT=1

lib_deps =
      bodmer/TFT_eSPI@^2.4.75
      fbiego/ESP32Time@^2.0.0

4,程序入口main.cpp如下:
#include <Arduino.h>
#include <WiFiMulti.h>
#include <ESP32Time.h>
#include "sntp.h"
#include <Wire.h>
#include "SparkFunBME280.h"
#include "SPIFFS.h"
#include <TJpg_Decoder.h>
#include "SPI.h"
#include <TFT_eSPI.h> // Hardware-specific library
#include "HANYI30.h"

struct tm timeinfo;
BME280 mySensor;
WiFiMulti WiFiMulti;
ESP32Time rtc;
TFT_eSPI tft = TFT_eSPI();               // Invoke custom library
TFT_eSprite greeting = TFT_eSprite(&tft);//创建子画面实体
TFT_eSprite LowerLeft = TFT_eSprite(&tft); //创建子画面实体

#define TFT_PINK 0xFE19
int imgNum = 0;
String IP;
const char *ssid = "ssid";
const char *password = "password";

const char *ntpServer1 = "ntp1.aliyun.com"; //阿里云NTP时间源服务器
const char *ntpServer2 = "s1a.time.edu.cn"; //北京邮电大学
const long gmtOffset_sec = 8 * 3600;      //参数就是用来修正时区的,比如对于我们东八区(UTC/GMT+08:00)来说该参数就需要填写 8 * 3600
const int daylightOffset_sec = 0;         //使用夏令时 daylightOffset_sec 就填写3600,否则就填写0;

void listSPIFFS(void)
{
Serial.println(F("\r\nListing SPIFFS files:"));
static const char line[] PROGMEM = "=================================================";

Serial.println(FPSTR(line));
Serial.println(F("File name                              Size"));
Serial.println(FPSTR(line));

fs::File root = SPIFFS.open("/");
if (!root)
{
    Serial.println(F("Failed to open directory"));
    return;
}
if (!root.isDirectory())
{
    Serial.println(F("Not a directory"));
    return;
}

fs::File file = root.openNextFile();
while (file)
{

    if (file.isDirectory())
    {
      Serial.print("DIR : ");
      String fileName = file.name();
      Serial.print(fileName);
    }
    else
    {
      String fileName = file.name();
      Serial.print("" + fileName);
      // File path can be 31 characters maximum in SPIFFS
      int spaces = 33 - fileName.length(); // Tabulate nicely
      if (spaces < 1)
      spaces = 1;
      while (spaces--)
      Serial.print(" ");
      String fileSize = (String)file.size();
      spaces = 10 - fileSize.length(); // Tabulate nicely
      if (spaces < 1)
      spaces = 1;
      while (spaces--)
      Serial.print(" ");
      Serial.println(fileSize + " bytes");
    }

    file = root.openNextFile();
}

Serial.println(FPSTR(line));
Serial.println();
delay(1000);
}

bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t *bitmap)
{
// Stop further decoding as image is running off bottom of screen
if (y >= tft.height())
    return 0;

// This function will clip the image block rendering automatically at the TFT boundaries
tft.pushImage(x, y, w, h, bitmap);

// Return 1 to decode next block
return 1;
}

void setup()
{
Serial.begin(115200);

pinMode(4, OUTPUT);
digitalWrite(4, HIGH);

pinMode(16, OUTPUT);
digitalWrite(16, HIGH);

pinMode(17, OUTPUT);
digitalWrite(17, HIGH);


pinMode(TFT_BL, OUTPUT);
digitalWrite(TFT_BL, TFT_BACKLIGHT_ON);

WiFi.mode(WIFI_STA);
WiFiMulti.addAP(ssid, password);

if (WiFiMulti.run() == WL_CONNECTED)
{
    IP = WiFi.localIP().toString();
    sntp_servermode_dhcp(1);
    configTime(gmtOffset_sec, daylightOffset_sec, ntpServer1, ntpServer2);
}



if (getLocalTime(&timeinfo))
{
    rtc.setTimeStruct(timeinfo);
}

Wire.begin();
Wire.setClock(400000);      //调节到快速 I2C 速度!
mySensor.setI2CAddress(0x76); // I2C地址0x76
mySensor.beginI2C();

mySensor.setFilter(1);      // 0 至 4 有效, 滤波器系数, 见手册 3.4.4 IIR filter
mySensor.setStandbyTime(0); // 0 至 7 有效 读数之间的时间

mySensor.setTempOverSample(1);   // 0 至 16 有效 ,为0时禁用温度传感.见手册 4.2.2、5.4.8
mySensor.setPressureOverSample(1); // 0 至 16 有效 ,为0时禁用大气压传感.见手册 5.4.7
mySensor.setHumidityOverSample(1); // 0 至 16 有效 ,为0时禁用湿度传感. 见手册5.4.9

mySensor.setMode(MODE_NORMAL); // MODE_SLEEP(睡眠模式), MODE_FORCED(突发模式), MODE_NORMAL (普通模式)有效,见手册 3.3 Sensor modes

if (!SPIFFS.begin())
{
    Serial.println("SPIFFS initialisation failed!");
    while (1)
      yield(); // Stay here twiddling thumbs waiting
}
Serial.println("\r\nInitialisation done.");
listSPIFFS();

tft.begin();
tft.init();
tft.setRotation(3);
tft.fillScreen(TFT_BLACK);

TJpgDec.setJpgScale(1);
TJpgDec.setSwapBytes(true);
TJpgDec.setCallback(tft_output);
}

void loop()
{
greeting.setColorDepth(8);
// 创建子画面清晰的背景大小设置色彩为黑色
greeting.createSprite(479, 179);
greeting.fillSprite(TFT_BLACK);
greeting.setTextWrap(true);

greeting.loadFont(hanyi30);
greeting.setTextDatum(MR_DATUM); //顶部中心基准
greeting.setCursor(5, 10);
greeting.setTextColor(TFT_PINK, TFT_BLACK);
greeting.print("深圳晶彩智能");
greeting.println("祝大家中秋节快乐!");
greeting.println();

greeting.setTextColor(TFT_GREEN, TFT_BLACK);
greeting.print("温度:");
greeting.println(mySensor.readTempC(), 0);
greeting.print("湿度:");
greeting.println(mySensor.readFloatHumidity(), 0);
greeting.print("高度:");
greeting.println(mySensor.readFloatAltitudeMeters(), 0);
greeting.print("大气压:");
greeting.println(mySensor.readFloatPressure(), 0);
greeting.unloadFont();
greeting.pushSprite(0, 0); //将子画面推到 x, y 处的TFT
greeting.deleteSprite();   //删除子画面

LowerLeft.setColorDepth(8);
LowerLeft.createSprite(240, 180);
LowerLeft.fillSprite(TFT_BLACK);
LowerLeft.loadFont(hanyi30);
LowerLeft.setTextWrap(true);
LowerLeft.setTextColor(TFT_YELLOW, TFT_BLACK);
LowerLeft.setCursor(5, 0);
LowerLeft.print("日期:");
LowerLeft.setCursor(5, 55);
LowerLeft.print("时间:");
LowerLeft.setCursor(5, 105);
LowerLeft.print("地址:");
LowerLeft.unloadFont();
LowerLeft.setTextColor(TFT_CYAN, TFT_BLACK);
LowerLeft.setTextFont(4);
LowerLeft.setCursor(5, 25);
LowerLeft.print(rtc.getDate());
LowerLeft.setCursor(5, 75);
LowerLeft.print(rtc.getTime());
LowerLeft.setCursor(75, 105);
LowerLeft.print(IP);
LowerLeft.pushSprite(0, 180);
LowerLeft.deleteSprite();

if (imgNum > 9)
    imgNum = 0;
String imgPath = "/frame_";
imgPath += imgNum++;
imgPath += ".jpg";

TJpgDec.drawFsJpg(240, 180, imgPath);

yield();
}
5,成品效果见抖音短视频。
https://www.douyin.com/video/7141723080203799819

6,示例项目开源Arduino版的见附件











页: [1]
查看完整版本: 深圳晶彩智能3.5寸彩色屏PlatformIO本地气象站时钟和播放GIF