LCD屏幕标准库代码

Tutorial: 卓越工程师 Category: 嵌入式 Published: 2026-10-23 11:05:29 Views: 0 Likes: 0 Comments: 0

202.3.1 LCD屏幕标准库代码

/*
 * 整体目的:运行中景园 3.5 英寸触摸屏的标准库演示,依次验证纯色填充、整屏图片、
 *           中文和小图标显示,以及电阻触摸坐标读取和手写轨迹绘制。
 * 硬件对象:ST7796 显示控制器与 XPT2046 电阻触摸控制器共用 SPI1,总线设备由各自片选区分。
 * 源码说明:下列代码忠实保留课程配套工程 main.c 的业务逻辑和字符串,只重新排版并替换为逐行注释。
 *           第一处填充色为 RED,是老师在课堂验证颜色时把 WHITE 改成 RED 后留下的源码。
 */

#include "delay.h"      /* 引入毫秒级延时函数 delay_ms() 和延时模块初始化函数 delay_init()。 */
#include "sys.h"        /* 引入 STM32F1 工程的基础类型、位带操作及系统级声明。 */
#include "led.h"        /* 引入板载 LED 的初始化函数和 LED 输出宏。 */
#include "lcd_init.h"   /* 引入 LCD 初始化函数、屏幕尺寸宏和底层控制引脚定义。 */
#include "lcd.h"        /* 引入填充、文字、数字、图片等 LCD 绘图接口。 */
#include "pic.h"        /* 引入取模后保存在单片机 Flash 中的 gImage_1、gImage_2 图片数组。 */
#include "touch.h"      /* 引入触摸设备对象 tp_dev、触摸初始化函数及粗线绘制接口。 */

