APP下载

Arduino 串口通信控制系统的研究

2022-02-27乐万德刘舟洲初建杰

电子设计工程 2022年4期
关键词:控制指令键值控制程序

乐万德,任 静,刘舟洲,初建杰

(1.西安航空学院计算机学院,陕西西安 710077;2.西北工业大学工业设计与人机工效工信部重点实验室,陕西 西安 710072)

Arduino因便捷灵活、开源等特性,成为了一款广泛使用的电子原型平台[1]。Arduino 不仅在高校创新创业及实验教学中发挥着越来越重要的作用[2-3],也逐渐走向产品及工程应用[4-6]。随着人工智能及机器人工程的发展,基于Arduino 的智能小车成为了研究热点[7-11]。

串口通信在Arduino 系统中具有十分重要的地位,Arduino 程序烧录最常用的方式是通过USB 从电脑上传到Arduino 板,使用的就是串口协议;Arduino板与红外、蓝牙模块、WiFi 模块等无线通信模块之间也是通过串口通信;基于此的衍生应用,如远程控制终端通过无线模块对Arduino 设备遥控指令的下发也是通过串口通信实现的。所以研究串口通信对于遥控指令系统具有十分重要的意义。

1 问题的提出

典型的串口通信控制指令使用控制端设备,通过无线模块如红外、蓝牙、WiFi 等发送字符或字符串命令到Arduino 对应的无线通信模块,对应无线通信模块将字符或者字符串送到Arduino 串口输入缓冲,Arduino 对字符或者字符串进行解析,并按照Arduino 程序定义,对不同的字符或者字符串执行不同的动作,从而实现对Arduino 设备的远程控制。一种Arduino 遥控连接示意图如图1 所示。

图1 Arduino遥控连接示意图

分析文献发现,通过解析字符或者字符串来实现串口通信控制算法和流程是一种常见方式[11-12]。以文献[11]为例,其定义的串口通信协议格式为:帧头+命令码+操作码。如向Arduino 下发不同的控制指令:0x55AA05、0x55AA06、0x55AA07、0x55AA08、0x55AA09,分别表示小车行进过程中的1 至5 个速度档位。其中0x55 为帧头,0xAA 为遥控指令,0x05~09 分别代表不同的速度。

这种串口通信控制协议对于简单的控制是可行的,其不足也十分明显:

1)程序可读性差,单条控制指令只是抽象的字符串,如0x55AA05,其含义不清楚。面对多条控制指令,开发及测试人员都很难顾名思义,出现问题不容易排查;

2)程序结构化程度低,各条指令扁平排布,即便相关性很强的指令之间也是如此,比如0x05~0x09代表小车的5 个档位。显然在复杂程序中,通过一个根节点来统领,组织成树状结构更优。

3)多条指令的组合缺乏灵活性。比如原始方案a 指令对应的动作和b 指令对应的动作是独立的,如果需要发一条指令同时执行原来a 指令和b 指令对应的动作,原始方案中需要定义一个新的字符串,并把原先对应a 指令和b 指令的动作代码合并。

2 解决方案

嵌入式系统对于外界事件的响应常用两种方式分别是轮询与中断。轮询方式采用循环结构[13],不断地主动查询某事件是否发生,一旦某事件发生,则采取相应的行动;中断方式则是被动地等待事件发生,一旦事件发生,则中断触发并调用中断处理函数对事件进行处理,文中遥控系统采用这种方式。

2.1 基于伪中断的控制程序框架

Arduino 系统从Arduino1.0 版本后,新增了serialEvent()函数,用于响应串口缓冲事件,即串口缓冲中收到字符串,则会调用该函数[14]。

需要注意的是,serialEvent()并非真正意义上的事件响应函数,因此无法做到严格意义上的实时响应。Arduino 系统在每次调用loop()函数后,检查串口缓冲是否有数据,确定是否调用serialEvent()函数。因此称其为伪中断,使用serialEvent()可改善程序结构,使程序脉络更为清晰。基于serialEvent 伪中断的控制程序框架如图2 所示。

