FTI.
← 返回博客
学习笔记

【嵌入式笔记】使用 ChatGPT 制作大彩串口屏 Skill

AI 总结以往串口屏工程与 STM32 工程的项目,精炼成 Skill 加入 AI 辅助工作流。

最近试了下让 ChatGPT 读取大彩的串口屏工程,发现工程文件和画面文件都是 XML 脚本,控件 ID、属性都是明文保存,理论上可以不通过大彩官方 Visual TFT 软件,直接使用文本编辑方式进行创建与编辑。

于是把自己以往用大彩串口屏的一些经验整理了一下,顺便让 GPT 帮我做成了以后可以重复使用的 Skill。

大彩官方库文件的移植

广州大彩官网

我们最开始写大彩串口屏配套的单片机控制程序,使用的是大彩官方提供的 STM32 工程示例。官方本来就有NotifyButton、NotifyText这些通知函数,但是全部都写在main.c文件里,后续页面和控件越加越多,逻辑越写越复杂,这个文件就变得臃肿不堪,可读性也很差。

我在这套模板的基础上,把协议解析、串口收发和具体业务拆分到不同的源文件中,方便换项目时继续用。接收中断负责收数据、放进队列,具体解析和业务处理放到主循环或接收任务(RTOS 版)里。底层串口改成了 HAL 接口,初始化函数中将串口句柄传入绑定,并将串口屏使用的接收中断处理函数注册到串口驱动,由 HAL 接收回调函数再统一分发,避免几个串口模块都挤在一个回调函数里写判断。

串口屏控件的接收处理函数也同理,将其从main.c中转移到新建的驱动文件cmd_process.c中,并建立回调函数数组,这样某个业务代码源文件需要使用串口接收处理,就只需要将定义在应用层的回调函数注册到驱动层里保存入口,当串口接收到有效数据帧时,驱动会逐一通知已经注册的所有回调函数,这样各个回调函数再在内部判断是不是自己需要的数据就行了。完美实现了应用层与驱动层的隔离,实现单向调用。

比如下面这种写法,例:

// DEMO 按钮控件通知回调函数
static void DEMO_HmiButtonCallback(
    uint16 screen_id, uint16 control_id, uint8 state)
{
    if (screen_id == DEMO_PAGE)
    {
        if (control_id == DEMO_BUTTON && state == 0)
        {
            ToggleDemoLed();
        }
    }
}

这个私有函数的定义在应用层 DEMO 页面的业务代码,如app_demo.c中,只需:

// 初始化时注册一次
HMI_RegisterHmiButtonCallback(DEMO_HmiButtonCallback);

当串口中断收到来自串口屏的按钮控件通知时,这个函数就会自动执行,而不需要在驱动层引用app_demo.h。

蒸馏 Skill

最近发现大彩串口屏的工程可以直接使用文本编辑器打开和修改,那么像 ChatGPT 这样的文字大模型肯定很擅长处理,而且工作一年多,我的编程风格也已经逐渐稳定,也有了一定量可以作为训练素材的工程样本。于是几个旧工程和官方资料交给 GPT 进行对照分析,最终蒸馏为 Skill。与其等着被别人蒸馏,不如先自己蒸馏了自己(

在制作 Skill 前,我先解释自己的使用习惯和踩过的坑,让它列出建议,再逐条确认,最后整理成两个独立的 Skill:一个负责串口屏工程,一个负责 STM32 业务代码。串口屏 UI 界面风格另外放模板,以后换一种仪器外观,也能沿用同一套流程。

AI 很擅长按指令完成任务,但是如果不加限制条件的提示词,每次产生的结果都有可能有很大不同,最终可读性变差,结构也变得杂糅。因此在 Skill 内记录的都是比较实际的小事,比如按钮统一用整页背景裁切、输入框设置初值和范围、文字编译后的偏移、表格滚动条,以及中文字符串的 GBK 编码。STM32 这边则约定业务主要放USER目录、驱动从库里复用,并分别准备裸机和 RTOS 模板。

完成后现在的流程就是:新项目到手先把功能说清楚,整理页面、控件 ID 和单片机动作的对应表,确认以后再生成工程。以后发现新的值得记录的问题,就补到对应文档里,不必每次开新项目都从头跟 GPT 解释一遍。