int main(void)                                                   /* 定义上电后进入的主函数。 */
{                                                                /* 主函数体开始。 */
    u8 i, j;                                                     /* 定义两层图片平铺循环使用的 8 位行、列计数器。 */
    float t = 0;                                                 /* 定义演示浮点数,初始值为 0。 */
    u16 lastpos[2];                                              /* 保存上一次触摸点的 X、Y 坐标,用于把相邻点连成线。 */

    delay_init();                                                /* 初始化延时模块,使后面的毫秒延时可用。 */
    LED_Init();                                                  /* 初始化板载 LED 对应的 GPIO。 */
    LCD_Init();                                                  /* 初始化 SPI、LCD 控制引脚,并向 ST7796 发送初始化序列。 */
    LCD_Fill(0, 0, LCD_W, LCD_H, RED);                           /* 用红色填满整个 320×480 显示区域。 */
    lastpos[0] = 0XFFFF;                                        /* 写入无效 X 坐标,作为“尚无上一触摸点”的哨兵值。 */
    LED = 0;                                                     /* 将配套工程定义的板载 LED 输出置为低电平。 */

    LCD_ShowPicture(0, 0, 320, 480, gImage_2);                   /* 从左上角显示 320×480 的整屏图片 gImage_2。 */
    delay_ms(1000);                                              /* 保持整屏图片 1 秒,便于观察。 */
    LCD_Fill(0, 0, LCD_W, LCD_H, WHITE);                         /* 把整屏清为白色,为文字与小图标演示准备背景。 */
    LCD_ShowChinese(0, 0, "中景园电子", RED, WHITE, 32, 0);     /* 在 (0,0) 显示 32 像素高的红色中文。 */
    LCD_ShowString(0, 40, "LCD_W:", RED, WHITE, 16, 0);         /* 在第 40 行显示屏幕宽度标签。 */
    LCD_ShowIntNum(48, 40, LCD_W, 3, RED, WHITE, 16);            /* 用 3 位十进制数显示 LCD_W,当前竖屏值为 320。 */
    LCD_ShowString(80, 40, "LCD_H:", RED, WHITE, 16, 0);        /* 在同一行显示屏幕高度标签。 */
    LCD_ShowIntNum(128, 40, LCD_H, 3, RED, WHITE, 16);           /* 用 3 位十进制数显示 LCD_H,当前竖屏值为 480。 */
    LCD_ShowString(80, 40, "LCD_H:", RED, WHITE, 16, 0);        /* 配套源码重复显示一次同一标签;此行虽冗余但按原样保留。 */
    LCD_ShowString(0, 70, "Increaseing Nun:", RED, WHITE, 16, 0); /* 原字符串拼写如此,用作浮点数演示标签。 */
    LCD_ShowFloatNum1(128, 70, t, 4, RED, WHITE, 16);            /* 显示当前浮点变量 t;此时它仍为 0。 */
    t += 0.11;                                                   /* 把 t 增加 0.11;后面没有再次显示,因此屏幕数值不会随之刷新。 */

    for (j = 0; j < 7; j++)                                     /* 纵向排列 7 行 40 像素高的小图片。 */
    {                                                            /* 外层行循环开始。 */
        for (i = 0; i < 8; i++)                                 /* 横向排列 8 列 40 像素宽的小图片。 */
        {                                                        /* 内层列循环开始。 */
            LCD_ShowPicture(40 * i, 200 + j * 40, 40, 40, gImage_1); /* 在计算出的网格位置显示 40×40 的 gImage_1。 */
        }                                                        /* 一列图片绘制结束,继续绘制下一列。 */
    }                                                            /* 一行图片绘制结束,继续绘制下一行。 */

    delay_ms(1000);                                              /* 保持中文、数字和 56 个小图标 1 秒。 */
    LCD_Fill(0, 0, LCD_W, LCD_H, WHITE);                         /* 再次清成白色,进入触摸白板阶段。 */

    TP_Init();                                                   /* 装载当前屏幕方向对应的触摸校准参数。 */
    LCD_ShowString(10, LCD_H - 40, "X:", RED, WHITE, 16, 0);    /* 在屏幕底部倒数第 40 行显示 X 坐标标签。 */
    LCD_ShowIntNum(26, LCD_H - 40, 0, 3, RED, WHITE, 16);        /* 先把 X 坐标显示为 000。 */
    LCD_ShowString(10, LCD_H - 20, "Y:", RED, WHITE, 16, 0);    /* 在屏幕底部倒数第 20 行显示 Y 坐标标签。 */
    LCD_ShowIntNum(26, LCD_H - 20, 0, 3, RED, WHITE, 16);        /* 先把 Y 坐标显示为 000。 */

    while (1)                                                    /* 无限循环扫描触摸屏,使白板持续响应。 */
    {                                                            /* 主循环的一轮开始。 */
        tp_dev.scan(0);                                          /* 读取触摸并把 XPT2046 原始 ADC 值换算成屏幕坐标。 */
        if (tp_dev.sta & TP_PRES_DOWN)                           /* 检查状态字的按下标志,判断当前是否检测到触摸。 */
        {                                                        /* 有触摸时进入处理分支。 */
            delay_ms(1);                                        /* 短暂延时,减轻连续采样抖动。 */
            if ((tp_dev.x[0] < (LCD_W - 1) && tp_dev.x[0] >= 1) && /* 先确认 X 位于 1~LCD_W-2 的有效范围。 */
                (tp_dev.y[0] < (LCD_H - 1) && tp_dev.y[0] >= 1)) /* 只处理位于屏幕内部、避开四周边界的坐标。 */
            {                                                    /* 有效坐标处理开始。 */
                if (lastpos[0] == 0XFFFF)                        /* 若哨兵仍在,说明这是程序启动后的第一个有效触摸点。 */
                {                                                /* 首点初始化分支开始。 */
                    lastpos[0] = tp_dev.x[0];                    /* 用当前 X 坐标初始化上一点的 X。 */
                    lastpos[1] = tp_dev.y[0];                    /* 用当前 Y 坐标初始化上一点的 Y。 */
                }                                                /* 首点初始化结束。 */

                LCD_DrawRoughLine(lastpos[0], lastpos[1], tp_dev.x[0], tp_dev.y[0], BLUE); /* 用蓝色粗线连接上一点和当前点。 */
                lastpos[0] = tp_dev.x[0];                        /* 保存当前 X,供下一次扫描作为线段起点。 */
                lastpos[1] = tp_dev.y[0];                        /* 保存当前 Y,供下一次扫描作为线段起点。 */
                LCD_ShowString(10, LCD_H - 40, "X:", RED, WHITE, 16, 0); /* 重绘 X 标签,避免坐标刷新破坏标签。 */
                LCD_ShowIntNum(26, LCD_H - 40, tp_dev.x[0], 3, RED, WHITE, 16); /* 显示当前触摸 X 坐标。 */
                LCD_ShowString(10, LCD_H - 20, "Y:", RED, WHITE, 16, 0); /* 重绘 Y 标签。 */
                LCD_ShowIntNum(26, LCD_H - 20, tp_dev.y[0], 3, RED, WHITE, 16); /* 显示当前触摸 Y 坐标。 */
            }                                                    /* 有效坐标处理结束。 */
        }                                                        /* 本轮触摸按下处理结束。 */
    }                                                            /* 返回循环顶部,继续扫描;程序不会正常退出。 */
}                                                                /* 主函数的语法边界。 */

