背景故事
上大学一直在划水,刚毕业时几乎啥也不会,是大佬的这个库拯救了我。
SCPI 是一种字符串解析协议。刚工作时,点完灯开完串口,就让我实现 SCPI 协议。那时还很菜,花了两周时间才把这个协议库开起来。
这个库中的内容真的特别丰富,也没有很动态的指针,基本上都是绑定性质的"静态"指针,哪怕 C 语言不怎么样的我也可以慢慢看得懂。
在慢慢使用大约两个月后,其中的大部分内容都浏览过,C 语言也正式入门了,
而且后续的应届生,我也是让他们先看这个库。
源码地址在这里
这个代码库的优势
Note
- 这是一个纯粹的协议解析库,与硬件并非强关联,需要关注的 port 也仅仅是数据流入和数据流出。非常迅速就可以使用起来(哪怕是 CodeBlocks 或 DEV-C++ 这样的学习环境)。
- 这是一个能胜任业务功能的库,SCPI 协议解析所需的所有功能或机制它都可以胜任,学习后的应用场景非常广,不会白白学习。
- 这是一个稳健的库,我目前还没有在这个库中发现致命 bug。举个反例,最近期望移植和修改的 freemodbus 库,其中就存在致命 bug 以及大大小小的设计缺陷。
- 这是一个相对简单的库,比起 rtos 内核、网络库、文件系统库等等,这个库几乎可以称得上非常易懂了,只要花时间,就能从其中学到 面向对象、宏翻译、宏条件编译、回调绑定、字符处理 等等 C 语言的常用语法及设计。
应该看什么
由于是要写给 C 语言入门级选手的,哪怕这个库的结构如此简单,也依然需要介绍一下。整个库只有两个文件夹如下
examples其中是一些示例,也是我们期望将库用起来首先要看的。libscpi其中就是所有的库源码。在这个文件夹下有test文件夹,是带有 main 入口的单元测试,实际工程中不必引入libscpi/test文件夹的源码。

image-20241205131859389
在examples 中建议重点查看如下两个文件夹
examples/common 下是例程所支持的指令表,以及对应指令的回调,其中可以学习一些库 API 的用法
examples/test-parser 下是最简单例程的 main 入口,以及如 SCPI_Write()、SCPI_Error()等接口函数的定义,还有少量指令的回调,在指令表中都可以找到绑定。

image-20241205132043166
大致使用流程如下
- 使用
SCPI_Init()函数绑定对象、设备 ID、各种 port 函数 - 使用
SCPI_Input()函数输入一条所支持的完整指令,库自动触发指令回调,自动使用 port 函数发送信息
优秀的库,使用就是如此简单。
一些库 API 介绍
在官方文档中实际上也有 API 介绍 ,但是几乎没有有效信息,毕竟官方也只有一个人,可参考。
About · SCPI parser (jaybee.cz)
Scpi-Def.c 中声明了整个 SCPI 处理过程中用到的接口参数 scpi interface
指令参数处理 API
产生回传 API
经结果生成处理 API,产生的回传参数会存入接口参数 scpi interface 中,并最终均会调用 SCPI_Write() 函
数,目前该函数为:将回传参数经 uart4口发出
以数组形式产生回传 API
与上一部分产生回传的 API 类似,本部分 API 产生数组存入接口参数 scpi interface 的结果存储中,并触发 SCPI_Write() 函数
size_t
SCPI_ResultArrayDouble(
scpi_t * context,
const double * array,
size_t count,
scpi_array_format_t format);
将 array 指向的 count 个 double 元素 转换为数组 format 选择系统大小端
SCPI_ResultArrayFloat(scpi_t * context,const Float * array,
size_t count,scpi_array_format_t format);
SCPI_ResultArrayInt16(scpi_t * context,const int16_t * array,
size_t count,scpi_array_format_t format);
SCPI_ResultArrayInt32(scpi_t * context,const int32_t * array,
size_t count,scpi_array_format_t format);
SCPI_ResultArrayUInt64(scpi_t * context,const uint64_t * array,
size_t count,scpi_array_format_t format);
SCPI_ResultArrayUInt8(scpi_t * context,const uint8_t * array,
size_t count,scpi_array_format_t format);
数据转字符串的 API
默认不对接口参数的回传值进行操作