一、实验说明
7 a6 [; N% H4 Y% R0 X& T9 G实验平台:STM32F103C8T6
" w% s( T% N0 L0 E( q3 F实验内容:使用串口一空闲中断结合DMA 完成不定长数据接收
" C8 E6 `" t5 g% v; h P/ Z. R/ `" D" L. z6 ^- L5 a
STM32的串口接收数据的方式7 A# i# b' |. n9 L. U
1、轮询接收
9 F. ]) V+ w1 Z 所谓轮询,就是在主函数中判断接收完成的标志位。举个不太恰当例子,就比如,此时你正在考试作弊,手机藏在兜里,你的队友再给你发答案,但是你的手机静音,所以你不得不写一会题看一会手机,有的时候答案已经发来了但是你此时在假装写,没有看,导致你没能及时看到答案浪费了时间(仅仅为了举例而已。。。。)。轮询接收数据也是这样。
, i5 J% u- j7 D: p! {5 K3 B' u( ]
2、中断接收
0 I1 i! K5 s# g2 {5 G/ s 串口接收配置为中断模式,当有数据收到时,进入到串口接收中断中读取数据。继续上面的例子(你为了不浪费时间且及时抄到答案,你把手机开了震动,消息一来立马看,这是就比上面好多了,能够及时发现消息。但是又出了一个问题,你的猪队友,写一个选择给你发一次,不停的震动,完全扰乱了你的节奏)。其实也就是,串口接收数据时,一次接收一个字节,当数据量较大时,显然这样频繁的进入中断,打断主程序,严重影响系统性能。
" p6 ?6 v" }4 i8 T7 E7 V/ t; l' |4 S! L
3、空闲中断接收! m9 Y. o, {4 r) ]. F+ y" H
空闲中断接收,当一帧数据接收完成之后,串口会进入到空闲中断中去,然后在空闲中断中处理收到的数据。这种模式对处理不定长数据帧带来很大的便利,我们不必频繁的进入接收中断处理数据,但是弊端也是明显的,由于每次都要接收完一个完整的数据帧后才空闲中断,所以当一帧数据出错时,我们也不得不接收这帧错误的数据。在通讯可靠的场合,使用空闲中断接收模式接收串口数据,将会大大提高系统的性能。4 l% Y) y2 B# P B6 \
# o; v' ?; D, P1 A* a7 G/ L( {
二、实验步骤
4 v0 G6 r) i+ _) L1、基础配置
6 Z. x6 B+ D, h$ E; y, p0 e, e; B1)、sys中,选好调试方式,例如jtag-4pin。
4 b1 l/ f7 E% j& X2 x/ K2)、RCC时钟,晶振选择。
. f3 Y7 i" e* a3)、时钟树配置。
) D: k9 R8 O) L! i/ {4)、中断分组配置。# r; X5 d- k. t8 b% r
以上步骤可以参考串口中断实验。6 N# t; D( U1 \' Q5 H5 c* E
+ S) p# _9 e: Q& l. W
串口中断实验配置! ]: P1 a: ]$ E8 `9 W% o( v9 ]& y8 q
本实验要配置好printf函数便于演示效果
F }# w4 i$ d$ Z1 ~: o0 o! \" K- L% V* c& C
2、串口和DMA配置, ~; K; D2 B6 `* u I0 W6 P
1)、串口一配置。- I- g1 w1 c& X
. d: L: g) M* I8 n* ]4 p4 j$ i
+ n/ w$ E4 k. v4 Q3 v0 O7 y
+ Y% `6 F6 q4 H0 N# M2)、DMA选择
/ o) x/ F C! C
# e* e3 U3 b7 W' `7 h% [
$ w0 v+ r0 J. S4 W9 z$ Q
) J! q1 ]; F+ k: y
$ t; v8 r# o5 M
3)、生成工程代码4 e; ~) ^5 @; T* p
- b" A- g( A: _9 I
( Z" A0 Z* t+ j+ p* p
" E* b) c$ L, a9 ?然后生成代码。
0 s# j4 ]; A' k7 a$ U, H o4)、添加代码
0 Q( I- K) B% y; a, g5 F' B8 J D5 g% H, B
/ C. z. U) Z# j8 Z$ |1 ? F v# X) }8 T; _: ]; ^- ^
- // 这里没有使用中断回调函数,这样写更直接一点。
7 u. Z2 W7 q7 T/ S - extern volatile uint8_t rx_len;//接收到的数据长度
3 l# G# c* {" w1 s1 d1 B* F0 f - extern volatile uint8_t recv_end_flag; //接收完成标志位# j. N# ^6 x, M- d
- extern uint8_t rx_buffer[200]; //数据缓存数组+ v& e: ~% [: ?
- void USART1_IRQHandler(void)) W# V" U! R; |9 v
- {& m. [( N. B( d7 v) d1 F
- /* USER CODE BEGIN USART1_IRQn 0 */
- q9 u+ a) H2 O4 b3 L& d9 W1 a0 z" a - uint32_t tmp_flag = 0;# r* G A4 `! r0 @. `
- uint32_t temp;# ]3 ]' ^$ @6 L4 m: Y* m
- tmp_flag =__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE);
$ P, x: Q) ]" F5 a - if((tmp_flag != RESET)), r+ i! B4 ]# Z& o1 ~
- { ; y+ S& W* {% T2 ?& B
- __HAL_UART_CLEAR_IDLEFLAG(&huart1);- ~8 I% f3 {5 T4 j, E; \
- temp = huart1.Instance->SR;
( f4 ?# D; X2 R - temp = huart1.Instance->DR;
2 x& E4 R! r. _- M - HAL_UART_DMAStop(&huart1); : H$ R' D6 F( E4 u5 Z
- temp = hdma_usart1_rx.Instance->CNDTR;
+ k/ H1 }: G$ P1 h+ a8 b0 _3 Y - rx_len = 200 - temp; 1 y9 P: R6 @$ O7 i0 ]( q. y8 k; l
- recv_end_flag = 1;
/ T: M7 _0 Q3 Q$ D5 e$ j - }3 d, f" S' c# b$ ?; E. R" E
- HAL_UART_IRQHandler(&huart1); . D( G- o1 L5 g G9 Z" K9 d
- }
复制代码
% s4 X$ P7 g$ }5 c& x3 U1 d如下图,在usart.c 文件中先把变量定义上,同时把支持printf的函数添加上。/ r3 ^" _' ]0 m7 G1 i( T1 ]8 x d
& Y, R* P7 a/ ?- T) V; r6 R9 z
- //注:**这三个变量 需要在stm32f1xx_it.c和main.c中外部声明**. G, k- S3 _& t- s& E h0 e
- volatile uint8_t rx_len=0; //接收到的数据长度
1 q4 ]: J( _0 Q - volatile uint8_t recv_end_flag=0;//接收成功标志位
- Z, ]2 v! r1 z! y4 J5 D; ` - uint8_t rx_buffer[200];//缓存数组
复制代码
# J! ~/ Z' W! q3 D
! u S# G! k8 T& o5 Y( |/ Q
3 Y2 ^: r2 s6 Z2 Z2 z
/ \7 ?' V6 c5 N) ^
; m& y( g( ~8 v0 u Q+ }% W- __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);0 C5 t8 O7 W, t4 p5 W! i$ G. t8 [
- HAL_UART_Receive_DMA(&huart1,rx_buffer,200);
复制代码
& Y; C |9 p: c O) A! D! }9 y
! e3 A& m& }8 M Q. U
- q2 u& ?$ H, t; f- int main(void)
" ?+ O4 x0 B: L; o) V - {
/ a5 b! m! W h& D - HAL_Init();
4 M/ X+ v; l, m" k+ r - SystemClock_Config();# @& J* M* L/ a" w( T
- MX_GPIO_Init();
+ k: D) I# H, N& S - MX_DMA_Init();
1 L3 F) }% `8 x0 E2 X( s/ D7 y - MX_USART1_UART_Init();
! `6 {+ o9 F7 Z! c4 e0 h( U Q- {2 Z - /* USER CODE BEGIN WHILE */
8 o: g0 u# }: b g$ W: G5 o - printf("DMA_TEST");
6 }& |/ o" j/ R! b) ^- J) h- x' T - while (1)
, x; u, l2 p$ A' Y - {
9 o2 ~3 e/ h% g Y - if(recv_end_flag ==1) ' f4 x: f- w8 g- Z+ M8 M
- { 2 n9 X8 G1 c" ?; J6 a- H" S7 }
- printf("接收到的数据长度为%d\r\n",rx_len);
8 n- b }8 X# v2 o& d0 n: [. @- Q - HAL_UART_Transmit(&huart1,rx_buffer, rx_len,200);
- Q, d7 ^' M- R8 ]3 x - for(uint8_t i=0;i<rx_len;i++)
( ?2 D1 j7 J- g! p. J" P8 J2 b - {7 D* _1 f# @4 S& } ~! o/ s
- rx_buffer<i>=0;8 d& o$ |- n# E- S P/ C) z
- }$ n i# Q8 n/ m( c, s& R: R
- printf("\r\n");
" x% v% P. k0 i" O2 T# L4 `% M - rx_len=0;
# f) Q$ @! U, T5 N* H0 a - recv_end_flag=0;+ y. }0 n8 w% W
- }
' Z: A2 X0 o A& S6 @ - HAL_UART_Receive_DMA(&huart1,rx_buffer,200);
5 N7 i( x; n: L' w% A; ` - /* USER CODE END WHILE */
) j& Q! z' T# B5 b. E4 i! E% R - }
. A$ `6 m$ l/ Q - }
. d" S( ?+ m$ [5 ^+ s - </i>
复制代码
" }* c2 @& w, G" @* n9 h3 烧录调试
3 m e$ R! {( e$ [: P) l添加链接描述" {: m0 d, ^/ X j. u4 e! a
& m; E, t7 o5 d9 ~- Y/ K
: {' i: N" m! Z9 g" Z+ d
|