本课是 LVGL 专题的第一课,但当前工程还没有运行 LVGL。课堂先用厂家标准外设库例程确认屏幕硬件、接线、显示接口和触摸接口都能工作,下一课才把这套驱动迁移到 HAL 库工程。

一、LVGL部分

整个 LVGL 专题分为五部分:中景园 LCD 屏幕使用、LVGL 源码移植、屏幕驱动优化、温湿度风扇实验,以及仪表盘显示项目。本课只完成第一部分中的硬件认识和标准库代码梳理。

1.1 中景园LCD屏幕使用

课堂使用一块 3.5 英寸触摸屏。“3.5 英寸”指显示区域对角线尺寸,不是屏幕的宽或高;当前竖屏逻辑分辨率是 320 × 480,总像素数为:

320 × 480 = 153600 个像素

屏幕模块包含两个需要单片机访问的芯片:

部分芯片作用本工程接口
TFT 显示ST7796接收命令和像素数据,驱动 320×480 液晶面板SPI1 写入
电阻触摸XPT2046给四线电阻触摸层施加激励,并把触点位置转换为 12 位 ADC 数据共用 SPI1,另有 PEN 状态输出

矽创官方产品页给出的 ST7796U 规格为 320RGB×480、内置显示 RAM、262K 色,并支持 3 线/4 线串行接口;配套模块资料将本模块写为 4 线 SPI 输入。这里的“4 线”是显示控制接口的分类,不等于排针只有四根线,整个带触摸模块实际有 11 个引脚。参考:Sitronix ST7796U 产品信息。

上电或按下开发板复位键后,程序的可见流程是:

红色整屏(课堂由白色改成红色做验证)
  → 320×480 整屏图片,停留 1 秒
  → 中文、宽高数值和 8×7 个小企鹅,停留 1 秒
  → 白色触摸板,实时画蓝线并显示 X/Y 坐标

图片不是运行时从 JPG/BMP 文件解码,而是取模后直接编译进程序的字节数组。配套 pic.h 中:

  • gImage_1[3200]正好对应 40 × 40 × 2 = 3200字节;
  • gImage_2[307200]正好对应 320 × 480 × 2 = 307200字节,约 300 KiB;
  • 每个像素占 2 字节,颜色采用 16 位 RGB565 表示,例如 RED = 0xF800、BLUE = 0x001F、WHITE = 0xFFFF。

因此包含整屏图片后,HEX 文件显著增大,课堂中烧录速度变慢是正常现象,不是 LCD 初始化卡住。

1.2 任务信息资源导图

课程资料位于:

