【嵌入式笔记】使用 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 解释一遍。