本教程开发平台 ubuntu
2.4 寸 TFT 显示屏选型说明
本次项目选用2.4 英寸 8 线 SPI 接口 TFT 彩色显示屏,核心参数与选型优势如下:
1.驱动芯片:ILI9341,兼容性强,STM32 标准库与 HAL 库均有成熟驱动代码,分辨率 240×320,显示色彩丰富,满足时钟界面的时间、日期等信息展示需求。
2.硬件配置:新款带片选 CS 引脚,8 线 SPI 通信包含 SDA、SCL、CS、RES、DC、BLK 等关键引脚,通过 CS 引脚可精准控制数据传输,避免无 CS 引脚导致的屏幕乱码、刷新异常问题,稳定性优于简化版接口。
3.易用性:出厂已预焊接排针,8 线引脚全部引出,到手后可直接通过杜邦线与 STM32F103C8T6 最小系统板对应引脚连接,无需额外焊接,降低新手接线难度。
4.接口优势:8 线 SPI 相比 4 线 SPI 保留了完整控制信号,通信更稳定,同时仅占用 STM32 的 SPI 接口及少量 GPIO 引脚,为后续拓展按键、蜂鸣器等功能预留空间。
该显示屏的 8 线 SPI 接口设计既保证了通信稳定性,又兼顾了制作便捷性,非常适合作为自制时钟的显示模块。
DS3231 高精度实时时钟模块
DS3231 实时时钟模块作为时间核心,核心参数与选型优势如下:
1.高精度计时:内置温补晶振,温度漂移低至 ±2ppm,年误差小于 1 分钟,远高于普通 DS1302 模块,确保时钟走时准确。
2.通信协议:采用 I2C 总线通信,仅需 SDA、SCL 两根信号线与 STM32F103C8T6 连接,节省 IO 资源,代码实现简单。
3.断电续航:板载 CR2032 纽扣电池座,断电后可依靠电池继续计时,重新上电后时间无需重新校准,提升使用体验。
4.功能拓展:预留 SQW 方波输出引脚,可配置为 1Hz/1kHz 等频率,方便后续拓展闹钟、秒脉冲指示等功能。
5.稳定性设计:模块自带电源稳压电路,支持 3.3V-5V 宽电压输入,与 STM32 的 3.3V 逻辑电平完美兼容,接线简单且不易损坏。
作为时钟项目的 “时间心脏”,DS3231 的高精度和低功耗特性,能为整个系统提供可靠的时间基准。
主控芯片:STM32F103C8T6
STM32F103C8T6 Type‑C 升级版最小系统核心板
64KB Flash、20KB SRAM
杜邦线接线清单;
显示屏接线:7 根母对母杜邦线、1 根母对公杜邦线
时钟模块接线:3 根母对母杜邦线、1 根母对公杜邦线
供电并联接线:1 母转 2 母杜邦线 1 根,将时钟模块与显示屏的供电端并联至单片机 3.3V 引脚,实现双模块同电压稳定供电。
ST - LINK V2 下载器:
ST-LINK 下载器针脚 对应 开发板对应针脚;
3.3V 3.3V
GND GND
SWCLK SWCLK
SWDIO SWIO
platformio.ini
[env:bluepill_f103c8]
platform = ststm32
board = bluepill_f103c8
framework = arduino
upload_protocol = stlink
debug_tool = stlink
upload_port = auto
lib_deps =
bodmer/TFT_eSPI
adafruit/RTClib
adafruit/Adafruit Unified Sensor
build_flags =
-D USER_SETUP_LOADED=1
-D ILI9341_DRIVER=1
-D TFT_MOSI=PA7
-D TFT_SCLK=PA5
-D TFT_CS=PA4
-D TFT_DC=PA2
-D TFT_RST=PA3
-D TFT_WIDTH=240
-D TFT_HEIGHT=320
-D SPI_FREQUENCY=4000000
-D LOAD_GLCD=1
-D USE_FONT_1=1
main.cpp
// 引入Arduino核心基础库
#include <Arduino.h>
// 引入TFT屏幕驱动库
#include <TFT_eSPI.h>
// 引入I2C通信库,用于和DS3231时钟模块通讯
#include <Wire.h>
// 引入RTC时钟功能库,驱动DS3231实时时钟
#include <RTClib.h>
// 实例化TFT屏幕对象
TFT_eSPI tft;
// 实例化DS3231时钟模块对象
RTC_DS3231 rtc;
// 记录上一次显示的小时,用于判断是否需要刷新
int last_hour = -1;
// 记录上一次显示的分钟,用于判断是否需要刷新
int last_min = -1;
// 记录上一次显示的秒数,用于判断是否需要刷新
int last_sec = -1;
// 初始化函数,上电只执行一次
void setup() {
delay(500); // 延时500ms,等待硬件上电稳定
tft.init(); // 初始化TFT显示屏
tft.setRotation(1); // 设置屏幕为横屏模式
tft.fillScreen(TFT_BLACK); // 全屏填充黑色,完成清屏
tft.setTextSize(5); // 设置屏幕字体大小为5号
Wire.begin(); // 启动I2C总线通信
rtc.begin(); // 初始化DS3231时钟模块
// 校准开关:取消//上传同步电脑时间;日常使用务必带//,防止上电重置时间
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
DateTime now = rtc.now(); // 读取DS3231芯片持续运行的时间
tft.fillRect(10, 70, 240, 70, TFT_BLACK); // 清空显示区域
// 显示小时
tft.setTextColor(TFT_YELLOW, TFT_BLACK);
tft.setCursor(20, 80);
tft.printf("%02d", now.hour());
// 第一个冒号
tft.setTextColor(TFT_GREEN, TFT_BLACK);
tft.setCursor(100, 80);
tft.print(":");
// 显示分钟
tft.setTextColor(TFT_YELLOW, TFT_BLACK);
tft.setCursor(130, 80);
tft.printf("%02d", now.minute());
// 第二个冒号
tft.setTextColor(TFT_GREEN, TFT_BLACK);
tft.setCursor(200, 80);
tft.print(":");
// 显示秒
tft.setTextColor(TFT_YELLOW, TFT_BLACK);
tft.setCursor(230, 80);
tft.printf("%02d", now.second());
last_hour = now.hour();
last_min = now.minute();
last_sec = now.second();
}
// 主循环持续刷新时间
void loop() {
DateTime now = rtc.now();
// 单独刷新小时
if (now.hour() != last_hour) {
tft.fillRect(20, 80, 65, 60, TFT_BLACK);
tft.setTextColor(TFT_YELLOW, TFT_BLACK);
tft.setCursor(20, 80);
tft.printf("%02d", now.hour());
last_hour = now.hour();
}
// 单独刷新分钟
if (now.minute() != last_min) {
tft.fillRect(130, 80, 65, 60, TFT_BLACK);
tft.setTextColor(TFT_YELLOW, TFT_BLACK);
tft.setCursor(130, 80);
tft.printf("%02d", now.minute());
last_min = now.minute();
}
// 单独刷新秒
if (now.second() != last_sec) {
tft.fillRect(230, 80, 65, 60, TFT_BLACK);
tft.setTextColor(TFT_YELLOW, TFT_BLACK);
tft.setCursor(230, 80);
tft.printf("%02d", now.second());
last_sec = now.second();
}
// 固定显示两个分隔冒号,防止刷新消失
tft.setTextColor(TFT_GREEN, TFT_BLACK);
tft.setCursor(100, 80);
tft.print(":");
tft.setCursor(200, 80);
tft.print(":");
delay(100);
}
本文部分文字由ai辅助优化