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

【经验分享】STM32L031 HAL 串口收发例程(中断配合轮询)

[复制链接]
STMCU小助手 发布时间:2021-11-16 01:34
代码环境
4 f, c" y: {9 a$ p9 h! T' Z& _开发工具:STM32CUBEIDE8 w6 P, u5 U% y/ c5 V5 X
芯片:STM32L031K6T6
7 X7 ^6 R6 r/ Q$ V端口: UART2
& J) }. P- l. Y' i* E基本配置5 w% o$ r* J9 D! i# I- B* u4 n
7 @/ K# `' o- A" S7 I
2019111911265218.png

4 u' c6 C! X, V7 @# ?0 y$ w: W1 \
! E0 C# z; y8 ?) v& I+ s
20191119112729252.png

% P) d+ t: y8 x1 a
4 t  U" s5 t# m
20191119112750442.png

: \7 S8 d4 s( b$ A, w
1 h# G8 S/ D$ d4 G* V% [其中,PA9 (RX)的输入上拉,在System Core的GPIO里配置。
+ W" F" \; B" e
5 w4 O4 F* T* u2 i% _1 |" Q! Z5 k1 |
20191119112920480.png

/ S( i# S% h2 T1 A7 i& f( r6 S# C- ^
TX(发送)设计3 @0 c* k$ J4 A2 ]
TX部分增加bsp_usart.c和bsp_usart.h文件,以支持printf重载。
" i+ d0 C1 A9 j' y- m( N
8 D; L0 W) h" ?0 P1 e' e+ o0 Bbsp_usart.h内容$ ?" P' U$ Q7 K% E
  b9 f4 e3 e9 u
  1. #ifndef __BSP_USART_H: l" I3 G- ]) b, Q4 G- T! i
  2. #define __BSP_USART_H
    / l" R7 y/ {2 q& z9 j( ]
  3. . @1 L7 M4 e5 \4 i, R( h6 G: E
  4. #include "stm32l0xx_hal.h"
    & _6 p6 V) l6 r" U3 S2 X
  5. #include "stdio.h"                           ( q* p# r) D  z; q) T: @. G
  6.   N' c2 l$ e1 b* j  p; P0 n
  7. int fputc(int ch, FILE *f);' @; Z3 L% F4 p. S" L

  8. 5 ~( W% {. K3 {1 ?& O
  9. #endif
复制代码
: c& K5 g6 ]0 w
bsp_usart.c内容
$ [* j# e) R, w1 i# y0 y2 i% L0 G& J0 D
  1. #include <bsp_usart.h>
    ) s8 D; k- v) c4 l& M

  2. 0 y* G" }; @/ n) D5 A8 T2 ?
  3. extern UART_HandleTypeDef huart2;% Q- [5 x9 T8 Q3 ~! M  c# d

  4. 6 M1 ?8 z$ y) b' u$ w' }  t. U# P1 q
  5. /* USER CODE BEGIN 1 */
    4 V8 J) W8 U7 L7 T
  6. #ifdef __GNUC__
    6 n: o. _$ J* Q, D5 k2 _: |2 Y% y2 }
  7. /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf+ Q7 i9 _* g3 F: l
  8. set to 'Yes') calls __io_putchar() */+ X0 m9 E. c/ a$ Q* J* q
  9. #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
    + i0 `7 g8 h3 [! l* F1 b- k
  10. #else8 N  B2 r  x" ]" Y2 D$ k5 w
  11. #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f); ?% y0 b1 S: L5 \2 c% ^
  12. #endif /* __GNUC__ */
    $ V3 ~9 [7 X" q  V0 X" Q( M: e
  13. /**
    - m6 c; G2 ~2 }. p0 U
  14. * @brief  Retargets the C library printf function to the USART.
    ( W3 b! O4 L- b
  15. * @param  None0 y5 z2 a) @  O
  16. * @retval None
    4 B% v  G+ F2 |7 W
  17. */
    7 G* y9 g; V% w% `1 {
  18. PUTCHAR_PROTOTYPE {2 d" I. P9 I) E: K+ i4 ~- \9 d
  19.         /* Place your implementation of fputc here */
    ' {" N8 q* I) r
  20.         /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */
    6 A8 [! L! m% v7 q
  21.         HAL_UART_Transmit(&huart2, (uint8_t*) &ch, 1, 0xFFFF);2 L: F' H' ]4 o# o
  22.         return ch;& V- B3 y! B% p
  23. }
    " c6 s% w0 M2 R# h
  24. /* USER CODE END 1 */
    % q, m, Y1 T) `7 Q
复制代码
, N( f2 a" I3 R/ x4 u5 S
在main.c文件里引入头文件6 T& ^& ^% H& s/ W; i2 A
  1. #include <stdbool.h>
    # C, A5 x/ S) @' G$ i& l  O5 F
  2. #include <string.h>
    4 X5 ]4 P9 M- {; N, N5 E3 t3 p
  3. #include <stdio.h>3 g1 H- B% Z0 |2 ]
  4. #include "bsp_usart.h"
复制代码
( n+ r# \( q& J/ |) c% ~3 ^3 i
然后,就可以使用printf(“uart2 output data = %d \r\n”, data);了。) n. A. K8 H6 V* U- i* x3 |

% A3 K! G0 q3 rRX(接收)设计
9 ]$ ?, `: }* D# g* \. N0 ~常规的串口接收设计,都需要设计当前接收字节后的超时识别,如果出现超时,认为接收结束。即使是固定字节长度的传输,也需要为异常情况下设计超时识别作为传输结束。
7 v! I0 `* F: M: R- S/ cSTM32 HAL库支持轮询超时的方式接收串口数据(HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)),也支持中断的方式接收串口数据(HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)),因此考虑将两种方式结合使用,以简化超时判断的设计。1 t2 T% o% Y) ~/ a5 ~
主要的设计思路是:1.通过中断接收第一个字节;2. 通过轮询接收后续字节。  @( n  u+ d* w  z: d

. o7 [1 Q- l8 a& Lmain()函数前初始化相关代码,部分代码由STM32CUBEIDE自动生成:: A4 Y$ s- a; V4 k' M- O

5 V3 z9 P) \) P
  1. /* Private macro -------------------------------------------------------------*/  P. e2 z9 _& \) Y- T
  2. /* USER CODE BEGIN PM */5 F7 n. h% g, R0 e  j( G
  3. #define UART2_RX_STOP 0
    2 {1 @1 \, d' P9 U/ x3 Y) v
  4. #define UART2_RX_START 1+ T; t: ^) e8 J$ r; Q; N
  5. /* USER CODE END PM */
    ; J2 q6 Z1 t) f
  6. /* Private variables ---------------------------------------------------------*/8 M% s' N4 z# Z8 t
  7. UART_HandleTypeDef huart2;/ R- q( N& w% Q1 Y
  8. /* USER CODE BEGIN PV */6 N, ]3 g8 a" ^' N( k
  9. uint8_t aRxBuffer;                        //RX int buffer, 1 byte8 q! C: E2 W# Q1 [* Y8 U
  10. uint8_t Uart2_RxBuff[10] = {0};                //Rx buffer,should be adjusted according to Rx max byte length per communication.7 b- F! r; u/ D; N0 C
  11. uint8_t uart2_rx_flag = UART2_RX_STOP;
    0 I' R- M8 e' {
  12. HAL_StatusTypeDef uart2_status_rx;6 I- h8 \4 J7 j
  13. /* Private function prototypes -----------------------------------------------*/
    2 @( h* T7 k1 s. R# ?
  14. void SystemClock_Config(void);/ @% g7 r* `1 X8 t0 K) F+ ]
  15. static void MX_USART2_UART_Init(void);
