请选择 进入手机版 | 继续访问电脑版

你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32F427IIH6芯片通过DMA+USART与树莓派进行双工通信

[复制链接]
STMCU小助手 发布时间:2021-7-26 11:27
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
  1. <font face="微软雅黑" size="3">def __init__(self):
    " f7 V+ I9 U/ j' |; I3 a
  2.         print("move init finish")
    , |7 y( Y( r0 z5 u4 O% J' j& w. O3 N
  3.         self.time1 = time.time()* [2 y- V% I9 ^5 a
  4.         self.time2 = time.time()4 |: K$ z- }0 g" j. B1 [- Z9 o' p
  5.         self.flag = False! n/ p4 {$ m/ @( {2 R
  6.         self.port_chassis = serial.Serial(CHASSIS_SERIAL_PORT, 9600, timeout=1)* @2 }, [& L; U) Z! V( |4 t- }
  7.         # print('port_chassis is :' + self.port_chassis.is_Open())5 y  G. J, ]+ a- X, `: R
  8.         self.port_chassis.flushInput()
    ; d8 [/ s4 `# w8 Y: w; c
  9.         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
  1. <font face="微软雅黑" size="3"> def move_by_grid(self, direction, distance=''):
    $ s: N1 E% B6 f( Q+ e5 z. m
  2.         # print('move by grid')! ?4 S+ ~. ~2 ]9 u; f% J
  3.         self.port_chassis.write((direction + str(distance)).encode())
    2 @) X+ _7 R$ U' I
  4.         self.time1 = time.time()
    * O( O' O0 ]7 ?+ i: g
  5.         print(direction + str(distance))1 s2 f7 {$ I' I; B; }. f
  6.         self.wait_for_act_end_signal_chassis(direction, distance)</font>
复制代码
最后是接收数据,既然树莓派要控制底盘,树莓派自然也要接收到底盘回传的数据,这里用到的USART(UART)接收数据函数是self.port_chassis.readline().decode(),sig就是树莓派接收到的USART(UART)数据,用户就可以对其做处理啦& ~1 r' w( B7 \
  1. <font face="微软雅黑" size="3">def wait_for_act_end_signal_chassis(self, ret=None, distance=0):1 S* b- e' Y/ o/ p
  2.         print('waiting chassis...')
    5 b0 w6 E* ]3 p: @' k6 _: o
  3.         while True:! u# B1 T' [! C+ G# z: f8 y
  4.             sig = self.port_chassis.readline().decode(); E. N. Q7 A$ x; Y

  5. 0 B' x, U6 I+ a8 j2 L6 m* I
  6.             # print(self.time2 - self.time1)
    ) N' V  N' J! I/ [

  7. 3 A1 T8 u6 }6 N; C/ }
  8.             sig = sig[0:2]
    ( x. w- P, Y/ {8 D7 i% S
  9.             print(sig)
    8 h0 j, k8 c8 r2 Y- r
  10.             #% C: n/ l/ s3 r  n% y+ v- r
  11.             if sig == 'HI':
    0 O' `! W6 ~8 Z" n
  12.                 self.time2 = time.time()/ `* a/ X# x& d8 u, E$ N
  13.                 print(self.time2 - self.time1)- ^0 H2 v6 b5 F& Q- V! \
  14.                 if self.time2 - self.time1 < 1.0 and self.flag == False and distance == 1:
    # j5 ]! C1 h& j$ h  a" J9 f% `
  15.                     print('1 step deal error')2 i0 ]3 d; m" j1 Z5 D0 R5 h2 L" A
  16.                     self.flag = True
    # _" ?* ~- J) o# M3 {& [4 J: j, T
  17.                     if (ret == dir_up or ret == dir_back):2 T* o& k  X, k: x$ U+ Y: ^/ v1 |
  18.                         self.move_by_grid(ret, 1)0 @1 O8 f/ T/ A9 R+ m2 z' r
  19.                     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 |, @  ^
  1. <font face="微软雅黑" size="3">void MX_DMA_Init(void)
    / _: t! W. y0 x  U
  2. {" T8 i8 Y6 z% K, k5 Q) i4 J% u
  3. 4 Y7 v+ r& b8 E# i, `/ D
  4.   /* DMA controller clock enable */6 n% T& h: N2 K% r" E% n1 ^7 X
  5.   __HAL_RCC_DMA1_CLK_ENABLE();
    . i- k! z2 b& r! }; j. D4 o0 r
  6.   __HAL_RCC_DMA2_CLK_ENABLE();
    . s) ?/ j6 B  Q( D( m; h) T2 ?

  7. 1 a; N8 [! N: x% U/ F$ l
  8.   /* DMA interrupt init */
    ; l. ?' B) \; P/ L* z# D
  9.   /* DMA1_Stream0_IRQn interrupt configuration */
    / M/ l3 @: |" ^6 j/ ^+ J& Y% ?0 V
  10.   HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 0, 0);5 }6 @) }3 Q6 V- G6 o
  11.   HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);9 ^( }2 @; Y7 ~# C. x2 ?
  12.   /* DMA1_Stream1_IRQn interrupt configuration */
    ) ]1 @% P' [& F* ]# ?( e0 X
  13.   HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 0);3 g/ S% t; ^) g3 A; ~; o2 i5 e2 s9 E
  14.   HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
    . |- X4 O- J/ f, }1 l, c2 |8 Y
  15.   /* DMA1_Stream3_IRQn interrupt configuration */
    - H0 t6 b% Q5 z9 P5 b+ ]' H
  16.   HAL_NVIC_SetPriority(DMA1_Stream3_IRQn, 0, 0);6 @, U+ ^, U$ b6 ?) m4 S4 k
  17.   HAL_NVIC_EnableIRQ(DMA1_Stream3_IRQn);
    # G( C% G  z9 l
  18.   /* DMA1_Stream6_IRQn interrupt configuration */( ?1 a. ]  u+ o/ c$ t  B7 [
  19.   HAL_NVIC_SetPriority(DMA1_Stream6_IRQn, 0, 0);9 c% w$ n7 `" T0 j/ J9 _/ Q
  20.   HAL_NVIC_EnableIRQ(DMA1_Stream6_IRQn);
    - p4 x5 l- E9 R; F  W+ a( m
  21.   /* DMA2_Stream1_IRQn interrupt configuration */
    7 u" Y0 |# G3 }$ ^0 \
  22.   HAL_NVIC_SetPriority(DMA2_Stream1_IRQn, 0, 0);
    $ U! K8 a; m: |' j7 q% V- A9 h# M
  23.   HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn);6 K; j9 O8 p' f# Z1 N
  24.   /* DMA2_Stream6_IRQn interrupt configuration */
    * A; l/ q# W1 g3 N. ?  O; X
  25.   HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 0, 0);  J) U  W3 Z; R% V! c  ^* X
  26.   HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn);1 q, h, y) m+ F6 o. C

  27. # k$ `+ I6 I' I  Q4 U
  28. }
    & K2 F- o/ v* \+ N
  29. </font>