图2 基于serialEvent的程序框架

2.2 结构化的控制指令

JSON(JavaScript Object Notation,JS 对象简谱)是一种轻量级的数据交换格式。它源于JavaScript,但其应用却更广泛。它基于ECMAScript 的一个子集,作为一种数据格式,完全独立于编程语言,并采用文本格式来存储和表示数据[15]。

JSON 只包含6 个构造字符,用以表达一个序列化的对象或数组,分别是:{}表示的对象,[]表示数组,逗号用于分隔对象成员,冒号用于分隔键值对。值可以是对象、数组、数字、字符串或者3 个字面值(false、null、true)中的一个。JSON 具有简洁和清晰的层次结构,不仅易于计算机生成和解析,也易于自然人读写。与XML 一样,JSON 是一种理想的数据交换语言。但比起XML 规范的标签形式,JSON 表达方式要比XML 少很多结构上的字符[16],因此更适合用于Arduino 这类资源受限的嵌入式设备及其串口控制。

最基本的JSON 对象是一个"key/value"(键值)对集合。一个对象以一对大括号括起来,每个"key"与"value"之间以冒号隔开;多个"key/value"对之间用逗号分隔。格式如下:

JSON 对象也可以具有层次结构。键值也可以是多个JSON 键值对构成的JSON 对象集合或数组。

2.3 Arduino控制指令

Arduino 板通过对其数字接口和模拟接口写入值,控制该接口相连的外设。Arduino 控制指令常用函数如下:

Arduino 数字端口为双向IO,因此在控制数字IO时,需首先用pinMode 函数把IO 口设置为OUTPUT模式。对数字端口的控制采用digitalWrite 函数,数字IO 端口的值valBool 为HIGH 或LOW。对模拟输出的控制采用analogWrite 函数,Arduino 在特定的数字IO 口上通过PWM(Pulse Width Modulation,脉宽调制)实现模拟输出,对外接设备进行模拟输出控制。以Arduino UNO 为例,其PWM 模拟输出端口为IO3、IO5、IO6、IO9、IO10、IO11。PWM 模拟输出的值域范围为0~255。

2.4 ArduinoJSON

2.4.1 ArduinoJSON主要类及方法

ArduinoJSON V6 版本[17]的主要类及方法如图3所示。

图3 ArduinoJSON主要元素示意图

ArduinoJSON主要分为三大类:

1)JsonDocument,是整个JSON 库的入口,它负责高效管理内存以及调用JSON 解析器;V6 版本的JSON 操作都在JsonDocument 上面进行。

2)JsonObject,存储key-value 键值对的集合,每一个key 是一个字符串,每一个value 是一个JsonVariant。最简单的JSON 对象可以用根节点为JsonObject,其内仅仅包含key-value 键值对的集合,没有嵌套JsonObject 或者JsonArray。以键为参数的[]操作符即可获取对应键的JSON 值。

3)JsonArray,是JSON 对象构成的数组。

JSON 的操作方法主要与解析、构造相关,其中deserializeJson()函数用于解析JSON 输入并将结果放入JsonDocument 中。

2.4.2 ArduinoJSON类转换

JsonDocument::as<T>()函数用于获取JSON 文档顶节点,并把它转成T类型,T类型包含上述JsonArray、JsonObject。

此方法只会返回JsonDocument 顶节点的引用。如果顶节点的类型和强制转换的T 类型不匹配,此方法将会返回空引用。比如,如果JsonDocument 是一个JsonArray,当调用JsonDocument::as(),会返回空JsonObject。

2.5 基于JSON的Arduino串口控制指令

遥控设备对Arduino 的控制是通过串口通信,将相关的控制指令传递给Arduino。Arduino 收到相关指令后,调用Arduino 相关数字和模拟接口函数对具体的端口进行控制。Arduino 函数中涉及到的端口及值可以是Arduino 中的预设值、计算值,可以通过串口从遥控终端传递到Arduino 设备[18]。

