【花雕学编程】Arduino TFT 之简单的菜单界面

在这里插入图片描述

Arduino是一个开放源码的电子原型平台,它可以让你用简单的硬件和软件来创建各种互动的项目。Arduino的核心是一个微控制器板,它可以通过一系列的引脚来连接各种传感器、执行器、显示器等外部设备。Arduino的编程是基于C/C++语言的,你可以使用Arduino IDE(集成开发环境)来编写、编译和上传代码到Arduino板上。Arduino还有一个丰富的库和社区,你可以利用它们来扩展Arduino的功能和学习Arduino的知识。

Arduino的特点是:
1、开放源码:Arduino的硬件和软件都是开放源码的,你可以自由地修改、复制和分享它们。
2、易用:Arduino的硬件和软件都是为初学者和非专业人士设计的,你可以轻松地上手和使用它们。
3、便宜:Arduino的硬件和软件都是非常经济的,你可以用很低的成本来实现你的想法。
4、多样:Arduino有多种型号和版本,你可以根据你的需要和喜好来选择合适的Arduino板。
5、创新:Arduino可以让你用电子的方式来表达你的创意和想象,你可以用Arduino来制作各种有趣和有用的项目,如机器人、智能家居、艺术装置等。

在这里插入图片描述
Arduino TFT 是指与 Arduino 开发板兼容的薄膜晶体管(Thin - Film - Transistor)液晶显示屏,以下是其主要特点、应用场景及注意事项的详细介绍:

一、主要特点
1、高分辨率显示:TFT 显示屏通常具有较高的分辨率,能够提供清晰、细腻的图像和文字显示效果。这使得它可以展示复杂的图形界面、丰富的色彩以及详细的信息,满足各种应用对显示质量的要求。
2、快速响应速度:TFT 技术能够实现快速的像素切换,响应速度比传统的液晶显示屏更快。这意味着在显示动态图像或进行交互操作时,不会出现明显的拖影或延迟,提供流畅的视觉体验。
3、宽视角:具有较宽的可视角度,无论从哪个方向观看显示屏,都能获得清晰的图像和一致的色彩表现。这使得在不同角度下观察显示屏时,都能保证信息的准确传达,方便多人同时查看或在不同位置操作设备。
4、丰富的色彩表现:能够呈现出丰富、鲜艳的色彩,具备较高的色彩饱和度和对比度。可以准确地显示各种颜色,使图像和界面更加生动逼真,适用于需要展示彩色图像或进行视觉交互的应用。
5、易于控制:通过 Arduino 开发板可以方便地对 TFT 显示屏进行控制。借助相应的库函数和代码,能够轻松实现图像绘制、文字显示、触摸交互等功能,降低了开发难度,即使对于没有深厚显示技术背景的开发者也较为友好。

二、应用场景
1、人机交互界面:在各种电子设备中,如智能仪器仪表、智能家居控制系统、工业自动化控制面板等,作为人机交互的窗口,用于显示菜单、参数设置界面、实时数据监测以及操作提示等信息,方便用户与设备进行交互。
2、教育领域:可用于制作教育实验设备、电子学习工具等。例如,在教学机器人中作为显示屏,展示机器人的状态信息、任务指令以及互动内容;在电子积木等教育玩具中,显示图形化的编程界面或游戏画面,增加学习的趣味性和互动性。
3、便携式设备:如手持游戏机、电子书阅读器、便携式多媒体播放器等。其高分辨率、宽视角和丰富的色彩表现能够为用户提供良好的视觉享受,同时快速响应速度也适合处理游戏中的动态画面和多媒体内容的播放。
4、物联网应用:在物联网项目中,作为节点设备的显示屏,用于展示传感器采集的数据、设备状态信息以及远程控制界面等。例如,在环境监测系统中,显示温度、湿度、空气质量等数据;在智能农业中,展示农田的灌溉状态、作物生长信息等。