复制代码
DMA使能完成之后就要进行USART(UART)的基本配置了,这里我设置的就是波特率9600(各个USART(UART)波特率初始化大同小异,因此在这里只放了usart6的初始化,其他类似,不做赘述)。6 [: v3 d' o; N
  1. <font face="微软雅黑" size="3">void MX_USART6_UART_Init(void)* |( ?$ [- B, T  H
  2. {
    ) F7 o: ^7 F6 S+ @3 V6 w3 D

  3. 0 L4 s% {  D4 `' r$ y. P
  4.   huart6.Instance = USART6;
    ) S* c" q0 G9 M5 |# O
  5.   huart6.Init.BaudRate = 9600;: |% _! Q* w4 L7 h& E4 ~
  6.   huart6.Init.WordLength = UART_WORDLENGTH_8B;2 u3 E. e: x4 M: U
  7.   huart6.Init.StopBits = UART_STOPBITS_1;' G! J- f& z8 {$ `1 @; n9 z8 n
  8.   huart6.Init.Parity = UART_PARITY_NONE;" H0 `/ b2 s4 x2 x$ [
  9.   huart6.Init.Mode = UART_MODE_TX_RX;
      E& h$ \/ u% X* L6 @8 c
  10.   huart6.Init.HwFlowCtl = UART_HWCONTROL_NONE;2 y7 Z% {7 I! h( P# G7 u7 Q
  11.   huart6.Init.OverSampling = UART_OVERSAMPLING_16;
    % s$ B3 P/ z% n6 a6 A, {
  12.   if (HAL_UART_Init(&huart6) != HAL_OK)
    - X1 Z* s  C& W  w
  13.   {
    * ?' U# o/ D0 g& M
  14.     Error_Handler();
    : m6 P6 _  O  m5 a  C7 M
  15.   }; g2 z$ o8 i" X* Z7 r& [% x) u

  16. ; t8 N# f% q3 i) b# J+ |
  17. }</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
  1. <font face="微软雅黑" size="3">4 ?1 H+ r1 V% d# p
  2. void USR_UartInit(void)3 |$ p# q2 B4 K
  3. {
    , k! c- J9 ^) E7 h* A
  4.     test1++;  @# L0 N( ?' W/ E5 U
  5. 9 E2 g, u$ P, W8 ^0 e4 }% k9 o
  6.     uart8RxLength = 0;   4 Y5 j% I" ~4 {* Q# _  |
  7.     HAL_UART_Receive_DMA(&huart8, uart8Rx, buffer_size);1 ~+ P6 L  P6 s! G5 E0 }. W
  8.     uart7RxLength = 0;   
    5 r% k. z2 Y/ P' }( g) T
  9.     HAL_UART_Receive_DMA(&huart7, uart7Rx, buffer_size);, p7 f1 H. G2 Z: P
  10.     uart6RxLength = 0;   # c0 U# f! @+ P/ k# M3 s5 O  f
  11.     HAL_UART_Receive_DMA(&huart6, uart6Rx, buffer_size);    # f. q& ~# X2 a+ ^+ i; S

  12. : F" w% o) j) ]/ u. [
  13.     __HAL_UART_ENABLE_IT(&huart8, UART_IT_IDLE);     
    * z8 i" [0 o: H$ k$ i5 K; H
  14.     __HAL_UART_ENABLE_IT(&huart7, UART_IT_IDLE);   
    1 q, S( D4 O' k: L
  15.     __HAL_UART_ENABLE_IT(&huart6, UART_IT_IDLE);   ) a; v. e: @  E% ?2 R
  16. }" u: K5 R2 I0 x$ n  m/ z+ i
  17. void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)0 V; T- i: \1 @' c' @0 |
  18. {+ Q- V# l3 N2 m/ T4 B% x  c

  19. 4 M; b$ ?" U, S9 X  e. G0 k6 ~
  20.     HAL_UART_Receive_DMA(&huart8, uart8Rx, buffer_size); 2 \( b" r: e7 Q6 k, N5 Q; g
  21.     HAL_UART_Receive_DMA(&huart7, uart7Rx, buffer_size);
    2 U1 H7 p. ^. s8 U8 t# L" d
  22.     HAL_UART_Receive_DMA(&huart6, uart6Rx, buffer_size);# q0 w; A- [7 F. y( t! H3 w
  23.     __HAL_DMA_ENABLE(&hdma_uart8_rx); 5 L5 o( v9 U. ?) w
  24.     __HAL_DMA_ENABLE(&hdma_uart7_rx);
    + Z! Q% p& u- u$ |$ v
  25.     __HAL_DMA_ENABLE(&hdma_usart6_rx);
    $ I6 V1 A* p# B  U
  26.     test2++;% f4 h6 F- h  J. o8 D# Y8 C
  27. }
    ; M/ S& l, W. m$ g, r5 a
  28. uint8_t RxLenHi, RxLenlo;  
    . ~+ j6 @" V6 _+ H# }
  29. void HAL_UART_IdleCpltCallback(UART_HandleTypeDef *huart)
    & ]8 u0 ]( q& z
  30. {7 w' }5 I% L' ~# \; G- m: t$ {# o
  31.     __HAL_UART_CLEAR_IDLEFLAG(huart);8 ~/ |3 o9 B- {# |0 m2 @

  32. 3 z" p3 b1 W$ [" h7 C) e4 Q
  33.         if( huart == &huart8)# U+ f) ~; C  F0 J& l
  34.         {
    + B: j' ]7 c! w1 O1 E9 k
  35.             test3++;; `! [6 q! M$ _$ P
  36.             HAL_UART_Receive_DMA(&huart8, uart8Rx, buffer_size);    ?1 r* P( z: w! K8 Z5 ?
  37. 1 l0 _+ ~7 `# n. b, ]7 j4 Z
  38.             uart8RxLength = buffer_size-__HAL_DMA_GET_COUNTER(&hdma_uart8_rx);     1 {. w& e7 m7 F! i
  39.             if(uart8Rx[0]=='@'
    8 [6 @9 L/ X7 M$ s! n3 z4 B7 \
  40.             &&uart8Rx[1]=='c'
    2 a) v/ X/ a" a2 V9 B* V
  41.             &&uart8Rx[2]=='m'
    - i+ X9 u" v# l3 U) v1 j
  42.             &&uart8Rx[3]=='d') ( A& k/ p* i* x0 B7 I& i5 t* b
  43.             {
    " z5 t8 x  w: \. @
  44.                 if(!SERDEB_CmdValid())
    ; O- t% e8 o9 [6 w
  45.                     SERDEB_PushCmd(uart8Rx, uart8RxLength);* Q3 h- o! @2 @
  46.             }
    2 I8 p8 o8 H) G% l5 E+ o* N
  47.             __HAL_DMA_DISABLE(&hdma_uart8_rx);
    " R' O" b/ m( p5 W" w9 k
  48.             HAL_GPIO_TogglePin(GPIOG,GPIO_PIN_8);    7 o: F% ]! z1 i6 S( [. ]' W
  49.         }: r/ l+ o$ A% `2 g. F- B; Z
  50. 4 L% G6 g2 O" B" e7 v
  51.           if( huart == &huart7)
    6 ?/ K# `0 z, P, i2 L9 [( ^
  52.         {        & J/ i: s, x. b- {$ e
  53.             __HAL_DMA_DISABLE(&hdma_uart7_rx);  : D) v) `% u) z( b8 c; V" L6 D
  54.             HAL_UART_Receive_DMA(&huart7, uart7Rx, buffer_size); ( x9 l! D# G; j
  55.             __HAL_DMA_DISABLE(&hdma_uart7_rx);
    % Z7 l* a' R) I: N/ D7 O
  56.         }2 w) r3 w) K' y1 C4 j8 V

  57. ) d( [& i9 S' i" L
  58.         if( huart == &huart6)$ T0 ?& x3 E! V3 E
  59.         {
    ) X. e) P( J8 M3 P
  60.             __HAL_DMA_DISABLE(&hdma_usart6_rx);
      I' L7 c/ s* S9 n8 R3 P% |
  61.             HAL_UART_Receive_DMA(&huart6, uart6Rx, buffer_size);
    1 a. X- S0 ~. _
  62.             __HAL_DMA_DISABLE(&hdma_usart6_rx);6 Y% C0 L0 r% e% J8 r' ~' _
  63.         }  \" V+ }$ `" ^. O, T

  64. 7 G; N9 `- j% R- {5 w& k" z" B0 s
  65. }</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
收藏 评论0 发布时间:2021-7-26 11:27

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版