|
概述 本文利用中断实现串口不定长接收(非DMA),使用HAL库,将接受的数据打印出去。
* q( D* p# y. W |" R 硬件准备 首先需要准备一个开发板,这里我准备的是NUCLEO-F030R8的开发板:
. o8 j) k. i7 b) k- |0 p1 w 5 y2 k% u+ `! e$ `8 U$ X; x$ n% |1 n
+ t; c4 ]& s* X+ C( S" ^选择芯片型号 使用STM32CUBEMX选择芯片stm32f030r8,如下所示: 8 x( u+ D4 {: p" g Y( k
7 z& L$ o7 r5 Z8 t4 u3 E8 E% b
配置时钟源 HSE与LSE分别为外部高速时钟和低速时钟,在本文中使用内置的时钟源,故都选择Disable选项,如下所示:# i% s2 h/ \8 h1 P
/ N) R, T8 n- K1 U8 J4 s
7 A5 S! H+ u/ D C' B2 M 配置时钟树 STM32F0的最高主频到48M,所以配置48即可:
5 Q: k9 i; u$ t: E 1 j5 W- Z# w' V3 X0 q
$ a/ a, H. }& g" O% O
串口配置 本次实验使用的串口1进行串口通信,波特率配置为115200。9 ~+ f7 D' c, i/ t/ i( h2 _# k. C
" W6 `" l# O8 b7 w# Q
+ }' S: h* p6 U% {9 `- _ 中断
5 O9 o5 n6 u) m$ n ( [( X' K3 i: t8 Z
3 C1 K% M7 B0 p% OGPIO配置 板子上led为PA5端口,故设置PA5闪烁来验证是否正确。
4 o# ]' o" |% h, Y/ P5 w+ U: b1 s5 B
$ N9 E4 E, J. a, c: }1 @
- H9 Q, `4 [! n" X- B9 ~4 z; g 定时器配置 本次实验使用的是TIM3来进行计数。
8 N; T# l6 ` z. a & |4 c3 c$ ~8 _0 L4 N6 ^* c, K- b
6 b+ `9 C& L8 ~5 Y, i
PWM频率计算如下所示。 # m, G! s: W% M! e
' [0 U2 o( M5 E' D# Y* @
在上面配置TIM3参数,预分频系数设置为480-1, 自动重载值设置为10000-1,那么PWM频率为48,000,000/((480-1+1)*(10000-1+1))=10Hz,即 100ms一个周期。
% h' g$ @ I# k& K; z8 u% X! } m9 R" q1 L6 e2 y
生成工程设置 注意在生产工程设置中不能出现中文,不然会报错。# L" ^1 h1 y, R0 w. D( w" Q: |
' P( M" h# G) q$ n
/ z9 ]0 f, A; @: F7 n+ o, l* H代码生成设置 最后设置生成独立的初始化文件:
* ~9 u5 \: O/ c0 l" Y: }# s
) j# Z" u# ?% h( L) G# m0 _$ k9 q& G: Y! T4 h7 p- b6 ^5 G
生成代码2 s4 L& M" T, c- z+ X
& D* s; V1 k9 Z& E/ X0 h( E$ u! ]
1 h# f! x- L; g
配置keil0 T4 i, k: L3 y3 G1 I/ F5 C
0 D9 h9 i3 p% u+ L; m' y
- W+ g( R- ?0 p; C3 r1 p6 i2 F7 @代码 在main.c中,先加入头文件。 - /* USER CODE BEGIN Includes */
/ r" Q/ @3 J' O9 U4 U$ O - #include "stdio.h"//printf头文件
: P9 I8 L0 j( }" u2 r" W" F( l - #include "string.h"//memset头文件
3 @1 v o( n1 i4 I3 \ - /* USER CODE END Includes */
复制代码
- s/ ^: C; K6 U' S8 L. q. x3 x! b 定义变量存储。 - /* USER CODE BEGIN PV */: j' Q' A( H7 Q4 o
- uint8_t RxBuff[1]; //进入中断接收数据的数组
5 f l) M Q8 ]# |0 p - uint8_t DataBuff[5000]; //保存接收到的数据的数组
0 T) z/ w2 y4 y6 \ - int RxLine=0; //接收到的数据长度
. p& V% F& ^4 d# J u' r$ l1 I+ H - int Rx_flag=0; //接受到数据标志
1 a4 j; `1 n( z: j e - /* USER CODE END PV */
复制代码 ( n- A1 H( M( U' E
定义printf的重定向函数fputc。 - /* USER CODE BEGIN 0 */
) z4 l; B# k' T" I. }4 W - void printf_usart(void);//输出内容
5 x9 l* @! X( Y1 }" Z+ e) _ - int fputc(int ch, FILE* file)//定义printf的重定向函数fputc,满足串口调试打印# n M% P6 C7 r7 F
- { _! I4 q; b& b5 x& d
- return HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, 100);
. q" o- } ?. w- ^7 p - }
$ K9 T5 k- K3 F! Z - /* USER CODE END 0 */
复制代码 打开串口和定时器。 - /* USER CODE BEGIN 2 */ K- {7 [3 K8 {
- HAL_UART_Receive_IT(&huart1, (uint8_t *)RxBuff, 1); //打开串口中断接收
" u9 b: i% e) J - HAL_TIM_Base_Start_IT(&htim3);//开启定时器
) |8 q8 R0 A; R) d1 K( b& k - /* USER CODE END 2 */
复制代码
# Q6 ~0 v8 Q. |+ X 串口接受代码,当接受到最后数据为FF时候,直接打印,否则等待100ms打印。 - /* USER CODE BEGIN 4 */- H2 d4 \8 H8 j/ z m
- void printf_usart(void)) U$ I. k. @% V' [, B7 T
- {
! Y! }. K' b& g' F6 n - printf("数据长度=%d\r\n",RxLine);
: i+ c6 y" c' I - for(int i=0;i<RxLine;i++)
$ f4 J8 L( ]- D# D - printf("数据:[%d] = 0x%x\r\n",i,DataBuff[i]);
& Q4 O& c' X+ e1 g, g9 F& L - memset(DataBuff,0,sizeof(DataBuff)); //清空缓存数组
/ J" k/ i2 w' D! N, {! H - //memset()作用:可以方便的清空一个结构类型的变量或数组。
" z* p1 D1 \; {+ m g - //例句:memset(aTxbuffer,0,sizeof(aTxbuffer)) 用memset清空aTxbuffer。1 f% O9 g3 K; n1 X0 G' T7 d: t
- RxLine=0; //清空接收长度) S, e# Y4 d- o: t! \, [* F+ h8 z
- }2 k6 u4 k2 m- ]( a: i8 X$ k
- void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim): o8 y$ o0 I2 N# F& _
- {
$ x6 j1 U6 a" N% I - if (htim->Instance == htim3.Instance)' m- Y. |" x9 @, H: i
- {% S& S) ~0 ]8 C7 p1 I- e
- HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_5);$ f V9 U( E1 G! W' E+ \7 J
- /* Toggle LED */7 K# y+ {# \9 `
- if(Rx_flag==1)
; C% \8 R: Q0 U! D2 ~ - {
) J/ Y2 w, r) D$ x. D$ q - printf_usart();
3 Y# V+ s( P+ p0 Y - Rx_flag=0;
* l0 d4 k: U& v$ Y% U- k" | - }
6 R/ F+ B' b7 t6 f - }
1 u% B X: ]5 ^7 ~4 S$ r - }5 I. i! @5 W% n) L
- // 捕获中断回调函数,每次捕获到信号就会进入这个回调函数; j8 a: g% P, A" w* G
- void HAL_UART_RxCpltCallback(UART_HandleTypeDef*UartHandle)
3 w" [) r1 ^6 [, j0 O# ?; k+ S' \0 v - {6 D9 t; i: i' {' u
- RxLine++; //每接收到一个数据,进入回调数据长度加1
( R8 D/ R( v0 v$ w - DataBuff[RxLine-1]=RxBuff[0]; //把每次接收到的数据保存到缓存数组
* ?* V. m3 u, D$ n( P! d4 h) M) L - Rx_flag=1;
, a* e$ |1 i( S% m" s- |* o' ~ - if(RxBuff[0]==0xff) //接收结束标志位,这个数据可以自定义,根据实际需求,这里只做示例使用,不一定是0xff" C0 R6 @. n3 C' `1 M2 y
- {2 Q! ~& N- r( j& V( h9 @6 M
- printf_usart();
$ y' y* b7 t& [/ P - }
$ r/ u* B, d: k: T, M) n - RxBuff[0]=0;
0 f- P# L- Q+ k) a" c) ?3 ]+ a+ e - HAL_UART_Receive_IT(&huart1, (uint8_t *)RxBuff, 1); //每接收一个数据,就打开一次串口中断接收,否则只会接收一个数据就停止接收& `3 o/ s) ~/ b; n
- __HAL_TIM_SET_COUNTER(&htim3, 1); // 计数清零,从头开始计
+ P0 J5 y' r& O/ \ - }/ O. M6 ?$ q2 w1 b
- /* USER CODE END 4 */
复制代码 9 w0 r9 _, V' s7 s
# i- A/ @: Z; K2 u演示效果 可以看到 发送11 12 13需要等待100ms左右才能发送,如果最后加上ff直接发送。
, c) X- Y4 b0 r( ~6 q* a; v4 I 2 M- u- b5 n; W& n: D. o s0 f* e+ N
! T! s+ T! m# o' ]
- R( s" h8 ^! U* ?( h% p( F
|