源码/3.1 CAN、LVGL、IAP固件升级专题/
└─ 模块资料/
   └─ 中景园ST7796触摸屏资料/
      ├─ 01-规格书与控制芯片手册.zip
      ├─ 02-3.5LCD带触摸程序源码.zip
      ├─ 03-LCD取模教程.zip
      └─ 04-示例图片.zip

四份资料分别用于核对模块/XPT2046 规格、取得各平台示例工程、学习汉字与图片取模,以及取得演示图片。取模的本质是把字形或图片转换成 MCU 可直接顺序发送的像素字节数组。

课堂中的购买入口位于思维导图链接所打开的外部文档中:选择“仪表盘项目”,再到该项目文档末尾查找商品链接。课堂当时建议多花约五毛钱选择已经焊好排针的 ST7796 版本;没有焊接经验时,不要为了这点差价选裸焊盘版本。购买页面和价格会变化,真正下单时应核对“控制器型号、分辨率、触摸类型、接口、是否焊排针”五项,而不是只看外观相似。

配套 ZJY350S110TTG11 规格书的封面和 Features 页写的是 ST7796,但机械尺寸图备注中又出现 ILI9486L,资料内部存在不一致。课程明确选择并使用 ST7796 工程,因此本课程应以实际商品型号、板上标识和 ST7796 初始化代码为准;不要把外形相同的 ILI9486 版本默认当成可直接替换。

1.3 思维导图屏幕接线方式

当前配套工程的 11 根连线如下。表中的方向均以 STM32 为参照:

模块引脚STM32F103 引脚方向初学者应理解的作用
GNDGND-两块电路的共同电位基准;没有共地,所有数字电平都没有可靠参照。
VCC3.3V电源给模块供电。配套规格书给出的模块电源上限为 3.3 V,不要按经验接 5 V。
CLK(源码注释也写 SCL)PA5 / SPI1_SCK输出SPI 串行时钟;这里不是 I²C 的 SCL。转录中的“PE5”是识别错误。
MOSI(源码注释也写 SDA)PA7 / SPI1_MOSI输出MCU 向显示芯片或触摸芯片发送命令;这里也不是 I²C 的 SDA。
RESPA0输出LCD 硬件复位,低电平有效,正常工作时保持高电平。
DCPA1输出LCD 命令/数据选择:低电平表示命令,高电平表示显示数据。
BLKPA2输出背光使能控制,高电平开、低电平关;它是控制信号,不是拿 GPIO 直接给背光供电。
MISOPA6 / SPI1_MISO输入XPT2046 向 MCU 返回触摸 ADC 数据;模块手册明确写作“Touch Chip data output”。
CS1PA3输出LCD 片选,低电平选中 ST7796,高电平释放。
CS2PA4输出触摸片选,低电平选中 XPT2046,高电平释放。
PENPB0输入触摸/笔状态输出;按下时为低电平,当前例程以输入上拉方式轮询它。

PA5、PA6、PA7由 SPI1_Init()配置;PA0~PA4及 PB0由 LCD_GPIO_Init()配置。源码中的 GPIO_Speed_50MHz是 STM32F1 GPIO 输出速度/边沿能力配置,不表示 SPI 一定以 50 MHz 运行。实际 SPI 分频由 SPI_BaudRatePrescaler决定。

显示与触摸共享 CLK/MOSI/MISO三根 SPI 总线线,但各有独立片选:

STM32 SPI1_SCK  PA5 ───────────────┬── ST7796 CLK
                                   └── XPT2046 DCLK
STM32 SPI1_MOSI PA7 ───────────────┬── ST7796 数据输入
                                   └── XPT2046 DIN
STM32 SPI1_MISO PA6 ◄───────────────── XPT2046 DOUT

STM32 PA3 ───────────────────────────► ST7796 CS1(低有效)
STM32 PA4 ───────────────────────────► XPT2046 CS2(低有效)

共享总线的关键规则是同一时刻只把目标设备的 CS 拉低。否则两个器件可能同时响应;若多个器件同时驱动 MISO,还会产生总线冲突。本模块的 LCD 数据路径主要是单向写入,所以 MISO在模块定义中专用于触摸芯片输出。

