前言
K: o. c& t8 P. i据上次博主写OpenMV与STM32通信的博客已经过去两个月了,今天在写下Jetson nano 与 STM32 的通信问题。6 b8 G2 @) Y1 B
我先把上次文章的地址贴过来:
7 S. G6 E7 r$ n* v, ]: SOpenmv与STM32通信
* j6 S- C' `3 F1 [: Y4 ?还有相关的程序,我也已经打包好上传到了CSDN上,我在把它贴出来:" @5 p: Y- T. N/ ]1 z* X5 b E! C
基于STM32C8T6的OLED+USART+OpenMV: C2 Y2 I, Y5 |; G! }1 u# z3 l, j
之所以要提到OpenMV的通信问题,是因为Jetson nano的串口通信过程和OpenMV相差不大,二者可以做一个对比。, \% k! s& k- _, O" N& [: j( K
; r7 `; {4 R% J! C" j) M8 Y# `一、Jetson nano串口配置
# _4 Y& h. C( h# u 这里的串口配置,CSDN上许多博主都有说到,而且也都挺详细的,所以我就不大做文章,我就一笔带过就好了。0 E( {$ D2 `0 r; Y
配置串口的时,记得给予Jetson nano串口权限,在终端控制区输入. u2 H) O0 L) Y" e0 q0 C/ G/ c* M) _3 t
- `sudo chmod 777 /dev/ttyTHS1`
复制代码
$ v% @ T7 @! \这个指令,打开串口权限,这个权限每次重新开机后都需要重新设置。
' v8 f% z& d q& U. t
0 I3 S& A T/ u% i2 B ~% p- import serial
; `( ]) P8 N0 T- ^6 \ - L% `/ R1 C! j* O! I8 W. w
- com = serial.Serial("/dev/ttyTHS1",115200)
复制代码
, i* R0 i' E6 y( @! L8 W; x 这就是打开串口所需要的代码,由于和OpenMv一样,也是基于python,所以也是一样的简洁和实用。
- D O5 R8 C) d v' v) q& `2 } 主要操作就是,调用serial库,然后使用其中的函数,打开和配置串口,像我在代码中所写的,打开串口,配置其波特率为115200。* w$ K" A3 G' G: i( i0 ~
二、通信过程
1 ]! V! X1 Y- m3 T1 Q4 a+ |" [2 x* S" P9 @1 F" e) d
在我之前的OpenMV与STM32通信的博客中,我提及到的OpenMV和STM32数据传输通信中所使用的方法,而现在改用Jetson nano来实现与STM32数据传输通信,基本上在OpenMV与STM32上传输数据能成功的方法也可以适用于Jetson nano上。
+ m; B: x) a2 z Jetson nano写串口的函数和OpenMV写串口的函数一样,都是 .write( ) 的函数来写入,这就对写入的数据有所要求。1 q s% t* n8 ?& f5 A$ ?
( W0 b$ `2 W7 @6 Z3 V9 f" B
1.使用数据包的形式发送数据
- G, T0 a; `& }# g) P代码如下:
/ A% {" M: l+ P- impor struct0 }3 h! w2 _" O, L* S+ h
- % [# ^1 H* T" A, d& v
- def pack_Data(a,b):
; h* g" g Y* x* N3 E - temp = struct.pack("<BBbb",0x2C,0x12,int(a),int(b))
. P0 u# a: Q) P( Q& A - print(temp)9 D& T2 r/ a0 Z2 |1 c
, ~9 z8 z! [6 v5 y& i- ~( h- com.write(temp)
复制代码
; E8 A* z; n2 I9 B7 R 首先这里需要引入struct库,然后调用struct中的 .pack 函数,使用该函数来对所需要发送的数据进行打包。9 K+ ?$ z7 R! p8 a# W; [4 J0 V( z
对于struct.pack() 的函数分析, 可以参考博主之前写的OpenMV的数据传输通信部分,也可以CSDN上搜索 struct.pack() 这个噶不是这里不在重复介绍解释,这里的主要操作是,我声明我所发送的几个数据的格式,并将其打包完成后,再一并发送。
& n* B+ v5 S6 o- E5 h- A; s* ? 对于0x2C、0x12这两个所对应的是**BB**,而B所对应的是有符号的char类型,但在这影响不大,0x2C、0x12都位于[-128,127]的区间中,毫无疑问,这里出现的这两个数据,便是起到数据帧头的作用。本来按理说,应该在数据串的末端再增加一个校验和来作为数据是否完全传输的判断来确保数据的准确性的,但在这就先不重复说明,大家应该都知道怎么操作。6 R' R; j" b) S3 [' A
而后面的两个数据——数据a、数据b,对应的是bb这两个类型格式,而b所对应的是无符号的char类型,区间位于[0,255],这个后面数据传输时候是需要稍加注意的。于此之外,还有在这个数据接收的过程应该格外注意下,不同的数据类型所占的数组大小不同,很多情况下数据为0,可能是因为你读取数组存放位置出现了问题,而不是数据没有送达到位。
9 P4 m/ h5 e: _, q& Q 最后再通过com. write( temp)将数据发送出去。+ O8 C' t. @9 N7 R; T7 m& ~
- z3 ?: ]8 |7 Q1 z3 a; {0 [9 i4 _
2.另外一种数据包形式发送数据! r$ b$ r. j. S6 t3 K. [
代码如下:
4 F- c2 l, D9 ?5 ]" f4 K2 c& _% _, M# T' c/ |( [
- BUF = bytearray(5)
5 d/ m$ `3 a2 R1 O1 a4 ~9 O% ~ - e/ O! i! u# q' P8 v- T% \! G1 F
- def packData( a , b, ):6 h2 ~4 ]6 h5 v) n7 W
- print(BUF)
+ v0 J0 l2 U3 |6 U; F - struct.pack_into('<2B2b', BUF, 0, 0x2C, 0x12, a, b, )) z4 w' A" u6 F3 o# H- r$ o
- checksum = 0( \. L! Q, E1 t- k9 Y, W
- for i in BUF[:-1]:0 O( E$ n; B# [7 m! M- N" e( k
- checksum += i& W. R- j* i5 T
- checksum = (checksum & 0xff) w8 i3 N; b" m! ~& U/ y" W/ _
- struct.pack_into('<B', BUF, 4, checksum): r4 R0 X4 }+ v" R
2 K% i7 N5 \9 c% m9 `) F$ `; A- com.write(BUF)
复制代码 这个方法是使用 struct 库中另外的函数, struct.pack_into() 函数 struct.pack_into(fmt, buffer, offset, v1, v2, ...)该函数的用法:
5 ~' O& u0 A+ y0 _. N2 p 按照指定的格式fmt,将v1,v2...打包到buffer中,其中偏移位置为offset。 也就说在这个函数中的作用就是将0x2C、0x12、数据a、数据b 都加入到数组BUF中,并在最后为这个数组添加一个校验位。而数据格式类型的选择与之前的 .pack( )函数中的相同,只是此处BBbb变成了2B2b而已。
$ d/ T0 P7 b1 x9 L6 e: R9 u( x0 n+ Q: o1 t! c, |
3.使用list直接发送数据% c/ A. L' D, T" Z* D4 Q) [: U
代码如下:6 y; q" }/ s6 c+ Z0 @5 u
6 o: L% R( K) e$ O1 t) v3 U; B- def Data(a,b):
0 K* x3 @7 H! f7 E8 w8 O) i - data = [0x2C,0x12,int(a),int(b),0xAA]
: X" k, ]. B4 [( X - data = bytearray(data)$ f% i8 n( i/ Q# H
& `- J7 }2 g* T$ B4 L- print(data)5 r* L1 A0 s1 l; a2 F
- com.write(data)
复制代码
7 k& X; b4 u9 U 相较于以数据包的形式发送数据,本人比较喜欢这样发送数据的方法,比较简单,但是数据区间是[0,255]。此方法减少了数据处理的工作量。
5 r$ F- o( k6 ~3 N 该方法最重要的一点就是对数据进行 bytearray() 的处理,只用这样处理后的数据才可以发送打印到串口上。需要注意。( ~7 e1 ^" S4 ]6 D' N. c+ r9 s; H
最后的0xAA便是校验位。$ n9 l( T4 b* g% D0 @1 A3 ]0 @
7 p3 f$ y& r& c0 d7 h* |6 Y三、STM32数据处理 N1 ?& L5 M" K
x) z1 f9 v0 o# i8 l: t STM32数据接收部分其实和OpenMv的那篇文章相同,同样也是打开串口1,改变波特率为115200。
% f7 P* r% G' ?2 x1 e# g 开启接收中断,然后在中断进行数据处理。首先需要前两个帧头正确了,最后是最后一位的校验位正确了,这段数据才算有效。
; v3 z/ y, Z4 i6 J8 Y1 L6 | 我大概的代码如下(偷懒了一下,我并没有检查最后一位的校验位):) S- g A# S9 h; P1 f
- void USART1_IRQHandler(void)
2 i7 s2 }2 j$ x9 d! ? - {
. @( y5 G" p/ E) L* L, f1 p
) b! h6 P+ k# x4 H6 C2 N- static u8 Rebuf[20]={0};
( O. o. V' H* A; c" e. V* a) r - static u8 i = 0;
. |" @ B1 F) ?* _( f+ I1 `$ Q - ; }- C: c! _5 T) K1 _7 i$ G, F
- if( USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET )
" e& [3 I$ p) y" {& G- c6 ` - {
1 w% q% I! T H8 ^7 \6 @ - Rebuf[i++] = USART_ReceiveData(USART1);. L$ u8 B* q9 }6 l c: Y
- if(Rebuf[0] != 0x2c)# n; [% ~4 L7 I c Y
- i = 0;) }; v+ {2 H5 M; }
- if((i==2)&&Rebuf[1] != 0x12)
- U7 J2 m/ \, D$ \ - i = 0;: Z, K& T. P0 C0 u w
- m+ p0 {' A5 @ S' M! D
- if(i>=10)# `% }4 R- k% I( R
- {4 \: c8 r' b+ D7 |" f2 [
- memcpy(OpenMV_Rx_BUF,Rebuf,i);0 W h1 r; G4 A
- i = 0;# Q6 J9 z" y2 c$ r0 W4 ?$ F/ [- q2 |
- }9 w' p) P. D2 E6 Q1 q
- USART_ClearITPendingBit(USART1,USART_IT_RXNE);//清除中断标志) W" e. n: C6 z. f/ j6 z
- & Q/ A2 f; J' \7 Z. A+ z! b
- }+ r3 P% T) o) X' x
- }
6 u p: V' N( n. j/ d
复制代码 1 f6 Z) Q+ g! m# N5 A1 E" x. N- j
总结
# C- I* X4 l; X4 j7 ? 因为之前有配置OpenMV和STM32数据传输通信的问题频出,所谓吃一堑长一智,这次Jetson nano的数据传输串口通信上,并没有那么多的问题。所以我在本文开头才说先看完我的OpenMV串口通信的博客再来看我这篇文章,这样才会比较容易读懂。
/ ?7 _ I5 H+ P5 J3 ]1 I
9 x9 m" L. J2 v. f9 L% I# F6 K0 Q+ s5 _, s7 P
0 Z) Z6 F0 \+ E/ r5 O2 ]; R
|