1.配置系统下载程序方式
- _3 U: \9 `6 f- m# v E6 _2 y0 o* m7 l% ~6 R8 B
, a: z: S# e! \3 I5 _# \6 a, V4 L! c( }1 d
2.RCC外部晶振
$ N2 o. n8 ?6 J& u. \) y; d# x D& k. C- |% D+ W$ n4 ~
4 I+ N& {" W, o- ^- n' z: V# J
, u/ z/ P4 T2 \/ e& Q1 m
3.串口声明
* |" J8 V2 X5 E! }( J% Q! r4 t3 N; S- k
" [* I% K+ L. M! M! a3 m2 n3 }4 `. K+ u4 t* j
- @) z) D# j( o
4 _- f5 s1 I: e2 T! P: ~8 I0 \0 b, V
9 `, g, L- q* }7 i7 q+ S- ]6 \; H( J
4.系统时钟- y2 I# ?$ }+ ^1 p& X A9 i* n
" o: q1 U$ u' w8 _. q a% {7 R" E, Z3 n3 z0 I- u
; |. f2 ?, ^, M
5.生成文件根据自己需求配置
; T1 A# z) T: H% h8 L- Y& w
, J2 |6 ]' {2 h, M# G& p$ H: N( O# R! b& I3 P/ U
1 F( J* o8 x' n Z. `
我这设置了所有库,可以选第二个仅需求的& `. e- C6 Q- ?* B8 w6 j# n3 Z% M
5 n8 z' |' x6 p4 p4 i: h
7 c. }2 Q! ]+ G2 P) E0 v2 w7 G, J
% e$ d# J D5 }9 G9 M 还加了其他功能,这里可不参考,DMA要放在串口前
: r% R/ n: {# r
$ G' ]. s8 ~! Q: A/ b% {3 e, N( X1 h, v' Y* `- ]* G5 `
. w: J+ R2 e( `
6.生成后修改
4 c3 ]) R! F# Q% X3 y( k
0 F0 f9 b% ?5 ^' I }1 U6.1 usart.h5 L5 M& E" N; l- f: g1 {9 ]& c( M
9 k$ E* F0 x% S9 |. x' _: H; o
- /* USER CODE BEGIN Includes */
7 B; Q: _. X5 T) r4 b( R n - #include "stdio.h"" F: I0 ]- k5 Y# v
- #include "string.h"" X$ K' x: J2 |0 {. i* N
- /* USER CODE END Includes */
复制代码- /* USER CODE BEGIN Private defines *// ]4 F) V0 c7 i% h8 \
- ) h) t) l0 D0 o1 k i( t5 E9 W
- #define USART1_DMA_REC_SIE 256
1 g; x+ I' L9 r - #define USART1_REC_SIE 512# Y b# K) r7 c
- #define USART_DMA_SENDING 1//DMA发送
# u9 q+ ]& a* n7 ~, v6 n: R - #define USART_DMA_SENDOVER 0//DMA发送结束
' e/ \+ X4 Q: P y4 { - typedef struct
, O) X: M7 h$ M9 j& X6 x" A - {9 y! K& k; [# V5 B; l( A
- uint8_t UsartRecFlag:1;//接收标志
1 X( K) z% f. u8 J/ A/ ? - uint8_t dmaSend_flag;//发送标志
; e5 R& v ^0 C! v6 J: ~ - uint16_t UsartDMAReclen;//DMA接收长度
# y; y5 m7 B+ g% F* [, Q: t - uint16_t UsartReclen;//串口数据缓存长度
/ S' u( T; I; @# S0 T9 F3 X - uint8_t Usart1DMARecBuffer[USART1_DMA_REC_SIE];//DMAbuffer缓存数据
4 w( ?- p: W3 ? h6 E2 i4 a4 M7 a" W - uint8_t Usart1RecBuffer [USART1_REC_SIE] ;//串口1缓存数据
* `. L* a n# ^3 K6 E - }teUsart1type;
& c1 {' s, ~* q! W9 o
: j5 x. X. h8 r: Y; X8 v- extern teUsart1type Usart1type;//定义数据7 d6 C+ q2 Y* r. T' \" j
' j- x2 v. h$ n0 x: }; }- void UsartReceive_IDLE(UART_HandleTypeDef *huart);
0 n p! ?# e6 ?/ I- E: f, D; Y, H8 w6 X - void Usart1SendData_DMA1(uint8_t *pdata, uint16_t Length);& s8 k; F8 C' w* ]0 r5 c# `& k5 T
- void Analysis_Serial_Data(void);# ]* e2 E j. M6 w% ~" u. h
- void EnableUsart_IT(void);& Q9 p- k4 a0 C! ]8 ?. o- P7 G
- 0 ?: c U" e1 i* p! J
- /* USER CODE END Private defines */
复制代码 % m2 M% m# H' u8 P: Q2 a1 a1 K" l
6.2 usart.c,接收为双缓存方式,一般DMA接收放在,DMArec里,若不及时处理,下次接收会丢失,放入usartrec里,可避免,实现处理多少拿多少,dma接收的数据根据处理情况放入相应位置。6 t* n* \: T0 P6 [2 ]1 v, S
. k2 G: ^, c0 A* s- teUsart1type Usart1type;$ t( t7 g6 @: H7 p2 ^; ^7 h
- /*****************************************************************************
+ S8 E/ A' w5 R" @5 C/ a - * 函 数 名 : EnableUsart_IT8 \0 p" F% { K. A
- * 负 责 人 : by M A1 L3 M4 K- [9 ]% O& P
- * 创建日期 : 2020年8月26日
( e+ V( [% r, ?6 P4 r K - * 函数功能 : 串口2初始化函数,空闲与DMA中断
% u* l N$ U6 J" x0 s - * 输入参数 : 无
N: w- n, m" A3 r) E1 T - * 输出参数 : 无
& u3 ^* v6 z% \$ o6 s" ^, s - * 返 回 值 : * P5 D: j5 [6 i7 u$ e. y1 \
- * 调用关系 : 9 I( G6 ^) ?, \
- * 其 它 :
4 g: i3 }$ U% f) N0 U: B% v - *****************************************************************************/ }7 I. l3 E: a
- void EnableUsart_IT(void)) R2 Q U' m7 b6 s7 p
- { 2 M: v& h) {! ]" n* ?1 ]& L
- __HAL_UART_ENABLE_IT(&huart2,UART_IT_IDLE); // 开启串口2 空闲接收中断: |% w/ U( ~7 O0 g0 {% Q
- HAL_UART_Receive_DMA(&huart2, Usart1type.Usart1DMARecBuffer, USART1_DMA_REC_SIE);//DMA中断
7 C$ n- T. I9 z/ d' ~ - }6 b+ j5 S; p# k* P; r. R* f3 T4 d
- /*****************************************************************************( ^/ ]: j4 R% T* G- {& S
- * 函 数 名 : Usart1SendData_DMA$ O( p: \ E% G' q B3 `
- * 负 责 人 : by* e: r3 Y* H* L/ s/ G2 }
- * 创建日期 : 2020年8月26日
: S4 l/ n3 s+ v$ P9 D - * 函数功能 : 串口2DMA发送函数
" Z3 A2 Q W5 b5 o0 l$ L - * 输入参数 : 无; o% y. X; T$ E
- * 输出参数 : 无
1 a& m/ R7 A/ O8 v - * 返 回 值 : . s5 x5 ?5 i" ]1 n8 u4 t
- * 调用关系 :
3 o) }. Z4 M5 Q' c+ S6 E - * 其 它 : # c: @2 ^: N; L: n
- *****************************************************************************/
( b0 |8 Q. H# ]: E; }( o2 | - void Usart1SendData_DMA(uint8_t *pdata, uint16_t Length)
& [7 c7 Z& @- U$ {
+ b8 E2 X& I* a ~- {
; |6 T- E1 m! ]5 n) x - //while(Usart1type.dmaSend_flag == USART_DMA_SENDING);
! n- Q7 H% F$ K, z* \8 M2 i( h - Usart1type.dmaSend_flag = USART_DMA_SENDING;
; O1 e' p1 V) K7 ?0 Q3 s - HAL_UART_Transmit_DMA(&huart2, pdata, Length);
' D. M# x; L: V& [8 i5 e - } ) T. e4 ^" _! y/ E% X( l7 q4 O/ ?, i
- /*****************************************************************************
9 |, O9 ?, g/ [% `- z% B1 K - * 函 数 名 : HAL_UART_TxCpltCallback6 M+ E4 t$ o/ n
- * 负 责 人 : by
5 u& p+ R* ^4 R8 M5 @" g5 w - * 创建日期 : 2020年8月26日1 |$ ]0 y( ^# b: g9 i* i# w3 z2 H
- * 函数功能 : 串口2DMA发送回调函数
' n: h9 O9 j) _5 ~ - * 输入参数 : 无
% ?1 {: m7 o/ ]; g/ W6 @( W) y - * 输出参数 : 无
" V" ?% h% ?8 t - * 返 回 值 : & Z7 e/ V; t" t8 U1 {1 N
- * 调用关系 :
8 r( M3 J I2 W9 k5 p) Y5 n - * 其 它 : , f$ E/ ~5 Y% U! V9 D3 s& D5 i
- *****************************************************************************/# C( e8 m9 Z! `) H
- void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) 6 D0 ^5 U7 L# p( h4 h/ V" b
- {
k( u: C0 J# ~( O& `6 H - __HAL_DMA_DISABLE(huart->hdmatx);
+ ~2 ?4 Y9 ?& D - if(huart->Instance == huart2.Instance) 9 ?8 u" O9 ~& q9 }! ?
- Usart1type.dmaSend_flag = USART_DMA_SENDOVER;
& X/ _0 x$ \5 L$ o4 V2 j - } / K- O: P n3 x1 R% C& S$ K& ?
- /*****************************************************************************
" X* \5 B* M5 y5 g- ` - * 函 数 名 : UsartReceive_IDLE
/ M' `% o( m$ g. ?1 F7 V8 v" k5 N - * 负 责 人 : by
: f: w2 t4 @7 A. c% x; ~# } - * 创建日期 : 2020年8月27日
% q/ Q1 o+ W" `, p1 L K0 `5 g) Q - * 函数功能 : 串口接受空闲中断处理函数: Z: @+ l- u' G+ q0 ^: c6 Z7 z! Q
- * 输入参数 : UART_HandleTypeDef *huart 串口句柄
2 r5 N7 d; l6 ~' m1 A2 x: o3 U - * 输出参数 : 无$ w3 x7 `. o8 S4 e0 p
- * 返 回 值 :
, {% E0 S L% Y E3 \ J/ V2 e! B - * 调用关系 :DMA接收的数据缓存在USART接收中,释放DMA继续接收
+ P- m. |9 X, N4 H% E - * 其 它 : 8 n9 q$ e: o* W, c v* k- l
- *****************************************************************************/
+ U3 M( R3 g- v - void UsartReceive_IDLE(UART_HandleTypeDef *huart)- E& M0 ]) E' D. y6 j) ~9 Q
- {
3 n2 x$ {' I L9 k( W: } - if((__HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE) != RESET))
! B: x4 B( s) b `% s8 d. j" k - { / h- q: B2 V P( F) X9 z( F" i, h& I
- if(huart->Instance == huart2.Instance)//判断是否为串口2/ N4 p8 m3 t2 b4 D9 g
- {
; ~* K- v8 `2 @! d3 f! s - if(RESET != __HAL_UART_GET_FLAG(&huart2, UART_FLAG_IDLE)) //是否为空闲中断
3 H; j; t& ~ u$ l - {: b7 i4 {8 I- E% f$ @: L4 T
- __HAL_UART_CLEAR_IDLEFLAG(&huart2); //清除空闲中断
7 P& W5 X/ @' H$ g& z$ B7 X - HAL_UART_DMAStop(&huart2); //停止本次DMA传输0 b5 R2 X* P( f3 V, C; r
- Usart1type.UsartDMAReclen = USART1_DMA_REC_SIE - huart2.hdmarx->Instance->NDTR; //计算本次传输数据长度
$ M$ B( Y I/ ?; \ - if(Usart1type.UsartReclen>0)
% P) i1 B7 I8 C - {$ L0 P% t! q; a: i- ]+ E
- memcpy(&Usart1type.Usart1RecBuffer[Usart1type.UsartReclen], Usart1type.Usart1DMARecBuffer, Usart1type.UsartDMAReclen);
9 n! b7 P2 N3 o - Usart1type.UsartReclen+=Usart1type.UsartDMAReclen;; |1 f8 P$ R* H. k
- }
8 M* a& A3 o" L/ ^" _5 G, J+ a - else if(Usart1type.UsartReclen>USART1_REC_SIE)//如果串口接收数据溢出,从0开始记录
; E( N5 [4 f8 O1 J - {. E/ d, C. L& ]7 u
- Usart1type.UsartReclen=0;) N0 G, y6 l1 l
- }
: C% G- Y9 C+ Y0 [: J' @ - else
: j) c* i- G# p5 v& {1 a ^ - {
% R1 i& j) a" L3 H# r* a - memcpy(Usart1type.Usart1RecBuffer, Usart1type.Usart1DMARecBuffer,Usart1type.UsartDMAReclen);
# R8 `9 g7 O9 y" R* Q. X$ C4 n - Usart1type.UsartReclen=Usart1type.UsartDMAReclen;# t7 U3 u" Z& B* E4 C% X' x
- } 7 A4 u0 `) P# b4 W: D% @% T
- memset(Usart1type.Usart1DMARecBuffer, 0x00, sizeof(Usart1type.Usart1DMARecBuffer ));//DMA数据清零
7 J4 }7 k; i4 H: J v \' m! _ - Usart1type.UsartRecFlag=1;//空闲标志位置1/ l0 \+ g4 z1 m4 B0 c
- HAL_UART_Receive_DMA(&huart2, Usart1type.Usart1DMARecBuffer, USART1_DMA_REC_SIE);//重新打开DMA$ X* {6 J/ U+ ~% w' y
- }
8 ^( H& h" }& Y ^: z - }
* j3 w/ G) h+ N+ ~8 o% D - }
% t' N6 \; J* U) {6 l( [" E - }
! D# n0 u$ l. x, K8 @6 \ - /*****************************************************************************+ t3 w* s: q, S
- * 函 数 名 : Analysis_Serial_Data
0 Z* p' C6 p% P7 d$ j - * 负 责 人 : by+ V. o5 h) _: E g2 I, j% I
- * 创建日期 : 2020年8月26日6 ]) U3 Q2 j9 M$ k
- * 函数功能 : 串口接收数据直接打印
4 H! f" g2 E3 I - * 输入参数 : void 无
2 w0 d4 w; c! }7 w8 a - * 输出参数 : 无# _/ Z; h$ R4 u1 D Q( `$ `
- * 返 回 值 : void7 k+ Q' }6 p1 a) h5 _( ]8 J& I
- * 调用关系 :
1 \. X p, O& A: p4 ? - * 其 它 : ! ]3 v/ }& ~, _
- *****************************************************************************/' j& j% B% v, t& R7 W, B
- void Analysis_Serial_Data(void)
% }$ H* J! v- U* Q, Z0 {( x8 C - {5 t4 g" A# C3 y, M* ~1 Q
- if(Usart1type.UsartRecFlag)$ A' T* L" `+ J$ O/ u* B5 y
- { 1 K! d+ S# q. i1 z
- Usart1SendData_DMA(Usart1type.Usart1RecBuffer,Usart1type.UsartReclen); + m9 T. s1 |+ |. u
- Usart1type.UsartRecFlag=0;
$ k6 a* B9 K- [/ Y9 J, E( { - Usart1type.UsartReclen=0;//测试处理为将全部数据进行打印处理,若需解析,可将解析长度进行减少,多次处理
5 N* W8 F# E0 }, S% C$ A8 L% a - }$ ~, z6 b$ y! c7 d, T6 X, o
- }9 }0 ^; T- z3 i' i- l# f
- /*****************************************************************************
) i9 Z* r0 {- u: S - * 函 数 名 : fputc8 @" R) s V* l9 m5 e0 D
- * 负 责 人 : by9 V( I# i. A* ?2 p; O4 Q/ P3 y
- * 创建日期 : 2020年8月26日8 A" e1 p6 W' f( M4 `5 Y
- * 函数功能 : 串口2 printf重定义
. C( m8 X0 l6 c9 B- A - * 输入参数 : printf(d%/s%/%c,a)
; w& n4 s [, V7 M: \& a - * 输出参数 : 无
8 E/ b8 e4 O5 f s' D; t1 j - * 返 回 值 : 6 R! A! H# p% q# E t0 ~- v9 R
- * 调用关系 :
, d! R5 W6 G, Z( }: X: d - * 其 它 : : F. s. G' N% ]7 K5 Z4 _
- *****************************************************************************/
2 }, B& F! ~/ r% R0 A# y - #ifdef __GNUC__
+ z/ s3 D z5 T- Q3 X
% V. Y) J; R- f3 W' w9 k! Z- /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
" `9 x- F Y$ V2 Y - set to 'Yes') calls __io_putchar() */
1 I! @ w; X. h9 K- N: C3 b& z - #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
3 w) _5 w) |9 r4 d4 n - #else
" }7 c( i- S$ f" l4 F: j - 9 m1 W7 A' q/ T$ @4 ]
- #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
8 z) t) y" o: a1 y, M - #endif /* __GNUC__ */2 H! p! \! n# n7 p
- # P; P8 r& S/ J( K7 j E
- PUTCHAR_PROTOTYPE
: t4 ~0 ]5 _/ j$ x - {* y8 s* ]9 Y* N: y4 J
- HAL_UART_Transmit(&huart2,(uint8_t *)&ch, 1, 0xFFFF);4 l$ o, V* Z. u0 Z
- return ch;
! B+ S% P, I6 P4 K* Q' }2 h - }
! p0 p. V0 W9 x3 |; y: Q( h" S
4 P9 f! d% P$ M* L% y. J- ; R: f1 h! e! x0 N9 `0 h, s* L& m
- /* USER CODE END 1 */1 ?9 V) r& N! H& D
- DMA发送函数,网上给的教程while是用来保证DMA收发节奏的,节奏错误会出现死循环情况,给注释掉了。。。。" z" Q1 B6 _6 V
: U. ~* `+ P/ a, B6 m* N9 }- //while(Usart1type.dmaSend_flag == USART_DMA_SENDING); / W1 l, K( a2 G
- Usart1type.dmaSend_flag = USART_DMA_SENDING;
复制代码
/ p- t D. r; ~# q$ B3 }0 V" r6 J
$ c: `& e$ U* A. W( t: ~9 G6.3 主函数,只用DMA通讯只需添加EnableUsart_IT();/*串口初始化*/,即可,对应usart.c里的函数- /* USER CODE BEGIN 2 *// Z# L$ O% {4 T8 I) ]; o! `
- HAL_TIM_Base_Start_IT(&htim3);/*使能定时器3中断***/
& C' b# X, T% z - HAL_TIM_Base_Start_IT(&htim2);/*使能定时器2中断*/
& c9 g7 J8 G4 W$ E4 }6 C - HAL_CAN_Start(&hcan1);/*can初始化*/
- p( V v8 t. J7 e1 Y5 N - HAL_CAN_ActivateNotification(&hcan1,CAN_IT_RX_FIFO0_MSG_PENDING);
9 T3 S t0 x& I+ F3 S$ [ - EnableUsart_IT();/*串口初始化*/7 K- ~. J O6 \' a+ C8 C/ ?
- CAN_User_Init(&hcan1);
0 J$ b3 j! z6 J$ |& T$ q0 D) C - /* USER CODE END 2 */
复制代码
! z* T9 D+ c& m2 t" {& N% _ 循环,对应数据输出1 t/ d# v6 A0 V% @! j
3 p! H7 f5 A6 Z2 u' u0 f
- /* USER CODE BEGIN WHILE */6 H* P6 W' j1 s7 x# _. c1 a9 m
- while (1)& p% D+ |7 V! n# j8 }2 y" r
- { + S% b% a1 m- A4 }1 U! G) D
- Analysis_Serial_Data(); P6 Q+ k4 F4 D& {( `+ u8 n4 r: R
- /* USER CODE END WHILE */4 O/ p& X% n4 D) ?* p
% v7 x4 `1 d5 ^; B# u9 N- /* USER CODE BEGIN 3 */5 D- Z5 e: @8 x( }
- }5 k. `5 G* S$ l4 |3 E! B( M: X
- /* USER CODE END 3 */6 U6 P6 y% \! O1 r; u* q _
- }0 p+ s' j1 k- L+ J1 Y2 y
- 7
复制代码
/ a; L9 `/ `! x2 r/ `、实验结果,间隔10ms,连续发送,未出现丢帧,或其他错误
. u: S0 X* D# t3 M- x$ `7 H3 d4 c3 i+ `: a+ B; N+ [2 m
% @7 b K" B; r' ?; R L
8 p, i/ N' K6 Q9 `- t8 {
0 h/ [: e% y( {: ]& ^! j9 V |