1.3.1 屏幕接线方式知识要点

接线时应断电操作,先连接 GND和 VCC,再按模块丝印逐根核对信号。建议从一排母对母杜邦线中连续取 11 根,使模块端排针排列整齐并减少单根松脱;线束颜色不能代替丝印和引脚表。

上电前至少检查:

  1. VCC确实接 3.3 V,且没有与 5 V 排针错位;
  2. STM32 与屏幕共地;
  3. CS1接 PA3、CS2接 PA4,没有对调;
  4. CLK/MOSI/MISO分别接 PA5/PA7/PA6;
  5. 11 针插头没有整体错开一位或反插;
  6. 杜邦线尽量短,出现花屏或触摸抖动时先排查接触不良和信号完整性。

配套规格书给出的背光典型电流约为 120 mA,所以模块电源必须来自有足够供电能力的 3.3 V 电源轨,不能从普通 GPIO 取电。BLK只负责打开/关闭模块上的背光控制。

1.4 任务信息资源导图库代码移植

本模块使用四线电阻触摸层。它通常由两层带电阻性的透明导电膜组成,中间有微小间隔;手指、触控笔或戴手套的手施加足够压力后,两层在触点处接触。控制器先在一个方向建立电压梯度,再从另一层采样触点电压,由 ADC 值推算一个轴的位置;切换驱动方向后得到另一个轴。

因此,原笔记中“电容屏仅响应活体手指、依靠生物电”的说法不准确。更准确的对比如下:

对比项电阻屏(本模块)电容屏(常见智能手机)
检测量压力使两层导电膜接触后形成的电压/电阻关系触点对电极电容或互电容分布的改变
操作物手指、指甲、普通触控笔、戴手套的手都可能操作,前提是施加足够压力通常需要导电目标;手指、导电触控笔和部分触控手套可用,并非“只认活体”
体验需要压力,表层会有机械形变,通常单点轻触即可,常见方案支持多点,体验通常更灵敏

历史上不少诺基亚机型和早期 Android 触屏手机使用过电阻屏;现代主流智能手机多采用电容屏,但不宜把它表述成任何年代、任何设备都绝无例外。

XPT2046 是带 12 位逐次逼近 ADC 的四线电阻触摸控制器。它输出的原始坐标范围理论上为 0~4095,但这还不是 LCD 像素坐标;驱动必须通过校准系数把原始值映射到 0~319和 0~479。芯片资料还说明 PENIRQ在允许笔中断的掉电状态下带内部上拉,触摸会把信号拉低。厂商资料可参阅:XPT2046 产品简介。

虽然模块把该脚命名为“触摸中断”,本例并未把 PB0 配成 EXTI 中断。TP_Scan()在主循环中直接读取 PEN == 0,因此这里采用的是轮询检测;只有另行配置 EXTI/NVIC 后,它才会真正触发 MCU 中断服务函数。

配套触摸驱动的采样流程是:

PEN 变低
  → SPI1 从 4 分频降到 32 分频
  → 发送 X 或 Y 采样命令
  → 接收 16 位串行数据并右移 4 位,取得高 12 位 ADC 结果
  → 每个轴连续采样 5 次,排序后去掉最大值和最小值,平均中间 3 次
  → 再完整读取一组 X/Y;两组偏差都小于 50 才接受
  → 使用 xfac/yfac/xoff/yoff 换算为屏幕坐标
  → SPI1 恢复 4 分频

这几层处理分别解决触摸芯片速度限制、瞬时噪声和偶发跳点。touch.h中的宏名 Adujust是原工程拼写;当前值为 1,表示直接使用按屏幕方向预置的校准参数。不同屏幕个体若坐标偏差明显,应重新执行校准并使用本机参数,不能盲信另一块屏的系数。

1.4.1 库代码移植知识要点

