【ESP32】实现使用esp32s3 使用st7789 并口屏幕驱动,进行tcp局域网投屏

基于clion ide和paltformio插件,在arduino框架下,实现投屏

常见的都是使用spi串口屏,但是为了提高刷新速度,这里希望通过使用并口屏实现屏幕的驱动。

完整程序代码如下:https://github.com/OULIHONG1999/esp32s3_tcp_screencpy.git
代码仓库连接

投屏软件界面展示

库文件

1. TFT_eSPI
2. TJpg_Decoder

其中主要是修改了User_Setup.h中的文件配置,并在main文件的setup()函数中,取消原来使用DMA方式的初始化,以及在绘制屏幕画面时,取消了DMA发送数据,绘制屏幕的方式

部分代码展示

  1. main.cpp文件
#include <Arduino.h>

#include <TFT_eSPI.h>
#include <SPI.h>
#include <WiFi.h>
#include <TJpg_Decoder.h>
#include <pgmspace.h>
#include <esp_lcd_panel_ops.h>

// 从32改为128,增加缓存,增加速度
uint16_t  PROGMEM dmaBuffer1[128 * 128]; // Toggle buffer for 32*32 MCU block, 1024bytes
uint16_t  PROGMEM dmaBuffer2[128 * 128]; // Toggle buffer for 32*32 MCU block, 1024bytes
uint16_t *dmaBufferPtr = dmaBuffer1;
bool dmaBufferSel = 0;

TFT_eSPI tft = TFT_eSPI();
TFT_eSprite clk = TFT_eSprite(&tft);
char *ssid = "CMCC-ABCD"; //填写你的wifi名字
char *password = "66668888"; //填写你的wifi密码
int httpPort = 8081; //设置监听端口
WiFiServer server; //初始化一个服务端对象
uint8_t buff[7000] PROGMEM = {0};//每一帧的临时缓存
uint8_t img_buff[50000] PROGMEM = {0};//用于存储tcp传过来的图片
uint16_t size_count = 0;//计算一帧的字节大小

bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t *bitmap) {
    if (y >= tft.height()) return 0;
    
    // Double buffering is used, the bitmap is copied to the buffer by pushImageDMA() the
    // bitmap can then be updated by the jpeg decoder while DMA is in progress
    if (dmaBufferSel) dmaBufferPtr = dmaBuffer2;
    else dmaBufferPtr = dmaBuffer1;
    dmaBufferSel = !dmaBufferSel; // Toggle buffer selection
    //  pushImageDMA() will clip the image block at screen boundaries before initiating DMA
//    tft.pushImageDMA(x, y, w, h, bitmap, dmaBufferPtr); // Initiate DMA - blocking only if last DMA is not complete // 不使用,注释掉
    tft.pushImage(x, y, w, h, bitmap); // 使用其他的绘制函数

    return 1;
}

byte loadNum = 6;

void loading(byte delayTime) {//启动动画
    clk.setColorDepth(8);
    
    clk.createSprite(200, 50);
    clk.fillSprite(0x0000);
    
    clk.drawRoundRect(0, 0, 200, 16, 8, 0xFFFF);
    clk.fillRoundRect(3, 3, loadNum, 10, 5, 0xFFFF);
    clk.setTextDatum(CC_DATUM);
    clk.setTextColor(TFT_GREEN, 0x0000);
    clk.drawString("Connecting to WiFi", 100, 40, 2);
    clk.pushSprite(20, 67);//20 110
    clk.deleteSprite();
    loadNum += 1;
    if (loadNum >= 195) {
        loadNum = 195;
    }
    delay(delayTime);
}


int power_on_key = 21;
// 开机使能按键,根据需求使用
void init_power() {
    pinMode(power_on_key, OUTPUT);
    digitalWrite(power_on_key, HIGH);
}
void setup() {
    init_power();
    // put your setup code here, to run once:
    Serial.begin(115200);
    tft.begin();
//    tft.initDMA(); // 不使用,注释掉
    tft.setRotation(3);//横屏
    tft.fillScreen(TFT_BLACK);//黑色
    tft.setTextColor(TFT_BLACK, TFT_WHITE);
    
    WiFi.begin(ssid, password); //连接wifi
    delay(1000); //等待1秒
    while (WiFi.status() != WL_CONNECTED) {
        for (byte n = 0; n < 10; n++) { //每500毫秒检测一次状态
            loading(50);
        }
    }
    while (loadNum < 195) { //让动画走完
        loading(3);
    }
    if (WiFi.status() == WL_CONNECTED) //判断如果wifi连接成功
    {
        
        //client.setNoDelay(false);//关闭Nagle算法
        Serial.println("wifi is connected!");
        Serial.print("SSID: ");
        Serial.println(WiFi.SSID());
        IPAddress ip = WiFi.localIP();
        Serial.print("IP Address: ");
        Serial.println(ip);
        Serial.println("Port: " + String(httpPort));
        //tft.setSwapBytes(true);
        tft.setRotation(0);
        tft.fillScreen(TFT_BLACK);//黑色
        tft.setTextColor(TFT_BLACK, TFT_WHITE);
        tft.drawString("Wifi Have Connected To " + String(WiFi.SSID()), 20, 20, 2);
        
        tft.drawString("IP: " + ip.toString(), 20, 40, 2);
        tft.drawString("Port: " + String(httpPort), 20, 60, 2);
        Serial.println("Waiting a client to connect.........");
        server.begin(httpPort); //服务器启动监听端口号
        server.setNoDelay(true);
    }
    TJpgDec.setJpgScale(1);
    TJpgDec.setSwapBytes(true);
    TJpgDec.setCallback(tft_output);//解码成功回调函数
}

