淘晶馳螢幕利用python,esp32更新tft檔

如果想要用uart來對淘晶馳的螢幕來進行軟體更新的話...

簡述

如果想要用uart來對淘晶馳的螢幕來進行軟體更新的話,官方網站有給一個範例檔及原始程式碼,但是他是用c#來寫的,並且用visual studio去開發,而且還強調不對TFTFileDownload二次開發給予技術支持,意思是你要二次開發可以,但是有甚麼問題不提供支持,基本上對於新手是非常不友善的,因此這篇主要教大家如何用python這種比較簡單的程式語言來更新,也可以利用esp32來更新,基本上esp32可以的話所有其他arduino開發版理論上也都支持,但是需要外掛一個flash來儲存tft檔。

正文

python更新

淘晶馳的螢幕其實就可以用sd卡進行更新,但是如果有特殊需求需要用電腦或者微控制器更新的話就要自己寫了,畢竟官方沒有範例程式,先上我自己改成python的程式碼

import serial
import time
import os

# 固定配置
TFT_FILE_PATH = "D:/Users/user/lcdtest.bin"  # 替換為你的 TFT 檔案路徑
COM_PORT = "COM12"  # 替換為你的串口號
BAUD_RATE = 115200  # 替換為你的波特率

# 初始化串口
def init_serial(port, baud_rate):
    try:
        ser = serial.Serial(port, baud_rate, timeout=1)
        print(f"串口 {port} 初始化成功,波特率:{baud_rate}")
        return ser
    except serial.SerialException as e:
        print(f"初始化串口失敗: {e}")
        return None

# 延遲函数
def delay_ms(ms):
    time.sleep(ms / 1000)

# 發送字串到串口
def send_string(ser, data, addr=0, add_end=True):
    try:
        if addr != 0:
            addr_bytes = bytearray([(addr & 0xFF), (addr >> 8)])
            ser.write(addr_bytes)
        ser.write(data.encode())
        if add_end:
            ser.write(bytearray([255, 255, 255]))
    except Exception as e:
        print(f"發送資料失敗: {e}")

# 等待從串口接收數據
def wait_for_byte(ser, timeout):
    start_time = time.time()
    while time.time() - start_time < timeout / 1000:
        if ser.in_waiting > 0:
            return ser.read(1)
    return None

# 燒錄文件
def download_tft(ser, file_path, baud_rate):
    if not os.path.exists(file_path):
        print("指定的 TFT 檔案不存在!")
        return False
    dtime = 1000000 / baud_rate + 50
    file_size = os.path.getsize(file_path)

    print(f"開始下載:檔案大小 {file_size} 位元組")
    send_string(ser, "\0", add_end=True)
    send_string(ser, "DRAKJHSUYDGBNCJHGJKSHBDN",65535, add_end=True)
    delay_ms(10)
    send_string(ser, "connect",0, add_end=True)

    delay_ms(dtime)

    # 發送下載命令
    send_string(ser, "delay=2500", add_end=True)
    delay_ms(1500)
    send_string(ser, f"whmi-wri {file_size},{baud_rate},0", add_end=True)
    delay_ms(80)

    # 切換波特率
    ser.baudrate = baud_rate
    delay_ms(50)
    ser.reset_input_buffer()  # 清空接收緩衝區

    # 檢查是否收到準備訊號
    if wait_for_byte(ser, 2500) != b'\x05':
        print("設備未準備好")
        return False

    # 开始传输文件
    with open(file_path, "rb") as file:
        sent_size = 0
        while sent_size < file_size:
            chunk_size = min(4096, file_size - sent_size)
            chunk = file.read(chunk_size)
            ser.write(chunk)
            if wait_for_byte(ser, 3000) != b'\x05':
                print("傳輸失敗")
                return False
            sent_size += chunk_size
            print(f"已下載 {sent_size}/{file_size} 位元組")

    print("下载完成!")
    return True

# 主函数
def main():
    # 初始化串口
    ser = init_serial(COM_PORT, BAUD_RATE)
    if ser is None:
        return

    try:
        # 燒錄程序
        if download_tft(ser, TFT_FILE_PATH, BAUD_RATE):
            print("程式燒錄成功")
        else:
            print("程式燒錄失敗")
    finally:
        ser.close()
        print("串口已關閉")

if __name__ == "__main__":
    main()

先在USART HMI中導出.tft檔,可以參考官方教學

導出後將下列的參數改為自己的路徑、端口及波特率(螢幕的)

# 固定配置
TFT_FILE_PATH = "D:/Users/user/lcdtest.bin"  # 替換為你的 TFT 檔案路徑
COM_PORT = "COM12"  # 替換為你的串口號
BAUD_RATE = 115200  # 替換為你的波特率

接著將螢幕接著任何的usb to ttl就可以更新程式碼啦~

esp32更新

esp32要更新也是非常簡單,按照傳送的數據就可以對螢幕進行更新,一樣上程式碼