基于JSON的Arduino串口控制指令流程图如图4所示,程序框架如前所述采用伪中断方式的串口事件方式,每次loop 执行完后,都会去检查串口输入缓冲里是否有字符串,一旦此前遥控终端通过红外、WiFi 或者蓝牙等无线通信方式将字符串及JSON 格式消息送到Arduino 串口缓冲,则执行伪中断serialEvent 函数的程序。

图4 基于JSON的Arduino串口控制指令流程图

该文算法中Arduino 从串口中读取JSON 格式控制指令,因此JSON 的数据源是串口。算法首先定义一个JsonDocument 对象,使用函数deserializeJson 解析从串口接收数据并放入JsonDocument 对象中,再通过JsonDocument 对象的模板方法as<T>,获取根节点,并把它转成T 类型[19]。这里的模板参数T 为JsonObject、JsonArray或者JsonVariant,根据JSON对象的实际情况来决定。上述解码过程的主要程序如下:

3 应用实例

图5 为实验硬件,在某型基于Arduino 的遥控车基础上进行改装而成。在原车基础上扩展了4 个led灯模拟汽车的前后灯和蜂鸣器buz2,并通过面包板进行线路扩展。

图5 遥控指令控制系统实验硬件

3.1 原车控制程序

原遥控控制程序为简单的读取字符并采用级联if-else if-else 结构进行控制。下面是原车控制程序片段:

以run()函数为例,原车中决定小车运行速度的PWM 的值在代码里是写死的,意味着从遥控终端不能控制行车速度。

3.2 改进的控制程序

采用基于JSON 的遥控指令系统,设计控制指令JSON 结构树及协议如下:

JSON根节点采用JsonObject,其内部第一层为motor对象、led嵌套对象和buzzer 数组。motor对象包括两个元素,分别是左轮的速度和右轮的速度,两个速度值不再是写死在Arduino 程序里,而是由遥控终端通过JSON 指令来传递的,增加了控制的灵活性。led 内嵌对象和buzzer 数组是在原车程序基础上针对扩充的部件增加的JSON 控制指令。led 对象内嵌两个对象,分别是front 和back,front 前灯一般同时亮灭,因此只用一个键值对表达。而back 表示后灯,作为转向指示时左右灯不同时亮灭,因而back 子对象又分别包含left 和right 两个元素。buzzer 数组则演示了JSON 数组的用法,可以通过索引直接访问数组元素。值得说明的是,JSON 对象是集合,通过key字符串访问元素,与元素位置无关;JSON 数组则通过index 访问元素,与元素位置有关。

针对上述JSON 控制指令设计的Arduino 解析核心代码片段如下:

对比原车run()函数,motor_left、motor_right 作为自变量参数传入run()函数,决定了小车运行速度,motor_left、motor_right 值相同且为正,小车前进并直行,为负则后退,两值有差异则转弯。同理,解析出来的led 参数和buzzer 参数控制led 灯和buzzer,不仅解决了参数的灵活传递,也使程序结构富有层次性,功能扩展也更方便。

4 结束语

文中设计了一种Arduino 遥控指令控制系统,系统采用Arduino 串口事件伪中断机制作为控制程序框架,基于JSON 格式化数据在遥控终端与Arduino之间传递控制指令。该控制系统解决了扁平结构的字符或者字符串控制算法中参数传递不灵活、程序结构可读性不佳、可扩展性可维护性差的问题。以智能小车为实验对象,验证了该控制系统的可行性和有效性。

猜你喜欢

控制指令键值控制程序
城轨车辆控制指令试验装置研制
非请勿进 为注册表的重要键值上把“锁”
宏指令控制的多轴系统研究及实现
一键直达 Windows 10注册表编辑高招
未成年人刑事案件撤回起诉制度立法思考
锅炉检验质量的控制体系与程序
高速公路隧道通风、照明联动控制方案探讨
重型车辆协同式自适应巡航控制系统的车际通信控制程序和信息交互
注册表值被删除导致文件夹选项成空白
“扫除”技巧之清除恶意程序