三、需要注意的事项
1、电源管理:TFT 显示屏通常需要稳定的电源供应,并且其功耗相对较高。在与 Arduino 连接时,要确保电源能够满足显示屏的需求,避免因电源不稳定导致显示屏出现闪烁、显示异常或损坏等问题。同时,要合理设计电源电路,考虑节能措施,特别是在电池供电的设备中,以延长设备的续航时间。
2、接口兼容性:不同型号的 Arduino 开发板和 TFT 显示屏可能具有不同的接口类型和通信协议。在选择和使用时,要确保两者之间的接口兼容,并且正确连接引脚。有些 TFT 显示屏可能需要额外的驱动电路或转接板才能与 Arduino 顺利连接,需要仔细阅读产品说明书并进行相应的配置。
3、显示内存限制:虽然 TFT 显示屏能够显示丰富的内容,但 Arduino 的内存资源有限。在绘制复杂图像或显示大量数据时,可能会遇到内存不足的问题。因此,需要合理规划显示内容,优化图像和数据的存储方式,避免因内存耗尽导致程序崩溃或显示异常。
4、驱动程序和库的使用:为了实现 TFT 显示屏的各种功能,需要使用相应的驱动程序和库。不同的显示屏可能需要不同的库,并且这些库可能会不断更新和改进。在使用过程中,要及时关注官方文档和社区资源,获取最新的驱动程序和库,并了解其使用方法和注意事项。同时,要注意库与 Arduino IDE 版本的兼容性,避免出现编译错误或运行时问题。
5、电磁干扰:在一些电磁环境较为复杂的场合,TFT 显示屏可能会受到电磁干扰,导致显示出现噪点、闪烁或颜色异常等问题。此时,需要采取相应的抗干扰措施,如合理布线、使用屏蔽线、添加滤波电容等,以确保显示屏的稳定工作。

在这里插入图片描述
Arduino TFT 简单菜单界面:详细解析
简单的菜单界面是基于 Arduino 和 TFT 显示屏开发的一种用户交互界面,常用于嵌入式系统中实现设备设置、参数调整或信息展示等功能。这种界面通常包括文本选项、按钮图标以及简单的导航逻辑(如上下选择和确认操作)。以下从主要特点、应用场景和注意事项三个方面进行专业解析。

一、主要特点
简洁直观的布局:
菜单界面通常采用分层结构,主菜单显示核心功能,子菜单显示详细选项。
布局设计清晰,常用元素包括标题栏、选项列表、滚动条(可选)和状态提示。
基本交互方式:
用户通过物理输入设备(如按键、旋转编码器或触摸屏)与菜单交互。
常见操作包括“上下移动光标”、“进入子菜单”和“返回上一级”。
动态更新内容:
使用 TFT_eSPI 库动态刷新屏幕内容,确保用户操作实时反映在界面上。
支持高亮显示当前选中项,增强用户体验。
模块化设计:
菜单逻辑通常以函数或类的形式封装,便于扩展和维护。
可根据需求灵活添加新选项或调整现有功能。
资源占用低:
简单的菜单界面占用较少的内存和计算资源,适合小型嵌入式设备(如 Arduino Uno 或 ESP32)。

二、应用场景
设备配置界面:
用于调整设备参数,例如时间设置、温度阈值、亮度调节等。
示例:智能家居控制器、工业设备操作面板。
数据监控与展示:
实时显示传感器数据或其他运行状态,并允许用户切换视图。
示例:气象站数据显示、健康监测仪。
教育与实验工具:
在教学实验中提供友好的交互界面,方便学生操作硬件设备。
示例:Arduino 教学开发板的功能演示菜单。
娱乐与互动装置:
在艺术装置或互动游戏中作为用户输入接口。
示例:触摸屏点餐机、互动展览控制台。
嵌入式系统调试:
开发者通过菜单界面快速测试硬件功能或读取调试信息。
示例:机器人控制系统的调试菜单。