解压 02-3.5LCD带触摸程序源码.zip后可看到六组示例:第 1 组是 C51,第 2~5 组是不同 STM32 型号的软件 SPI 工程,第 6 组是 STM32F103 硬件 SPI + DMA 工程。课程把第 6 组改名后放到专题代码目录中,作为当前标准库基线。

移植分为两个相互关联的部分:

  • 显示部分:SPI、显示控制 GPIO、ST7796 初始化、设置显示窗口和批量发送 RGB565 像素;
  • 触摸部分:XPT2046 片选、ADC 数据读取、滤波、坐标校准和按下状态判断。

二者共用 SPI1,所以迁移时不能只复制 lcd.c或 touch.c。还必须统一 GPIO 定义、SPI 模式/速度、片选时序,以及显示结束后切换到触摸读取时的总线状态。

1.4.1.1 例程文件位置

本课直接打开的工程是:

源码/3.1 CAN、LVGL、IAP固件升级专题/
└─ uint3code/
   └─ 11中景园硬件SPI带触摸标准库例程/

在 Keil 中进入 USER目录并打开 .uvprojx工程。移植前先让原标准库工程在正确接线的硬件上正常显示和触摸,这样后面 HAL 版本出现问题时,才能区分是硬件/线序问题,还是迁移造成的软件问题。

本课涉及的文件职责如下:

文件职责迁移关注点
USER/main.c串联整屏图片、文字、小图标和触摸白板演示业务调用顺序,已完整列在本文开头
HARDWARE/LCD/lcd_init.c/.h控制引脚、SPI 写总线、显示窗口和 ST7796 初始化GPIO 与 HAL SPI 的替换重点
HARDWARE/LCD/lcd.c/.h填充、画点/线/矩形/圆、文字、数字和图片LVGL 后续主要需要高效区域填充/刷新能力
HARDWARE/TOUCH/touch.c/.hXPT2046 读取、滤波、校准、坐标扫描触摸片选、SPI 降速、PEN 轮询和方向映射
HARDWARE/SPI/spi.c/.h初始化 SPI1、切换分频、收发字节标准库 API 到 HAL API 的对应关系
HARDWARE/DMA/dma.c/.h让 DMA 重复发送同一个 16 位颜色LCD_Fill()性能与 HAL DMA 迁移
HARDWARE/LCD/pic.h保存两幅 RGB565 图片数组数组很大,会占用片内 Flash
HARDWARE/LCD/lcdfont.h保存字库点阵仅在传统文字绘制接口中使用
1.4.1.2 标准库代码介绍
  • 1.4.1.2.1 main函数介绍

main()先初始化延时、LED 和 LCD,再执行显示演示,最后进入触摸扫描死循环。它是本节需要掌握的业务代码;驱动库内部函数在视频里只是追踪调用关系,因此不在标题下方重复抄入完整库源码。

LCD_Init()的调用链可以概括为:

SPI1_Init()
  → 配置 PA5/PA6/PA7 和 SPI1 参数
LCD_GPIO_Init()
  → PA0~PA4:推挽输出并默认置高
  → PB0:上拉输入
LCD_RES 低 100 ms → 高 100 ms
LCD_BLK 高 → 等待 100 ms
发送 ST7796 初始化命令和参数

配套 SPI1_Init()选择主机、8 位数据、MSB 先发、软件 NSS、时钟空闲为高且第二边沿采样,即 SPI Mode 3,并使用 4 分频。触摸采样时临时切到 32 分频,结束后再恢复。具体频率还取决于 SPI1 外设时钟,不能只看分频数字判断绝对速率。

LCD 的命令与数据共用 MOSI,靠 DC区分:

发送命令:DC=0 → CS1=0 → SPI 发送 1 字节 → CS1=1 → DC=1
发送数据:DC=1 → CS1=0 → SPI 发送数据   → CS1=1

初始化序列中的寄存器值与具体控制器型号、面板方向和厂家参数有关。当前代码包含 0x11、0x36、0x3A、伽马参数以及最后的 0x29等命令;课堂要求迁移时保留原序列,并没有逐项重新设计这些参数。外形和分辨率相同不代表另一款控制器能直接复用同一序列。

