代码环境
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
4 u' c6 C! X, V7 @# ?0 y$ w: W1 \
! E0 C# z; y8 ?) v& I+ s
% P) d+ t: y8 x1 a
4 t U" s5 t# m
: \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 |
/ 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
- #ifndef __BSP_USART_H: l" I3 G- ]) b, Q4 G- T! i
- #define __BSP_USART_H
/ l" R7 y/ {2 q& z9 j( ] - . @1 L7 M4 e5 \4 i, R( h6 G: E
- #include "stm32l0xx_hal.h"
& _6 p6 V) l6 r" U3 S2 X - #include "stdio.h" ( q* p# r) D z; q) T: @. G
- N' c2 l$ e1 b* j p; P0 n
- int fputc(int ch, FILE *f);' @; Z3 L% F4 p. S" L
5 ~( W% {. K3 {1 ?& O- #endif
复制代码 : c& K5 g6 ]0 w
bsp_usart.c内容
$ [* j# e) R, w1 i# y0 y2 i% L0 G& J0 D
- #include <bsp_usart.h>
) s8 D; k- v) c4 l& M
0 y* G" }; @/ n) D5 A8 T2 ?- extern UART_HandleTypeDef huart2;% Q- [5 x9 T8 Q3 ~! M c# d
6 M1 ?8 z$ y) b' u$ w' } t. U# P1 q- /* USER CODE BEGIN 1 */
4 V8 J) W8 U7 L7 T - #ifdef __GNUC__
6 n: o. _$ J* Q, D5 k2 _: |2 Y% y2 } - /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf+ Q7 i9 _* g3 F: l
- set to 'Yes') calls __io_putchar() */+ X0 m9 E. c/ a$ Q* J* q
- #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
+ i0 `7 g8 h3 [! l* F1 b- k - #else8 N B2 r x" ]" Y2 D$ k5 w
- #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f); ?% y0 b1 S: L5 \2 c% ^
- #endif /* __GNUC__ */
$ V3 ~9 [7 X" q V0 X" Q( M: e - /**
- m6 c; G2 ~2 }. p0 U - * @brief Retargets the C library printf function to the USART.
( W3 b! O4 L- b - * @param None0 y5 z2 a) @ O
- * @retval None
4 B% v G+ F2 |7 W - */
7 G* y9 g; V% w% `1 { - PUTCHAR_PROTOTYPE {2 d" I. P9 I) E: K+ i4 ~- \9 d
- /* Place your implementation of fputc here */
' {" N8 q* I) r - /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */
6 A8 [! L! m% v7 q - HAL_UART_Transmit(&huart2, (uint8_t*) &ch, 1, 0xFFFF);2 L: F' H' ]4 o# o
- return ch;& V- B3 y! B% p
- }
" c6 s% w0 M2 R# h - /* 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
- #include <stdbool.h>
# C, A5 x/ S) @' G$ i& l O5 F - #include <string.h>
4 X5 ]4 P9 M- {; N, N5 E3 t3 p - #include <stdio.h>3 g1 H- B% Z0 |2 ]
- #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- /* Private macro -------------------------------------------------------------*/ P. e2 z9 _& \) Y- T
- /* USER CODE BEGIN PM */5 F7 n. h% g, R0 e j( G
- #define UART2_RX_STOP 0
2 {1 @1 \, d' P9 U/ x3 Y) v - #define UART2_RX_START 1+ T; t: ^) e8 J$ r; Q; N
- /* USER CODE END PM */
; J2 q6 Z1 t) f - /* Private variables ---------------------------------------------------------*/8 M% s' N4 z# Z8 t
- UART_HandleTypeDef huart2;/ R- q( N& w% Q1 Y
- /* USER CODE BEGIN PV */6 N, ]3 g8 a" ^' N( k
- uint8_t aRxBuffer; //RX int buffer, 1 byte8 q! C: E2 W# Q1 [* Y8 U
- 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
- uint8_t uart2_rx_flag = UART2_RX_STOP;
0 I' R- M8 e' { - HAL_StatusTypeDef uart2_status_rx;6 I- h8 \4 J7 j
- /* Private function prototypes -----------------------------------------------*/
2 @( h* T7 k1 s. R# ? - void SystemClock_Config(void);/ @% g7 r* `1 X8 t0 K) F+ ]
- 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- int main(void)
5 |. T+ x: L+ }% L - {2 T" _) M# l5 d3 f# N
- /* USER CODE BEGIN 1 */
+ T3 R7 G- V L% H - /* USER CODE END 1 */
\- Q8 l4 E6 O( g. G/ ~: O - /* MCU Configuration--------------------------------------------------------*// a/ I7 R8 ?# N5 ~9 c+ c
- /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
) M0 ^$ N# h8 }: T$ K' U$ u - HAL_Init();
5 F% T1 K% I8 U* w+ j - /* USER CODE BEGIN Init */ q# S8 w8 ^6 g# R5 ^
- /* USER CODE END Init */9 k! c* {9 A7 T9 z8 r
- /* Configure the system clock */
# d9 W6 j0 O) y8 ^: E% O: ] - SystemClock_Config();8 k! C4 j3 Y! v& X7 R" W" @
- /* USER CODE BEGIN SysInit */* }, a$ u T3 j+ m- A$ u6 k
- /* USER CODE END SysInit */6 A/ f7 s* \9 V1 W/ a5 K
- /* Initialize all configured peripherals */$ g) w; s! \. m& U" k/ H" a! ?/ E( u
- MX_USART2_UART_Init();
* z7 ^$ {: k E& o e5 e/ K$ ^ - /* USER CODE BEGIN 2 */
% r6 l+ Y9 ~! v; I: { - /* USER CODE END 2 */
1 ?! {) P8 `9 c: H0 |/ u! F - /* Infinite loop */
2 ]' O, Q5 |! L0 P - /* USER CODE BEGIN WHILE */
3 T% \ f- s2 H# q) C) u - 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 - while (1)
6 U, I! J5 d0 Q; t R - {
# @9 n) @% v. i$ j0 m - /* USER CODE END WHILE */7 F$ ^. `3 ]6 s5 W0 s" u
- /* USER CODE BEGIN 3 */6 a8 `4 F! d/ s0 j. Q" Z0 L: }4 v
- if (uart2_rx_flag == UART2_RX_START)" i K* j' @9 o; ~ U
- {+ P, O; i4 b4 _1 u8 G( }
- uart2_status_rx = HAL_UART_Receive(&huart2, Uart2_RxBuff+1, 9, 100); i6 E6 U% L% d+ N1 |* W/ A
- 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( {
- uart2_rx_flag = UART2_RX_STOP;
/ c# ^" g% Q& F: n& T2 x! s - memset(Uart2_RxBuff, 0, sizeof(Uart2_RxBuff));
7 ^0 O, w1 i) Q$ ` - MX_USART2_UART_Init(); + u8 H# G# y ~* h7 L$ n6 _
- HAL_UART_Receive_IT(&huart2, (uint8_t *)&aRxBuffer, 1);
2 E) C8 P. R* @& z% d4 G
( D5 b5 n }; s) @$ N- }; m9 N" R$ O% A( j; ?
- HAL_Delay(1); //must for timing
d/ q1 p7 [5 M3 F# u# ~8 G4 i. b - } K5 Z: c* j7 y6 |
- /* USER CODE END 3 */
7 ]& X- |. K; R/ p; I" ~& n - }
复制代码
$ 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- void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
; O& y8 }( I) C4 z; U - {- J4 w% C4 L9 H7 r8 P
- ( P% v8 Q& w! k6 @ l/ ]
- Uart2_RxBuff[0] = aRxBuffer; a l& {2 P/ \* d) l. a
- uart2_rx_flag = UART2_RX_START;
! s& C1 e' i9 S1 e% q' C+ J - 6 Z3 s3 r2 R' z7 H
- //printf("uart2 get rx interrupt!\r\n");, }% \4 }: V' v2 W
- return;( v+ p0 r! O. }# s
- }
复制代码
! 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
|