三、需要注意的事项
输入设备的选择与适配:
如果使用物理按键,需考虑按键去抖动处理,避免误操作。
如果使用触摸屏,需校准触摸坐标并优化响应区域,防止误触。
屏幕分辨率与字体大小:
不同分辨率的 TFT 屏幕可能影响菜单布局的美观性。
字体大小需适中,确保文字清晰易读,同时避免过大的字体占用过多屏幕空间。
性能优化:
避免频繁清屏和重绘整个界面,建议仅更新需要变化的部分(如高亮项)。
对于复杂菜单,可以使用双缓冲技术(如果硬件支持)减少闪烁。
用户体验设计:
提供明确的视觉反馈(如高亮选中项、按钮按下效果),让用户清楚当前操作状态。
确保菜单层级不要太深,避免用户迷失在复杂的选项中。
代码结构与可扩展性:
使用模块化设计(如状态机或面向对象方法)管理菜单逻辑,便于后续功能扩展。
定义通用的菜单项结构(如名称、回调函数),简化新增选项的流程。
电源管理与稳定性:
如果设备长时间运行,需考虑屏幕背光控制和功耗优化。
在多任务环境中,确保菜单界面不会阻塞其他重要任务的执行。

四、总结
Arduino TFT 简单菜单界面是一种高效且实用的用户交互解决方案,其核心优势在于简洁直观的设计、低资源占用以及良好的可扩展性。在实际应用中,开发者需要根据具体场景选择合适的输入设备、优化屏幕布局,并注重用户体验和性能平衡。通过合理的规划和实现,这种界面可以广泛应用于设备配置、数据监控、教育工具等多个领域,为用户提供便捷的操作体验。

在这里插入图片描述
1、智能家居控制菜单界面

#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
 
#define TFT_CS 10
#define TFT_DC 9
#define TFT_RST 8
 
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
 
void setup() {
  tft.begin();
  tft.fillScreen(ILI9341_BLACK);
  tft.setRotation(1);
  drawMenu();
}
 
void loop() {
  // 模拟按钮输入切换选项
  static int selected = 0;
  delay(1000); // 每秒切换一次
  selected = (selected + 1) % 3;
  drawMenu(selected);
}
 
void drawMenu(int selected = -1) {
  tft.fillScreen(ILI9341_BLACK);
  tft.setTextColor(ILI9341_WHITE);
  tft.setTextSize(2);
  
  String options[] = {"Light Control", "Temperature", "Fan Speed"};
  for (int i = 0; i < 3; i++) {
    if (selected == i) {
      tft.setTextColor(ILI9341_RED);
    } else {
      tft.setTextColor(ILI9341_WHITE);
    }
    tft.setCursor(20, 50 + i * 40);
    tft.print(options[i]);
  }
}

要点解读
硬件配置:使用ILI9341控制器与Arduino UNO连接,通过SPI接口通信。
功能实现:
显示3个智能家居控制选项(灯光、温度、风扇)。
使用drawMenu()函数动态更新选中项的颜色。
应用场景:适用于智能家居面板,用户可通过物理按钮或触摸屏切换选项。

2、环境监测数据展示界面

#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
 
#define TFT_CS 10
#define TFT_DC 9
#define TFT_RST 8
 
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
 
void setup() {
  tft.begin();
  tft.fillScreen(ILI9341_BLACK);
  tft.setRotation(1);
}
 
void loop() {
  float temp = 25.6; // 模拟温度数据
  float hum = 60.2;  // 模拟湿度数据
  displayData(temp, hum);
  delay(2000); // 每2秒更新一次
}
 
void displayData(float temp, float hum) {
  tft.fillScreen(ILI9341_BLACK);
  tft.setTextColor(ILI9341_WHITE);
  tft.setTextSize(2);
  
  tft.setCursor(20, 30);
  tft.print("Temp: ");
  tft.print(temp);
  tft.print(" C");
  
  tft.setCursor(20, 70);
  tft.print("Hum: ");
  tft.print(hum);
  tft.print(" %");
}

