我是老温,一名热爱学习的嵌入式工程师。关注我,一起变得更加优秀!
为了可以让嵌入式Linux产品方便地对接AT指令通信模组,我们在设计嵌入式应用程序的时候,可以用 C/C++ 设计一个通用的AT指令解析器,这个AT指令解析器具有以下特性:
2、AT指令容易扩展,提供处理函数的注册接口。
3、通过队列进行指令管理,发送、接收、处理、多线程同步互斥。
4、具有超时重发机制,可设置超时时间与重发次数。
5、面向对象设计,高内聚,容易移植使用。
前段时间,小熊派官方发布了星闪核心板 H2821-Pico 的AT指令固件,并且支持 1 对 8 组网通信,有了丰富的AT指令集,单片机或者其他MPU芯片就可以很容易地通过星闪网络进行互联通信。
关于星闪 AT 固件的详情,可以查看之前的文章进行回顾:开启星闪互联,组建一对多小型网络!
这个通用的 AT 指令解析器主要由以下两部分组成:串口通信模块 serial_port,AT指令解析器模块 at_cmd_paeser,以下是解析器的具体设计过程。
1、头文件 serial_port.h 主要提供底层串口硬件的操作接口,包括配置串口,打开或关闭串口,数据发送和接口,以及判断串口是否已经打开,具体代码如下图所示。
2、源文件 serial_port.cpp 主要是实现底层串口硬件的操作逻辑,相关的操作都通过 termios 提供的接口进行实现,串口硬件在配置或者数据收发时,要先判断 is_port_opened 是否置位,串口成功打开后才能进行相关的操作。
3、头文件 at_cmd_parser.h 主要是把AT 指令解析器抽象成一个类 class at_cmd_parser,这个类提供了AT指令和处理函数的注册接口,解析器的启停,AT指令发送,三个线程,数据收发队列,互斥锁与条件变量,等等。
4、源文件 at_cmd_parser.cpp 主要是对解析器类的接口实现,构造函数主要是打开和配置串口,start() 和 stop() 函数主要是启动和停止三大线程,代码实现如下图所示。
5、函数 add_command_handler() 主要是把AT指令和处理函数进行注册绑定,把处理函数用一个哈希表 command_handler 进行管理,AT指令的字符串是键key,具体的处理函数是健对应的值value。
6、调用 send_at_cmd() 函数发送 AT 指令,在这个函数里面,主要是把待发送的AT指令放入队列 send_queue,入队列采用互斥锁保护,然后调用 send_cv 事件唤醒发送线程 send_thread() 进行指令发送。
7、在发送线程 send_thread() 里面,先获取 send_mtx 互斥锁,然后等待send_cv信号的到达,使用for循环不断从send_queue里面取出 struct at_command 类型的数据,然后调用 serial.send_data() 进行发送。
在发送AT指令之前,先记录发送前的时间点,超过一定时间之后还没有收到当前AT指令的正确回复,则会继续重新发送并记录重发次数,达到最大重发次数后,丢弃该条AT指令。
8、在数据接收线程 receiving_thread() 里面,每隔100ms轮询读取串口缓冲区,如果读取到数据,先尝试获取互斥锁,并把数据存入 recv_queue 接收队列,然后发送 recv_cv 事件唤醒数据处理线程 processing_thread()
9、在数据处理线程 proessing_thread() 里面,获取数据接收互斥锁,然后等待收到 recv_cv 事件后,从数据接收队列 revv_queue 里面取出数据,不断从 command_handler 哈希表里进行键值匹配,执行对应的注册函数,执行成功后,把该条AT指令从发送队列里面删除。
10、把星闪核心板 Bearpi-Pico H2821 通过USB接口连接到Linux开发板上面,开发板的内核需要支持CH34x驱动,会在/dev 目录下生成 ttyUSB0 节点,我们可以做一个简单的界面来进行指令发送,点击【指令:AT】按钮,可以看到调试终端输出打印信息,AT指令解析器可以在开发板上面顺利运行。
下一步,我们将会基于这个通用的 AT 指令解析器,把星闪核心板BearPi-Pico H2821的 AT 指令都集成到一个模块组件里面,通过这个组件,就可以让嵌入式 Linux 开发板轻松获得星闪通信功能。