|
概述 本文利用中断实现串口不定长接收(非DMA),使用HAL库,将接受的数据打印出去。
4 W, x8 ?9 q9 Z6 s _, J 硬件准备 首先需要准备一个开发板,这里我准备的是NUCLEO-F030R8的开发板:
2 D2 a* {# c6 G
8 k& J! }# ?5 Z) O9 s* F; Y+ b; a! j5 s
选择芯片型号 使用STM32CUBEMX选择芯片stm32f030r8,如下所示:
2 r* {' N0 n6 C" J5 s
& `3 h2 B' ]4 {配置时钟源 HSE与LSE分别为外部高速时钟和低速时钟,在本文中使用内置的时钟源,故都选择Disable选项,如下所示:
7 z- e1 e+ j9 Z& P8 Z) | / X/ K8 A8 p8 b* A8 {' {, f r
9 Z! @) s+ Y1 _8 v4 i1 E* V9 P
配置时钟树 STM32F0的最高主频到48M,所以配置48即可:
6 A& l/ r& ]$ F6 W& J ' I/ N i6 g0 Q5 |+ P9 S" b
3 N; ` _& k' r6 o, u1 v% ^
串口配置 本次实验使用的串口1进行串口通信,波特率配置为115200。) x4 Z' |1 [. y4 ]2 Z
3 ?0 D- C0 T$ k
& u0 X( i7 \/ s. i: l1 m" t8 z 中断5 E1 ^* k# h7 L
8 B9 g7 y9 g' [1 C4 m4 w. B) a! Z' Q0 U
GPIO配置 板子上led为PA5端口,故设置PA5闪烁来验证是否正确。
+ T$ ?4 w$ `* @: T5 @/ m3 ^
/ O/ `+ Y/ _1 S
' C+ k3 M8 N4 {4 \) y 定时器配置 本次实验使用的是TIM3来进行计数。
6 y# {" X# p% L) q
% f3 m$ Z$ ^: M2 v" x4 _
4 w5 U; @( X0 p+ ^
PWM频率计算如下所示。
7 q0 l* q9 m m9 p1 Y ?) G8 z$ N" s6 D# G
在上面配置TIM3参数,预分频系数设置为480-1, 自动重载值设置为10000-1,那么PWM频率为48,000,000/((480-1+1)*(10000-1+1))=10Hz,即 100ms一个周期。& T1 d7 y- E' m6 U* R, l" ]5 h
/ Y" Y/ [! x4 _/ ^* F生成工程设置 注意在生产工程设置中不能出现中文,不然会报错。3 p0 p+ L: ^ A( N8 j
9 A4 R1 P1 T, {6 V* ?
' ^$ s) H) l- F6 \: ?4 J
代码生成设置 最后设置生成独立的初始化文件:$ s: W7 m/ l" b; C
: ?8 C, V. m0 w" }% b% Y1 Z
: \) t8 ]" e0 ~+ B
生成代码
, k; I- v# y0 G. ^$ b1 J! @% I+ O
q. ]# I& M" Y( e$ s4 K Q6 P& R# B" q6 p7 b
配置keil
0 R. h; X+ S# J8 i
, P6 E L, i: N5 P
! |7 X* l$ J$ y代码 在main.c中,先加入头文件。 - /* USER CODE BEGIN Includes */
: b4 S5 ~, k' s, |6 W { x! v- l - #include "stdio.h"//printf头文件
7 s8 M9 H3 D" T; v' | - #include "string.h"//memset头文件7 Z: }$ {% Q- @* W! ~
- /* USER CODE END Includes */
复制代码
+ C& {3 R& k7 P O 定义变量存储。 - /* USER CODE BEGIN PV */" q3 ~/ f4 X! C' R& O
- uint8_t RxBuff[1]; //进入中断接收数据的数组& M9 U, I$ u/ m+ U1 k
- uint8_t DataBuff[5000]; //保存接收到的数据的数组
1 Y: F* w4 r' u% ^ - int RxLine=0; //接收到的数据长度 E) r+ M3 z1 c/ K5 j
- int Rx_flag=0; //接受到数据标志
$ s9 }+ k) y, b* i6 w - /* USER CODE END PV */
复制代码
5 h9 Q8 v) ?/ ^( T: @% f, N7 Y" K 定义printf的重定向函数fputc。 - /* USER CODE BEGIN 0 */: N9 r9 Y% R- D6 ]
- void printf_usart(void);//输出内容" d2 c( C( g2 H4 u u C# x+ q
- int fputc(int ch, FILE* file)//定义printf的重定向函数fputc,满足串口调试打印9 i8 g0 Q# ?" V& O. Q* P
- { A& Y$ s$ _9 _& p
- return HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, 100);) w% X! H8 W3 l5 B
- }
/ P9 w2 w O: \( p& C - /* USER CODE END 0 */
复制代码 打开串口和定时器。 - /* USER CODE BEGIN 2 */* k# X. X# h4 x4 `4 A
- HAL_UART_Receive_IT(&huart1, (uint8_t *)RxBuff, 1); //打开串口中断接收9 k# A( i$ B+ a" q# u, d
- HAL_TIM_Base_Start_IT(&htim3);//开启定时器
9 \/ U! V3 N- e6 o% i- C" M* t+ z - /* USER CODE END 2 */
复制代码
- T) `! |5 S) J6 ~8 Y 串口接受代码,当接受到最后数据为FF时候,直接打印,否则等待100ms打印。 - /* USER CODE BEGIN 4 */
; x! @9 d! T4 J0 Q: f - void printf_usart(void)
4 \3 j& I+ z g9 f, X1 O - {8 l+ U3 |$ E6 M) a
- printf("数据长度=%d\r\n",RxLine);
: ~4 D& b5 w; i) V - for(int i=0;i<RxLine;i++)1 H- r1 \2 Y; P& K
- printf("数据:[%d] = 0x%x\r\n",i,DataBuff[i]); - z, q& I! K8 ]# c% t8 s; x0 U
- memset(DataBuff,0,sizeof(DataBuff)); //清空缓存数组
# i* {5 c8 K( A - //memset()作用:可以方便的清空一个结构类型的变量或数组。
: T, L5 Y: |% e0 y1 N: m - //例句:memset(aTxbuffer,0,sizeof(aTxbuffer)) 用memset清空aTxbuffer。9 a7 k9 H# H+ e5 s0 c! y
- RxLine=0; //清空接收长度+ F' }* M$ l% t) l1 [& Y; A
- }
8 J5 f( ]# ?" f! _ - void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)6 z: K$ c _+ K8 N
- {
) P6 ~6 z$ n3 x& I5 g5 e y# Y - if (htim->Instance == htim3.Instance)
2 ?; @8 c9 I x/ }1 ?& h2 c - {
& Q5 \( S+ P. K% Y# G/ @0 d3 l6 ]- f - HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_5);5 v% h/ K8 T/ ]4 g* ~
- /* Toggle LED */
1 g4 R, z9 P$ v2 g - if(Rx_flag==1)3 N4 y; a' t7 \) }
- {( a l% M; n% [9 E# Q
- printf_usart();
2 [$ P- K6 O, \ - Rx_flag=0;
/ Z/ d: L- e3 n$ X/ M - }
. M; o7 @& B4 Z t7 M - }
: S+ I* c% L9 u) o - }
4 ^9 ^+ w% r" ~ - // 捕获中断回调函数,每次捕获到信号就会进入这个回调函数
, ]$ h+ C/ }3 Y( V/ I - void HAL_UART_RxCpltCallback(UART_HandleTypeDef*UartHandle)
3 U- ?! F$ i3 J# H1 X - {' b5 H8 g% A3 P: U: D- t$ D
- RxLine++; //每接收到一个数据,进入回调数据长度加1
$ {2 F' T6 [9 K# C - DataBuff[RxLine-1]=RxBuff[0]; //把每次接收到的数据保存到缓存数组. U$ q. p4 g- L( H0 j2 v. G
- Rx_flag=1;- ]1 @7 q# g% N$ ~+ o2 L6 m
- if(RxBuff[0]==0xff) //接收结束标志位,这个数据可以自定义,根据实际需求,这里只做示例使用,不一定是0xff$ [% B, N" R0 j
- {6 ^; V. K1 n1 V. R3 X
- printf_usart();2 s0 ?0 ]9 v8 u8 o
- }
( H5 w' i! s2 A. S( i8 A# d - RxBuff[0]=0;
. n- z5 [( @ \- x, u - HAL_UART_Receive_IT(&huart1, (uint8_t *)RxBuff, 1); //每接收一个数据,就打开一次串口中断接收,否则只会接收一个数据就停止接收* O& J4 `% r7 m8 d) H5 Q; M
- __HAL_TIM_SET_COUNTER(&htim3, 1); // 计数清零,从头开始计
8 ` H& P* `5 {; \; O - }& x0 U9 u4 T) e9 Z2 M0 Z# |8 [: I
- /* USER CODE END 4 */
复制代码
. w U6 A% n5 ^- x: m8 z* ?2 u9 G# ], p
演示效果 可以看到 发送11 12 13需要等待100ms左右才能发送,如果最后加上ff直接发送。
1 O3 o( g7 [( N) a
+ ?4 p/ }; W+ f* Y: p4 n' m- c+ E( v+ P4 m8 @
/ Z% R' p$ L0 }- K
|