方向宏为 USE_HORIZONTAL:

值逻辑尺寸含义
0或 1LCD_W=320、LCD_H=480竖屏,当前工程使用 0
2或 3LCD_W=480、LCD_H=320横屏

LCD_Fill(xsta, ysta, xend, yend, color)把后两个坐标当作不包含在区域内的结束边界,所以内部设置的最后像素是 (xend-1, yend-1),像素数为:

(xend - xsta) × (yend - ysta)

全屏填充是 320 × 480 = 153600个 16 位像素。驱动把 SPI 切成 16 位传输,并让 DMA 的存储器地址保持不变,反复发送同一个 color。由于单次 DMA 计数使用 16 位长度,源码按最多 65534 个像素分块,全屏会分为:

65534 + 65534 + 22532 = 153600 个像素

这比 CPU 为每个像素反复调用字节发送函数更高效,也是后续 LVGL 刷屏性能的基础。课堂指出,传统的画点、画线、矩形和圆接口在 LVGL 中通常不会逐个调用;LVGL 更关注把已经渲染好的矩形像素区域快速送到屏幕,因此 LCD_Fill()及其批量传输思路最值得后续继续分析。

主函数各阶段与可见现象一一对应:

代码现象与关键点
LCD_Fill(..., RED)短暂显示红色;老师由 WHITE改为 RED来证明填充色参数生效。
LCD_ShowPicture(..., gImage_2)显示一幅 320×480 图片;数组占 307200 字节。
LCD_ShowChinese/ShowString/ShowIntNum显示“中景园电子”、LCD_W=320、LCD_H=480等。
双层 for循环在 (40*i, 200+40*j)平铺 8 列×7 行,共 56 幅 40×40 小图片。
TP_Init()载入当前方向的触摸校准系数。
tp_dev.scan(0)轮询 PEN,读取并换算触摸坐标。参数 0 表示返回屏幕坐标而非原始坐标。
LCD_DrawRoughLine()把相邻采样点连成蓝色粗线,减少低采样率造成的断点。

阅读源码时还要保留以下事实,不能为了让示例看起来更漂亮而擅自改写:

  • "Increaseing Nun:"存在英文拼写问题,较自然的文字应是 Increasing Num:,但开头代码按配套源码原样保留;
  • LCD_H:标签在同一位置被写了两次,第二次没有新增效果,但仍属于原源码;
  • t先显示为 0,随后加 0.11,却没有再次刷新,因此它并不是持续增长的动态数字;
  • lastpos只在程序启动时用 0XFFFF初始化,松手后没有恢复哨兵值,所以再次从别处落笔时,当前实现可能把上一次终点与新起点连起来;
  • TP_PRES_DOWN只是触摸状态位,不等同于 MCU 外部中断;当前代码始终在 while(1)中轮询。

本节的移植目标是理解现有代码的数据流和硬件依赖,而不是重写厂家驱动。实际迁移时应先保持显示时序、初始化参数、坐标方向和校准行为一致,再逐步做性能或结构优化。

1.4.1.3 课堂结束

下一课开始把这套 STM32 标准外设库代码移植到 HAL 库工程;转录中的“hive 库”是对 HAL 库的识别错误。课前可以先自行尝试以下映射:

标准库 GPIO/SPI/DMA 初始化
  → CubeMX 生成 HAL 外设初始化

GPIO_SetBits/ResetBits
  → HAL_GPIO_WritePin

SPI1_ReadWriteByte
  → HAL_SPI_TransmitReceive 或按实际方向使用 HAL_SPI_Transmit

轮询 DMA 完成标志
  → HAL DMA 接口及完成状态/回调

自行尝试时先以“显示和触摸现象与原标准库工程一致”为验收标准;移植不成功时,再结合下一课逐层核对 GPIO、SPI 模式、片选、复位、背光和触摸降速逻辑。