项目概述
我成功实现了基于SAME51J20A的ST7735 TFT显示屏驱动,为后续菜单系统开发奠定了基础。项目核心是创建一个实时时钟应用。
第一章 关键外设配置
1.1 SPI接口驱动ST7735显示屏
硬件连接:
软件配置:
时钟相位:第一个边沿采样
时钟极性:空闲时低电平
速率:4MHz
1.2 DMA降低CPU开销
软件配置:
使每次触发传输一个Beat (Beat:最小传输单元, Block: 单次传输长度, Transaction:一组传输 )
源地址自增,目的地址不变
1.3 RTC实时时钟模块
软件配置
1.4 TC定时计数器
软件配置
第二章 ST7735驱动详解
2.1、整体驱动架构概览
ST7735 驱动模块
├── HAL 层(硬件抽象层)
│ ├── GPIO 控制(DC、CS、RES)
│ ├── SPI 通信
│ └── 背光控制(PWM)
├── 显示控制
│ ├── 初始化
│ ├── 显示方向设置(MADCTL)
│ ├── 屏幕刷新
│ └── 显存管理(双缓冲)
├── 绘图接口
│ ├── 基础图形:点、线、矩形、圆
│ ├── 填充图形:矩形、圆
│ └── 图像显示(如 ikun 图像)
├── 文字渲染
│ ├── 8x8 字体
│ ├── 16x16 字体
│ └── 自动换行与格式化输出(printf 风格)
├── 帧率统计
│ ├── FPS 计数器
│ └── FPS 显示
└── DMA 传输
└── SPI + DMA 实现高速刷新
2.2、驱动接口详解2.2.1 HAL 层接口(st7735_hal.c)
函数名 | 功能 | 说明 |
ST7735_HAL_Init() | 初始化 GPIO、SPI、PWM 背光 | 包括 DC、CS、RES 引脚初始化 |
ST7735_HAL_WriteCommand() | 发送命令 | 通过 SPI 发送 ST7735 命令 |
ST7735_HAL_WriteData() | 发送单个数据 | 用于发送寄存器配置数据 |
ST7735_HAL_WriteDataDMA() | 使用 DMA 发送大量数据 | 用于传输显存数据 |
ST7735_HAL_SetBacklight() | 设置背光亮度 | 使用 PWM 控制亮度(0~100) |
示例:
cST7735_HAL_WriteCommand(ST7735_SWRESET); // 发送软件复位命令ST7735_HAL_WriteData(0x01); // 发送数据
2.2.2 显示控制接口(st7735.c)
函数名 | 功能 | 说明 |
ST7735_Init() | 初始化屏幕 | 包括复位、初始化寄存器、配置显示方向 |
ST7735_SetWindow() | 设置显示区域 | 设置显存写入范围(用于绘图) |
ST7735_FillScreen() | 填充整个屏幕颜色 | 清屏操作 |
ST7735_SwapBuffers() | 切换前后缓冲区 | 实现双缓冲机制 |
ST7735_Flush() | 刷新屏幕 | 使用 DMA 传输显存数据 |
ST7735_Task() | 主循环中调用 | 负责帧率统计与自动刷新 |
显示方向配置:
cST7735_HAL_WriteCommand(ST7735_MADCTL);ST7735_HAL_WriteData(0xC8); // 0xC8 = RGB | landscape mode
2.2.3 绘图接口(st7735.c)
函数名 | 功能 | 说明 |
ST7735_DrawPixel() | 画点 | 在指定坐标绘制像素点 |
ST7735_DrawLine() | 画线 | 使用 Bresenham 算法绘制线段 |
ST7735_DrawRect() | 画矩形框 | 由四条线组成 |
ST7735_FillRect() | 填充矩形 | 逐像素填充 |
ST7735_DrawCircle() | 画圆 | 使用 Bresenham 圆算法 |
ST7735_FillCircle() | 填充圆 | 逐像素填充 |
ST7735_FillScreen_Ikun() | 显示 ikun 图像 | 使用图像数组填充显存 |
2.2.4 文字渲染接口(st7735.c)
函数名 | 功能 | 说明 |
ST7735_DrawChar8x8() | 绘制 8x8 字符 | 使用 font_8x8[] 数组 |
ST7735_DrawString8x8() | 绘制 8x8 字符串 | 支持背景色 |
ST7735_DrawChar16x16() | 绘制 16x16 字符 | 使用 font_16x16[] 数组 |
ST7735_DrawString16x16() | 绘制 16x16 字符串 | 支持换行 |
ST7735_Printf8x8() / ST7735_Printf16x16() | 格式化输出字符串 | 类似 printf |
ST7735_Printf8x8AutoWrap() / ST7735_Printf16x16AutoWrap() | 自动换行输出 | 支持换行和自动滚动 |
使用示例:
cST7735_Printf16x16(10, 10, COLOR_GREEN, COLOR_BLACK, 0, "Hello, ST7735!");
2.2.5 帧率统计(st7735.c)
函数名 | 功能 | 说明 |
ST7735_FPSCounterTask() | 帧率计数 | 每秒统计刷新次数 |
ST7735_DrawFPS() | 显示帧率 | 在屏幕指定位置显示当前帧率 |
2.2.6 双缓冲机制(st7735.c)
使用两个显存缓冲区 frameBuffer[2][ST7735_WIDTH * ST7735_HEIGHT]
通过 ST7735_SwapBuffers() 切换缓冲区
使用 ST7735_Task() 实现自动刷新
void ST7735_Task(void){ ST7735_FPSCounterTask(); if (ST7735_SPI_DMA_IsIdle()) { ST7735_SwapBuffers(); // 切换缓冲区 ST7735_Flush(); // 刷新屏幕 }}
2.2.7 DMA 传输(st7735_spi_dma.c)
函数名 | 功能 | 说明 |
ST7735_SPI_DMA_Init() | 初始化 SPI + DMA | 使用 SERCOM1 SPI |
ST7735_SPI_DMA_Transfer() | DMA 传输显存 | 使用 SPI DMA 高效传输数据 |
2.3 关键配置项(st7735.h)
宏定义 | 说明 |
USE_ST7735S / USE_ST7735R | 选择芯片型号 |
ST7735_WIDTH / ST7735_HEIGHT | 屏幕分辨率(128x128) |
FONT_8x8 / FONT_16x16 | 字体大小 |
COLOR_BLACK / COLOR_WHITE 等 | 颜色定义(RGB565) |
2.4 主流程调用示例(main.c)
c#include "../custom/inc/st7735.h"int main(void){ ST7735_Init(); ST7735_FillScreen(COLOR_BLACK); while (1) { ST7735_FillScreen(COLOR_BLACK); ST7735_Printf16x16(10, 10, COLOR_RED, COLOR_BLACK, 0, "FPS: %d", fps); ST7735_Task(); // 刷新屏幕 }}
2.5 关键寄存器配置
寄存器配置值作用
ST7735_SWRESET | - | 软件复位 |
ST7735_SLPOUT | - | 退出睡眠模式 |
ST7735_FRMCTR1 | 0x01, 0x2C, 0x2D | 设置帧率(ST7735S) |
ST7735_PWCTR1~5 | 多个值 | 设置电源控制参数 |
ST7735_GMCTRP1 / GMCTRN1 | Gamma 校正 | 提升显示质量 |
ST7735_MADCTL | 0xC8 | 设置显示方向(landscape) |
ST7735_COLMOD | 0x05 | 设置颜色格式(RGB565) |
ST7735_DISPON | - | 打开显示 |
2.6 关键文件路径文件功能
st7735.h | 接口声明、颜色、字体、宏定义 |
st7735.c | 显示驱动、绘图函数、帧率统计 |
st7735_hal.c | 硬件抽象层(SPI、GPIO、PWM) |
st7735_spi_dma.c | DMA 传输支持 |
font_8x8.h / font_16x16.h | 字体数据 |
ikun.h | ikun 图像资源 |
第三章 时钟模块
3.1 功能概述
时钟模块 ├── RTC 获取时间 ├── 模拟时钟绘制 │ ├── 表盘绘制(刻度、圆圈) │ ├── 指针绘制(时针、分针、秒针) │ └── 指针动画优化(可选) ├── 日期信息显示 │ ├── 年月日 │ ├── 星期几(支持中英文) ├── 主任务接口 │ ├── Clock_Task():主循环调用 │ └── UpdateClockDisplay():更新显示内容 └── 数学计算 ├── 角度计算(DEG2RAD) └── 坐标计算(cos/sin)
3.2 模块接口详解
3.2.1 RTC 时间获取(依赖硬件)
函数功能
RTC_RTCCTimeGet(¤tTime) | 获取当前 RTC 时间(struct tm 结构) |
RTC_Timer32CounterGet() | 获取系统时间戳(32位) |
localtime(&tick) | 将时间戳转换为 struct |
3.2.2 时钟绘制函数
(1) 表盘绘制函数
cvoid DrawClockFace(void);
绘制外圈(白色)
绘制60个刻度线(每5个为1小时,长度不同)
支持毫秒级秒针动画(可选)
(2) 指针绘制函数
cvoid DrawClockHands(struct tm *time);
时针:基于 tm_hour % 12 和 tm_min 计算角度(考虑分钟偏移)
分针:基于 tm_min 和 tm_sec(考虑秒偏移)
秒针:基于 tm_sec 和当前系统时间毫秒偏移(实现秒针平滑移动)
(3) 日期信息显示函数
cconst char *GetDayOfWeek(int dayOfWeek);
将 tm_wday(0~6)转换为星期几字符串(可自定义中英文)
cvoid UpdateClockDisplay(void);
获取当前时间
清屏
绘制表盘和指针
显示年月日 + 星期几信息
3.2.3 主任务接口
void Clock_Task(void);
每秒检测一次时间变化
若秒数变化,则调用 UpdateClockDisplay() 更新屏幕
3.3 关键数学与绘图逻辑
1. 角度计算宏
c#define DEG2RAD(deg) ((deg) * M_PI / 180.0f)
将角度转换为弧度,用于 cos() 和 sin() 计算坐标
2. 指针坐标计算
cint x = CLOCK_CENTER_X + (int)(cos(DEG2RAD(angle)) * length);int y = CLOCK_CENTER_Y + (int)(sin(DEG2RAD(angle)) * length);
CLOCK_CENTER_X、CLOCK_CENTER_Y 是表盘中心坐标(如 64, 64)
length 是指针长度(时针 30px,分针 45px,秒针 55px)
3.4 LCD 显示接口(依赖 st7735.h / st7735.c)
函数 说明
ST7735_FillScreen(COLOR_BLACK) 清屏
ST7735_DrawLine(x1, y1, x2, y2, color) 画线(用于指针)
ST7735_Printf16x16(x, y, color, bgColor, format, ...) 显示格式化文本(如日期)
ST7735_DrawString16x16(x, y, str, color, bgColor)直接绘制字符串
第四章 未来计划
gitee仓库链接: https://gitee.com/YuThirteen/SAME51J20A
效果演示视频:https://ww1.microchip.com/downloads/aemDocuments/documents/MCU32/ProductDocuments/DataSheets/SAM-D5x-E5x-Family-Data-Sheet-DS60001507.pdf
[2] ST7735数据手册: https://www.alldatasheet.com/html-pdf/1775164/SITRONIX/ST7735S/447/1/ST7735S.html