代码环境
0 Y( K8 [# t$ s) H8 _开发工具:STM32CUBEIDE
+ @/ y3 e( s- k! ^" R" G, a芯片:STM32L031K6T6
9 t. R3 d( _% b) e. F+ V0 D% l端口: UART2* U; k& L& \! W% _( G: [
基本配置 r! n# a0 j9 x$ I
" V7 E1 {) @: ^! E7 ]; {) b# v" e7 J% B+ Y0 B$ X! v J7 H j
( r! _9 `- V' s$ |# i& e2 X0 z1 U8 R1 N
. M9 I) ^. e* @
5 [6 h0 b5 k, o$ f+ v- W# E) x0 \: V8 _4 l6 H5 d
其中,PA9 (RX)的输入上拉,在System Core的GPIO里配置。
. e2 M+ L9 Q5 J& e( v a: k( V9 A$ G* A7 z7 S5 P$ O) U( q
7 W" I$ M( r: n3 H5 |/ N( k: ^5 ?4 |; E
TX(发送)设计
' g( d; O4 I; KTX部分增加bsp_usart.c和bsp_usart.h文件,以支持printf重载。
9 h4 [; q$ v2 P: O$ t8 R" H
9 c, T) y- `5 l: }: M; {bsp_usart.h内容
$ D, U' i" m" \; q# O, Y) M% _) L
- #ifndef __BSP_USART_H1 Y5 Y) V) g1 C9 g; t6 N
- #define __BSP_USART_H
! _1 H5 i6 C6 r2 u1 U. g. n - . C, z2 i u! d* k$ F
- #include "stm32l0xx_hal.h"
$ I+ q) m2 c) b% v7 e; G - #include "stdio.h"
Q" F$ Z* Y2 g4 s* I" r
: P L/ E/ k* G8 b4 ?+ ~0 M- int fputc(int ch, FILE *f);
7 N8 k! z; @3 S9 a+ i) \; f, }# N - # _' Z/ D3 f2 u# T: s. E
- #endif
复制代码
# |, b; J# U" E( Z x' ^bsp_usart.c内容4 w# c9 b6 C6 C7 Q& S5 A- U
; l+ c/ @" h0 C5 Z* A8 ^) |
- #include <bsp_usart.h>
5 C- r* x( K0 K# w
! w7 n0 K+ d4 M. c, x- extern UART_HandleTypeDef huart2;- r7 {" Y) O! E3 H& K+ S
- ; _, P. |) B7 C: }5 V: m
- /* USER CODE BEGIN 1 */
7 f- q. x1 Z: N. t/ ~7 D - #ifdef __GNUC__
j% N4 c0 N- B% Z0 j. Q) ~: _9 q: G - /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf; c0 K( P+ e; {$ \4 b4 c# ^9 c
- set to 'Yes') calls __io_putchar() */
' k. B0 z, A# w" K) c/ s - #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
1 }2 x4 r; {+ N$ |8 O - #else4 e1 I) v! X( y" l" `4 y
- #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
+ Q. H& f" f9 Z0 {- I" t - #endif /* __GNUC__ */0 W5 t ~9 x) A( W/ x
- /**
8 ~0 U8 U- W% O) w# r - * @brief Retargets the C library printf function to the USART., Z# n6 l6 }! W8 @& I
- * @param None0 w! r1 I7 z$ d" X. |
- * @retval None
- O: S `0 J5 j7 u! Y: ]5 J - */
# Y' k2 @3 E* c, @9 [ - PUTCHAR_PROTOTYPE {
- _0 A9 |1 g7 D. h7 D; q - /* Place your implementation of fputc here */* c7 `0 a" i$ g! y8 z
- /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */
! Z6 L* a ^. T4 e - HAL_UART_Transmit(&huart2, (uint8_t*) &ch, 1, 0xFFFF);
5 v/ O! J/ f8 F" j0 H - return ch;6 B+ s8 f- ^' q1 f1 J: S; w1 g. F
- }
& g& x" X+ N0 N& z - /* USER CODE END 1 */
+ N4 L& o" E" k0 R/ c
复制代码
: [: n$ e; K9 K2 ^8 r3 W4 F/ q! ]在main.c文件里引入头文件, r2 q$ q5 f- M: l
- #include <stdbool.h>
6 a- [1 h& P, L" v/ E - #include <string.h>
2 ?$ ]& e3 _2 {# C, r9 v - #include <stdio.h>. E# d4 K5 I6 f7 `4 u# x5 U8 m. p
- #include "bsp_usart.h"
复制代码
& d" s% j' V h$ o9 w( {0 j2 s; |然后,就可以使用printf(“uart2 output data = %d \r\n”, data);了。
% q- [5 H" }7 n5 H' G) b4 b2 `% K# `) k0 ?3 f
RX(接收)设计) o9 v7 b$ { [0 j% y
常规的串口接收设计,都需要设计当前接收字节后的超时识别,如果出现超时,认为接收结束。即使是固定字节长度的传输,也需要为异常情况下设计超时识别作为传输结束。, W6 ~% ?6 i* R: S0 c1 X& |
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)),因此考虑将两种方式结合使用,以简化超时判断的设计。% P) C/ x# n! ]( e: S% k- Z
主要的设计思路是:1.通过中断接收第一个字节;2. 通过轮询接收后续字节。
7 j6 Q, S B& j- y) k1 U! F! s6 t! z; O+ e# k" {$ E0 P) J
main()函数前初始化相关代码,部分代码由STM32CUBEIDE自动生成:
9 ]0 k" x! B# U) `/ ?
' u$ X0 X# a* [6 y- /* Private macro -------------------------------------------------------------*/+ f' m {9 L! G, {7 S& K
- /* USER CODE BEGIN PM */
8 ~3 ]* b: o2 D3 o. j& n$ B - #define UART2_RX_STOP 0# v; ?* n a/ D/ p) t8 X+ X5 U/ e
- #define UART2_RX_START 1
6 B9 ^- x5 Z' { L3 Q7 o - /* USER CODE END PM */* a! a& p0 F, \, T1 f# V
- /* Private variables ---------------------------------------------------------*/: p- X+ y& {- G8 Z' ]+ y a7 p
- UART_HandleTypeDef huart2;
) N3 l7 {' h) `3 |6 x2 b! W - /* USER CODE BEGIN PV */
! y; d2 s6 k% O9 c6 Q$ z3 {' N& f - uint8_t aRxBuffer; //RX int buffer, 1 byte7 w/ j) o% i9 y: }% I7 c- K
- uint8_t Uart2_RxBuff[10] = {0}; //Rx buffer,should be adjusted according to Rx max byte length per communication.: c1 g9 }8 b" ?
- uint8_t uart2_rx_flag = UART2_RX_STOP;
2 [* ^: w& i) ` - HAL_StatusTypeDef uart2_status_rx;. }. ^5 x( G# Z$ ]2 m! @
- /* Private function prototypes -----------------------------------------------*/
W5 [+ C& y8 D2 r. M8 W - void SystemClock_Config(void);
* B7 r7 O- l9 |' M7 o - static void MX_USART2_UART_Init(void);
复制代码 ) k6 i ]; [0 B9 T# U- B4 ?
main()函数相关代码,部分代码由STM32CUBEIDE自动生成:' b; W: H3 v; s% ?+ ]. C2 D
& k9 D$ m5 L: D) h/ N# X0 o) G- int main(void)
* ], V4 @. C! f/ G: m" A7 Z - {. b) {* O5 ]! S* b- v# \
- /* USER CODE BEGIN 1 */
- }7 E3 q: X8 `2 i2 l3 n6 `0 [ - /* USER CODE END 1 */
$ ~5 Z( y" F# [. L - /* MCU Configuration--------------------------------------------------------*/
7 |3 v* l7 B3 \7 b4 } b7 _/ K; f; P - /* Reset of all peripherals, Initializes the Flash interface and the Systick. */8 M+ j* i, `# N9 S/ C/ u! j
- HAL_Init();5 E) e4 P0 a8 @7 Q" J
- /* USER CODE BEGIN Init */
3 T6 A+ P4 A( C, m - /* USER CODE END Init */
) K5 q3 ~+ W) s9 x% o' W' x - /* Configure the system clock */
5 @3 c ^- h2 v5 ` V B - SystemClock_Config();1 O% }& Q5 R' @6 N6 p, u
- /* USER CODE BEGIN SysInit */
. {" ~: o: `8 Z0 a8 f - /* USER CODE END SysInit */
3 ^% J2 v9 U( @7 ^& K( B* G - /* Initialize all configured peripherals */3 n! Q! J f8 A3 B: P1 @9 t
- MX_USART2_UART_Init();& X: G P" \1 @& @
- /* USER CODE BEGIN 2 */; l2 j' F( P4 H) g+ X
- /* USER CODE END 2 */
) r7 d1 b: n' Z8 y - /* Infinite loop */
3 S3 v2 U) {) M) { J- ^ _ - /* USER CODE BEGIN WHILE */
( j; y$ W$ b( d; M. R - if (HAL_UART_Receive_IT(&huart2, (uint8_t *)&aRxBuffer, 1)!=HAL_OK) printf("UART2 IT FAILED! \r\n");; `3 `' s c3 o. i1 y9 h& I
- while (1)
+ r* W% Y* b# B6 A) x: \9 E - {
. T: D; w+ [: S) e2 b& g - /* USER CODE END WHILE */, d- K! t6 J7 t5 N( |6 t5 J
- /* USER CODE BEGIN 3 */
0 M1 Z5 p- {! g9 r- A2 _( o% l& M3 _ - if (uart2_rx_flag == UART2_RX_START)! J" ?. G( k* n( W- |2 i* ^, s' Z
- {
# g" w, {* Q7 f4 ~; S0 n4 N - uart2_status_rx = HAL_UART_Receive(&huart2, Uart2_RxBuff+1, 9, 100); + \8 @3 f) z, p/ k7 n" _4 O
- 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]);: G2 f$ X# ]' \! x6 l$ W( Q8 s5 |
- uart2_rx_flag = UART2_RX_STOP;& |& x" h* n3 \
- memset(Uart2_RxBuff, 0, sizeof(Uart2_RxBuff));
8 g& U0 B* }8 F' s' }( I$ ` - MX_USART2_UART_Init(); 9 y- t9 y: a) g3 q* ?
- HAL_UART_Receive_IT(&huart2, (uint8_t *)&aRxBuffer, 1);/ Z$ a- n0 c$ i. S( `& K& F
% S4 A6 s8 G$ K1 o7 F8 M- }
6 ^& m, X- N# y$ p( D& ?1 `) \6 | - HAL_Delay(1); //must for timing
0 q4 P) \0 J4 i8 L$ v. ?- z1 K - }% S) N- R/ v! a
- /* USER CODE END 3 */4 Z- b6 C$ E4 d5 V5 U: M5 Y
- }
复制代码 : a y* @6 y% z X: E' d$ _
中断响应通过函数HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)的重载实现。
/ K+ N9 |' t6 o7 s* X! g
" Z1 Q% N' W2 ?0 K7 T4 E4 z- void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
' }( A2 d! I, J7 G - {
! d) W0 ?; X$ O: ~9 {; g) K
) K! `$ k% O" D, U! U- Uart2_RxBuff[0] = aRxBuffer;
- t G% o$ d3 r! w& S9 R - uart2_rx_flag = UART2_RX_START;4 G$ u8 F' x, N
# Y# F$ t6 V6 U4 s# h% M& |- //printf("uart2 get rx interrupt!\r\n");
7 z$ [8 `+ r7 c1 b& U |5 P - return;
' e0 W9 E: j3 B- s @3 _2 z1 Y- Q; g - }
复制代码
1 n/ d0 i3 t- c6 z注意事项" g1 Z4 ^& y! N U. j: G# y, r
HAL_UART_Receive()不能放在HAL_UART_RxCpltCallback()函数里处理,HAL_UART_Receive()的Timeout会失效。这是因为SysTick的中断优先级低于了外设UART的中断优先级,在UART的中断处理过程中无法响应SysTick中断。(如果一定要把HAL_UART_Receive()放在HAL_UART_RxCpltCallback()函数里,就需要调整SysTick中断的优先级)。
9 B" Z, M/ N# mmain()里的while(1)循环,需要延时HAL_Delay(1), 时序才正常。6 N `9 \- w7 f: X
-End-. }4 a$ h. B; c6 \% w3 M
$ T% J4 U, E: X; ]8 V) M* ]; s; U
|