一、开发板平台简介:. w. v7 _4 a* J. J1 O& K/ B8 O2 W: J
1、开发板资源简介
8 f9 a' i! i0 k% ^6 l$ R7 z(1)开发板主芯片型号:STM32L431RCT6(2)开发板主芯片封装:LQFP-64_10x10x05P
3 ~# B B T. Y1 o(3)开发板主芯片内核:ARM® Cortex®-M4
- I$ h" v4 q1 ?) i" L(4)开发板主芯片主频:80MHz
. ?* ~0 n! \$ n(5)开发板主芯片Flash大小:256KB
9 ?/ U2 ?2 y& ]' |(6)开发板主芯片RAM大小:64KB% f( I+ q6 v) H0 r' l( [) a
6 m( X/ o+ B4 b2 L
x O; ^- N/ q1 A
; h3 u: Z0 ^ T3 s: A0 P% v# Q- V
+ U$ W. s; R3 p T0 {
~! a. u( a f9 V* m
# p' @/ l& r0 m; C1 K. d# C- \2、LED灯资源
1 | Z( L1 @! q+ Z5 T6 Y(1) STM32L431RCT6开发板共5个LED灯资源,其中一个红色LED为系统指示灯,指示开发板供电系统是否正常,如供电系统正常,红色LED为上电常亮状态,硬件原理图如下图所示:
0 X/ J" h! q" D
9 S0 l/ r6 b: i2 p! `
/ |5 A' R4 o- \% _2 P
* k2 k- d. o5 i(2)其他四个LED灯为黄绿色可控LED,高电平点亮、低电平熄灭,计划用LED常亮验证看门狗的作用,硬件原理图如下图所示:
7 z. l+ y. t4 a$ F9 {; R/ s7 ~# y* F2 |( n( S% H5 S
f/ Y* Z9 h. L
: m, t9 B& q5 m/ w" R3 }
3 T8 {) P/ u- ?3 ^" J: n% e3、串口DMA收发工作原理
! M, e' ]7 Z1 O) F9 b+ q 串口全称为串行通讯接口,即数据在通信线上一次传输一位,按先后一定顺序传输。我们通常所说的单片机串口准确来说应该是串行异步收发传输器(Universal Asynchronous Receiver/Transmitter,UART),使用TTL电平,串口需要RXD、TXD、GND三根线进行通信。5 M7 g7 t$ A% b7 D8 U% p
/ p$ ? a, @1 Q. F u# j (1)最常用的RS485收发换向方法是程序换向,即由MCU的一个I/O端口控制RS485收发器件的收发使能引脚,在平时使RS485收发器件处于接收状态
8 i& Q, ?9 h- f( T* Y) D" ?
2 X% ]4 e8 ~- P (2)我们选用的STM32L431RCT6开发板串口2作为RS485通信的串口,PA1作为RS485串口收发的使能控制引脚。
( g# |$ e. _- l( J' b7 W
8 n# }. h# Z5 c (3)RS485端口使用时,需要使用USB转485模块和开发板进行通信,使用方法为USB转485模块的A接开发板的A,USB转485模块的B接开发的B,GND可不接。
0 b% x6 I* ~9 X2 v$ T6 z, u, W* t) E1 a6 a5 C9 Y
RS485串口,硬件原理图如下所示:
8 l0 d% S+ M. R
: _8 n6 V, Z% ~3 _
! g) U! w+ p7 O; [9 {( Z: f: F( h% K9 }8 N! f5 P- ]
: K, @" F- F. i5 `. h
5 |0 ^& Y$ S! t: N7 JDMA(Direct Memory Access) :直接存储器存取,是单片机的一个外设,它的主要功能是用来搬数据,但是不需要占用 CPU,即在传输数据的时候, CPU 可以干其他的事情,好像是多线程一样。数据传输支持从外设到存储器或者存储器到存储器,这里的存储器可以是 SRAM 或者是 FLASH。: M: g, f/ c0 g8 o) @
, ?* H/ _. x8 @; a
DMA 控制器包含了 DMA1 和 DMA2,其中 DMA1 有 7 个通道, DMA2 有 5 个通道,这里的通道可以理解为传输数据的一种管道。要注意的是 DMA2 只存在于大容量的单片机中。1 ]6 ]6 t) K3 K* b p z( d
* G" M" x5 Q! t% C' {# H) t ?/ C1 a
! ^5 M; C8 z- X' |( F
1 F$ }$ y9 N# \+ D' e& f6 g* L 二、串口DMA收发实验过程
8 f1 s* k/ _6 j0 Y2 N1、新建STM32CubeMX基础工程
+ J, x* _. Y, V) P(1)打开STM32CubeMX,点击“File”-->"New Project"
5 J9 `& p& R' ~9 [4 z% A3 `( H ^
8 g1 k% q2 t( n; R5 Q2 H
+ g6 v, [/ K6 D(2)等待打开主芯片选项界面(大约1分钟时间)。
; H6 {; G* D; W4 g2 K- L$ ~9 ]$ Z: U' @; W' x6 d
9 T* i) _. `: V% a5 ~
F' o/ g5 J2 C* C. _3 ~(3)昨天搜索框中输入(或选择)所需的主芯片型号(因为我们用的是STM32L431RCT6开发板,所以此处选择STM32L431RC),然后在右下角选择STM32L431RCTx(因为开发板主芯片是STM32L431RCT6),左键双击即可打开新建的项目。3 O* M1 T6 N- L% s# K! q5 w$ e
' p- }+ a' W; r$ `9 O9 o% b+ k
6 m: i. d2 z, U: ]) n) `8 v3 s ?% I
) P& u4 ~1 Z% e8 ? p! h) J4 M9 j/ {% I) S6 |
(4)选择时钟源。
- F" ]) I' D% I; V" _ 因为开发板上有8M外部时钟,硬件原理图如下所示,所以此处选择使用外部高速时钟(HSE)。
n1 X1 ^1 g( s; o& c
! {+ ?6 T' H/ |# P
8 ?# E; C2 c8 b/ {9 l$ S2 Z5 Q
% y3 q5 }/ R5 r! J" B
因为我们没有用到外部低速时钟(LSE),此处不做处理,如下图所示。
3 F' i# s2 @6 F1 {0 z2 O; [+ r* d0 x, u3 A; O4 \+ q0 v
7 u$ n9 W8 S. N0 c h: V3 t4 h( n
% |2 L4 i) [+ D7 k% Q# d: w2、配置GPIO控制LED
8 f0 Q* y6 t" I; h7 |6 g$ g/ L(1)查开发板原理图得,LED1、LED2、LED3、LED4的控制引脚分别为:( C* @. D o0 a
LED1——PC0
7 B# t1 q( D$ y, Z$ e5 pLED2——PC1
6 D1 y- C8 Y& R: _LED3——PC2
% f$ M0 C3 f! T7 I( ULED4——PC3
& ]' T R/ E9 V5 X! g# u- f. ]7 u/ R r; `* ~8 c7 W7 t/ W
(2)配置LED的控制引脚为输出,输出频率、输出方式默认即可。, @- [$ ?) b5 n) S) q' }
鼠标左键点击PC0,选择“GPIO_Output”,表示设置该引脚为输出模式。
( q. {' s; x4 ?) L4 Y- x鼠标左键点击PC1,选择“GPIO_Output”,表示设置该引脚为输出模式。
1 K% T, x' V. L8 x1 D: j& Q鼠标左键点击PC2,选择“GPIO_Output”,表示设置该引脚为输出模式。' a- m. C. q( x6 I# ?
鼠标左键点击PC3,选择“GPIO_Output”,表示设置该引脚为输出模式。
9 _! |" Z* E/ P" o. W5 t/ L. M) c! }7 E2 \- W# O
' n7 T L! e% J" q" X3 ?
7 I3 ~' ^$ p7 O9 ^2 N* j. F0 g; M
$ J* v* i. f6 ?, u2 r$ K D9 J/ D4 Z
, F3 q1 r5 V* h
(3)也根据自己的需求配置GPIO的参数,如输出方式、输出频率、上拉下拉等。因为GPIO控制LED的要求比较低,此处采用默认参数即可,不用修改。* x; g6 v+ I# z( a
# u1 v6 p( ?0 F
+ K D8 \3 j5 p0 X {! p/ f6 d* l5 p4 R1 K P7 f5 Q
3、配置PA2、PA3为串口( u" t3 Y) V9 W2 @
(1)查原理图得知,串口2使用STM32L431RCT6引脚为PA2-USART2_TX,PA3-USART2_RX,引脚设置如下:
& \ o% l% p/ o) Q. i
; o% @- A) \1 ^: \# N5 P. r! s
' ^" g" [7 T$ ]/ u$ a) |8 ?- v
" j8 @" V- R/ ]/ Y* N# F; V
串口参数默认即可:波特率115200-N-8-1,并使能收发控制引脚。
3 r0 G J" m( A* \4 a5 v2 S. a$ ?9 e: ?) h0 f
: U4 v( d6 ~* G6 m1 R0 ^4 Y/ z0 {1 k5 N
(2)设置NVIC settings 使能接收中断。
0 } c: ?5 g- I& P% q; N' B& q5 @# A' A- y; N V J
6 Q' c& ~% `5 m6 R6 P! J1 U: N6 j
8 E3 h3 [2 c0 m t) B: E! X% R3、串口DMA设置 ' `2 {/ v: y6 k5 f' P. J! ~( A
. g! `! F0 W2 l! l
, L9 k9 o! }2 [
q2 T5 p: G7 G2 d: t
(1)根据DMA1通道预览可以得出,我们用的串口2的TX、RX分别为通道6、通道7:/ F9 m* T0 L r7 i# k- x8 N, U( `
点击DMASettings 点击 Add 添加通道3 c1 P) ?" y( E9 M* `
选择USART_RX USART_TX 传输速率设置为中速
& l. D2 f0 O1 VDMA传输模式为正常模式,即发送一次就结束。
7 w3 Z" P5 @& G7 _2 H; eDMA内存地址自增,每次增加一个Byte(字节)4 w- C4 h. _9 N3 g
8 }& F: F3 K9 i
) i8 M$ V- X: a/ ^4 W( [+ {
% R0 q; {4 r8 Z# ?; F) V4 ?) e (2)DMA相关参数解析& j. g, Z1 v$ ?( M" e5 z
Dirction : DMA传输方向有四类' e' p1 r$ W0 n. \9 k
外设到内存 Peripheral To Memory, b+ ~7 g% w8 u. k1 n
内存到外设 Memory To Peripheral' z0 A2 v0 W1 ?2 P# w; w
内存到内存 Memory To Memory
0 U. X% W4 {# y" c外设到外设 Peripheral To Peripheral& h/ f# o, {/ J8 @
: M1 m2 [8 Z4 `2 P
Priority: DMA通信传输速度有四类+ G$ V- [6 U8 A4 u
最高优先级 Very Hight
& U" ^7 p, J! U/ I( V# k高优先级 Hight9 @/ B& G2 X: c
中等优先级 Medium
1 @, O) E8 J- Z! c, f* e. @低优先级;Low+ {- e, a8 Z6 j2 O
8 L+ J) A+ Z( z9 B& G- ~Mode:DMA传输模式有两类
8 U; C4 v3 Z' [
5 R( b1 A+ ^3 ^: H- @
5 U( K* R; r7 H
4 J! ]! {! Z- ~9 y, f% V
Normal正常模式:当一次DMA数据传输完后,停止DMA传送 ,也就是只传输一次。- a$ c0 e: X' m( ~ s F
Circle循环模式:传输完成后又重新开始继续传输,不断循环永不停止。
* r# c7 d1 K7 B9 `3 z0 Z
2 D# h$ @" t5 J) d+ k) vIncrement Address-DMA指针递增设置:( p1 C+ w0 \' o
/ G' b* U$ a& u* R" V
$ m- ?$ n- X, y" S4 N
% D5 R% f' P* c; f, s# s' w
2 m. _ z( D8 ]+ M8 U9 F4、配置项目工程参数; ]" A# _$ v& S Y% x2 E5 s
(1)配置时钟树,用于系统内部时钟,以及各个外设时钟等。此处选择外部8M晶振作为主时钟频率,内部最大倍频80MHz。0 x6 r5 ^; m& s; c: u d
) ~% c) v! Z+ d6 D q- l
2 `; \/ e$ }' {2 F7 s- B
! g& q1 I2 F9 o# b(2)完成配置工程。
( Z: t. l4 ~& x: Y( O9 a备注:需要注意代码生成过程中的继承关系,如图所示:需要保留开发者自己编写的代码时,请根据配置设置,不然生成代码后会删除自己编写的代码(从这个方面也可以看出开发者备份自己的代码是多么的重要。)
9 Q$ k; @- ^. x; R- y! p" ^# \3 v
: F3 M! i" {8 ?' h
2 b! J8 V& n0 o9 k7 |
0 w) h S# a& O9 v" _5 X
+ B% ?" ?& Q7 O5 K
( r* C) ~9 f4 `" J
(3)生成代码。
6 b9 R. u, r D* b) i9 m" w8 g备注:使用Generate CODE生成工程代码前,请确保文件路径无中文,否则会生成项目失败。! U* s9 M+ F. }# v- F
9 p3 J" S: Q- l$ X: g& F9 U
, m' W7 G+ q) H* q# s. H [- p+ o5 t$ A1 K) P Q, n. O; n
(4)工程代码生成成功。
# p" A/ o: _& |, |1 P- E3 J1 G, P6 h& s/ U0 a! B
% s% n( L+ G! D
; e) ?5 L- w% j4 W+ w
. U n, a/ I* P$ [ 三、在KEIL 5中编写代码/ g- W% w6 |5 y: Y; j% R
1、使用KEIL 5(MDK)打开项目工程文件
) o" t( _. ^6 A7 P8 h- Y# I源码使用说明:使用前必须把项目工程复制到无中文路径的文件夹下使用。
# C& A" q& e, F, \7 B/ c: X) n) h# w
(1)找到刚才新建工程的存储路径,安装项目名称,打开项目工程.uvprojx。8 k6 c# z% G- l; ]4 [0 l
/ a! u" y; ]' F8 l, p
# A& _8 ^0 ^4 T% r. { A7 ~1 b
0 N N/ V$ F5 h- s5 i+ g
2、添加LED指示灯作为系统提示
. A( \" w O2 A* n添加每隔100ms,LED1、LED2、LED3、LED4闪烁一次的系统提示,用于提示程序运行正常。
$ {5 I$ K4 X" B( N3 i* z; }5 P7 o3 g' m* j z& i, Z. R9 u5 k9 A* U) g
; L/ O$ v) `; D! r
# f4 R/ ]; P+ y; j) V5 D7 L
3、添加HAL库UART DMA 发送函数代码
6 e5 }& g" s# b+ g$ ]& _(1)STM32 HAL函数库的串口DMA相关函数如下:9 n) W; s& s: M% ^
- HAL_UART_Transmit();串口发送数据,使用超时管理机制
( o. N9 E# l6 P' k - HAL_UART_Receive();串口接收数据,使用超时管理机制5 i# q9 N* B1 }2 | C/ g a
- HAL_UART_Transmit_IT();串口中断模式发送
/ R o v0 b' Z% M. |* j! n - HAL_UART_Receive_IT();串口中断模式接收6 b* |) y8 A: Q
- HAL_UART_Transmit_DMA();串口DMA模式发送
" x7 @0 b& h5 }6 X - HAL_UART_Transmit_DMA();串口DMA模式接收
1 \* x" J: H! h8 O% b9 \( q% h - HAL_UART_DMAPause() 暂停串口DMA
+ v% _6 G/ v1 T/ A - HAL_UART_DMAResume(); 恢复串口DMA
: U6 L( X8 i2 C( \ ~9 r, T4 o - HAL_UART_DMAStop(); 结束串口DMA
复制代码 ; X5 }2 R# d9 U/ I
(2)main.c添加RS485发送函数相关代码:/ L$ Q/ A& t4 }
7 B# s0 i, |1 W% J+ }
3 P- G) p) X# o+ u7 Y+ g. p9 q
- /* USER CODE BEGIN 0 */' D! M0 R0 v/ z* Q
- uart_rx_struct uart_rx_struct_t= {0}; //串口接收数组
2 Y! b, ^& O9 c, | - uart_rx_struct uart2_rx_struct_t= {0}; //RS485串口接收数组 ^. L4 e# g+ F
- /*******************************************
( Y2 S3 m8 z: u. B - *函数名:DMA_Usart_Send: n+ S7 b9 ?3 X7 Z
- *功能说明: 串口发送功能函数
$ i6 y. Q4 s; b' Q - *形 参: buf,len& [- b# @% W4 Z! M5 {8 v7 A" A0 P
- *返 回 值: 无1 j$ k |$ o: M' I$ _( @
- ********************************************/4 C+ O6 C/ _7 b# G: m3 Q! U$ a
-
! a) Z( t) g3 f - void DMA_Usart2_Send(uint8_t *buf,uint8_t len)
6 u5 ]$ S: W8 V! h* p' ]/ k2 X W - {- D! f) ~! B9 `/ {
- HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_SET); //设置485为发送状态
1 E3 u5 L, W, K+ D - if(HAL_UART_Transmit_DMA(&huart2, buf,len)!= HAL_OK) //判断是否发送正常,如果出现异常则进入异常中断函敿 }/ r. d C6 j W% E; i
- {3 \. h* W; d" b7 j4 y9 x6 ~
- Error_Handler(); //异常提醒
4 c# _9 Y9 I0 T - }0 Q9 i" W& j. E
- HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_RESET); //设置485为接收状态
. h- ]3 L: g2 f { - }4 ^4 e1 ]/ F2 i5 c
-
) n; r2 ^# @2 U7 s - /* USER CODE END 0 */
复制代码
6 b8 v0 K6 \0 n% F; v1 K8 U1 C" A(3)main.c文件中添加main函数的处理,上电初始化打印一次log,然后等待接收,等串口收到数据后从原串口发出。( l% k! x- h' y
* c5 X- z' t" c' j+ O
8 `# V# u3 D7 j0 \: w) u4 F2 f. S1 E b% U) @% n
/ Q$ H0 q2 p; a7 l. @
9 D- E& [+ ^" N7 G5 Y
+ v2 t% e& D0 [6 w& X1 Y
! W4 y6 J; r' O4 g) w+ w, x
: P" ^% a; x: {7 h w
- int main(void)/ F0 C. P5 A8 ~0 t) d0 s/ I" f% e
- {
( j5 g. V5 O# F1 y- L" s' J$ U# m( a$ B - /* USER CODE BEGIN 1 */1 ~1 {. W* t6 a3 y/ D9 @" y
- uint8_t transmit_str[50]= {"hello world,this is uart dma function!\r\n"};( g) T$ `1 ]6 O* M. R) [) F- J2 T
- uint8_t rs485_str[50]= {"hello world,this is uart2 dma function!\r\n"};; @9 q9 t% g' h3 Z0 W! p
- /* USER CODE END 1 */
" a0 @2 f4 _$ ^1 o0 Y - , X! i4 M) l1 I& E) Z' m% M
- /* MCU Configuration--------------------------------------------------------*/ U9 L; Y* Q( f) P6 x# i
- ; ?( N: N8 P' J- F1 l* N
- /* Reset of all peripherals, Initializes the Flash interface and the Systick. */, R5 @2 W) h4 d
- HAL_Init();, Z! i5 U% C) g5 F3 K1 [9 v
- 2 Y% D4 G( D# T- T2 R( |4 a
- /* USER CODE BEGIN Init */
5 m. W3 }2 ^$ h) _ - 3 e8 \3 \/ d/ V
- /* USER CODE END Init */
2 q" W+ d5 M2 P! ?. p -
( E# h) W Z& W: x% M" Y - /* Configure the system clock */, d' d2 c5 j( l" _ E: Q2 {" Z5 T
- SystemClock_Config();8 _: s% M5 P! m( N H
-
: _8 Z! Y- F0 S9 U( m! ] m - /* USER CODE BEGIN SysInit */
; _. K& T( G( C% {+ x4 Z2 V - & |- { ~; E" r" K+ O. @+ y
- /* USER CODE END SysInit */8 k. g l. V+ ^ D4 o0 C
-
- {* @& g' C" A, f+ u/ w% E - /* Initialize all configured peripherals */
. P+ Q. C+ e7 I, ?! H* Q - MX_GPIO_Init();5 m2 I% N% n" T" V: c+ b
- MX_DMA_Init();- @- q% e9 {- M9 N
- MX_USART1_UART_Init();7 z9 I. V/ }0 J$ `; `0 A
- MX_USART2_UART_Init();1 z2 M' p- o5 Y4 N$ H! @
- /* USER CODE BEGIN 2 */0 u2 \$ Y6 ^ R. B# E1 D% _
- HAL_GPIO_WritePin(GPIOC,GPIO_PIN_0,GPIO_PIN_SET); //初始化LED灯,默认点亮# S+ T2 a9 R% D( A# q5 A
- HAL_GPIO_WritePin(GPIOC,GPIO_PIN_1,GPIO_PIN_SET); //初始化LED灯,默认点亮0 X3 H* w7 z; D- F- d* A
- HAL_GPIO_WritePin(GPIOC,GPIO_PIN_2,GPIO_PIN_SET); //初始化LED灯,默认点亮
1 a% C- S' W0 _/ C, h2 g$ L Y - HAL_GPIO_WritePin(GPIOC,GPIO_PIN_3,GPIO_PIN_SET); //初始化LED灯,默认点亮
- j' j1 e- ]5 W* w. r - HAL_UART_Transmit_DMA(&huart1, (uint8_t*)transmit_str, sizeof(transmit_str));
. i- s2 R% @$ M* O7 l - DMA_Usart2_Send((uint8_t*)rs485_str, sizeof(rs485_str)); //初始化log提示
( K: z" L; p! ~( d+ s8 @ - HAL_Delay(5);
9 F8 e6 t$ A0 J - HAL_UART_Receive_DMA(&huart1, uart_rx_struct_t.uart_rx_buf, UART_RX_LEN); // 启动DMA接收; x: Z9 b3 Z3 T4 @- ]
- HAL_UART_Receive_DMA(&huart2, uart2_rx_struct_t.uart_rx_buf, UART_RX_LEN); // 启动DMA接收
& w7 `5 ~; [& o: f# X2 y -
6 h: p( M6 b& f8 @0 y5 e5 R* | - __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); // 使能空闲中断. V2 ? z3 [! i# |- o( E# W
- __HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE); // 使能空闲中断
/ F7 K7 n! V! ^# r - , o' f: ]3 c/ P/ B' W' {5 h
- /* USER CODE END 2 */" P1 I! Y p3 W! Z
-
s$ H' [2 S, d0 D - /* Infinite loop */
$ O8 n1 X5 Q- y! X( v: P7 O6 L* z - /* USER CODE BEGIN WHILE *// y; Y+ c, S' t- j3 s
- while (1)2 _8 m2 \8 y0 t, A _ z
- {
4 |" Z5 Y6 v( i0 }+ s9 s3 S - /* USER CODE END WHILE */
) C4 Y% M- {: I# R' Y$ A - ! J0 F4 |+ K3 S( ]& h3 V7 G* F
- /* USER CODE BEGIN 3 */: d4 h6 p( c4 N
- HAL_Delay(100);
! h: j( l& W- S - HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0); //反转LED点亮熄灭切换
: I6 f% D/ f" Q: j& F* z! X - HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_1); //反转LED点亮熄灭切换
6 U2 i7 Q2 v2 H* z) G - HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_2); //反转LED点亮熄灭切换
0 e1 K: Z5 e% v+ T* v0 n3 W/ ? - HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_3); //反转LED点亮熄灭切换) m, K, z1 b0 U5 S4 T
- if(uart_rx_struct_t.uart_rx_flag & 0X80) //DMA接收完成
$ U! g0 ^* `( L9 V. d0 u5 u& y* \ - {
' x$ n/ X, E0 y* p, W+ Y- F e! I - HAL_UART_Transmit_DMA(&huart1, uart_rx_struct_t.uart_rx_buf, uart_rx_struct_t.uart_len); // 将接收到的数据发送回去( @6 M3 J1 _' |0 Z! {0 }
- uart_rx_struct_t.uart_rx_flag = 0;
3 c" ~ H/ d) m1 T1 a1 i - }
! D4 E/ d% s( a( ]6 o8 ?0 D9 R - if(uart2_rx_struct_t.uart_rx_flag & 0X80) //RS485 串口DMA接收完成8 \2 c5 l N) O* b6 H
- {$ Z% ?; X+ I" [& t
- DMA_Usart2_Send((uint8_t*)uart2_rx_struct_t.uart_rx_buf, uart2_rx_struct_t.uart_len); //rs485发送
: |0 [$ p$ u) _- q! J: Y" U( _ - uart2_rx_struct_t.uart_rx_flag = 0;
) X$ i. C$ J+ U4 Y) t - }1 r( e( I2 ~6 C! z5 t9 s e# B" a
- - F5 [+ o1 h8 }- F
-
' d" i2 c- m; ?( P4 ^" i2 M - }
% h2 K$ M* M( _; m - /* USER CODE END 3 */
% j% ]; F5 l# `0 q T1 G( F* f6 I/ k N - }
复制代码
% Y+ L3 Q2 r; e$ h3 `$ M(3)main.h相关变量声明" L8 L8 E+ S3 t. k0 x
" Y1 d( a' }3 j( e$ B$ \2 Y
; p" B: y' E+ d$ M- u, @! J) H2 N! r( t+ h
- /* USER CODE BEGIN ET */
( i' j5 ]+ w* z4 @1 l - #define UART_RX_LEN 1024 // 一次最大接收的数据量' j8 R& _( c0 i" F6 P
- typedef struct
7 p: Q; v/ D/ k* I9 b - {+ i! Q) T; n& a0 p& [. |4 G( j
- uint8_t uart_rx_buf[UART_RX_LEN]; // DMA数据接收缓存数组 A- O- `2 |" b( M
- uint16_t uart_len; //DMA数据接收长度- O& Z4 P! E- N# |* C% l) _
- uint8_t uart_rx_flag; //接收完成标志位& K( ?3 m x+ i7 v$ w
- }uart_rx_struct;/ X# ?4 E" ?& T; }& r# t
- extern uart_rx_struct uart_rx_struct_t;
: C' m: n1 y! w2 a5 d" Q, i - extern uart_rx_struct uart2_rx_struct_t;
5 m" I" l) S! w - /* USER CODE END ET */
复制代码 % J. f a3 H( {, O
4、添加HAL库UART DMA 接收函数代码& F& z( h+ g) J* Q1 c# i1 H5 k
(1)DMA接收设置前铺垫知识点:
7 h. g, J. y+ s3 c4 Y& C8 q; H* F" d
5 f" K6 F' l6 W STM32的IDLE的中断产生条件:在串口无数据接收的情况下,不会产生,当清除IDLE标志位后,必须有接收到第一个数据后,才开始触发,一但接收的数据断流,没有接收到数据,即产生IDLE中断停止。
. Z$ U( l/ C8 k& Q P0 E2 T
! u) K* Q! W! I$ U(2)stm32f1xx_it.c中添加添加DMA接收处理代码:" L i5 q! J0 f- t+ n3 E
- void USART2_IRQHandler(void)" m$ N! K- a9 V6 k3 |) {6 O
- {
7 B8 Q# t) {* t6 H7 H" J+ Q - /* USER CODE BEGIN USART2_IRQn 0 */
! D# v$ b n5 W - if(__HAL_UART_GET_FLAG(&huart2, UART_FLAG_IDLE) != RESET) // 空闲中断标记被置使" f0 z8 P1 B& Y7 n% b/ I
- {
0 p8 e- G! s% P6 q! K+ o1 K - __HAL_UART_CLEAR_IDLEFLAG(&huart2); // 清除中断标记
( s9 i& U/ r* [/ E; w - HAL_UART_DMAStop(&huart2); // 停止DMA接收+ A* w9 C8 N! X
- uart2_rx_struct_t.uart_len = UART_RX_LEN - __HAL_DMA_GET_COUNTER(huart2.hdmarx); // 总数据量减去未接收到的数据量为已经接收到的数据量
$ @& [! _; g0 Z- c2 N% K; T7 Z - uart2_rx_struct_t.uart_rx_buf[uart2_rx_struct_t.uart_len] = 0; // 添加结束笿, W/ w& [, _( g; l" h
- uart2_rx_struct_t.uart_rx_flag |= 0x80; // 标记接收结束: S7 x; U: h x/ C- k
- HAL_UART_Receive_DMA(&huart2, uart2_rx_struct_t.uart_rx_buf, UART_RX_LEN); // 启动DMA接收
! ~+ D1 R& T X% d5 G -
/ g9 g I, C/ [( F: n - }- S0 t: \2 I" U2 R& b. v7 Z
- /* USER CODE END USART2_IRQn 0 */
) R( R/ M; |7 e1 @ {/ u/ F - HAL_UART_IRQHandler(&huart2);
) f3 q8 i$ Z( Z - /* USER CODE BEGIN USART2_IRQn 1 *// ~2 k& v' c7 b' D# A0 n) i
-
% e, w" U3 ?; E6 L, V - /* USER CODE END USART2_IRQn 1 */4 N4 ?9 M9 K9 F2 g( G ~
- }
复制代码
7 d& l' T5 g8 c4 i# _(3)至此,RS485串口DMA收发数据需要添加的代码已经完成。, t/ c+ `" J$ h0 z! O' M
2 b# {2 x9 h; ^0 E- u
; Q% W, V* n/ o& `& _
5、设置编程仿真下载模式5 A; q3 {0 A% B' |
(1)选择Options for target ...>>Debug>>J-Link/J-JTRACE Cortex,点击Settings>>选择Port(SW),可以看到搜索成功SW Device,表示芯片可用,可以下载。
& y2 {9 T0 ~. v) I
" P4 H3 }7 q5 H; V/ ?
3 R2 i& h: t4 a( o6 X
3 V5 w# S9 p0 X# g% _# i( o(2)点击编译,完成后提示“0 error(s),0 warning(s)”。8 U& [1 m" t" L8 h: r' n$ Q* j4 L
: ~# ~! z ?' f: [
( g( T1 l/ K' a4 h+ D3 m( G9 Z
, J0 N5 a" X& v1 i8 W
(3)点击Download(或者快捷键F8),即可下载程序。
- X- m0 z* |2 C% D9 _/ J, P4 t5 v' _( t7 i' Q
3 h4 N' C7 [) @/ \/ s
8 _/ g4 O: ?4 h( c2 D(4) 如果下载程序后,没有看到LED1、LED2、LED3、LED4闪烁,可以按下述方式设置一下(Reset and run表示下载后自动复位和重启运行)。或者重新彻底断电再次上电(或按开发板的Reset按键复位MCU即可)。
4 q' n4 K6 ]& ^' y4 l$ e+ W7 i/ P" M# w" w
8 P2 M0 M" T4 u# u8 n2 G( {
4 s- ^7 O+ H% n, u
6、串口DMA收发实验效果展示
8 O9 {; B. L; Z* I0 G+ v r 程序烧录到开发板后,即可看到LED1、LED2、LED3、LED4初始化后每隔100ms闪烁一次,并且打开串口助手后(串口参数:波特率115200、N、8、1),通过串口助手可以看到,开发板接收到发送的数据转发出来。) n: a+ u7 Y! j" r* |' r; B2 ]2 x
: ]& l# L" A& X+ A
* H4 M2 P2 T N) E6 K% i' Q& l
% P5 C, [8 w8 R% }6 d) w0 _————————————————2 H. E8 R7 D" v5 {0 Y- y$ X
版权声明:智能小屋ZYXC
B. {/ H6 L* K4 |6 s2 H- D6 W7 x: o. e! B9 c: Y" H# R
4 p9 W8 j5 d3 H+ f; T- j; }1 b) n
|