一、实验说明1 `7 l( g7 j+ ?) q& t% o+ A# {2 P
实验平台:STM32F103C8T6
& d5 L1 k2 m6 H Y* ^实验内容:使用串口一空闲中断结合DMA 完成不定长数据接收6 f' F, I3 @/ {+ m- P$ I, t' Q, i* C
0 ?5 v) u: \1 ]( `1 K, [9 e+ j
STM32的串口接收数据的方式- c' Z0 X; `3 e
1、轮询接收
9 s1 Q, I1 ?) f 所谓轮询,就是在主函数中判断接收完成的标志位。举个不太恰当例子,就比如,此时你正在考试作弊,手机藏在兜里,你的队友再给你发答案,但是你的手机静音,所以你不得不写一会题看一会手机,有的时候答案已经发来了但是你此时在假装写,没有看,导致你没能及时看到答案浪费了时间(仅仅为了举例而已。。。。)。轮询接收数据也是这样。3 d$ T9 q/ |2 {
9 B$ T6 c, S' K# X' C2 X2、中断接收
& Q! a* y: r9 y; L$ Q 串口接收配置为中断模式,当有数据收到时,进入到串口接收中断中读取数据。继续上面的例子(你为了不浪费时间且及时抄到答案,你把手机开了震动,消息一来立马看,这是就比上面好多了,能够及时发现消息。但是又出了一个问题,你的猪队友,写一个选择给你发一次,不停的震动,完全扰乱了你的节奏)。其实也就是,串口接收数据时,一次接收一个字节,当数据量较大时,显然这样频繁的进入中断,打断主程序,严重影响系统性能。" q# a% l; F- ^
5 ~9 r& y" a/ [" x3 P! s4 i$ `3、空闲中断接收 s8 g$ k8 z. }+ ]' m0 E% o
空闲中断接收,当一帧数据接收完成之后,串口会进入到空闲中断中去,然后在空闲中断中处理收到的数据。这种模式对处理不定长数据帧带来很大的便利,我们不必频繁的进入接收中断处理数据,但是弊端也是明显的,由于每次都要接收完一个完整的数据帧后才空闲中断,所以当一帧数据出错时,我们也不得不接收这帧错误的数据。在通讯可靠的场合,使用空闲中断接收模式接收串口数据,将会大大提高系统的性能。
. Z" ?" Y5 ?* [8 c; ]! Q2 h% h/ }
二、实验步骤4 w+ b& R7 @0 D& i3 ~. R
1、基础配置9 ~9 J2 M' h0 D6 ]
1)、sys中,选好调试方式,例如jtag-4pin。& }& M: S) O( M, B& U, m. H, ?
2)、RCC时钟,晶振选择。) g0 q. B; s0 v2 k
3)、时钟树配置。7 ]% Z9 }# y1 H7 J8 L# y6 G
4)、中断分组配置。
5 O3 }2 [ u* `# K: r; c以上步骤可以参考串口中断实验。# W0 j6 w) a, u$ U9 W8 f" D
. U! h* R Y! P6 j6 h
串口中断实验配置
3 B. {+ Q) x2 {0 I本实验要配置好printf函数便于演示效果
+ q; r9 f0 L% O R% t, X, {) ]; z0 c1 f4 |2 Q
2、串口和DMA配置+ C2 e- R; a! u2 K0 g7 L9 `# o. l' A
1)、串口一配置。
% P4 M P0 d: E) C" V5 N( I; [& w3 u& c1 O
. w3 d8 Y4 M9 D8 U, N1 Q
' {, ?5 k. D N k4 X2)、DMA选择8 o- c1 \+ }% v4 h! `3 k8 R6 F
* M. ]: P k z+ n
+ Y& w4 h6 K! M V
# J+ e+ V: y: C; n: v
' }) W+ I: K9 k5 ^3 [3)、生成工程代码
9 @7 Y. O$ q! P
9 q. Z( d3 [' u5 [( O
) }' ?$ [( x1 q4 U* p, D4 q2 c
3 n# V& Q# Y' F* S
然后生成代码。
: X2 T! ?- ]( B, Z, F! I/ N4)、添加代码
9 C' D4 Z8 b0 ~" y4 M
* K$ S0 i/ e3 N
, n- O) p* F3 V8 z9 w( y5 } o# m) x/ ~
- // 这里没有使用中断回调函数,这样写更直接一点。( y# ]$ ?8 b% u: k z
- extern volatile uint8_t rx_len;//接收到的数据长度9 {9 n# o0 L+ x2 @6 X
- extern volatile uint8_t recv_end_flag; //接收完成标志位
9 e1 i- r: _' n: `4 ~ - extern uint8_t rx_buffer[200]; //数据缓存数组" ` r* s0 X% @/ ^& H
- void USART1_IRQHandler(void)' L8 t+ y [6 J: ]
- {
+ M3 Q% y' U5 x, }( K. J& w0 c+ g - /* USER CODE BEGIN USART1_IRQn 0 */
+ ~3 e2 e. T9 l ^1 g. X* { - uint32_t tmp_flag = 0;: ]# e7 V# }" r, g8 R0 Y& i
- uint32_t temp;
. w$ }1 t/ _! g+ i5 }9 S - tmp_flag =__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE);
9 _( h3 W' F8 O - if((tmp_flag != RESET))& U3 t8 L( N0 d2 @0 M
- { % p3 q: z' v( N8 s5 i) [
- __HAL_UART_CLEAR_IDLEFLAG(&huart1);; P) A: t4 l! e( m: l
- temp = huart1.Instance->SR;
5 _! n' x& ^" x - temp = huart1.Instance->DR;
4 f, ^# k; x/ v' \+ m+ O& X - HAL_UART_DMAStop(&huart1); 4 v) X3 ~% U! e4 w6 l# y: b
- temp = hdma_usart1_rx.Instance->CNDTR;+ W& t) V7 G+ f$ z
- rx_len = 200 - temp; 5 S& `% a& D5 r2 C9 f
- recv_end_flag = 1;
3 e( d0 ?% G; f - }/ s/ ~+ }+ l* L/ R
- HAL_UART_IRQHandler(&huart1);
' Q _9 J7 _ f: w/ ~: H { - }
复制代码 : B: y4 ~" {1 N( j1 L D. @( e/ v
如下图,在usart.c 文件中先把变量定义上,同时把支持printf的函数添加上。0 b, s* U3 y: c# u" y
8 ]/ G+ U! _! x9 l; ~9 G- //注:**这三个变量 需要在stm32f1xx_it.c和main.c中外部声明**- J( K& x8 T/ M( V) Y3 k& F
- volatile uint8_t rx_len=0; //接收到的数据长度
$ M* K' k- n) T - volatile uint8_t recv_end_flag=0;//接收成功标志位
. o- X+ T9 w7 @; [! F) |8 b - uint8_t rx_buffer[200];//缓存数组
复制代码 ( g! Z6 T- U4 w, s, g; I* h
) l. ^: |* T1 N# H/ {& p/ p
# P9 k \5 L! Y: k1 i& N& T7 t
# S8 ~( R* }& ~9 X
' {! M8 N4 T) B3 u7 b- Q- __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
; {; k p) X7 h6 N1 I n) y - HAL_UART_Receive_DMA(&huart1,rx_buffer,200);
复制代码
% E8 R3 u- @" X* v# n
% q" j" Q% ]; I" S: k! W' _) F. Z F; W) j: X% e
- int main(void)5 n" |1 p4 n" {+ j7 P4 G$ m
- {& \! T4 T Q3 n: U7 [1 d
- HAL_Init();. j: D [4 g) Q9 a" U0 ^9 M
- SystemClock_Config();" |0 o7 L. W8 V. y% A8 P
- MX_GPIO_Init();
5 m+ h. ?) C' F4 \* h$ S - MX_DMA_Init();$ C- y. e; B' R5 k8 `( M- e( B- H
- MX_USART1_UART_Init();% J7 z2 @7 _) L9 ~5 }( \3 \% I0 E5 R
- /* USER CODE BEGIN WHILE */
% }8 r; O2 M8 o L: H5 y- O - printf("DMA_TEST");% }& {4 Z$ \9 o4 p5 c
- while (1)
: v% _% |7 W2 h" v; v6 ^' f' e - {
' G, M& m( j$ x4 k* b' ^2 N1 u - if(recv_end_flag ==1) ' S2 Q5 B# Q5 u' {9 c9 x# o
- {
- Q" G4 y( ?' z% v2 h0 x - printf("接收到的数据长度为%d\r\n",rx_len);- F& N* z( g9 i; [% h
- HAL_UART_Transmit(&huart1,rx_buffer, rx_len,200);! M3 x1 Y) R& |& ]) x+ X8 D6 m
- for(uint8_t i=0;i<rx_len;i++)
/ d$ P9 n6 V% G3 p$ J1 E - {( v3 v, d( C4 }
- rx_buffer<i>=0;1 i% Q' j/ K5 @' z
- }
4 ~' o1 I# v% Z2 a4 i6 c V - printf("\r\n");) g7 J0 v" e! X9 V: R
- rx_len=0; C- t8 g. E% z" `
- recv_end_flag=0;
1 M& j2 b4 N. t! L5 d* D - }9 }$ {% S1 K8 |; }& b7 h# `; J8 Z, B5 x
- HAL_UART_Receive_DMA(&huart1,rx_buffer,200); , M: M; k5 t8 d' {
- /* USER CODE END WHILE */
6 T' S/ }! `3 J# ^8 W% f - }
8 F1 S' u i3 U9 a' `8 T5 e9 ? - }
7 Y# Z/ K4 V7 b' ?6 T# b1 P3 l. G - </i>
复制代码
( h: v# v7 Q/ b) l1 D( f3 烧录调试
9 I' _( B b5 e' z9 F, E0 c0 h添加链接描述) o: b; U5 F/ l- ^$ e+ @$ m$ {
" ]+ H1 J1 O$ q W
! v: \+ C4 R* [0 c" S |