要点解读
硬件配置:同案例一,使用ILI9341控制器。
功能实现:
实时显示温度和湿度数据。
使用displayData()函数更新屏幕内容。
应用场景:适用于环境监测设备,如气象站或温室控制系统。

3、教育机器人状态显示界面

#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
 
#define TFT_CS 10
#define TFT_DC 9
#define TFT_RST 8
 
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
 
void setup() {
  tft.begin();
  tft.fillScreen(ILI9341_BLACK);
  tft.setRotation(1);
  displayStatus();
}
 
void loop() {
  // 模拟状态变化
  delay(3000);
  displayStatus();
}
 
void displayStatus() {
  tft.fillScreen(ILI9341_BLACK);
  tft.setTextColor(ILI9341_WHITE);
  tft.setTextSize(2);
  
  tft.setCursor(20, 30);
  tft.print("Robot Status:");
  
  tft.setCursor(20, 70);
  tft.print("Battery: 80%");
  
  tft.setCursor(20, 110);
  tft.print("Task: Moving");
}

要点解读
硬件配置:同案例一,使用ILI9341控制器。
功能实现:
显示教育机器人的状态信息,包括电池电量和当前任务。
使用displayStatus()函数更新屏幕内容。
应用场景:适用于教学机器人或教育实验设备,帮助学生理解机器人状态监测。
总结
共性要点:
使用Adafruit_GFX和Adafruit_ILI9341库简化图形绘制。
通过fillScreen()清屏,setTextColor()和setTextSize()设置文本样式。
使用setCursor()定位文本位置。
差异要点:
案例一侧重于菜单导航,案例二侧重于数据展示,案例三侧重于状态监测。
每个案例根据应用场景调整了显示内容和更新频率。

在这里插入图片描述
4、基础文本菜单界面

#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>

// 定义TFT引脚
#define TFT_CS     10
#define TFT_RST    9
#define TFT_DC     8
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

// 菜单选项
const char *menuItems[] = {"Option 1", "Option 2", "Option 3"};
const int numMenuItems = sizeof(menuItems) / sizeof(menuItems[0]);
int selectedItem = 0;

void setup() {
  // 初始化串口通信
  Serial.begin(9600);
  // 初始化TFT屏幕
  tft.initR(INITR_BLACKTAB);
  tft.setRotation(1);
  tft.fillScreen(ST7735_BLACK);
}

void loop() {
  // 绘制菜单
  drawMenu();

  // 模拟菜单选择(这里用延时模拟用户操作)
  delay(2000);
  selectedItem = (selectedItem + 1) % numMenuItems;
}

void drawMenu() {
  tft.fillScreen(ST7735_BLACK);
  for (int i = 0; i < numMenuItems; i++) {
    if (i == selectedItem) {
      tft.setTextColor(ST7735_YELLOW);
    } else {
      tft.setTextColor(ST7735_WHITE);
    }
    tft.setCursor(10, 20 + i * 20);
    tft.println(menuItems[i]);
  }
}

要点解读:
库的引入:引入了Adafruit_GFX.h和Adafruit_ST7735.h库,前者是图形库,后者针对特定的 TFT 屏幕驱动。
菜单数据:借助数组menuItems存储菜单选项,numMenuItems记录选项数量,selectedItem表示当前选中的选项。
初始化:在setup()函数里初始化串口通信与 TFT 屏幕。
菜单绘制:drawMenu()函数负责绘制菜单,选中项以黄色显示,其他项以白色显示。
菜单选择:在loop()函数中,通过延时模拟用户操作,不断切换选中项。

5、带简单交互的菜单界面

#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>

#define TFT_CS     10
#define TFT_RST    9
#define TFT_DC     8
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

const char *menuItems[] = {"Item A", "Item B", "Item C"};
const int numMenuItems = sizeof(menuItems) / sizeof(menuItems[0]);
int selectedItem = 0;

