|
概述 本文利用中断实现串口不定长接收(非DMA),使用HAL库,将接受的数据打印出去。
# w a$ P( N, O 硬件准备 首先需要准备一个开发板,这里我准备的是NUCLEO-F030R8的开发板:
! t8 o3 v3 h& Q' c/ S/ P
/ j \6 n! A1 u1 _; o
: v$ |0 I5 M: T; T, b& X, q6 J8 p2 V选择芯片型号 使用STM32CUBEMX选择芯片stm32f030r8,如下所示:
3 R( V8 t# N$ t8 y% Q0 I. H; u: R2 \" Q& R
配置时钟源 HSE与LSE分别为外部高速时钟和低速时钟,在本文中使用内置的时钟源,故都选择Disable选项,如下所示:0 B8 f& R: D/ l6 Y2 y
7 ~0 H: g/ T* _# d' U3 A; F
' J/ S* A# E! y& G3 _, M0 c 配置时钟树 STM32F0的最高主频到48M,所以配置48即可:- B+ b0 H6 X' N3 o& B0 b3 G/ J% V
5 {' }+ X. U, F/ i/ s; P' e* j. k
串口配置 本次实验使用的串口1进行串口通信,波特率配置为115200。
) |- \5 \3 p \# y Q . z1 h4 P! }! H& z- U2 P* v* Q
H- @. I- J5 N. W- @% {& H
中断% @5 i/ N: E" j$ T2 t; P
/ f" D2 b: I6 ~. a! R7 {7 n1 x1 N5 Y& o* K3 l4 g
GPIO配置 板子上led为PA5端口,故设置PA5闪烁来验证是否正确。0 D" ]; Z3 f1 P. ~1 }7 d
) z% ]3 n) K- X
- H( d' J- _0 W
定时器配置 本次实验使用的是TIM3来进行计数。
% d, v( I$ ~/ | G. h
( x: T: v8 Z6 t
8 \! B/ e N+ m- U
PWM频率计算如下所示。
2 @0 D* k4 d8 e& Y
; @1 k* n* n; ?3 u! u 在上面配置TIM3参数,预分频系数设置为480-1, 自动重载值设置为10000-1,那么PWM频率为48,000,000/((480-1+1)*(10000-1+1))=10Hz,即 100ms一个周期。
, A. n- A! R$ T8 F+ ^
$ Q9 [9 r0 i" u1 \生成工程设置 注意在生产工程设置中不能出现中文,不然会报错。 E5 X5 _: e. g1 F8 ~4 a! `: ~
- P1 U6 T7 |1 o
: A+ _+ t3 s* @- J# N6 o: |代码生成设置 最后设置生成独立的初始化文件:
* }& }0 n5 l9 B4 r- ~$ L
3 F, d+ ~/ R& ]! w9 r( g6 O% Q/ C
生成代码
, d: P4 }# g, o) t; ]# G- F, F% B9 V6 u. g3 ~/ t5 e2 v' u8 f
8 R% O @1 d/ Q" y+ N# _$ e
配置keil
" f+ l. b/ ^+ Q( R" J. H9 w- d! o# H3 F6 x: | K f
o7 s8 I- x' n. @+ C: y6 c
代码 在main.c中,先加入头文件。 - /* USER CODE BEGIN Includes */* Z) R, r& d: x
- #include "stdio.h"//printf头文件, x: g- S& P3 ^& z& L
- #include "string.h"//memset头文件* @7 @2 @6 U% Q8 p1 Y& D
- /* USER CODE END Includes */
复制代码
3 X W% ~3 G* a0 t: I% [" z 定义变量存储。 - /* USER CODE BEGIN PV */9 ? m2 p/ l2 _4 B
- uint8_t RxBuff[1]; //进入中断接收数据的数组2 H- [* F/ `4 \. m+ C4 |
- uint8_t DataBuff[5000]; //保存接收到的数据的数组
' [. R' w* r! a) Y9 a8 A( M - int RxLine=0; //接收到的数据长度/ l4 O! v: v6 d' A s8 \
- int Rx_flag=0; //接受到数据标志! z X" Q V4 e6 Y% F+ s" x
- /* USER CODE END PV */
复制代码 ; n/ S3 V" A* | r6 L/ ]. k
定义printf的重定向函数fputc。 - /* USER CODE BEGIN 0 */
7 p( O/ }8 v+ } n - void printf_usart(void);//输出内容
1 |8 t9 o; U$ F) Z* v- ?5 E - int fputc(int ch, FILE* file)//定义printf的重定向函数fputc,满足串口调试打印
4 c$ Z3 B+ O f! f1 ^ - {* M- d% _. L9 o Z8 b
- return HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, 100);
?; @+ S1 l1 t$ q/ e - }: i, V' |0 E$ X' s2 R9 {
- /* USER CODE END 0 */
复制代码 打开串口和定时器。 - /* USER CODE BEGIN 2 */# S0 V8 H0 a3 ^+ @# D4 `7 b. N) V
- HAL_UART_Receive_IT(&huart1, (uint8_t *)RxBuff, 1); //打开串口中断接收* ]/ X6 E$ H" P4 @
- HAL_TIM_Base_Start_IT(&htim3);//开启定时器
, j, m3 e* i& f7 G- A6 y - /* USER CODE END 2 */
复制代码 . T/ |+ p9 }9 d/ ?
串口接受代码,当接受到最后数据为FF时候,直接打印,否则等待100ms打印。 - /* USER CODE BEGIN 4 */5 s4 r. S. ]. h
- void printf_usart(void)
. a% N+ e0 ?0 C b/ h" z - {
& b- [8 j# _+ u0 y - printf("数据长度=%d\r\n",RxLine); * }* s' P9 a; l, ^- H" w$ P
- for(int i=0;i<RxLine;i++)
$ l0 X; F0 ^6 y: W" s5 q - printf("数据:[%d] = 0x%x\r\n",i,DataBuff[i]); 4 q/ q/ [" F3 a
- memset(DataBuff,0,sizeof(DataBuff)); //清空缓存数组
4 G) s# Z7 k' n4 w' j8 B. G) M - //memset()作用:可以方便的清空一个结构类型的变量或数组。$ e- S# J% s5 c3 ~$ a* `7 y9 q
- //例句:memset(aTxbuffer,0,sizeof(aTxbuffer)) 用memset清空aTxbuffer。
9 ^ r' u; J) ], ^; U - RxLine=0; //清空接收长度1 \9 M4 [! a# `+ r, g
- }5 F! |% R6 Y, g0 v, o
- void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
, d& p$ B: l6 G. c! @2 W6 S1 _ r - {
9 h$ `7 B% f6 T4 d) t8 s1 X - if (htim->Instance == htim3.Instance)
. r! t4 F- C, U: ~7 F - {
6 a( o; i8 G, r b - HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_5);$ Q$ U/ I, ]6 O- s) Y
- /* Toggle LED */" T* p) Y5 y$ y4 }' ^
- if(Rx_flag==1)
* o1 Y Z, Z+ _2 {8 O/ [ - {
5 p/ Z' X. g: ` c# n; z - printf_usart();$ d! ^9 f9 L* O, x: {- g! t% p2 Z
- Rx_flag=0;3 L3 k4 H, Z0 k" R; a9 V
- }
5 X1 V$ m; r5 ]1 f4 L" K T+ u - } ( u1 h" Y7 M& Z7 [1 T
- }/ z2 w" l" D2 i1 v
- // 捕获中断回调函数,每次捕获到信号就会进入这个回调函数
- k+ R/ C- ?* K g" Y- S) f9 Z* S - void HAL_UART_RxCpltCallback(UART_HandleTypeDef*UartHandle)( i- @8 J0 o/ g d
- {
/ r6 ?& V6 ]2 C8 d - RxLine++; //每接收到一个数据,进入回调数据长度加1$ e5 [% o8 m7 Q/ B( E3 d% E& Q1 k" w
- DataBuff[RxLine-1]=RxBuff[0]; //把每次接收到的数据保存到缓存数组
; }/ \& |) O( s# Q - Rx_flag=1;+ a2 ~- M* {0 z
- if(RxBuff[0]==0xff) //接收结束标志位,这个数据可以自定义,根据实际需求,这里只做示例使用,不一定是0xff. W" I! m. `+ ?1 J" W
- {: T! z4 b) _2 m
- printf_usart();
4 j( F: @8 A+ {# |: K - } & o3 G) ?" B% d$ {! e2 A5 J
- RxBuff[0]=0;' J* {; K1 d9 q$ D$ _
- HAL_UART_Receive_IT(&huart1, (uint8_t *)RxBuff, 1); //每接收一个数据,就打开一次串口中断接收,否则只会接收一个数据就停止接收4 x8 |1 v, Q! U2 q
- __HAL_TIM_SET_COUNTER(&htim3, 1); // 计数清零,从头开始计
5 j8 Y& z* Z: Q# w8 E - }
7 n9 l q( Z! [ - /* USER CODE END 4 */
复制代码 + S/ n" s& L# w6 w$ g5 K
4 |; Q; u0 h; Z/ Z2 H, A' g
演示效果 可以看到 发送11 12 13需要等待100ms左右才能发送,如果最后加上ff直接发送。
) H& p% h3 F6 U k% H* I1 y
; ]7 A1 S+ T) j
6 C5 {" Y/ O9 a) U3 G
3 F- B2 _. [) A# M# O x& d3 F* ~ |