|
概述 本文利用中断实现串口不定长接收(非DMA),使用HAL库,将接受的数据打印出去。
7 {* r) e L) m- t& O7 r 硬件准备 首先需要准备一个开发板,这里我准备的是NUCLEO-F030R8的开发板: ; F* Z4 d" Y( [4 r8 X! S
& w2 C3 D' g1 R4 T6 H8 \5 j, p. t1 N1 h/ ^5 ^! P/ x3 ^
选择芯片型号 使用STM32CUBEMX选择芯片stm32f030r8,如下所示: j& t% p( j2 a4 a8 z+ S- n
( G- F! Z4 g. [7 J5 \, P配置时钟源 HSE与LSE分别为外部高速时钟和低速时钟,在本文中使用内置的时钟源,故都选择Disable选项,如下所示:; V: E3 N$ k% [1 u4 C, e( v
7 n F' _" F. T& s0 }7 ]4 P
6 J$ U( V1 E4 v- c% V8 k; ], y8 A
配置时钟树 STM32F0的最高主频到48M,所以配置48即可:$ E! j; W5 T5 K E9 t8 E
5 z( P3 _4 k$ q" N
- @4 E- W- k8 v% N! p1 E8 h$ X串口配置 本次实验使用的串口1进行串口通信,波特率配置为115200。* U+ C- b6 Z8 q& Z( u" t' H
3 D& E( Q" r" D( I, y8 y
' L' B* V3 ?+ a 中断. O* h4 z9 ~7 ~
/ P( h) y. U& e; j$ `( ^8 E$ k
& r! @, G9 a6 V( V5 \) cGPIO配置 板子上led为PA5端口,故设置PA5闪烁来验证是否正确。4 e8 e) K9 ^3 b2 f( Q0 z3 R, v
( \6 }* [3 @4 b4 ~ J: r) k8 K/ x
& d2 p/ M+ Z0 a0 p- g8 X
定时器配置 本次实验使用的是TIM3来进行计数。
. n" b/ `" `7 A + {. k- n6 R; W- v. b0 Q$ a+ O4 n
: I3 b3 }0 f/ [: R1 l
PWM频率计算如下所示。
+ j/ J" u0 m7 d% v: G6 X$ V9 S: A; p3 ^* e& [0 R" o
在上面配置TIM3参数,预分频系数设置为480-1, 自动重载值设置为10000-1,那么PWM频率为48,000,000/((480-1+1)*(10000-1+1))=10Hz,即 100ms一个周期。1 ?* C: N. r3 v0 \& G3 ?
# ~5 Y! U$ G- A- o. ]
生成工程设置 注意在生产工程设置中不能出现中文,不然会报错。+ y4 a# _1 I3 _ m+ `0 r
( X8 {7 P! W+ |! ?0 P
6 W. N" h+ |: L$ Q( @" o代码生成设置 最后设置生成独立的初始化文件:
+ x: F6 O9 y6 c8 H* I- R9 S: i' G) Q
3 M+ O) {+ @9 x+ \9 T" |
^ \8 g0 {' `0 f3 W生成代码- n' L0 O6 J0 U
0 S' k5 [6 F! E( Z) ~
( w; h% Q; y) U6 ? R g% n% A
配置keil
7 f( t; S! Z8 R- u" y$ w! ^* \8 [1 G- N4 Y' D3 L5 |
Q1 B& t' a: T6 Z# u4 A
代码 在main.c中,先加入头文件。 - /* USER CODE BEGIN Includes */
5 E6 Q7 g6 ` h- P4 a. p3 n - #include "stdio.h"//printf头文件
$ A4 J |( F0 z - #include "string.h"//memset头文件
. n/ r. m- s& G4 } - /* USER CODE END Includes */
复制代码 ' n/ J0 G) z8 M! d- y
定义变量存储。 - /* USER CODE BEGIN PV */
7 @5 U- I1 l2 F: M. _ - uint8_t RxBuff[1]; //进入中断接收数据的数组
; I2 t# H3 {- p M - uint8_t DataBuff[5000]; //保存接收到的数据的数组" h8 |0 T: [% l( f3 }
- int RxLine=0; //接收到的数据长度
0 U3 y) P# @1 ]) @ - int Rx_flag=0; //接受到数据标志; ?1 X. l4 k$ D" z4 V3 b5 ~
- /* USER CODE END PV */
复制代码
' y2 y% @0 {3 B6 s* N) j 定义printf的重定向函数fputc。 - /* USER CODE BEGIN 0 */
: l" x( h. @' I+ _ - void printf_usart(void);//输出内容
# x" ]" L; R, q% K; B - int fputc(int ch, FILE* file)//定义printf的重定向函数fputc,满足串口调试打印& Z1 e$ q L4 L
- {
, }5 e) h" s% {2 n% W - return HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, 100);
0 a6 R5 b% m. m5 D( [9 Y - }, J+ s6 G9 e- q2 ^0 @
- /* USER CODE END 0 */
复制代码 打开串口和定时器。 - /* USER CODE BEGIN 2 */$ {3 ]0 o9 v# A
- HAL_UART_Receive_IT(&huart1, (uint8_t *)RxBuff, 1); //打开串口中断接收
$ j/ e) h. n- e8 x& |0 a - HAL_TIM_Base_Start_IT(&htim3);//开启定时器
! @* [5 { H. R. ^ - /* USER CODE END 2 */
复制代码 ( S9 F4 E) L6 m7 C$ Y p* w2 p
串口接受代码,当接受到最后数据为FF时候,直接打印,否则等待100ms打印。 - /* USER CODE BEGIN 4 */8 F1 B) \. A% q
- void printf_usart(void)
$ z, F4 P1 }7 h: ~6 v3 f; s - {( }) g& f, w2 Y6 A$ z
- printf("数据长度=%d\r\n",RxLine);
" l8 N* v$ b+ V @/ A$ V - for(int i=0;i<RxLine;i++)3 N; K c6 k7 k$ }3 Q; p
- printf("数据:[%d] = 0x%x\r\n",i,DataBuff[i]);
+ i$ X9 {8 L; T" G - memset(DataBuff,0,sizeof(DataBuff)); //清空缓存数组
# M, g. K, a5 n- Y& s - //memset()作用:可以方便的清空一个结构类型的变量或数组。
$ X5 q f/ c4 P4 E - //例句:memset(aTxbuffer,0,sizeof(aTxbuffer)) 用memset清空aTxbuffer。) ^* |2 B x2 X' s
- RxLine=0; //清空接收长度4 _! ^6 n$ [" \) u. S
- }8 w6 r2 _ X# `- H% m
- void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
' d; F* E% U/ q- Y - {
( X4 K3 E7 H6 b {0 [ - if (htim->Instance == htim3.Instance)) O8 N( M- |3 u( K( }
- {9 n+ ?/ i" u# S. Z# ]- P9 v" b, S
- HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_5);9 k+ y. |7 q }- s4 X3 L! R" }( ?3 k
- /* Toggle LED */
, P* ?8 `* u3 F - if(Rx_flag==1)
2 u; d& X$ v) V6 l2 |9 l - {
6 N8 q+ Q2 Y* \9 X8 e# e - printf_usart();, U7 m$ F. k$ P) S. e
- Rx_flag=0;+ w; A# x) W A7 L. n+ }
- }
3 m" n1 F+ j. K E$ S( _8 W4 f - } & y, l" \. |7 i" k5 p f t* S
- }
$ w% q5 x/ J* j; L, ]+ R3 r - // 捕获中断回调函数,每次捕获到信号就会进入这个回调函数
9 o# Z ?9 R9 U3 _ - void HAL_UART_RxCpltCallback(UART_HandleTypeDef*UartHandle)
0 }8 t7 |$ _3 _) \# Y - {) Z: S9 B3 L! i; J, j- d. d
- RxLine++; //每接收到一个数据,进入回调数据长度加1
! m: y" E! a0 D+ Y8 o0 E% F - DataBuff[RxLine-1]=RxBuff[0]; //把每次接收到的数据保存到缓存数组
+ \) N) I( F+ ` - Rx_flag=1;& H& c3 e4 Y# e5 R# g
- if(RxBuff[0]==0xff) //接收结束标志位,这个数据可以自定义,根据实际需求,这里只做示例使用,不一定是0xff
7 k! m/ ]% U4 n- V/ t - {. }" a, E' T! w! a* k
- printf_usart();
7 s' M- O' [# b9 u. e1 k/ f2 r - } 6 N, |" g/ J) h* e! t! m0 Y
- RxBuff[0]=0;
; H c) Y5 N) ^; b% r# O - HAL_UART_Receive_IT(&huart1, (uint8_t *)RxBuff, 1); //每接收一个数据,就打开一次串口中断接收,否则只会接收一个数据就停止接收# M! m4 }7 L5 @/ s2 e% {
- __HAL_TIM_SET_COUNTER(&htim3, 1); // 计数清零,从头开始计( {9 u/ T( N" N3 h( N7 l. F# ^
- }
$ o \6 {2 ~" T1 P - /* USER CODE END 4 */
复制代码 % H( L* ^- X7 O1 x& y
: c+ K" X9 G4 A* K
演示效果 可以看到 发送11 12 13需要等待100ms左右才能发送,如果最后加上ff直接发送。
0 `- t% U7 D y2 \6 A! ~- A
1 _; N e6 ~- q" m0 F. m
0 w) t* d- b+ a% g" {7 x
9 p+ K& X; i; u! Q$ B* N7 J |