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