#include <Arduino.h>
#include <SPIFFS.h>

// 固定配置
#define TFT_FILE_PATH "/lcdtest.bin" // SPIFFS 中的文件路徑

#define BAUD_RATE 115200             // 替換為你的波特率

#define LED 2
#define BOOT 0

// 延遲函數
void delay_ms(uint32_t ms) {
  delay(ms);
}

// 發送字串到串口
void sendString(HardwareSerial &serial, const char *data, uint16_t addr = 0, bool addEnd = true) {
  if (addr != 0) {
    uint8_t addrBytes[] = {static_cast<uint8_t>(addr & 0xFF), static_cast<uint8_t>(addr >> 8)};
    serial.write(addrBytes, sizeof(addrBytes));
  }
  serial.print(data);
  if (addEnd) {
    uint8_t endBytes[] = {255, 255, 255};
    serial.write(endBytes, sizeof(endBytes));
  }
}

// 等待從串口接收資料
bool waitForByte(HardwareSerial &serial, uint32_t timeout) {
  uint32_t startTime = millis();
  while (millis() - startTime < timeout) {
    if (serial.available() > 0) {
      return serial.read() == 0x05;
    }
  }
  return false;
}

// 燒錄文件
bool downloadTFT(HardwareSerial &serial, const char *filePath, uint32_t baudRate) {
  if (!SPIFFS.exists(filePath)) {
    Serial.println("指定的 TFT 文件不存在!");
    return false;
  }

  File file = SPIFFS.open(filePath, "r");
  if (!file) {
    Serial.println("無法打開 TFT 文件!");
    return false;
  }

  size_t fileSize = file.size();
  Serial.printf("開始下載:文件大小 %u 字節\n", fileSize);

  sendString(serial, "\0", 0, true);
  sendString(serial, "DRAKJHSUYDGBNCJHGJKSHBDN", 65535, true);
  delay_ms(10);
  sendString(serial, "connect", 0, true);
  delay_ms(10);

  // 發送下載命令
  sendString(serial, "delay=2500", 0, true);
  delay_ms(1500);
  char cmd[64];
  snprintf(cmd, sizeof(cmd), "whmi-wri %u,%u,0", fileSize, baudRate);
  sendString(serial, cmd, 0, true);
  delay_ms(80);

  delay_ms(50);
  
  while(serial.available() > 0)
  {
    serial.read();
  }

  // 檢查是否收到準備信號
  if (!waitForByte(serial, 2500)) {
    Serial.println("設備未準備好");
    file.close();
    return false;
  }

  // 開始傳輸文件
  size_t sentSize = 0;
  uint8_t buffer[4096];
  while (sentSize < fileSize) {
    size_t chunkSize = min(sizeof(buffer), fileSize - sentSize);
    file.read(buffer, chunkSize);
    serial.write(buffer, chunkSize);
    if (!waitForByte(serial, 3000)) {
      Serial.println("傳輸失敗");
      file.close();
      return false;
    }
    sentSize += chunkSize;
    Serial.printf("已下載 %u/%u 字節\n", sentSize, fileSize);
  }

  Serial.println("下載完成!");
  file.close();
  return true;
}

// 設置串口
void setup() {
  Serial.begin(115200);
  Serial.println("初始化開始");

  pinMode(LED, OUTPUT);
  pinMode(BOOT, INPUT_PULLUP);

  digitalWrite(LED, LOW);

  // 初始化 SPIFFS
  if (!SPIFFS.begin(true)) {
    Serial.println("SPIFFS 初始化失敗!");
    while (true) {
      delay(1000);
    }
  }

  // 初始化 Serial2
  Serial2.begin(BAUD_RATE);
  Serial.println("串口初始化完成,等待按鈕燒入");

  while (1)
  {
    if (digitalRead(BOOT) == 0)
    {
      break;
    }
    delay(1);
  }

  while (1)
  {
    if (digitalRead(BOOT) == 1)
    {
      break;
    }
    delay(1);
  }

  // 燒錄程序
  if (downloadTFT(Serial2, TFT_FILE_PATH, BAUD_RATE)) {
    Serial.println("程序燒錄成功");
  } else {
    Serial.println("程序燒錄失敗");
  }
}

void loop() {
  // 空循環
}

要燒入前需要將燒入檔寫入到esp32中可以利用spiffs,可以參考這裡來寫入檔案。

寫入完成後要記得將SPIFFS 中的文件路徑及波特率(螢幕的)改成自己的即可

// 固定配置
#define TFT_FILE_PATH "/lcdtest.bin" // SPIFFS 中的文件路徑

#define BAUD_RATE 115200             // 替換為你的波特率

⚠️注意事項⚠️

從USART HMI中是導出.tft檔,也是可以將檔案改成.bin都是一樣的,esp32範例是有改成.bin所要注意一下。

這樣就可以用esp32進行燒入啦~燒入完成後要按下boot的按鈕才會開始燒入

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *