代码环境; K1 h. h- x. K; Z* e8 x. @
开发工具:STM32CUBEIDE2 N t/ H; J7 Q. r& C$ k/ f
芯片:STM32L031K6T6
- L2 c9 \/ X' l+ z% x端口: UART21 f7 s; \% m1 z$ I
基本配置8 u4 Z1 L$ Y1 ]! r/ D
4 q$ V9 k# y H5 K7 m1 Y# Z. d- R
2 v; F$ O$ ?( X f( a5 A# d: V, F: Q
; k- b6 g2 H9 Z2 O/ ]
& V I' s" h# h% J
+ ]- n3 c" b& q5 P4 v+ E4 g3 w% P8 d6 `0 ~1 N0 U5 L. m
其中,PA9 (RX)的输入上拉,在System Core的GPIO里配置。% W- I. F' F; v. W
5 d# c; M6 a! C
* t, {' e/ D$ u W C- N; l
7 T! M# j- a F" D9 Y3 _6 cTX(发送)设计* r/ z. g% H T, T
TX部分增加bsp_usart.c和bsp_usart.h文件,以支持printf重载。* M" B4 V2 S1 q9 ]
4 Q$ A- n$ e" g. ?& c% A" z; tbsp_usart.h内容, r' [/ X, x5 z# l: A
6 u" v( T- n; H7 V
- #ifndef __BSP_USART_H/ x6 I. z, f! q- |
- #define __BSP_USART_H
4 i x1 H; m" x# j9 [ - + J3 ^/ ^) \6 L. P2 i
- #include "stm32l0xx_hal.h"4 I# C6 c7 @4 A. ?
- #include "stdio.h" " t! Y2 t6 k; K$ B8 s* @1 J
& h; \4 c" T' u$ s/ u- int fputc(int ch, FILE *f);* J( c# O5 m2 q8 X7 x
9 ?; ]4 Y5 \1 }" l& Y- #endif
复制代码 , u$ J& G7 P" {8 i. `3 p; a6 j
bsp_usart.c内容
+ w( _( f+ C4 F! v2 @' D& ^0 [9 S4 w& n" N% ^
- #include <bsp_usart.h>0 m8 J" h" N8 T3 w8 |' C
- ) [+ r2 |( v* l& m" Y+ \
- extern UART_HandleTypeDef huart2;
# u( Y% A9 w. T1 z$ ?2 o
% t$ O9 Q9 h( Y- _9 O$ c- /* USER CODE BEGIN 1 */
0 [! }( \' s9 N: B$ N. m- t' n - #ifdef __GNUC__" r, ~, R8 j4 x" O/ U. f! w
- /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf* d) I2 A& Z4 z' f) l9 Y6 E
- set to 'Yes') calls __io_putchar() */8 q' Y) B" @, z! {; a) a0 J
- #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)9 g( S2 T" q8 _( F
- #else* ~4 T! V; V4 X S" D% ^
- #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)& J1 G4 [9 W0 t* r
- #endif /* __GNUC__ */
" p: l, \3 o# U) s; L% t$ w& F$ l$ } - /**
. q- Z" b9 b: K* i! @: I - * @brief Retargets the C library printf function to the USART.
9 I4 f: O/ j8 T) ~$ F - * @param None
* B3 {5 J6 ?, e9 h - * @retval None
) Z& K0 m* K4 D+ d! y, J - */
1 F$ p9 o5 n9 M - PUTCHAR_PROTOTYPE {
# V& P, U7 ?6 \% I( }% M! r - /* Place your implementation of fputc here */9 X8 L* K0 W8 y
- /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */" E+ d# T. N, G$ _
- HAL_UART_Transmit(&huart2, (uint8_t*) &ch, 1, 0xFFFF);
& b! w) ]' `/ z _- i h! ~ - return ch;
$ {5 i" e! A/ _ - }0 f- ^" i/ o; U9 u- d; O
- /* USER CODE END 1 */
% i' G6 u+ ^& z$ r
复制代码
, \; l/ f3 D& }2 q; P2 B. z在main.c文件里引入头文件
# I0 b3 k% e' C; a" z3 w' G! g9 {' X- #include <stdbool.h>( P. c! _4 @5 E. h; `
- #include <string.h>1 q$ l7 r0 z1 B$ x7 @8 z/ [% B
- #include <stdio.h>
4 |; S2 Y* q0 r - #include "bsp_usart.h"
复制代码
8 A; T; c' C4 u2 K/ L8 R* V' e( w然后,就可以使用printf(“uart2 output data = %d \r\n”, data);了。
2 ^" _" S4 ]9 {
3 Y$ \1 }% w7 M( gRX(接收)设计
4 Z/ B% i* S2 h$ k4 E常规的串口接收设计,都需要设计当前接收字节后的超时识别,如果出现超时,认为接收结束。即使是固定字节长度的传输,也需要为异常情况下设计超时识别作为传输结束。
8 P/ |, o5 s# z8 {STM32 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)),因此考虑将两种方式结合使用,以简化超时判断的设计。, n. i3 K. A. w; O1 t4 n
主要的设计思路是:1.通过中断接收第一个字节;2. 通过轮询接收后续字节。
8 s) A2 J2 [; q6 y; q7 O0 N O9 a& e" K6 }, b2 |
main()函数前初始化相关代码,部分代码由STM32CUBEIDE自动生成:
- |8 K9 _0 L: h0 k! b: }1 G) h' p: D A! A6 v* a* y6 g( N
- /* Private macro -------------------------------------------------------------*/9 N$ t" e* \% {4 V* E
- /* USER CODE BEGIN PM */
Q! H6 N( d$ G' \- h - #define UART2_RX_STOP 0
/ n& p0 m& [% T3 N4 T6 R/ W - #define UART2_RX_START 1; n% V+ ~' r2 w/ L. K% V
- /* USER CODE END PM */
3 n% C* s1 D9 Z- ` - /* Private variables ---------------------------------------------------------*/
1 z* Q j* `2 v" [4 M( i1 ~ - UART_HandleTypeDef huart2;: J0 f$ R: z; [5 j( X
- /* USER CODE BEGIN PV */
7 R% B5 F% t7 j - uint8_t aRxBuffer; //RX int buffer, 1 byte s, Y) A; t/ z; p
- uint8_t Uart2_RxBuff[10] = {0}; //Rx buffer,should be adjusted according to Rx max byte length per communication.! |5 {9 C4 \1 e/ d% Q1 q
- uint8_t uart2_rx_flag = UART2_RX_STOP;
2 j% {8 s# h: R5 n7 R - HAL_StatusTypeDef uart2_status_rx;5 s8 r4 T! l9 [5 z
- /* Private function prototypes -----------------------------------------------*/
, _1 @* m+ }+ n) Q - void SystemClock_Config(void);
; D L! z! l- s8 r: j0 U - static void MX_USART2_UART_Init(void);
复制代码
" r n6 r1 I- Omain()函数相关代码,部分代码由STM32CUBEIDE自动生成:" l! P+ z" P+ \! d( w- r) ]
" |4 ^7 R3 S: y4 [3 u( p( e/ c- int main(void)
+ f7 t$ [: g* Q4 I# a% g - {5 O. `6 {, a/ z& l9 \& R
- /* USER CODE BEGIN 1 */
: I% i6 x! {2 s1 \ - /* USER CODE END 1 */0 R; |( @# R1 a3 @
- /* MCU Configuration--------------------------------------------------------*// p* b( X9 {/ D% T2 u& J
- /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
- S% j7 ~# R- v0 w) R5 Y - HAL_Init();
! E% c6 v- w' O3 }8 Q& ` - /* USER CODE BEGIN Init */* c1 a* k: d: C' r
- /* USER CODE END Init */$ h$ k. Y/ F: Z& a) y" n
- /* Configure the system clock */( i: b- O$ A% k! o6 j4 g& |
- SystemClock_Config();
# g: [! D1 w4 @3 q2 z9 }( G - /* USER CODE BEGIN SysInit */
: R. i; r0 _" B: d# J/ e - /* USER CODE END SysInit */: t" V3 K5 x [' y' u& E$ X" D
- /* Initialize all configured peripherals */; u" @% X* d$ E z. ^) P7 ~6 q$ T
- MX_USART2_UART_Init();
4 c6 Y9 G: u) C* f( L0 s- U - /* USER CODE BEGIN 2 */
2 ]4 r0 u8 n4 f2 W6 o - /* USER CODE END 2 */
$ U7 c* b0 d0 h6 d: q; z' l" s - /* Infinite loop */
/ a, _+ r7 {, r# { - /* USER CODE BEGIN WHILE */( E9 H, S5 E \
- if (HAL_UART_Receive_IT(&huart2, (uint8_t *)&aRxBuffer, 1)!=HAL_OK) printf("UART2 IT FAILED! \r\n");
/ O( H0 a$ `) m C - while (1)( X/ I% o j3 T, S' n0 t/ V
- {$ r9 k+ J! i4 c! i v7 ~
- /* USER CODE END WHILE */0 E" H1 ?( _4 t0 ?
- /* USER CODE BEGIN 3 */
3 u) Z [$ M: P. ^6 j, G) T - if (uart2_rx_flag == UART2_RX_START)
6 M. K: s! n1 M" A& O - {
+ J" L( a7 r4 O( }; ~ - uart2_status_rx = HAL_UART_Receive(&huart2, Uart2_RxBuff+1, 9, 100);
( ]4 V! G7 R7 L% B6 N - 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]);$ N8 K% i- `3 L" ]4 z0 a K) Q% W
- uart2_rx_flag = UART2_RX_STOP;
" L) d- h1 Y. U1 ^ - memset(Uart2_RxBuff, 0, sizeof(Uart2_RxBuff));
4 _/ q) i r8 A - MX_USART2_UART_Init();
) i- B. r1 }- {" y - HAL_UART_Receive_IT(&huart2, (uint8_t *)&aRxBuffer, 1);
, K% ?* x) @! l
0 b" m6 L2 Q( s4 r$ d- }3 b* w5 C& x; f5 z" N
- HAL_Delay(1); //must for timing
7 E$ N! Q p& f8 n; H! i - }0 h2 F9 z0 I) [1 J E; i P" X9 `
- /* USER CODE END 3 */
) }4 R( f/ W& E- @ - }
复制代码
C+ W5 a# _3 `0 e$ S0 l中断响应通过函数HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)的重载实现。3 i, K6 v3 D# t& U, G6 F d# k& ]) C
. o( ?1 { F# y, L- void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
0 C: `: b8 E/ Y( h - {6 b7 W% v) M( m% \3 B1 S
. J5 N; Z0 w6 {- Uart2_RxBuff[0] = aRxBuffer;
6 h+ H4 ~) A' U9 t - uart2_rx_flag = UART2_RX_START;$ a3 {- z6 K; Y
1 h7 R/ W+ K6 {: _* P' ^0 I- //printf("uart2 get rx interrupt!\r\n");$ `6 V2 d) I$ p: j# {4 t$ k
- return;
: T: m H+ L- y - }
复制代码
- A! ]+ x7 y- B$ N注意事项1 q7 l; ^1 K7 {/ E& U3 C$ W
HAL_UART_Receive()不能放在HAL_UART_RxCpltCallback()函数里处理,HAL_UART_Receive()的Timeout会失效。这是因为SysTick的中断优先级低于了外设UART的中断优先级,在UART的中断处理过程中无法响应SysTick中断。(如果一定要把HAL_UART_Receive()放在HAL_UART_RxCpltCallback()函数里,就需要调整SysTick中断的优先级)。
8 v/ A5 C& R7 x, M5 V, f6 Imain()里的while(1)循环,需要延时HAL_Delay(1), 时序才正常。0 U3 t" t R7 u) f! Y! d q
-End-! S5 @; E; z9 j: s8 Z$ f
; R. ?) W$ I0 h! Z9 f( m E
+ v3 t! E0 A, x
|