// 模拟按键引脚
#define UP_BUTTON 2
#define DOWN_BUTTON 3
#define SELECT_BUTTON 4

void setup() {
  Serial.begin(9600);
  tft.initR(INITR_BLACKTAB);
  tft.setRotation(1);
  tft.fillScreen(ST7735_BLACK);

  // 设置按键引脚为输入模式
  pinMode(UP_BUTTON, INPUT_PULLUP);
  pinMode(DOWN_BUTTON, INPUT_PULLUP);
  pinMode(SELECT_BUTTON, INPUT_PULLUP);
}

void loop() {
  drawMenu();

  // 处理按键输入
  if (digitalRead(UP_BUTTON) == LOW) {
    delay(20); // 消抖
    if (digitalRead(UP_BUTTON) == LOW) {
      selectedItem = (selectedItem - 1 + numMenuItems) % numMenuItems;
      while (digitalRead(UP_BUTTON) == LOW); // 等待按键释放
    }
  } else if (digitalRead(DOWN_BUTTON) == LOW) {
    delay(20);
    if (digitalRead(DOWN_BUTTON) == LOW) {
      selectedItem = (selectedItem + 1) % numMenuItems;
      while (digitalRead(DOWN_BUTTON) == LOW);
    }
  } else if (digitalRead(SELECT_BUTTON) == LOW) {
    delay(20);
    if (digitalRead(SELECT_BUTTON) == LOW) {
      Serial.print("Selected: ");
      Serial.println(menuItems[selectedItem]);
      while (digitalRead(SELECT_BUTTON) == LOW);
    }
  }
}

void drawMenu() {
  tft.fillScreen(ST7735_BLACK);
  for (int i = 0; i < numMenuItems; i++) {
    if (i == selectedItem) {
      tft.setTextColor(ST7735_YELLOW);
    } else {
      tft.setTextColor(ST7735_WHITE);
    }
    tft.setCursor(10, 20 + i * 20);
    tft.println(menuItems[i]);
  }
}

要点解读:
按键处理:定义了三个模拟按键引脚UP_BUTTON、DOWN_BUTTON和SELECT_BUTTON,在setup()函数中把它们设置为输入上拉模式。
消抖处理:在loop()函数里,对按键输入进行处理时,采用延时消抖,防止按键抖动引发误操作。
菜单选择与确认:按下上、下按键能够切换选中项,按下选择按键会在串口输出选中项的信息。

6、多级菜单界面

#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>

#define TFT_CS     10
#define TFT_RST    9
#define TFT_DC     8
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

// 一级菜单
const char *mainMenuItems[] = {"Submenu 1", "Submenu 2", "Back"};
const int numMainMenuItems = sizeof(mainMenuItems) / sizeof(mainMenuItems[0]);
// 二级菜单1
const char *subMenu1Items[] = {"Option 1.1", "Option 1.2", "Back"};
const int numSubMenu1Items = sizeof(subMenu1Items) / sizeof(subMenu1Items[0]);
// 二级菜单2
const char *subMenu2Items[] = {"Option 2.1", "Option 2.2", "Back"};
const int numSubMenu2Items = sizeof(subMenu2Items) / sizeof(subMenu2Items[0]);

int selectedItem = 0;
int currentMenu = 0; // 0: 主菜单, 1: 子菜单1, 2: 子菜单2

#define UP_BUTTON 2
#define DOWN_BUTTON 3
#define SELECT_BUTTON 4

void setup() {
  Serial.begin(9600);
  tft.initR(INITR_BLACKTAB);
  tft.setRotation(1);
  tft.fillScreen(ST7735_BLACK);

  pinMode(UP_BUTTON, INPUT_PULLUP);
  pinMode(DOWN_BUTTON, INPUT_PULLUP);
  pinMode(SELECT_BUTTON, INPUT_PULLUP);
}

