代码环境) Z- H" |$ B. r
开发工具:STM32CUBEIDE& r) W! T i$ Y, ?
芯片:STM32L031K6T6# c# C1 q& n9 w. B& [) G
端口: UART2( j% y& i8 l4 R# [$ a% \, L9 C
基本配置
* w" L/ q. S+ h9 m' Z6 h$ A3 j
% |2 G+ u, m5 S) M
8 s5 `: i2 W' @2 B8 k* [
7 A7 T1 {2 U2 V+ N( j m$ U" v- B/ _5 _: ?' o
1 W5 R1 b& M& j4 M$ w! M ]7 o
8 B5 C/ ]% |: Q
7 [0 f. Q* X0 b, V8 A6 y其中,PA9 (RX)的输入上拉,在System Core的GPIO里配置。
% l4 L/ v G7 U" ], o/ Y
6 Z) \* z/ v4 J" v1 l- q' ~" e% s# C6 X
- ]1 ^3 n! S% o/ o0 b
TX(发送)设计
! O5 m/ Y( J6 h5 FTX部分增加bsp_usart.c和bsp_usart.h文件,以支持printf重载。
6 J1 Q, m0 I/ {- A8 R$ @. U! P6 c) n4 n/ G( T# J9 l
bsp_usart.h内容
+ O4 r% b+ l0 A; C' E; o A. @8 Y3 p" W9 j- P* k
- #ifndef __BSP_USART_H
1 z. u2 U" H4 }/ d, ] - #define __BSP_USART_H
& I; I3 `; I' \ - / ]( f5 q6 ` L3 T7 o
- #include "stm32l0xx_hal.h"9 y' Y) @# f& {8 a5 C5 r% F
- #include "stdio.h" 2 Y$ v. ^9 r, R7 @; j5 O
- & y7 i0 l0 M7 a$ P" z" a
- int fputc(int ch, FILE *f);
. \+ q# H$ F# w1 W* u
+ s" v6 u2 w, H* t' c* f- #endif
复制代码 1 v: p# F1 s: u+ y+ s
bsp_usart.c内容* Z+ A: R5 K6 i1 p
5 Z$ w* y7 `! H( R
- #include <bsp_usart.h>
1 }: _7 p Y7 A: \) S. y m
% B* M! w9 ]7 Q$ L9 h1 {- extern UART_HandleTypeDef huart2;8 ]9 k) `; Q/ c$ p. ]3 r$ R
- ) R% l& C* Y! L, W, @1 p: e/ h
- /* USER CODE BEGIN 1 */
8 p, t9 l; ?; w/ g( ~- ], p( b2 d, T* A - #ifdef __GNUC__
0 `4 @8 ]& F1 L$ R- k - /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
7 C2 w; e' c3 p3 d3 B4 Y5 L - set to 'Yes') calls __io_putchar() */
, [* T, T6 W7 Y6 ?' L - #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
) i u8 E/ X8 J, X - #else
& S; l( c3 g- K* L - #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
B/ G4 w/ u; @: k: o4 s - #endif /* __GNUC__ */
9 f/ x. N0 u% k - /**7 e! ^8 |/ p7 E9 a& Y/ w
- * @brief Retargets the C library printf function to the USART./ |4 u+ L) d2 D
- * @param None& ]. I+ M' k( X" y5 p$ K7 j
- * @retval None
- b$ J* V1 T1 n. E/ B& b$ L/ v" | - */; L- w1 T) Q. T8 b1 x7 S8 N+ Q
- PUTCHAR_PROTOTYPE {
1 w9 R9 a8 T; k2 r- X2 p - /* Place your implementation of fputc here */
^. {" l/ v# C - /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */0 k, f% h& |: q" B! ]: d
- HAL_UART_Transmit(&huart2, (uint8_t*) &ch, 1, 0xFFFF);' |; U4 Y' m# w! S
- return ch;6 `4 Y9 r% t* A M9 ~4 @
- }
8 O3 f$ j0 b0 V `( d! |$ {7 V - /* USER CODE END 1 */" v8 {! P# I+ h) |- A/ j3 `. E
复制代码
, k" ^4 n5 C* @在main.c文件里引入头文件
2 g+ I3 i% H8 T% |7 u- #include <stdbool.h>
" }% x; W( F4 I2 u! P0 L. k1 t - #include <string.h>* b q" h( T+ q9 Q
- #include <stdio.h>
8 F" ~* V: \# H: T - #include "bsp_usart.h"
复制代码
0 S) F8 w/ t2 C然后,就可以使用printf(“uart2 output data = %d \r\n”, data);了。3 b# q* B, r6 _. ?% c8 g
+ I$ O) N9 L! t: M! KRX(接收)设计
* T: [% M7 D5 D5 Y常规的串口接收设计,都需要设计当前接收字节后的超时识别,如果出现超时,认为接收结束。即使是固定字节长度的传输,也需要为异常情况下设计超时识别作为传输结束。
5 Z9 c' ]. |! x `! p( vSTM32 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)),因此考虑将两种方式结合使用,以简化超时判断的设计。9 A: l. i0 t* M" o
主要的设计思路是:1.通过中断接收第一个字节;2. 通过轮询接收后续字节。
% H- u- o+ p' t |! j* J
' O( I3 T- H) R+ \# J" Y3 }main()函数前初始化相关代码,部分代码由STM32CUBEIDE自动生成:
- N0 d0 Y' S, R' }7 y8 q8 J4 K t: y; t( Z0 S& W
- /* Private macro -------------------------------------------------------------*/
; Z+ h3 r5 `2 `7 V* n: T& J& w - /* USER CODE BEGIN PM */
9 E: n$ u& n' _( Q3 ]: z; G( ^! e - #define UART2_RX_STOP 0
; ?5 t# E* G* E. @: X2 X - #define UART2_RX_START 1
! d3 @) U8 {$ I( J* ]3 ~ - /* USER CODE END PM */
0 P% g, r% _% R8 ~" K: T - /* Private variables ---------------------------------------------------------*/
$ ]+ O. {1 n8 X$ E. w" s$ X - UART_HandleTypeDef huart2;
# ~2 M/ G* q/ N, T - /* USER CODE BEGIN PV */
. B' B h Z( h2 m - uint8_t aRxBuffer; //RX int buffer, 1 byte7 l5 [* E9 |6 o3 h$ y
- uint8_t Uart2_RxBuff[10] = {0}; //Rx buffer,should be adjusted according to Rx max byte length per communication.
( A. \) K: g" Q - uint8_t uart2_rx_flag = UART2_RX_STOP;
- ?! u* ~: W. _& u$ h - HAL_StatusTypeDef uart2_status_rx;
; A) K" }% K. _$ |3 l - /* Private function prototypes -----------------------------------------------*/
1 J4 E, ?5 _/ U9 L$ x5 [9 l - void SystemClock_Config(void);: P6 t& Y/ D" \# P# p c
- static void MX_USART2_UART_Init(void);
复制代码
! t, y% e! _5 dmain()函数相关代码,部分代码由STM32CUBEIDE自动生成:8 z/ e0 `( T1 w( D6 q7 W& P
7 I' D8 J" X, f2 U6 S- e. d1 h- int main(void)" |. Q8 K% X7 q
- {
6 j( ?5 B5 A, q$ W# W; z9 i0 V5 g - /* USER CODE BEGIN 1 */
! h% t/ i2 o6 j/ G% S - /* USER CODE END 1 */0 _- Y( e3 ^8 E+ F9 j+ _( [3 \
- /* MCU Configuration--------------------------------------------------------*/; ?: U) R. e6 `6 W% D8 v
- /* Reset of all peripherals, Initializes the Flash interface and the Systick. */+ x; c9 w. W- G
- HAL_Init();
& ]9 j- k9 ?6 i7 P3 {3 F - /* USER CODE BEGIN Init */
2 x; [, l4 } v2 E" K( g" s, \) K1 ^ - /* USER CODE END Init */8 ?* {+ G/ P" j) v
- /* Configure the system clock */
0 y9 T1 G* S9 u0 Y; e/ H6 O' r' L - SystemClock_Config();( B+ E0 h- w6 m/ O0 {7 s
- /* USER CODE BEGIN SysInit */( r. M3 r: o. Y P4 p
- /* USER CODE END SysInit */( g/ s$ E# U" v. ^) i) g4 |5 w
- /* Initialize all configured peripherals */( K/ _" v& A( }
- MX_USART2_UART_Init();
: f# l2 F" |9 Q! o: P5 \ - /* USER CODE BEGIN 2 */
+ M* ^1 I+ E1 k( q4 z - /* USER CODE END 2 */# }2 S/ E4 ~) n1 H
- /* Infinite loop */
/ J* v1 c' i! q! h8 T0 F - /* USER CODE BEGIN WHILE */5 k. e' g _- H
- if (HAL_UART_Receive_IT(&huart2, (uint8_t *)&aRxBuffer, 1)!=HAL_OK) printf("UART2 IT FAILED! \r\n");
. Q( l8 [/ e& M - while (1)
4 M. h! H+ Z) j8 n' W( I' w - {7 ~+ H) F9 [. H( l: ~1 H0 u
- /* USER CODE END WHILE */
0 J4 R* F' p+ h6 ? - /* USER CODE BEGIN 3 */
. I2 W* W8 I$ z j& g - if (uart2_rx_flag == UART2_RX_START)* b2 F- P" x, f" C9 g% B1 k( X3 a
- {0 k5 Z% ?+ S& [8 t% ^8 R' B& G! N
- uart2_status_rx = HAL_UART_Receive(&huart2, Uart2_RxBuff+1, 9, 100); & H. O: B4 l/ M) n# G
- 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]);% T( _! H! E& V; _$ p4 O8 O
- uart2_rx_flag = UART2_RX_STOP;
& L. B! f4 y1 E& g, z- S, c - memset(Uart2_RxBuff, 0, sizeof(Uart2_RxBuff));3 ^' C$ V2 b2 {5 ^. c
- MX_USART2_UART_Init();
0 p3 f: S/ R- g/ F$ ^# Y - HAL_UART_Receive_IT(&huart2, (uint8_t *)&aRxBuffer, 1);9 @0 |8 z+ w1 i$ d+ v9 S
4 a& o* z }0 V' }: a6 w- }! B9 U# L1 y7 _' |
- HAL_Delay(1); //must for timing2 X" A3 E* _3 V$ Z
- }! S E" A, U8 m R
- /* USER CODE END 3 */5 [. T1 A7 @9 ?, E; I
- }
复制代码 ! W; A6 x! `7 o. k) Q7 v/ t+ `
中断响应通过函数HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)的重载实现。0 i0 ?' \- ?- A: t* p" z
( ]9 f- Z2 M2 F, @. ?& `+ C5 X- void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
* s) ?0 o3 D* w ~ - {
b- S; z: |4 _3 K4 T& k - * t$ i. P1 J6 n; f
- Uart2_RxBuff[0] = aRxBuffer;
. \; a5 J w" N4 D - uart2_rx_flag = UART2_RX_START;& @& F* ^% }- i3 c
- D7 q4 H+ G1 L7 M+ w+ M2 A
- //printf("uart2 get rx interrupt!\r\n");1 S3 o/ H9 H, o
- return;# {5 R& f- g1 i2 w4 w! b. ~6 o
- }
复制代码 1 n G9 Q, i( F' b
注意事项
! l2 o' o2 F, L& }HAL_UART_Receive()不能放在HAL_UART_RxCpltCallback()函数里处理,HAL_UART_Receive()的Timeout会失效。这是因为SysTick的中断优先级低于了外设UART的中断优先级,在UART的中断处理过程中无法响应SysTick中断。(如果一定要把HAL_UART_Receive()放在HAL_UART_RxCpltCallback()函数里,就需要调整SysTick中断的优先级)。7 c- `& e( K1 ~" M) E' x1 G5 f
main()里的while(1)循环,需要延时HAL_Delay(1), 时序才正常。
) q2 }5 L% a* u; A-End-8 g b; A8 }* {& F: d t* M
8 K" o( z2 o5 c: [: x/ X# H* |7 c5 p; }% l; W
|