复制代码
2 S, z, t" C- @0 Y8 t
main()函数相关代码,部分代码由STM32CUBEIDE自动生成:; c8 g3 x$ d3 @% f

  X$ o/ s& ]+ [9 d
  1. int main(void)
    5 |. T+ x: L+ }% L
  2. {2 T" _) M# l5 d3 f# N
  3.   /* USER CODE BEGIN 1 */
    + T3 R7 G- V  L% H
  4.   /* USER CODE END 1 */
      \- Q8 l4 E6 O( g. G/ ~: O
  5.   /* MCU Configuration--------------------------------------------------------*// a/ I7 R8 ?# N5 ~9 c+ c
  6.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    ) M0 ^$ N# h8 }: T$ K' U$ u
  7.   HAL_Init();
    5 F% T1 K% I8 U* w+ j
  8.   /* USER CODE BEGIN Init */  q# S8 w8 ^6 g# R5 ^
  9.   /* USER CODE END Init */9 k! c* {9 A7 T9 z8 r
  10.   /* Configure the system clock */
    # d9 W6 j0 O) y8 ^: E% O: ]
  11.   SystemClock_Config();8 k! C4 j3 Y! v& X7 R" W" @
  12.   /* USER CODE BEGIN SysInit */* }, a$ u  T3 j+ m- A$ u6 k
  13.   /* USER CODE END SysInit */6 A/ f7 s* \9 V1 W/ a5 K
  14.   /* Initialize all configured peripherals */$ g) w; s! \. m& U" k/ H" a! ?/ E( u
  15.   MX_USART2_UART_Init();
    * z7 ^$ {: k  E& o  e5 e/ K$ ^
  16.   /* USER CODE BEGIN 2 */
    % r6 l+ Y9 ~! v; I: {
  17.   /* USER CODE END 2 */
    1 ?! {) P8 `9 c: H0 |/ u! F
  18.   /* Infinite loop */
    2 ]' O, Q5 |! L0 P
  19.   /* USER CODE BEGIN WHILE */
    3 T% \  f- s2 H# q) C) u
  20.   if (HAL_UART_Receive_IT(&huart2, (uint8_t *)&aRxBuffer, 1)!=HAL_OK) printf("UART2 IT FAILED! \r\n");
    ' z0 d. `, q! ^1 ~8 e% ], X
  21.   while (1)
    6 U, I! J5 d0 Q; t  R
  22.   {
    # @9 n) @% v. i$ j0 m
  23.     /* USER CODE END WHILE */7 F$ ^. `3 ]6 s5 W0 s" u
  24.     /* USER CODE BEGIN 3 */6 a8 `4 F! d/ s0 j. Q" Z0 L: }4 v
  25.      if (uart2_rx_flag == UART2_RX_START)" i  K* j' @9 o; ~  U
  26.      {+ P, O; i4 b4 _1 u8 G( }
  27.              uart2_status_rx = HAL_UART_Receive(&huart2, Uart2_RxBuff+1, 9, 100);   i6 E6 U% L% d+ N1 |* W/ A
  28.              printf("uart2 got rx data: %d  %d %d %d %d %d %d %d %d %d\r\n", Uart2_RxBuff[0], Uart2_RxBuff[1], Uart2_RxBuff[2], Uart2_RxBuff[3], Uart2_RxBuff[4], Uart2_RxBuff[5], Uart2_RxBuff[6], Uart2_RxBuff[7], Uart2_RxBuff[8], Uart2_RxBuff[9]);' `- L9 u+ I6 u* |$ u( {
  29.              uart2_rx_flag = UART2_RX_STOP;
    / c# ^" g% Q& F: n& T2 x! s
  30.              memset(Uart2_RxBuff, 0, sizeof(Uart2_RxBuff));
    7 ^0 O, w1 i) Q$ `
  31.              MX_USART2_UART_Init(); + u8 H# G# y  ~* h7 L$ n6 _
  32.              HAL_UART_Receive_IT(&huart2, (uint8_t *)&aRxBuffer, 1);
    2 E) C8 P. R* @& z% d4 G

  33. ( D5 b5 n  }; s) @$ N
  34.      }; m9 N" R$ O% A( j; ?
  35.           HAL_Delay(1);   //must for timing
      d/ q1 p7 [5 M3 F# u# ~8 G4 i. b
  36.   }  K5 Z: c* j7 y6 |
  37.   /* USER CODE END 3 */
    7 ]& X- |. K; R/ p; I" ~& n
  38. }
复制代码

$ Y8 p- f+ r- R$ Z9 \9 V中断响应通过函数HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)的重载实现。
- c" r0 S9 d  a. x
7 {: ]' U# r: @4 a8 P6 i
  1. void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
    ; O& y8 }( I) C4 z; U
  2. {- J4 w% C4 L9 H7 r8 P
  3. ( P% v8 Q& w! k6 @  l/ ]
  4.         Uart2_RxBuff[0] = aRxBuffer;  a  l& {2 P/ \* d) l. a
  5.         uart2_rx_flag = UART2_RX_START;
    ! s& C1 e' i9 S1 e% q' C+ J
  6. 6 Z3 s3 r2 R' z7 H
  7.           //printf("uart2 get rx interrupt!\r\n");, }% \4 }: V' v2 W
  8.       return;( v+ p0 r! O. }# s
  9. }
复制代码

! Q7 @+ v& A$ B0 e9 w6 k# e注意事项+ J. ?/ ~" g# `, O
HAL_UART_Receive()不能放在HAL_UART_RxCpltCallback()函数里处理,HAL_UART_Receive()的Timeout会失效。这是因为SysTick的中断优先级低于了外设UART的中断优先级,在UART的中断处理过程中无法响应SysTick中断。(如果一定要把HAL_UART_Receive()放在HAL_UART_RxCpltCallback()函数里,就需要调整SysTick中断的优先级)。7 Y( B) u6 s2 Q4 U0 Z& _
main()里的while(1)循环,需要延时HAL_Delay(1), 时序才正常。
( Q) L! o* `8 n# J9 b) o  P-End-
9 k" m% w5 ?4 U! ^5 P( r+ H* F6 Y3 P3 w/ c- |) m& L6 B( s- Y8 j
9 ]# z" X2 E8 v8 t" N: B
赞 收藏 评论0 发布时间:2021-11-16 01:34

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版