ESP32 GC9A01 实现仪表盘项目

在刚开始学习时即使示例放到面前,也根本无从下手,所以有了这篇文章,让我们进入正题

一、

先看效果:

 

看着还不错吧,中间的表针是可以移动的哦,那么直接进入正题

二、接线

这次接线和之前有一些不同,因为参考了其他的代码,也可以改成自己喜欢的

VCC - 3.3V
GND - GND
SCL - D18
SDA - D23
DC  - D16
CS  - D22
RST - D4

三、环境

首先安装Adafruit_GC9A01A 库

GitHub - adafruit/Adafruit_GC9A01A: Adafruit_GFX-compatible library for GC9A01A display drivericon-default.png?t=N7T8https://github.com/adafruit/Adafruit_GC9A01A这是库的github地址,安装后还需要安装TFT_eSPI 库,这个库可以直接在Arduino IDE中安装

选择最左边的第三个,然后搜索安装就可以了

四、修改文件

因为TFT_eSPI库兼容很多显示屏和开发板,所以需要设置一下

在 C:\Users\Admin\Documents\Arduino\libraries\TFT_eSPI 下找到User_Setup.h文件复制一份,然后修改User_Setup.h文件(不要修改到你复制的文件了,那个只是为了让你备份一份),将里面的内容替换如下

#define GC9A01_DRIVER
#define TFT_MOSI 23
#define TFT_SCLK 18
#define TFT_CS   22
#define TFT_DC   16                                                                                                                                                                               
#define TFT_RST  4

#define LOAD_GLCD   // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
#define LOAD_FONT2  // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
#define LOAD_FONT4  // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters
#define LOAD_FONT6  // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm
#define LOAD_FONT7  // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:-.
#define LOAD_FONT8  // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-.
#define LOAD_GFXFF  // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts

#define SMOOTH_FONT

#define SPI_FREQUENCY  27000000
#define SPI_READ_FREQUENCY  20000000
#define SPI_TOUCH_FREQUENCY  2500000 

然后保存退出

五、查看示例,录入程序

现在打开你的Arduino IDE 依次 文件->示例->TFT_eSPI->Sprite->Animated_dial

然后点击录入,就可以了,现在你就可以看到你的屏幕上显示了一个随机移动表针的仪表盘了,因为官方的是英文的,所以我让chatGPT为我翻译了一下

// 定义指针的长度、宽度、半径和颜色
#define NEEDLE_LENGTH 35  // 可见长度
#define NEEDLE_WIDTH   5  // 指针宽度 - 设置为奇数
#define NEEDLE_RADIUS 90  // 指针顶端的半径
#define NEEDLE_COLOR1 TFT_MAROON  // 指针外围颜色
#define NEEDLE_COLOR2 TFT_RED     // 指针中心颜色
#define DIAL_CENTRE_X 120  // 表盘中心的X坐标
#define DIAL_CENTRE_Y 120  // 表盘中心的Y坐标

// 加载字体
#include "NotoSansBold36.h"
#define AA_FONT_LARGE NotoSansBold36

#include <TFT_eSPI.h>
TFT_eSPI tft = TFT_eSPI();  // 创建TFT对象
TFT_eSprite needle = TFT_eSprite(&tft);  // 用于指针的精灵对象
TFT_eSprite spr    = TFT_eSprite(&tft);  // 用于显示刻度的精灵对象

// 加载jpeg图片数据
#include "dial.h"

// 包含jpeg解码库
#include <TJpg_Decoder.h>

uint16_t* tft_buffer;  // 用于存储TFT屏幕像素块的缓冲区
bool      buffer_loaded = false;  // 缓冲区是否已加载
uint16_t  spr_width = 0;  // 精灵宽度
uint16_t  bg_color =0;  // 背景颜色

// 这个函数将在解码jpeg文件时被调用
bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap)
{
  // 如果图片超出了屏幕边界,停止进一步解码
  if ( y >= tft.height() ) return 0;

  // 该函数会自动剪裁图像块,并将其渲染到TFT屏幕上
  tft.pushImage(x, y, w, h, bitmap);

  // 返回1以解码下一个块
  return 1;
}

