|
概述 本文利用中断实现串口不定长接收(非DMA),使用HAL库,将接受的数据打印出去。
( e- A% d* f3 m9 F 硬件准备 首先需要准备一个开发板,这里我准备的是NUCLEO-F030R8的开发板:
! q# o4 O3 d& T K # N# A7 _1 Q, c
3 E2 @2 o. W$ z: l3 U* T/ q
选择芯片型号 使用STM32CUBEMX选择芯片stm32f030r8,如下所示: z- q4 n4 [7 N6 v5 Y0 S9 v8 m
& F& Q3 l; s5 e# n( y7 w配置时钟源 HSE与LSE分别为外部高速时钟和低速时钟,在本文中使用内置的时钟源,故都选择Disable选项,如下所示:0 `6 X2 y% k/ o, E6 f
' d& Z. W$ \) ?: r- T% c
3 N' ^( k* z7 U/ B3 i, _ J$ j 配置时钟树 STM32F0的最高主频到48M,所以配置48即可:) ~6 Q2 n7 L6 e' W" `2 e
) A* ]+ Q2 h! |8 H7 t0 H1 F! n0 D
. v" c! \) D6 Q/ a' t8 r- O串口配置 本次实验使用的串口1进行串口通信,波特率配置为115200。
2 m `- z8 q, D; V5 G, J9 k) ^ 1 K2 W8 q& b! L6 {# P
( O, [9 y. }# F9 r& b8 K 中断+ g. z; V" p+ X$ ^4 L. r
, W% X- {9 |* H! r2 O3 [
" U3 `% H' z: f2 B
GPIO配置 板子上led为PA5端口,故设置PA5闪烁来验证是否正确。( P. Y$ S2 i( d( E8 f
* C9 L, W8 k1 x# S/ e; O
* n3 l$ W; o$ L
定时器配置 本次实验使用的是TIM3来进行计数。
+ e7 G0 ~4 z$ q5 F , D# Y: t! y8 M: e' j6 T* b
0 b9 G# s V( ?2 j N
PWM频率计算如下所示。 2 e M, h& u' V
( x) Y/ ]$ F# g' W 在上面配置TIM3参数,预分频系数设置为480-1, 自动重载值设置为10000-1,那么PWM频率为48,000,000/((480-1+1)*(10000-1+1))=10Hz,即 100ms一个周期。
" y. Z% ?" w) P6 b& f$ J
7 q1 j" R+ n2 {$ B4 O% M生成工程设置 注意在生产工程设置中不能出现中文,不然会报错。
- N G* g- b& W4 U8 m
; N8 p% h1 D& h( m/ V: Q' S1 y: f ) o3 v- U% z. `, ]# v
代码生成设置 最后设置生成独立的初始化文件:" D# R3 e1 f5 V( A3 q
9 K4 `6 j5 d6 \0 X0 a
7 E7 X6 g) ?+ }5 z( ?& q( I生成代码. J- Q( }8 D: R" S8 d2 z
. d* i+ d& b) L# b
$ r! n8 r i H1 J1 o配置keil
5 H* q& K4 k4 a |3 Q7 \' N; j. K- _2 F3 o
0 [; i% E' a! H代码 在main.c中,先加入头文件。 - /* USER CODE BEGIN Includes */
& N3 s* }) }% \2 u8 j - #include "stdio.h"//printf头文件/ s% n3 w6 y# Q. G
- #include "string.h"//memset头文件' X0 ?7 [& H3 M6 d9 B
- /* USER CODE END Includes */
复制代码
1 n! G9 X, J) l& `) { F9 ] 定义变量存储。 - /* USER CODE BEGIN PV */
n9 u# S' R7 n - uint8_t RxBuff[1]; //进入中断接收数据的数组6 a6 t6 O7 I5 d8 {2 V1 B1 ?" B
- uint8_t DataBuff[5000]; //保存接收到的数据的数组/ {/ Y6 p) ~9 ?" k
- int RxLine=0; //接收到的数据长度
2 W1 `" I" Q) @1 G2 l - int Rx_flag=0; //接受到数据标志& a( p) }) ~1 Z6 j& m, h- i
- /* USER CODE END PV */
复制代码
, ]* q0 B0 x4 B" ^9 h 定义printf的重定向函数fputc。 - /* USER CODE BEGIN 0 */
1 J; k4 H. A+ |& H - void printf_usart(void);//输出内容
' s5 x% p' J+ w - int fputc(int ch, FILE* file)//定义printf的重定向函数fputc,满足串口调试打印
- @. G6 }1 S6 X+ Z/ T8 J O - {
8 o4 T' ^( y9 X/ @( p" C: B - return HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, 100);
! l; ~8 l! n4 g' u - }
! C. B+ O* d v4 M! V3 N3 ~3 S - /* USER CODE END 0 */
复制代码 打开串口和定时器。 - /* USER CODE BEGIN 2 */
y1 S; f9 d: y; q) S$ R - HAL_UART_Receive_IT(&huart1, (uint8_t *)RxBuff, 1); //打开串口中断接收
6 O: z+ X/ x: ]& F& j, k8 z - HAL_TIM_Base_Start_IT(&htim3);//开启定时器; u, V9 C( `% i H9 z0 \
- /* USER CODE END 2 */
复制代码
9 _+ y l7 A, w5 W% B$ V' K 串口接受代码,当接受到最后数据为FF时候,直接打印,否则等待100ms打印。 - /* USER CODE BEGIN 4 */
/ R; ?1 J( N3 s3 @ - void printf_usart(void)
: E( c6 n# }3 f; G% i - {
1 O0 f$ T/ q" ~3 _ - printf("数据长度=%d\r\n",RxLine);
q- s' [1 q( H$ C8 q; P, J" C - for(int i=0;i<RxLine;i++)" V8 ?! v# I: t5 ^6 |; ^
- printf("数据:[%d] = 0x%x\r\n",i,DataBuff[i]); ' G3 Z% t* y: E6 x
- memset(DataBuff,0,sizeof(DataBuff)); //清空缓存数组* g2 a# p3 y j7 w
- //memset()作用:可以方便的清空一个结构类型的变量或数组。/ L3 i$ C+ v* e) e& g
- //例句:memset(aTxbuffer,0,sizeof(aTxbuffer)) 用memset清空aTxbuffer。
- T0 T1 s, w+ K3 W) p& ^9 R' k3 p - RxLine=0; //清空接收长度
( j7 U, \; @# c - }2 c$ K( u7 ]- G/ z+ W- i
- void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
! ]' ^0 o4 u, `+ V - {; V: q& Z0 @! p/ v3 k5 e
- if (htim->Instance == htim3.Instance)
9 w* [6 v/ ]3 l - {
H/ H% L: |2 [! t; U9 K4 E - HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_5);
+ [8 W: e& ], h4 Y W" Z - /* Toggle LED */
R; F; }4 G/ o - if(Rx_flag==1)5 n; s! J/ g1 }1 M0 u' [/ W! L2 {
- {
3 {! K. u4 Z# N! p8 a - printf_usart();* G: d! d, E* Z! a, X0 N4 h. v
- Rx_flag=0;: [5 M% M" ]0 E; f: s
- }1 \* L9 P1 D4 ?1 \) s @$ Q8 n* W
- } , ]* A+ O4 U* d/ S
- }! I P) e5 Q7 f: K; h; \" {4 i9 w
- // 捕获中断回调函数,每次捕获到信号就会进入这个回调函数, [" s E3 L0 S0 P4 z
- void HAL_UART_RxCpltCallback(UART_HandleTypeDef*UartHandle)
; r+ [5 l4 K. f! P* M - {9 I' [" t9 O: }: ]6 W
- RxLine++; //每接收到一个数据,进入回调数据长度加1
7 M) {3 _5 r3 h0 D, C( s - DataBuff[RxLine-1]=RxBuff[0]; //把每次接收到的数据保存到缓存数组/ W# d3 Y8 w- J1 X: s8 ~5 w0 K1 U
- Rx_flag=1;
' g8 g' y+ X4 `& t - if(RxBuff[0]==0xff) //接收结束标志位,这个数据可以自定义,根据实际需求,这里只做示例使用,不一定是0xff
! c( O/ C8 f. T: T u( t - {# D( }! o- M/ t( |. H, `
- printf_usart();
% |2 u' f" S5 w - }
# D# q! p. N" ?0 F9 D/ d - RxBuff[0]=0;/ y" u. X+ A6 o- O5 Q
- HAL_UART_Receive_IT(&huart1, (uint8_t *)RxBuff, 1); //每接收一个数据,就打开一次串口中断接收,否则只会接收一个数据就停止接收% u! y2 m$ B% G; g u7 _# [8 t
- __HAL_TIM_SET_COUNTER(&htim3, 1); // 计数清零,从头开始计& ~# P4 h* L# f' Q# a% g
- }
+ ?6 j) a! p+ _. | - /* USER CODE END 4 */
复制代码
z8 L. F; I1 h9 f; o) l' G% v, R8 Z' ~$ R, C6 O9 }
演示效果 可以看到 发送11 12 13需要等待100ms左右才能发送,如果最后加上ff直接发送。 4 d- L3 ~; m& b: s D) L+ J
# L' X2 R+ i4 L0 v T9 y
+ u: L: T, Y- F4 Z; D l0 O . k: n: a3 j. Y5 B
+ l, C5 _' l1 E# ?5 M$ s |