1. 树莓派
0 f; E* B8 N) \; x5 {6 Z% P3 @
% ?) x) N X' M8 M树莓派端我们需要找到USB端口设备,我的树莓派上是CHASSIS_SERIAL_PORT = '/dev/ttyUSB0',获得了端口设备之后就可以开始调库了,这也是python语言的拿手好戏。这次我们用的库是serial,我们需要这个库里的函数& M; \8 N% T* c* e6 U
; Q5 {/ s. }* T S6 Z% H
串口初始化:self.port_chassis = serial.Serial(CHASSIS_SERIAL_PORT, 9600, timeout=1)
# D2 J/ _0 n% p6 k6 \- z: Q0 v" B! }3 m1 X
发送数据:self.port_chassis.write((direction + str(distance)).encode())* j% }, k# P5 Q8 j1 g
7 w9 o f y% p) n3 {- Q: W" q& i
读取数据:self.port_chassis.readline().decode(): C* } I" L/ i3 x
. X* t2 M0 ], e! _$ x
流初始化:+ q& S1 z/ b( y5 h7 ?5 f
self.port_chassis.flushInput();self.port_chassis.flushOutput()- l Z9 Q5 @. g* i; U+ N
# v9 v$ C6 X9 o! V2 e- Z3 y* i有了上面几个函数之后,就可以开始写python脚本啦,结合代码来进行分析: S3 ]1 `. E- H; Y
首先是类的初始化函数,目的主要是初始化USART(UART)的波特率" c" b9 J6 ^$ p1 P' I& \8 w3 r
- <font face="微软雅黑" size="3">def __init__(self):
" f7 V+ I9 U/ j' |; I3 a - print("move init finish")
, |7 y( Y( r0 z5 u4 O% J' j& w. O3 N - self.time1 = time.time()* [2 y- V% I9 ^5 a
- self.time2 = time.time()4 |: K$ z- }0 g" j. B1 [- Z9 o' p
- self.flag = False! n/ p4 {$ m/ @( {2 R
- self.port_chassis = serial.Serial(CHASSIS_SERIAL_PORT, 9600, timeout=1)* @2 }, [& L; U) Z! V( |4 t- }
- # print('port_chassis is :' + self.port_chassis.is_Open())5 y G. J, ]+ a- X, `: R
- self.port_chassis.flushInput()
; d8 [/ s4 `# w8 Y: w; c - self.port_chassis.flushOutput()</font>
复制代码 接下来就是发送数据,我们的购物机器人是通过树莓派做为整个的 “大脑”,是由树莓派里的python脚本给底盘发送指令,所以这个函数就是python让底盘移动distance个格子的函数,这个函数里面也是通过USART(UART)给底盘发送指令的,所用函数就是self.port_chassis.write((direction + str(distance)).encode()). {0 W- D' S0 J7 z& ^1 L
- <font face="微软雅黑" size="3"> def move_by_grid(self, direction, distance=''):
$ s: N1 E% B6 f( Q+ e5 z. m - # print('move by grid')! ?4 S+ ~. ~2 ]9 u; f% J
- self.port_chassis.write((direction + str(distance)).encode())
2 @) X+ _7 R$ U' I - self.time1 = time.time()
* O( O' O0 ]7 ?+ i: g - print(direction + str(distance))1 s2 f7 {$ I' I; B; }. f
- self.wait_for_act_end_signal_chassis(direction, distance)</font>
复制代码 最后是接收数据,既然树莓派要控制底盘,树莓派自然也要接收到底盘回传的数据,这里用到的USART(UART)接收数据函数是self.port_chassis.readline().decode(),sig就是树莓派接收到的USART(UART)数据,用户就可以对其做处理啦。& ~1 r' w( B7 \
- <font face="微软雅黑" size="3">def wait_for_act_end_signal_chassis(self, ret=None, distance=0):1 S* b- e' Y/ o/ p
- print('waiting chassis...')
5 b0 w6 E* ]3 p: @' k6 _: o - while True:! u# B1 T' [! C+ G# z: f8 y
- sig = self.port_chassis.readline().decode(); E. N. Q7 A$ x; Y
-
0 B' x, U6 I+ a8 j2 L6 m* I - # print(self.time2 - self.time1)
) N' V N' J! I/ [ -
3 A1 T8 u6 }6 N; C/ } - sig = sig[0:2]
( x. w- P, Y/ {8 D7 i% S - print(sig)
8 h0 j, k8 c8 r2 Y- r - #% C: n/ l/ s3 r n% y+ v- r
- if sig == 'HI':
0 O' `! W6 ~8 Z" n - self.time2 = time.time()/ `* a/ X# x& d8 u, E$ N
- print(self.time2 - self.time1)- ^0 H2 v6 b5 F& Q- V! \
- if self.time2 - self.time1 < 1.0 and self.flag == False and distance == 1:
# j5 ]! C1 h& j$ h a" J9 f% ` - print('1 step deal error')2 i0 ]3 d; m" j1 Z5 D0 R5 h2 L" A
- self.flag = True
# _" ?* ~- J) o# M3 {& [4 J: j, T - if (ret == dir_up or ret == dir_back):2 T* o& k X, k: x$ U+ Y: ^/ v1 |
- self.move_by_grid(ret, 1)0 @1 O8 f/ T/ A9 R+ m2 z' r
- else:</font>
复制代码
/ b% p: H' M* v$ ?! ?6 C8 Q! l
, C! E& `4 z* S2. STM32F427IIH6
$ J/ q5 B" Z+ j/ O5 b
2 X o" e" j, U
# u- y" C/ a# i N$ j# X9 R在嵌入式芯片STM32F427IIH6里,我们首先要打开芯片的DMA功能,然后进行USART(UART)的初始化,最后设置USART(UART)的回调函数即可。) ^3 Q( v7 |/ C/ g' n. D
" z( O1 r8 q, F% F1 A; E# ?+ ?0 Y
! [! V' G; ^% ]$ J首先进行DMA的初始化,在这些初始化里面完成的就是DMA时钟的使能和DMA中断的使能。
* e; e% f8 K8 ?% b; |2 i
) }8 `' @& ?3 |, @ ^- <font face="微软雅黑" size="3">void MX_DMA_Init(void)
/ _: t! W. y0 x U - {" T8 i8 Y6 z% K, k5 Q) i4 J% u
- 4 Y7 v+ r& b8 E# i, `/ D
- /* DMA controller clock enable */6 n% T& h: N2 K% r" E% n1 ^7 X
- __HAL_RCC_DMA1_CLK_ENABLE();
. i- k! z2 b& r! }; j. D4 o0 r - __HAL_RCC_DMA2_CLK_ENABLE();
. s) ?/ j6 B Q( D( m; h) T2 ? -
1 a; N8 [! N: x% U/ F$ l - /* DMA interrupt init */
; l. ?' B) \; P/ L* z# D - /* DMA1_Stream0_IRQn interrupt configuration */
/ M/ l3 @: |" ^6 j/ ^+ J& Y% ?0 V - HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 0, 0);5 }6 @) }3 Q6 V- G6 o
- HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);9 ^( }2 @; Y7 ~# C. x2 ?
- /* DMA1_Stream1_IRQn interrupt configuration */
) ]1 @% P' [& F* ]# ?( e0 X - HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 0);3 g/ S% t; ^) g3 A; ~; o2 i5 e2 s9 E
- HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
. |- X4 O- J/ f, }1 l, c2 |8 Y - /* DMA1_Stream3_IRQn interrupt configuration */
- H0 t6 b% Q5 z9 P5 b+ ]' H - HAL_NVIC_SetPriority(DMA1_Stream3_IRQn, 0, 0);6 @, U+ ^, U$ b6 ?) m4 S4 k
- HAL_NVIC_EnableIRQ(DMA1_Stream3_IRQn);
# G( C% G z9 l - /* DMA1_Stream6_IRQn interrupt configuration */( ?1 a. ] u+ o/ c$ t B7 [
- HAL_NVIC_SetPriority(DMA1_Stream6_IRQn, 0, 0);9 c% w$ n7 `" T0 j/ J9 _/ Q
- HAL_NVIC_EnableIRQ(DMA1_Stream6_IRQn);
- p4 x5 l- E9 R; F W+ a( m - /* DMA2_Stream1_IRQn interrupt configuration */
7 u" Y0 |# G3 }$ ^0 \ - HAL_NVIC_SetPriority(DMA2_Stream1_IRQn, 0, 0);
$ U! K8 a; m: |' j7 q% V- A9 h# M - HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn);6 K; j9 O8 p' f# Z1 N
- /* DMA2_Stream6_IRQn interrupt configuration */
* A; l/ q# W1 g3 N. ? O; X - HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 0, 0); J) U W3 Z; R% V! c ^* X
- HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn);1 q, h, y) m+ F6 o. C
-
# k$ `+ I6 I' I Q4 U - }
& K2 F- o/ v* \+ N - </font>
复制代码 DMA使能完成之后就要进行USART(UART)的基本配置了,这里我设置的就是波特率9600(各个USART(UART)波特率初始化大同小异,因此在这里只放了usart6的初始化,其他类似,不做赘述)。6 [: v3 d' o; N
- <font face="微软雅黑" size="3">void MX_USART6_UART_Init(void)* |( ?$ [- B, T H
- {
) F7 o: ^7 F6 S+ @3 V6 w3 D -
0 L4 s% { D4 `' r$ y. P - huart6.Instance = USART6;
) S* c" q0 G9 M5 |# O - huart6.Init.BaudRate = 9600;: |% _! Q* w4 L7 h& E4 ~
- huart6.Init.WordLength = UART_WORDLENGTH_8B;2 u3 E. e: x4 M: U
- huart6.Init.StopBits = UART_STOPBITS_1;' G! J- f& z8 {$ `1 @; n9 z8 n
- huart6.Init.Parity = UART_PARITY_NONE;" H0 `/ b2 s4 x2 x$ [
- huart6.Init.Mode = UART_MODE_TX_RX;
E& h$ \/ u% X* L6 @8 c - huart6.Init.HwFlowCtl = UART_HWCONTROL_NONE;2 y7 Z% {7 I! h( P# G7 u7 Q
- huart6.Init.OverSampling = UART_OVERSAMPLING_16;
% s$ B3 P/ z% n6 a6 A, { - if (HAL_UART_Init(&huart6) != HAL_OK)
- X1 Z* s C& W w - {
* ?' U# o/ D0 g& M - Error_Handler();
: m6 P6 _ O m5 a C7 M - }; g2 z$ o8 i" X* Z7 r& [% x) u
-
; t8 N# f% q3 i) b# J+ | - }</font>
复制代码 完成了芯片级的配置之后,就要开始配置用户自己需求的USART(UART)功能了,简单点来说就是就是设置回调函数,并且编写回调函数内容。
6 y$ |. `1 M$ V$ b; C" B6 k- X4 C
# u$ p; Q7 B9 Q' v
( e9 S2 q, H7 [5 D: G* l) x' ?' K( |: ?( s* f6 v
1 b1 F% z3 J4 o在void USR_UartInit(void)中主要是打开USART(UART)的DMA接收功能,并且开启USART(UART)接收中断,HAL_UART_IdleCpltCallback(UART_HandleTypeDef *huart)就是我们的回调函数,uart6Rx[1024],uart7Rx[1024],uart8Rx[1024]这3个数组就是STM32F427IIH6的3个(USART6,UART7,UART8)USART(UART)接收到的数组数据 啦,接下来用户就可以对其做处理啦。
N0 Z6 |0 D" w2 j- <font face="微软雅黑" size="3">4 ?1 H+ r1 V% d# p
- void USR_UartInit(void)3 |$ p# q2 B4 K
- {
, k! c- J9 ^) E7 h* A - test1++; @# L0 N( ?' W/ E5 U
- 9 E2 g, u$ P, W8 ^0 e4 }% k9 o
- uart8RxLength = 0; 4 Y5 j% I" ~4 {* Q# _ |
- HAL_UART_Receive_DMA(&huart8, uart8Rx, buffer_size);1 ~+ P6 L P6 s! G5 E0 }. W
- uart7RxLength = 0;
5 r% k. z2 Y/ P' }( g) T - HAL_UART_Receive_DMA(&huart7, uart7Rx, buffer_size);, p7 f1 H. G2 Z: P
- uart6RxLength = 0; # c0 U# f! @+ P/ k# M3 s5 O f
- HAL_UART_Receive_DMA(&huart6, uart6Rx, buffer_size); # f. q& ~# X2 a+ ^+ i; S
-
: F" w% o) j) ]/ u. [ - __HAL_UART_ENABLE_IT(&huart8, UART_IT_IDLE);
* z8 i" [0 o: H$ k$ i5 K; H - __HAL_UART_ENABLE_IT(&huart7, UART_IT_IDLE);
1 q, S( D4 O' k: L - __HAL_UART_ENABLE_IT(&huart6, UART_IT_IDLE); ) a; v. e: @ E% ?2 R
- }" u: K5 R2 I0 x$ n m/ z+ i
- void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)0 V; T- i: \1 @' c' @0 |
- {+ Q- V# l3 N2 m/ T4 B% x c
-
4 M; b$ ?" U, S9 X e. G0 k6 ~ - HAL_UART_Receive_DMA(&huart8, uart8Rx, buffer_size); 2 \( b" r: e7 Q6 k, N5 Q; g
- HAL_UART_Receive_DMA(&huart7, uart7Rx, buffer_size);
2 U1 H7 p. ^. s8 U8 t# L" d - HAL_UART_Receive_DMA(&huart6, uart6Rx, buffer_size);# q0 w; A- [7 F. y( t! H3 w
- __HAL_DMA_ENABLE(&hdma_uart8_rx); 5 L5 o( v9 U. ?) w
- __HAL_DMA_ENABLE(&hdma_uart7_rx);
+ Z! Q% p& u- u$ |$ v - __HAL_DMA_ENABLE(&hdma_usart6_rx);
$ I6 V1 A* p# B U - test2++;% f4 h6 F- h J. o8 D# Y8 C
- }
; M/ S& l, W. m$ g, r5 a - uint8_t RxLenHi, RxLenlo;
. ~+ j6 @" V6 _+ H# } - void HAL_UART_IdleCpltCallback(UART_HandleTypeDef *huart)
& ]8 u0 ]( q& z - {7 w' }5 I% L' ~# \; G- m: t$ {# o
- __HAL_UART_CLEAR_IDLEFLAG(huart);8 ~/ |3 o9 B- {# |0 m2 @
-
3 z" p3 b1 W$ [" h7 C) e4 Q - if( huart == &huart8)# U+ f) ~; C F0 J& l
- {
+ B: j' ]7 c! w1 O1 E9 k - test3++;; `! [6 q! M$ _$ P
- HAL_UART_Receive_DMA(&huart8, uart8Rx, buffer_size); ?1 r* P( z: w! K8 Z5 ?
- 1 l0 _+ ~7 `# n. b, ]7 j4 Z
- uart8RxLength = buffer_size-__HAL_DMA_GET_COUNTER(&hdma_uart8_rx); 1 {. w& e7 m7 F! i
- if(uart8Rx[0]=='@'
8 [6 @9 L/ X7 M$ s! n3 z4 B7 \ - &&uart8Rx[1]=='c'
2 a) v/ X/ a" a2 V9 B* V - &&uart8Rx[2]=='m'
- i+ X9 u" v# l3 U) v1 j - &&uart8Rx[3]=='d') ( A& k/ p* i* x0 B7 I& i5 t* b
- {
" z5 t8 x w: \. @ - if(!SERDEB_CmdValid())
; O- t% e8 o9 [6 w - SERDEB_PushCmd(uart8Rx, uart8RxLength);* Q3 h- o! @2 @
- }
2 I8 p8 o8 H) G% l5 E+ o* N - __HAL_DMA_DISABLE(&hdma_uart8_rx);
" R' O" b/ m( p5 W" w9 k - HAL_GPIO_TogglePin(GPIOG,GPIO_PIN_8); 7 o: F% ]! z1 i6 S( [. ]' W
- }: r/ l+ o$ A% `2 g. F- B; Z
- 4 L% G6 g2 O" B" e7 v
- if( huart == &huart7)
6 ?/ K# `0 z, P, i2 L9 [( ^ - { & J/ i: s, x. b- {$ e
- __HAL_DMA_DISABLE(&hdma_uart7_rx); : D) v) `% u) z( b8 c; V" L6 D
- HAL_UART_Receive_DMA(&huart7, uart7Rx, buffer_size); ( x9 l! D# G; j
- __HAL_DMA_DISABLE(&hdma_uart7_rx);
% Z7 l* a' R) I: N/ D7 O - }2 w) r3 w) K' y1 C4 j8 V
-
) d( [& i9 S' i" L - if( huart == &huart6)$ T0 ?& x3 E! V3 E
- {
) X. e) P( J8 M3 P - __HAL_DMA_DISABLE(&hdma_usart6_rx);
I' L7 c/ s* S9 n8 R3 P% | - HAL_UART_Receive_DMA(&huart6, uart6Rx, buffer_size);
1 a. X- S0 ~. _ - __HAL_DMA_DISABLE(&hdma_usart6_rx);6 Y% C0 L0 r% e% J8 r' ~' _
- } \" V+ }$ `" ^. O, T
-
7 G; N9 `- j% R- {5 w& k" z" B0 s - }</font>
复制代码 至此完成了双工通信的基本配置。
0 r7 c; F: d3 i! ]" g/ [3 M, E" G- h: a3 O, p3 f+ Y: ^
) K- {4 c1 G- a9 s$ `/ f( ~9 b! [5 T+ T( } |8 ? ]4 ?
+ E/ w2 Q7 }) z& H ^3 E
|