void loop() {
  drawMenu();

  if (digitalRead(UP_BUTTON) == LOW) {
    delay(20);
    if (digitalRead(UP_BUTTON) == LOW) {
      if (currentMenu == 0) {
        selectedItem = (selectedItem - 1 + numMainMenuItems) % numMainMenuItems;
      } else if (currentMenu == 1) {
        selectedItem = (selectedItem - 1 + numSubMenu1Items) % numSubMenu1Items;
      } else if (currentMenu == 2) {
        selectedItem = (selectedItem - 1 + numSubMenu2Items) % numSubMenu2Items;
      }
      while (digitalRead(UP_BUTTON) == LOW);
    }
  } else if (digitalRead(DOWN_BUTTON) == LOW) {
    delay(20);
    if (digitalRead(DOWN_BUTTON) == LOW) {
      if (currentMenu == 0) {
        selectedItem = (selectedItem + 1) % numMainMenuItems;
      } else if (currentMenu == 1) {
        selectedItem = (selectedItem + 1) % numSubMenu1Items;
      } else if (currentMenu == 2) {
        selectedItem = (selectedItem + 1) % numSubMenu2Items;
      }
      while (digitalRead(DOWN_BUTTON) == LOW);
    }
  } else if (digitalRead(SELECT_BUTTON) == LOW) {
    delay(20);
    if (digitalRead(SELECT_BUTTON) == LOW) {
      if (currentMenu == 0) {
        if (selectedItem == 0) {
          currentMenu = 1;
          selectedItem = 0;
        } else if (selectedItem == 1) {
          currentMenu = 2;
          selectedItem = 0;
        } else if (selectedItem == 2) {
          // 退出程序或其他操作
        }
      } else if (currentMenu == 1) {
        if (selectedItem == 2) {
          currentMenu = 0;
          selectedItem = 0;
        }
      } else if (currentMenu == 2) {
        if (selectedItem == 2) {
          currentMenu = 0;
          selectedItem = 0;
        }
      }
      while (digitalRead(SELECT_BUTTON) == LOW);
    }
  }
}

void drawMenu() {
  tft.fillScreen(ST7735_BLACK);
  if (currentMenu == 0) {
    for (int i = 0; i < numMainMenuItems; i++) {
      if (i == selectedItem) {
        tft.setTextColor(ST7735_YELLOW);
      } else {
        tft.setTextColor(ST7735_WHITE);
      }
      tft.setCursor(10, 20 + i * 20);
      tft.println(mainMenuItems[i]);
    }
  } else if (currentMenu == 1) {
    for (int i = 0; i < numSubMenu1Items; i++) {
      if (i == selectedItem) {
        tft.setTextColor(ST7735_YELLOW);
      } else {
        tft.setTextColor(ST7735_WHITE);
      }
      tft.setCursor(10, 20 + i * 20);
      tft.println(subMenu1Items[i]);
    }
  } else if (currentMenu == 2) {
    for (int i = 0; i < numSubMenu2Items; i++) {
      if (i == selectedItem) {
        tft.setTextColor(ST7735_YELLOW);
      } else {
        tft.setTextColor(ST7735_WHITE);
      }
      tft.setCursor(10, 20 + i * 20);
      tft.println(subMenu2Items[i]);
    }
  }
}

要点解读:
多级菜单结构:定义了主菜单和两个二级菜单,利用currentMenu变量来记录当前所处的菜单层级。
菜单切换:在loop()函数中,根据当前菜单层级和选中项处理按键输入,实现菜单的切换。
菜单绘制:drawMenu()函数依据当前菜单层级绘制相应的菜单。

注意,以上案例只是为了拓展思路,仅供参考。它们可能有错误、不适用或者无法编译。您的硬件平台、使用场景和Arduino版本可能影响使用方法的选择。实际编程时,您要根据自己的硬件配置、使用场景和具体需求进行调整,并多次实际测试。您还要正确连接硬件,了解所用传感器和设备的规范和特性。涉及硬件操作的代码,您要在使用前确认引脚和电平等参数的正确性和安全性。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

驴友花雕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值