// 初始化设置
void setup()   {
  Serial.begin(115200); // 仅用于调试

  // 设置字节顺序(对于TFT_eSPI设置为true)
  TJpgDec.setSwapBytes(true);

  // 必须给jpeg解码器指定渲染函数
  TJpgDec.setCallback(tft_output);

  tft.begin();
  tft.setRotation(0);
  tft.fillScreen(TFT_BLACK);

  // 绘制表盘
  TJpgDec.drawJpg(0, 0, dial, sizeof(dial));
  tft.drawCircle(DIAL_CENTRE_X, DIAL_CENTRE_Y, NEEDLE_RADIUS-NEEDLE_LENGTH, TFT_DARKGREY);

  // 加载字体并创建显示刻度的精灵
  spr.loadFont(AA_FONT_LARGE);
  spr_width = spr.textWidth("777"); // 数字7在此字体中最宽
  spr.createSprite(spr_width, spr.fontHeight());
  bg_color = tft.readPixel(120, 120); // 从表盘中心获取颜色
  spr.fillSprite(bg_color);
  spr.setTextColor(TFT_WHITE, bg_color, true);
  spr.setTextDatum(MC_DATUM);
  spr.setTextPadding(spr_width);
  spr.drawNumber(0, spr_width/2, spr.fontHeight()/2);
  spr.pushSprite(DIAL_CENTRE_X - spr_width / 2, DIAL_CENTRE_Y - spr.fontHeight() / 2);

  // 绘制标签文字
  tft.setTextColor(TFT_WHITE, bg_color);
  tft.setTextDatum(MC_DATUM);
  tft.drawString("(degrees)", DIAL_CENTRE_X, DIAL_CENTRE_Y + 48, 2);

  // 在创建指针之前,定义指针在TFT上的旋转中心点
  tft.setPivot(DIAL_CENTRE_X, DIAL_CENTRE_Y);

  // 创建指针精灵
  createNeedle();

  // 将指针位置重置为0
  plotNeedle(0, 0);

  delay(2000);  // 延迟2秒
}

// 主循环
void loop() {
  uint16_t angle = random(241); // 随机生成0到240范围内的角度

  // 以每次40ms的增量绘制指针到随机角度
  plotNeedle(angle, 30);

  // 在新位置暂停2.5秒
  delay(2500);
}

// 创建指针精灵
void createNeedle(void)
{
  needle.setColorDepth(16);  // 设置颜色深度
  needle.createSprite(NEEDLE_WIDTH, NEEDLE_LENGTH);  // 创建指针精灵

  needle.fillSprite(TFT_BLACK); // 用黑色填充精灵

  // 定义相对于精灵左上角的指针旋转点
  uint16_t piv_x = NEEDLE_WIDTH / 2; // 精灵的旋转点x(在中间)
  uint16_t piv_y = NEEDLE_RADIUS;    // 精灵的旋转点y
  needle.setPivot(piv_x, piv_y);     // 设置旋转点

  // 在精灵中绘制红色指针
  needle.fillRect(0, 0, NEEDLE_WIDTH, NEEDLE_LENGTH, TFT_MAROON);
  needle.fillRect(1, 1, NEEDLE_WIDTH-2, NEEDLE_LENGTH-2, TFT_RED);

  // 获取旋转后边界的参数
  int16_t min_x;
  int16_t min_y;
  int16_t max_x;
  int16_t max_y;

  // 计算必须从TFT上抓取的最坏情况区域(45度旋转时)
  needle.getRotatedBounds(45, &min_x, &min_y, &max_x, &max_y);

  // 计算缓冲区大小并分配用于抓取TFT区域的缓冲区
  tft_buffer =  (uint16_t*) malloc( ((max_x - min_x) + 2) * ((max_y - min_y) + 2) * 2 );
}

// 将指针移动到新位置
void plotNeedle(int16_t angle, uint16_t ms_delay)
{
  static int16_t old_angle = -120; // 初始角度为-120度

  // 边界框参数
  static int16_t min_x;
  static int16_t min_y;
  static int16_t max_x;
  static int16_t max_y;

  if (angle < 0) angle = 0; // 限制角度以模拟指针停止
  if (angle > 240) angle = 240;

  angle -= 120; // 从-120度开始

  // 逐步移动指针,直到达到新角度
  while (angle != old_angle || !buffer_loaded) {

    if (old_angle < angle) old_angle++;
    else old_angle--;

    // 仅在偶数值时绘制指针以提高绘制性能
    if ( (old_angle & 1) == 0)
    {
      if (buffer_loaded) {
        // 将原始区域推回到屏幕上以擦除旧指针图形
        tft.pushRect(min_x, min_y, 1 + max_x - min_x, 1 + max_y - min_y, tft_buffer);
      }

      if ( needle.getRotatedBounds(old_angle, &min_x, &min_y, &max_x, &max_y) )
      {
        // 在绘制指针之前抓取该区域的副本
        tft.readRect(min_x, min_y, 1 + max_x - min_x, 1 + max_y - min_y, tft_buffer);
        buffer_loaded = true;
      }

      // 在新位置绘制指针,指针图像中的黑色为透明
      needle.pushRotated(old_angle, TFT_BLACK);

      // 在下一次更新之前延迟
      delay(ms_delay);
    }

    // 更新表盘中心的数字
    spr.setTextColor(TFT_WHITE, bg_color, true);
    spr.drawNumber(old_angle+120, spr_width/2, spr.fontHeight()/2);
    spr.pushSprite(120 - spr_width / 2, 120 - spr.fontHeight() / 2);

    // 在指针接近新位置时稍微放慢速度
    if (abs(old_angle - angle) < 10) ms_delay += ms_delay / 5;
  }
}

这是翻译后的文章,你可以发现,使用这个代码非常简单,在loop函数中随机数据然后直接显示在表盘中,这非常的便捷,所以我们可以直接利用这个方法,增加一个可变电阻器来控制这个仪表盘的显示

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值