uint16_t read_count = 0;//读取buff的长度
uint8_t pack_size[2];//用来装包大小字节
uint16_t frame_size;//当前帧大小
float start_time, end_time;//帧处理开始和结束时间
float receive_time, deal_time;//帧接收和解码时间

void loop() {
    // put your main code here, to run repeatedly:
    //沾包问题 recv阻塞,长时间收不到数据就会断开
    //断开连接原因,读取buff太快,上位机发送太快造成buff溢出,清空缓冲区会断开(FLUSH)
    WiFiClient client = server.available(); //尝试建立客户对象
    if (client) {
        Serial.println("[New Client!]");
        client.write("ok");//向上位机发送下一帧发送指令
        
        while (client.connected())//如果客户端处于连接状态client.connected()
        {
            client.write("no");//向上位机发送当前帧未写入完指令
            while (client.available()) {
                while (client.available()) {//检测缓冲区是否有数据
                    if (read_count == 0) {
                        start_time = millis();
                        client.read(pack_size, 2);//读取帧大小
                        frame_size = pack_size[0] + (pack_size[1] << 8);
                    }
                    read_count = client.read(buff, 7000);//向缓冲区读取数据
                    memcpy(&img_buff[size_count], buff, read_count);//将读取的buff字节地址复制给img_buff数组
                    size_count = size_count + read_count;//计数当前帧字节位置
                    //           Serial.println(size_count);
                    if (img_buff[frame_size - 3] == 0xaa && img_buff[frame_size - 2] == 0xbb &&
                        img_buff[frame_size - 1] == 0xcc)//判断末尾数据是否当前帧校验位
                    {
                        receive_time = millis() - start_time;
                        deal_time = millis();
                        img_buff[frame_size - 3] = 0;
                        img_buff[frame_size - 2] = 0;
                        img_buff[frame_size - 1] = 0;//清除标志位
                        tft.startWrite();//必须先使用startWrite,以便TFT芯片选择保持低的DMA和SPI通道设置保持配置
                        TJpgDec.drawJpg(0, 0, img_buff,
                                        sizeof(img_buff));//在左上角的0,0处绘制图像——在这个草图中,DMA请求在回调tft_output()中处理
                        tft.endWrite();//必须使用endWrite来释放TFT芯片选择和释放SPI通道吗
                        //            memset(&img_buff,0,sizeof(img_buff));//清空buff
                        size_count = 0;//下一帧
                        read_count = 0;
                        client.write("ok");//向上位机发送下一帧发送指令
                        end_time = millis(); //计算mcu刷新一张图片的时间,从而算出1s能刷新多少张图,即得出最大刷新率
                        Serial.printf("帧大小:%d ", frame_size);
                        Serial.print("MCU处理速度:");
                        Serial.print(1000 / (end_time - start_time), 2);
                        Serial.print("Fps");
                        Serial.printf("帧接收耗时:%.2fms,帧解码显示耗时:%.2fms\n", receive_time,
                                      (millis() - deal_time));
                        break;
                    }
                }
            }
        }
        client.stop();
        Serial.println("连接中断,请复位重新创建服务端");
    }
}
  1. User_Setup.h 部分配置文件代码
// Tell the library to use 8-bit parallel mode (otherwise SPI is assumed)

// st7789使用到的并口引脚,需要打开的内容

#define TFT_PARALLEL_8_BIT

// The ESP32 and TFT the pins used for testing are:
#undef TFT_CS // 防止重复定义
#define TFT_CS   6  // Chip select control pin (library pulls permanently low
#undef TFT_DC
#define TFT_DC   7  // Data Command control pin - must use a pin in the range 0-31
#undef TFT_RST
#define TFT_RST  5  // Reset pin, toggles on startup

#define TFT_WR    8  // Write strobe control pin - must use a pin in the range 0-31
#define TFT_RD    9  // Read strobe control pin

#define TFT_D0   39  // Must use pins in the range 0-31 for the data bus
#define TFT_D1   40  // so a single register write sets/clears all bits.
#define TFT_D2   41  // Pins can be randomly assigned, this does not affect
#define TFT_D3   42  // TFT screen update performance.
#define TFT_D4   45
#define TFT_D5   46
#define TFT_D6   47
#define TFT_D7   48
#define PIN_POWER_ON                 21

#undef TFT_BL
#define TFT_BL   38            // LED back-light control pin
#define TFT_BACKLIGHT_ON HIGH  // Level to turn ON back-light (HIGH or LOW)
  1. 在配置代码中,记得取消掉原来的其他配置,防止编译时冲突
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值