【Arduino】189种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验二百四十九:1.28寸圆形彩色TFT显示屏 高清IPS 模块 240*240 SPI接口GC9A01驱动
项目实验之三十九:模拟手表时钟指针、数字时间显示、日期窗口和装饰性刻度
实验开源代码
/*
【Arduino】189种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验二百四十九:1.28寸圆形彩色TFT显示屏 高清IPS 模块 240*240 SPI接口GC9A01驱动
项目实验之三十九:模拟手表时钟指针、数字时间显示、日期窗口和装饰性刻度
*/
// GC9A01---------- ESP32
// RST ------------ NC(复位引脚,此处未连接)
// CS ------------- D4(片选引脚,连接到ESP32的D4引脚)
// DC ------------- D2(数据/命令选择引脚,连接到ESP32的D2引脚)
// SDA ------------ D23 (green)(主数据输出引脚,连接到ESP32的D23引脚,绿色线)
// SCL ------------ D18 (yellow)(时钟信号引脚,连接到ESP32的D18引脚,黄色线)
// GND ------------ GND(接地引脚,连接到ESP32的接地端)
// VCC -------------3V3(电源引脚,连接到ESP32的3.3V电源)
#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_GC9A01A.h"
// 定义屏幕引脚
#define TFT_CS 4 // 片选引脚
#define TFT_DC 2 // 数据/命令引脚
#define TFT_RST -1 // 重置引脚(未使用时设置为 -1)
// 初始化屏幕对象
Adafruit_GC9A01A tft = Adafruit_GC9A01A(TFT_CS, TFT_DC, TFT_RST);
// 定义屏幕中心
#define SCREEN_CENTER_X 120
#define SCREEN_CENTER_Y 120
#define CLOCK_RADIUS 100
#define HAND_COLOR GC9A01A_WHITE // 指针颜色
// 初始化时间变量
int hours = 01, minutes = 42, seconds = 00; // 初始化时间为 01:42:00
void drawClockFace() {
// 绘制表盘外圈
tft.drawCircle(SCREEN_CENTER_X, SCREEN_CENTER_Y, CLOCK_RADIUS, GC9A01A_WHITE);
tft.drawCircle(SCREEN_CENTER_X, SCREEN_CENTER_Y, CLOCK_RADIUS - 5, GC9A01A_CYAN);
// 绘制小时刻度
for (int i = 0; i < 12; i++) {
float angle = i * 30 * 3.14159 / 180;
int x1 = SCREEN_CENTER_X + (CLOCK_RADIUS - 10) * cos(angle);
int y1 = SCREEN_CENTER_Y + (CLOCK_RADIUS - 10) * sin(angle);
int x2 = SCREEN_CENTER_X + (CLOCK_RADIUS - 20) * cos(angle);
int y2 = SCREEN_CENTER_Y + (CLOCK_RADIUS - 20) * sin(angle);
tft.drawLine(x1, y1, x2, y2, GC9A01A_WHITE);
}
// 绘制分钟刻度
for (int i = 0; i < 60; i++) {
if (i % 5 != 0) { // 避开小时刻度
float angle = i * 6 * 3.14159 / 180;
int x1 = SCREEN_CENTER_X + (CLOCK_RADIUS - 10) * cos(angle);
int y1 = SCREEN_CENTER_Y + (CLOCK_RADIUS - 10) * sin(angle);
tft.drawPixel(x1, y1, GC9A01A_YELLOW);
}
}
}
void drawHands() {
// 计算时针位置
float hourAngle = (hours % 12 + minutes / 60.0) * 30 * 3.14159 / 180;
int hourX = SCREEN_CENTER_X + (CLOCK_RADIUS - 50) * cos(hourAngle);
int hourY = SCREEN_CENTER_Y + (CLOCK_RADIUS - 50) * sin(hourAngle);
tft.drawLine(SCREEN_CENTER_X, SCREEN_CENTER_Y, hourX, hourY, HAND_COLOR);
// 计算分针位置
float minuteAngle = (minutes + seconds / 60.0) * 6 * 3.14159 / 180;
int minuteX = SCREEN_CENTER_X + (CLOCK_RADIUS - 30) * cos(minuteAngle);
int minuteY = SCREEN_CENTER_Y + (CLOCK_RADIUS - 30) * sin(minuteAngle);
tft.drawLine(SCREEN_CENTER_X, SCREEN_CENTER_Y, minuteX, minuteY, GC9A01A_GREEN);
// 计算秒针位置
float secondAngle = seconds * 6 * 3.14159 / 180;
int secondX = SCREEN_CENTER_X + (CLOCK_RADIUS - 20) * cos(secondAngle);
int secondY = SCREEN_CENTER_Y + (CLOCK_RADIUS - 20) * sin(secondAngle);
tft.drawLine(SCREEN_CENTER_X, SCREEN_CENTER_Y, secondX, secondY, GC9A01A_RED);
}
void displayDigitalTime() {
// 绘制数字时间
tft.setTextSize(2);
tft.setTextColor(GC9A01A_WHITE, GC9A01A_BLACK); // 白色文字,黑色背景
tft.setCursor(73, 160);
tft.printf("%02d:%02d:%02d", hours, minutes, seconds);
// 显示日期窗口
tft.setTextSize(2);
tft.setCursor(62, 180);
tft.printf("2025/03/28");
}
void updateClock() {
seconds++;
if (seconds >= 60) {
seconds = 0;
minutes++;
}
if (minutes >= 60) {
minutes = 0;
hours++;
}
if (hours >= 24) {
hours = 0;
}
}
void setup() {
Serial.begin(115200); // 初始化串口通信
Serial.println("Complex Watch Face");
tft.begin(); // 初始化屏幕
tft.setRotation(2); // 设置屏幕方向
tft.fillScreen(GC9A01A_BLACK); // 清屏设置为黑色背景
drawClockFace(); // 绘制表盘
}
void loop() {
// 清除上一帧的指针和数字区域
tft.fillCircle(SCREEN_CENTER_X, SCREEN_CENTER_Y, CLOCK_RADIUS - 5, GC9A01A_BLACK);
// 更新动态内容
drawClockFace();
drawHands();
displayDigitalTime();
updateClock();
delay(1000); // 每秒刷新一次
}
代码说明
1、复杂表盘设计:
多层刻度:包括小时刻度和分钟刻度。
双功能显示:模拟指针显示和数字时间显示同时存在。
2、动态时间更新:
时间每秒更新,分针和时针会根据当前时间调整位置。
3、多色指针:
不同颜色用于区分秒针(红色)、分针(绿色)和时针(白色)。
4、装饰性圆圈:
表盘边缘绘制多层圆圈,增强设计美感。
5、时间和日期显示:
在表盘底部显示当前时间和固定的日期信息。
6、效果描述
表盘中央模拟指针式时钟,刻度和指针分明,色彩丰富。
底部数字显示当前时间和固定日期信息,结合现代和经典设计。
动态更新的时间显示,让表盘实时变化。
代码解读
1、屏幕初始化
#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_GC9A01A.h"
引入 SPI 和 Adafruit_GFX 库,用于图形绘制功能。
引入 Adafruit_GC9A01A 库,专用于驱动 GC9A01A 圆形屏幕,提供绘制圆形、线条、文字等能力。
2、屏幕硬件配置
#define TFT_CS 4
#define TFT_DC 2
#define TFT_RST -1
Adafruit_GC9A01A tft = Adafruit_GC9A01A(TFT_CS, TFT_DC, TFT_RST);
TFT_CS、TFT_DC 和 TFT_RST 是屏幕的引脚定义。
TFT_RST 为 -1,表示未使用复位引脚。
使用 Adafruit_GC9A01A 初始化屏幕对象 tft。
3、 屏幕中心和表盘参数
#define SCREEN_CENTER_X 120
#define SCREEN_CENTER_Y 120
#define CLOCK_RADIUS 100
#define HAND_COLOR GC9A01A_WHITE
定义屏幕中心 (120, 120),适配 GC9A01A 的圆形屏幕(分辨率 240x240 像素)。
表盘半径设置为 100 像素,指针颜色设为白色。
4、时间变量初始化
int hours = 01, minutes = 42, seconds = 00;
时间初始化为 01:42:00。
5、绘制表盘的功能
5.1 绘制表盘外圈
tft.drawCircle(SCREEN_CENTER_X, SCREEN_CENTER_Y, CLOCK_RADIUS, GC9A01A_WHITE);
tft.drawCircle(SCREEN_CENTER_X, SCREEN_CENTER_Y, CLOCK_RADIUS - 5, GC9A01A_CYAN);
绘制两个同心圆,形成表盘外圈,分别使用白色和青色,增加美感。
5.2 绘制小时刻度
for (int i = 0; i < 12; i++) {
float angle = i * 30 * 3.14159 / 180;
int x1 = SCREEN_CENTER_X + (CLOCK_RADIUS - 10) * cos(angle);
int y1 = SCREEN_CENTER_Y + (CLOCK_RADIUS - 10) * sin(angle);
int x2 = SCREEN_CENTER_X + (CLOCK_RADIUS - 20) * cos(angle);
int y2 = SCREEN_CENTER_Y + (CLOCK_RADIUS - 20) * sin(angle);
tft.drawLine(x1, y1, x2, y2, GC9A01A_WHITE);
}
使用 cos 和 sin 函数计算小时刻度位置(角度每小时增加 30°)。
两点 (x1, y1) 和 (x2, y2) 通过 drawLine 绘制刻度线。
5.3 绘制分钟刻度
for (int i = 0; i < 60; i++) {
if (i % 5 != 0) { // 避开小时刻度
float angle = i * 6 * 3.14159 / 180;
int x1 = SCREEN_CENTER_X + (CLOCK_RADIUS - 10) * cos(angle);
int y1 = SCREEN_CENTER_Y + (CLOCK_RADIUS - 10) * sin(angle);
tft.drawPixel(x1, y1, GC9A01A_YELLOW);
}
}
使用 cos 和 sin 函数计算分钟刻度位置(角度每分钟增加 6°)。
每 5 分钟避开小时刻度,仅绘制点刻度。
6、绘制指针的功能
6.1 时针
float hourAngle = (hours % 12 + minutes / 60.0) * 30 * 3.14159 / 180;
int hourX = SCREEN_CENTER_X + (CLOCK_RADIUS - 50) * cos(hourAngle);
int hourY = SCREEN_CENTER_Y + (CLOCK_RADIUS - 50) * sin(hourAngle);
tft.drawLine(SCREEN_CENTER_X, SCREEN_CENTER_Y, hourX, hourY, HAND_COLOR);
根据当前时间计算时针角度:
每小时角度增量为 30°,并加入分钟的偏移。
时针长度为半径减 50 像素。
6.2 分针
float minuteAngle = (minutes + seconds / 60.0) * 6 * 3.14159 / 180;
int minuteX = SCREEN_CENTER_X + (CLOCK_RADIUS - 30) * cos(minuteAngle);
int minuteY = SCREEN_CENTER_Y + (CLOCK_RADIUS - 30) * sin(minuteAngle);
tft.drawLine(SCREEN_CENTER_X, SCREEN_CENTER_Y, minuteX, minuteY, GC9A01A_GREEN);
分针角度每分钟增加 6°,同时加入秒数偏移。
分针长度为半径减 30 像素。
6.3 秒针
float secondAngle = seconds * 6 * 3.14159 / 180;
int secondX = SCREEN_CENTER_X + (CLOCK_RADIUS - 20) * cos(secondAngle);
int secondY = SCREEN_CENTER_Y + (CLOCK_RADIUS - 20) * sin(secondAngle);
tft.drawLine(SCREEN_CENTER_X, SCREEN_CENTER_Y, secondX, secondY, GC9A01A_RED);
秒针角度每秒增加 6°。
秒针长度为半径减 20 像素。
7、显示数字时间
tft.setTextSize(2);
tft.setTextColor(GC9A01A_WHITE, GC9A01A_BLACK); // 白色文字,黑色背景
tft.setCursor(73, 160);
tft.printf("%02d:%02d:%02d", hours, minutes, seconds);
显示数字时间,格式为 01:42:00,居中显示在表盘下方。
8、更新时间
seconds++;
if (seconds >= 60) {
seconds = 0;
minutes++;
}
if (minutes >= 60) {
minutes = 0;
hours++;
}
if (hours >= 24) {
hours = 0;
}
每秒更新时间变量,并递归处理分钟和小时的变化。
9、主循环
tft.fillCircle(SCREEN_CENTER_X, SCREEN_CENTER_Y, CLOCK_RADIUS - 5, GC9A01A_BLACK);
drawClockFace();
drawHands();
displayDigitalTime();
updateClock();
delay(1000);
清除上一帧内容,绘制表盘、指针和数字时间,并更新时间。
以每秒 (delay(1000)) 的速率刷新表盘内容。
实验场景图 动态图



评论