我是老温,一名热爱学习的嵌入式工程师
3 f, B* N0 i, J5 s. _关注我,一起变得更加优秀!
) s6 H" E1 Y' _# B8 o# J为了可以让嵌入式Linux产品方便地对接AT指令通信模组,我们在设计嵌入式应用程序的时候,可以用 C/C++ 设计一个通用的AT指令解析器,这个AT指令解析器具有以下特性:
, G4 C$ [9 {8 {( y1、使用UART串口进行硬件连接通信。2、AT指令容易扩展,提供处理函数的注册接口。3、通过队列进行指令管理,发送、接收、处理、多线程同步互斥。4、具有超时重发机制,可设置超时时间与重发次数。5、面向对象设计,高内聚,容易移植使用。
! l+ `! Y! W5 \5 r3 I# m+ \前段时间,小熊派官方发布了星闪核心板 Bearpi-Pico H2821 的AT指令固件,并且支持 1 对 8 组网通信,有了丰富的AT指令集,单片机或者其他MPU芯片就可以很容易地通过星闪网络进行互联通信。6 [# k, D" J# a/ d% u! t6 _5 O/ m8 U
关于星闪 AT 固件的详情,可以查看之前的文章进行回顾:开启星闪互联,组建一对多小型网络!: I" e# Y5 A( `6 O7 W. m
b5tsd0d15eh64022643033.jpg
) Q/ ^# q7 T% I) D# U% [! D5 A这个通用的 AT 指令解析器主要由以下两部分组成:串口通信模块 serial_port,AT指令解析器模块 at_cmd_paeser,以下是解析器的具体设计过程。" I* |+ h+ b5 v. M$ v
1、头文件 serial_port.h 主要提供底层串口硬件的操作接口,包括配置串口,打开或关闭串口,数据发送和接口,以及判断串口是否已经打开,具体代码如下图所示。
3 j( f- k/ ^! l
1f5e1fqwoog64022643133.png
6 O1 d, }* r$ a p* s
2、源文件 serial_port.cpp 主要是实现底层串口硬件的操作逻辑,相关的操作都通过 termios 提供的接口进行实现,串口硬件在配置或者数据收发时,要先判断 is_port_opened 是否置位,串口成功打开后才能进行相关的操作。
4 z' {9 M4 N4 Y; O! c2 z( A9 a$ c
kveostk2isb64022643234.png
* y9 G) o2 m5 @+ G; H
% m' c @ Q% n; P2 P
( Y3 _, W5 l# j0 F* R9 K
uibk3co3dnb64022643334.png
' b% e# }; S" N2 i. d
. d. O9 V+ J- S. B. X: E& o
awdgtlbzurs64022643434.png
% n9 [8 n% {, v! n
3、头文件 at_cmd_parser.h 主要是把AT 指令解析器抽象成一个类 class at_cmd_parser,这个类提供了AT指令和处理函数的注册接口,解析器的启停,AT指令发送,三个线程,数据收发队列,互斥锁与条件变量,等等。3 ?' x3 q: k1 ]5 r
d4pwexbl14y64022643534.png
1 a, @$ L7 w4 L
4、源文件 at_cmd_parser.cpp 主要是对解析器类的接口实现,构造函数主要是打开和配置串口,start() 和 stop() 函数主要是启动和停止三大线程,代码实现如下图所示。
" E: X+ Y' O9 \( s+ ], Z1 P
euwebkikb4z64022643635.png
+ G! A2 F0 m; n5 k; y7 |$ v% z5、函数 add_command_handler() 主要是把AT指令和处理函数进行注册绑定,把处理函数用一个哈希表 command_handler 进行管理,AT指令的字符串是键key,具体的处理函数是健对应的值value。
: O7 d" @. U: \( R0 k; F8 D- s; E
jowb21poqjd64022643735.png
4 m, R6 `: ]$ Z6 g: O6 U
6、调用 send_at_cmd() 函数发送 AT 指令,在这个函数里面,主要是把待发送的AT指令放入队列 send_queue,入队列采用互斥锁保护,然后调用 send_cv 事件唤醒发送线程 send_thread() 进行指令发送。5 [* S6 q4 h+ C# {' u/ f
dxrhggtxc1q64022643835.png
1 j7 @8 p$ w, U7、在发送线程 send_thread() 里面,先获取 send_mtx 互斥锁,然后等待send_cv信号的到达,使用for循环不断从send_queue里面取出 struct at_command 类型的数据,然后调用 serial.send_data() 进行发送。
' ^2 p# i5 g. N, H
1jvnfthsln464022643935.png
$ i7 K* n& s& R9 K, y! @1 I
在发送AT指令之前,先记录发送前的时间点,超过一定时间之后还没有收到当前AT指令的正确回复,则会继续重新发送并记录重发次数,达到最大重发次数后,丢弃该条AT指令。; N/ @8 E% A1 L% x- Q* l3 C
8、在数据接收线程 receiving_thread() 里面,每隔100ms轮询读取串口缓冲区,如果读取到数据,先尝试获取互斥锁,并把数据存入 recv_queue 接收队列,然后发送 recv_cv 事件唤醒数据处理线程 processing_thread() * }2 T4 } C* E/ p
4ayql4g2jhk64022644035.png
9 ^0 m0 E2 f, k/ r) d" i9、在数据处理线程 proessing_thread() 里面,获取数据接收互斥锁,然后等待收到 recv_cv 事件后,从数据接收队列 revv_queue 里面取出数据,不断从 command_handler 哈希表里进行键值匹配,执行对应的注册函数,执行成功后,把该条AT指令从发送队列里面删除。
+ ]7 f6 S2 I( Q" }
kdmsg13jnmm64022644135.png
1 G' E7 l, K a3 w5 Z6 [
10、把星闪核心板 Bearpi-Pico H2821 通过USB接口连接到Linux开发板上面,开发板的内核需要支持CH34x驱动,会在/dev 目录下生成 ttyUSB0 节点,我们可以做一个简单的界面来进行指令发送,点击【指令:AT】按钮,可以看到调试终端输出打印信息,AT指令解析器可以在开发板上面顺利运行。: h; \0 h# I+ V. _% J+ `1 x
rhreaxi3plr64022644236.png
, W/ z$ a7 s A" n# I
下一步,我们将会基于这个通用的 AT 指令解析器,把星闪核心板BearPi-Pico H2821的 AT 指令都集成到一个模块组件里面,通过这个组件,就可以让嵌入式 Linux 开发板轻松获得星闪通信功能。" q! A4 C2 O1 S, ]
-END-
p& b& S: t J6 g8 H! t/ W! ^往期推荐:点击图片即可跳转阅读7 ]8 Q/ K* Z, q4 C7 V2 q; E K
! c' p' S( ~' e3 Z/ @
: E: a( U/ j* C1 |6 Q0 I/ L ) |( c) A! N9 f3 J# K% ?
5 d* M! _% a, {& y- t/ K1 Q
' R+ G# y% \' F; k + ?0 O7 c8 I2 k1 c. j
0ydacxmfplt64022644336.jpg
4 Z$ ?/ l9 b$ ^, D$ I" y Z
& E& P1 z. Y9 ]8 h) ~) P" a1 L
开启星闪互联,组建一对多小型网络!
/ |+ R' p7 a2 g8 Q & d6 Z l Q9 s6 ]. Y# a/ }5 c1 k
5 q1 @* \9 q% ?# c$ H* k6 C) I5 j
2 R+ p& @7 P. [4 u% e7 w+ y# ? # a3 ~! Q0 V; G! i5 y) x; i
14w22t5cjce64022644436.jpg
) z0 C% d, i* Z% y, k
- b2 k; @" `3 e3 w3 c4 ]- j 现场实测,用数据说话,星闪通信距离突破3.3公里!
: O8 Z' P1 ~* M6 ^! T 8 N. ]0 b/ U8 F
/ D9 _3 K3 M; j" t ' U1 |! b/ s" ^ c, a2 p( Y
i0t3bitb11n64022644537.jpg
4 c. @0 S+ g) i) M9 z
$ C' D) b0 {9 h- ~
【分享】好玩的嵌入式 AI ,机器视觉和音视频处理
4 }6 N9 V# U3 n3 F( m
1 o: t' K9 R. ~6 E1 U : O4 k. l; P* Q
, H7 _7 L8 C3 S w+ u( g- I0 z: q0 b 我是老温,一名热爱学习的嵌入式工程师0 t. d- o$ }* \1 {/ r
关注我,一起变得更加优秀! |