HAL驱动的串口编程陷阱
a" a+ U- D9 G! _, ]# |
' e, ?" K+ ?: Y3 Q7 N$ CSTM32远程升级(基于串口本地升级与WiFi通信远程升级)
9 V0 S/ a0 m! A, O5 e
# H2 ]: }/ P0 j6 U0 u2 T9 d0 _- j8 G+ _% b8 Y" I" I
& p& Z/ M- \; F: z
串口是嵌入式开发中最常前的外设设备,既可以用作不同单片机之间的通信,也可以用作在STM32 MCU和PC机之间的通信,STM32F407的串口功能非常强大,可以接红外,可以接流控,也可以接SIM卡接口,但我这里只介绍我们最常用的UART通信的一点调试经验,以STM32F407为例,对其它STM32芯片也适用,希望对大家有所帮助,如有错误不当之处欢迎大家联系指正。
m$ p1 F! l7 C1 J! I& w" \
: B$ n' u5 N3 b) p$ v% I一、串口的三种工作方式8 K9 G8 \. O6 ?+ ]- m, l3 m1 Z
操作串口一般有两种方式:查询和中断;STM32还支持第三种DMA方式。( p! _7 z1 g( _0 M8 ]
(1)查询:串口程序不断地循环查询标志,看看当前有没有数据要它传送或接收。如果有的话进行相应的写操作和读操作进行传送或接收数据。
- }& Y* b# g' S- T. h(2)中断:平时串口只要打开中断即可。如果发现有一个中断来,则意味着有数据需要接收(接收中断)或数据已经发送完成(发送中断)。5 N0 L$ w4 R% H H8 f+ k
(3)DMA方式,设置好DMA工作方式,由DMA来自动接收或发送数据。
/ e$ f) J2 ^& f) v3 R一般来说,查询方式的效率是比较低的,并且由于STM32的UART硬件上没有FIFO,如果程序功能比较多,查询不及时的话很容易出现数据丢失的现象, 故实际项目中这种方式用的并不多。
+ }8 @" x7 }3 w- w7 n4 q* Q2 {中断方式的话我们可以分别设置接收中断和发送中断,当串口有数据需要接收时才进入中断程序进行读读操,这种方式占用CPU资源比较少,实际项目中比较常用,但需要注意中断程序不要太复杂使执行时间太长,如果执行时间超过一个字符的时间的话也会出现数据丢失的现象,这个波特率比较高的串口编程中比较容易出现,可以考虑用循环BUF方法,在中断程序中只负责实时地接收实数数和发送时的填数(写发送寄存器),其它操作放在中断外处理。
% S) m& [2 `. F" n1 a. h1 ]; p9 tSTM32还提供了第三种DMA方式用来支持高速地串口传输。这种方式只要设置好接收和发送缓冲位置,可以由DMA来自动接收和发送数据,这可以最小化占用CPU时间。
$ Y: q; O1 k: R% X
1 ~. i- L9 n# F, d5 o+ ~二、串口的使用步骤: Y( H' @3 T" [
(1)中断方式8 W" X7 q5 r( I! ~/ k; B$ |
基本步骤是初试化时钟,脚位、波特率设置、安装中断服务程序、开中断等,参考代码如下:
# R& a8 Z4 }$ e# g1 |0 x) V4 o5 I2 b) ?9 d( m
- void uart_init(void)
7 Q, d& {9 z( ~3 H g! Y, R - {; i3 o, D5 E/ T' F
- USART_InitTypeDef USART_InitStructure;
8 j4 n) z7 ~3 L' Q - NVIC_InitTypeDef NVIC_InitStructure;
/ R& ]* \) R+ d0 u+ s! z7 [1 P5 h - GPIO_InitTypeDef GPIO_InitStructure;1 R/ v. H& C; k* K
- : Z& \: p% Y# W; Z/ b7 y$ _
- /* Enable GPIO clock */
, [- B- l6 i( X7 a- |) j( q0 ~) Q - RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);2 l& t8 B5 T% ], b7 U4 O3 G" N2 \
-
3 f' @5 W$ N* o# o) ]2 K; B* }2 ? - /* Enable USART clock */4 P$ b7 n/ C. @9 s) E) z& K, p0 i5 A
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
: |' V1 ]% T) ^6 b2 ^ - / L8 ]* h! k2 i. O# p
- /* Connect USART pins to AF7 */
1 b3 w- @0 Z+ g; J% V - GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_USART3);
! E& N" B7 p, {9 v/ j - GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_USART3);: d' ^8 j; t1 I6 @! X$ c* T+ V
- , u: J. w6 F3 B8 ?# U3 z
- /* Configure USART Tx and Rx as alternate function push-pull */
# ~9 p# S# j$ |6 h - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;5 i9 f& Q2 K/ r- b: M+ g4 U6 T
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
" }( w* n& g6 J* ?. B - GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
' y- E5 J" r2 c- R - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
5 E4 s* C: ^; A$ ^) A r: h r - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;9 ^- U+ P: z( Q, d! H' C
- GPIO_Init(GPIOC, &GPIO_InitStructure);
7 i1 r' ? w x5 L" P -
, N! j4 G0 i! d - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
* ]6 C9 k. `) n; q5 a$ a J - GPIO_Init(GPIOC, &GPIO_InitStructure);* ]: u* h) f( Z" W2 E* z
- /* USARTx configuration ----------------------------------------------------*/
" m! X% f5 B- X& P - /* USARTx configured as follow:
, Y8 V+ q& u/ y1 |4 f5 X7 V - - BaudRate = 3750000 baud
9 W9 D. P. s/ K8 y - - Maximum BaudRate that can be achieved when using the Oversampling by 8" E& I* d; J. b p
- is: (USART APB Clock / 8) 9 h: E; F8 S4 |; c, B4 [7 @' t
- Example:
4 I3 k/ |; e; i( Q - - (USART3 APB1 Clock / 8) = (30 MHz / 8) = 3750000 baud' \ `3 ]5 h2 h$ Q
- - (USART1 APB2 Clock / 8) = (60 MHz / 8) = 7500000 baud! h6 W/ t* D& M$ w! ?0 k5 `2 K
- - Maximum BaudRate that can be achieved when using the Oversampling by 16
: W( j) M2 L5 ?8 k - is: (USART APB Clock / 16) 0 U. u# \2 \9 x9 J+ V
- Example: (USART3 APB1 Clock / 16) = (30 MHz / 16) = 1875000 baud
( A ?9 S1 E' n( b, l+ e8 ] - Example: (USART1 APB2 Clock / 16) = (60 MHz / 16) = 3750000 baud
; q7 p3 s3 `. c; k8 w+ h$ | - - Word Length = 8 Bits5 V5 c6 a2 J- F, y: w2 D1 S1 f/ J$ U- z5 B
- - one Stop Bit
) q: B% k* O: y! Q& G0 C+ N; K - - No parity
' z1 I& R& o, C+ N6 F7 S - - Hardware flow control disabled (RTS and CTS signals)1 H/ H+ v7 U3 F ^
- - Receive and transmit enabled
! Z- `1 a$ f4 }4 L1 C - */
! i$ X4 u/ x& Q5 K - USART_InitStructure.USART_BaudRate = 115200;
; L) \/ O" W+ U - USART_InitStructure.USART_WordLength = USART_WordLength_8b;
x7 c% V0 I1 h: g& g9 m - USART_InitStructure.USART_StopBits = USART_StopBits_1;
. F- {/ ?4 c( v - USART_InitStructure.USART_Parity = USART_Parity_No;6 G% }' i$ _1 u- z. P; V, j
- USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;; K- m S" h5 Z, I1 n" F- J
- USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
* B- A2 |9 e7 A" _( E - USART_Init(USART3, &USART_InitStructure);6 I4 y* J) ^9 r3 f L4 V
-
- T7 E% p* k$ z: B5 y& v9 G9 Q7 e - /* NVIC configuration */7 K& q: `4 e1 ?: a* [' L+ N/ W
- /* Configure the Priority Group to 2 bits */
( C" k5 m4 P M: s! d# _ - NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);% V+ ?/ {" \, }9 e7 Q: D& W
- . m/ G/ w4 d1 \
- /* Enable the USARTx Interrupt */
8 z2 O" o9 D" Z" Q% y - NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;* h. r3 v) i$ C; z4 t
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;* |! E1 Z5 W9 F7 w/ R
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
! j+ F: ~5 u3 `1 G - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;1 Y; q X7 T2 @ [1 ]3 p2 z1 m
- NVIC_Init(&NVIC_InitStructure);
' d8 n9 \3 r* P1 C- c) D -
) V; H+ C6 K9 p6 w6 W - /* Enable USART */7 @$ ^0 w% |- i0 L
- USART_Cmd(USART3, ENABLE);
- u% {9 R2 @. @) m* I2 D - USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);8 }& F# W6 S5 D' ?
- }
- M! b8 E- a( Z
复制代码
9 B r; G8 d3 q9 n+ a+ Z; `中断服务程序如下:, F+ h+ f" H2 B0 N; w& [
- void USART3_IRQHandler(void)2 d; u/ O: G( s3 ~8 P$ [3 j
- {
/ T. O4 s. H* d' m+ c% w - unsigned char ch;
6 A' {( w: [/ n9 M- z# J5 v3 o - if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET); a4 `& m; B, u8 v! y
- {
0 c( f3 W9 b. h, X# O+ e8 V - /* Read one byte from the receive data register */) V2 l4 T" t! \
- ch = (USART_ReceiveData(USART3));* N2 k9 |. v' n8 g/ f
- 4 {/ H5 X6 V* {3 [5 H
- printf("in[%c].\r\n",ch);
& X* N$ g0 R! d- F - }
" d" |5 E; q% J - }
复制代码 " [7 D( }) k" ]+ `4 U
# Q- L' c# v7 g- d* M直接把接收到的字符打印出来。
9 z. o; n" u( _) _# T
; p: X, v1 P4 p7 M" N(2)DMA方式- x5 j' z# `) v* q6 u
基本步骤同中断方式,额外需要DMA的初始化配置,参考代码如下:& |! z# C- t& W' a. o t' s
- void uart_init(void)
9 B6 g1 k6 O3 d9 A! \+ a! @& N - {) T8 z# }2 a0 i: ]/ Z
- USART_InitTypeDef USART_InitStructure;
& ~% Q0 p! P: b0 V7 H - NVIC_InitTypeDef NVIC_InitStructure;& R$ _( _ I, t( D9 p0 i$ r
- GPIO_InitTypeDef GPIO_InitStructure;
8 ^6 o; D1 c0 C/ Y8 ~$ n( o2 F - DMA_InitTypeDef DMA_InitStruct;
/ b j7 c! _% l9 {/ I5 V: W -
. e' c( x4 ^- T. N) ]( S - /* Enable GPIO clock */
1 z: f! U9 k7 l: D5 B - RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);7 X( e7 w8 {' C( k. b* C8 l
-
( E) g+ H9 A" S$ H, f6 e - /* Enable USART clock */. u7 J8 o: M! L& B, v6 [
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);" ^/ i& H: f, @+ C! d
-
) u+ L9 t$ D1 C/ y: Z3 C - /* Connect USART pins to AF7 */
" q+ j& W2 |% b0 O - GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_USART3);
$ H& D0 |4 r- _ - GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_USART3);
% }7 W* \" z. |' h -
4 T5 \. c. R( m8 }/ v$ [ ] - /* Configure USART Tx and Rx as alternate function push-pull */; p/ Y8 ~6 I1 S5 X
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;: o9 s' j9 p- e, ?# x
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;' j. G1 f6 D7 X# V+ g3 c
- GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;& B& [& v2 E4 x: F: I" l
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
3 p8 W6 ^: H+ w3 w/ i/ D - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
6 m/ V( i' s6 w3 x# e+ c0 [ - GPIO_Init(GPIOC, &GPIO_InitStructure);/ Q: [, A e7 {8 L3 J
- 7 H: j; E5 U+ W2 b
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;7 r) p. B% e8 [( j( D0 X
- GPIO_Init(GPIOC, &GPIO_InitStructure);
* S% c4 F1 ^7 x3 ^6 e; y( M9 y - /* USARTx configuration ----------------------------------------------------*/
, L, _$ q1 B8 k3 E6 n - /* USARTx configured as follow:" }) {& n# h5 r* f* U* J3 R7 v, c
- - BaudRate = 3750000 baud
* K# m3 K" i1 k" A' t9 m# K# O0 a - - Maximum BaudRate that can be achieved when using the Oversampling by 8! h1 A$ H$ k1 o0 h2 q
- is: (USART APB Clock / 8) ! |) L4 c5 m) a. c
- Example: / H$ z( E* I9 L; b q6 d
- - (USART3 APB1 Clock / 8) = (30 MHz / 8) = 3750000 baud s4 n! W M) b; B7 I! c# b1 @
- - (USART1 APB2 Clock / 8) = (60 MHz / 8) = 7500000 baud
7 N4 B( W" `- D% H2 R - - Maximum BaudRate that can be achieved when using the Oversampling by 16
/ `- J- O0 L2 l9 U9 v( g - is: (USART APB Clock / 16) / M5 S4 N+ I) T8 W
- Example: (USART3 APB1 Clock / 16) = (30 MHz / 16) = 1875000 baud- K5 G; {4 ?, U+ O$ t6 m5 O
- Example: (USART1 APB2 Clock / 16) = (60 MHz / 16) = 3750000 baud& D5 _+ k7 G6 z+ q; U
- - Word Length = 8 Bits
" a( A% D+ o5 S! g* i8 o J - - one Stop Bit
$ ^8 @7 c3 W$ }) A; f- H6 M! H - - No parity5 W, M% E# h% t L
- - Hardware flow control disabled (RTS and CTS signals)
& ]7 z$ E4 T ~8 h - - Receive and transmit enabled8 g( Q/ t; ~4 p+ C
- */
. D5 B7 @, i& P! Z! M/ C - USART_InitStructure.USART_BaudRate = 115200;
* g* O% G7 M$ w! O; j - USART_InitStructure.USART_WordLength = USART_WordLength_8b;* k# P; L; O( u8 R8 s: R1 C
- USART_InitStructure.USART_StopBits = USART_StopBits_1;1 D: K/ U ~( [8 q1 c0 y
- USART_InitStructure.USART_Parity = USART_Parity_No;2 y7 [3 A& p- P0 c ?+ _
- USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;, X; o7 q' a I
- USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;0 g+ O+ E* b3 R" C
- USART_Init(USART3, &USART_InitStructure);' ~ W1 c7 R7 F9 v, p; H8 Q( d
' I/ n/ O& K9 i1 y H( s- /* DMA_Configuration */" l8 x4 N6 b1 H' o3 h
- DMA_DeInit(DMA1_Stream1); 5 V' i6 P( C9 f
- 1 U1 c* F3 p% ~' U
- DMA_InitStruct.DMA_Channel = DMA_Channel_4;
2 r C1 B% q* {# R- L+ y - DMA_InitStruct.DMA_PeripheralBaseAddr = (u32)&USART3->DR; //source buf
$ Q. e* }( h3 Z7 h - DMA_InitStruct.DMA_Memory0BaseAddr = (u8)pdata; //target buf
, z! Y w& F3 O2 _1 X9 K) U( |$ I - % D# ]) \# Q4 S7 s; O) U* A
- DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralToMemory;! U: }) D ~3 B. f- P
- DMA_InitStruct.DMA_BufferSize = lenght; //BuffSize;. E1 ], J6 ]: u) b7 r
- DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 4 ]; z6 p4 M+ o: z L7 l; c' {1 ^' ?
- DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
; y- V% [0 T+ ?+ J+ n( g/ T$ g1 N - DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;3 v$ l% @" G9 h. h8 l
- DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
: U3 A2 W, N: c" d. \; v6 N - DMA_InitStruct.DMA_Mode = DMA_Mode_Circular; //DMA_Mode_Normal; ; P2 @* X: ~& @; w' e
- DMA_InitStruct.DMA_Priority = DMA_Priority_High;
* x( l5 j) C1 t9 T, d, z; y5 d - DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable;
: J. ]& J3 ~3 g" h5 p+ }( Z - DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;. Y' A! A: V/ s# m- e
- DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;
" R, ^- P; l, Y - DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
P' }0 W9 }# r% L - DMA_Init(DMA1_Stream1, &DMA_InitStruct);
( s; R b# w0 Z - 8 S/ p( f1 Y4 C! ^2 |- B
- /* NVIC configuration */
- F) C; o; @ \# T$ Z' O! c - /* Configure the Priority Group to 2 bits */6 K7 d2 L7 }' @6 t# x
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
+ @) ~# {3 B4 N F ] - + N! t: F9 v( `+ [- `; e
- /* Enable the USARTx Interrupt */( j. c# I; k% Z( c5 g
- NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream1_IRQn;
, k) z, q% l) Q+ u% L* Q- W. N - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
; C& K+ X# x$ Q - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;1 C" G0 b: E' ]1 h
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
: R+ `) O+ ?, l% G3 Q/ H - NVIC_Init(&NVIC_InitStructure); 2 C& Y! ~6 V# ~4 @
0 j. {& y2 q* r' I& ?! w- /* Open DMA interrupt*/: K/ }8 i/ f' _7 i6 I6 v8 |
- DMA_ITConfig(DMA1_Stream1, DMA_IT_TC, ENABLE);# j8 o9 L: u8 m- s, ?) s
- DMA_Cmd(DMA1_Stream1, ENABLE);! x% ]3 V9 ], q# w" l
- USART_Cmd(USART3, ENABLE);
0 w( ^* d& \, ~ - USART_DMACmd(USART3,USART_DMAReq_Rx,ENABLE);+ m+ h$ C* d7 S# {7 \! c; _
- }
复制代码 . s2 Y3 o" m; p
% k* |! R; e Y0 @! L4 F
DMA中断服务程序如下:3 l5 t* w( D0 }/ u
- void DMA1_Stream1_IRQHandler(void) //UART3_RX
+ C" m0 i; X8 L3 h5 T5 D5 U4 K. } - {
3 S, i& q% i; T( j8 A5 q9 F - static short i;# \, z& W7 m$ P1 q* P- P
( T$ P, E6 y2 _7 J- i' \1 j* n; h- ]3 V- //When a Transfer Complete6 p$ q( n/ k7 v# Y5 g0 W, x1 J
- if(SET == DMA_GetITStatus(DMA1_Stream1, DMA_IT_TCIF1))
& C! S& D. X; ~' E6 b; G1 s - {2 z# \" [9 @6 k$ f
- DMA_ClearITPendingBit(DMA1_Stream1, DMA_IT_TCIF1);
2 K B( G- _9 }( p7 J3 F5 G6 u# U - i++;0 d9 Q3 N7 P- o7 k% i
- }
# U9 v2 w$ P2 E9 n - }
复制代码
$ H4 g! x) ?, G7 F4 c% ^( u/ S6 V
上面程序只配了DMA接收,发送类似。( ~$ p( l, h. z( b0 A* K
4 F3 r; _" {: G/ w: ^9 d
2 [& I3 q0 j2 y2 [6 k三、实现DMX512协议: X4 z$ U" I: d9 Y; {
DMX512 协议是美国剧场技术协会( United States Institute for Theater Technology, USITT) 制定的数字多路复用协议, 其制定的初衷是为了使舞台、剧场等地所使用的众多的调光器和控制器能相互兼容。虽然它不是一个行业或国家标准, 但是由于它的简单性和实用性, 自从出台以来, 得到了世界各地生产商和使用者普遍承认,这个协议在LED控制方面应用很广泛,利用STM32 USART可以高速传输的特性,我们很容易用STM32来实现DMX512协议。
( L; J( |+ ?$ i H+ `(1)数据的格式及传输6 {- Z( B, _# I* z/ I( A. }
DMX512 协议规定数据以数据包的形式通过异步通讯的方式进行传输。每个数据包由若干数据帧组成, 每帧数据包括1 位低电平起始位、8 位数据位和2 位高电平停止位。DMX 协议要求数据传输的波特率为250kb/s, 亦即每位的传输时间为4us, 每帧数据的传输时间为44us, 它支持多达512 帧数据传输, 每帧数据与相应的控制支路相对应。数据包的传送要符合一定的格式和时序要求。为了使接收器能够分辨出第一帧数据, 每一个数据包以一个不短于88us 的低电平信号为起始信号, 即所谓的“Break”信号, 接收器接收到“Break”信号就准备接受随后而来的数据帧; 紧接着“Break”信号之后是不短于8us 的高电平信号M. a. b ( Mark after Break) ; 之后就是数据帧。在DMX512 协议中, M. a. b 之后的第一帧数据被称& A7 \: T# u6 ~5 Z W' j
为“Star-t code”, 在协议中规定其为零, 但在实际应用中可以由生产厂家自己确定其具体的值, 以传递特殊消息。“Star-t code”标明其后面的数据是8 位控制信号数据帧。数据帧之间可以有时间间隔, 也可以没有; 同样, 数据包之间可以有时间间隔, 也可以没有。DMX512 协议规定“Break”信号、M. a. b 信号的最短时间, 并规定“Break”信号、M. a. b 信号、9 D; P0 B8 A% z; V. i: Z
数据帧之间及数据包之间的时间间隔的最大值不得超过1s, 否则做出错处理, 但是DMX512 协议并未对出错处理做任何规定。为了严格实现DMX512 数据的时序要求,“Break”和M. a. b信号我们可以用定时器来实现。
. q" y4 a$ [! e/ u( a7 v N" K2 j S具体的UART配置如下:- s8 a" i7 @0 T/ C" i1 K
- USART_InitStructure.USART_BaudRate = 250000;
+ p( |& v( w( b0 ~) s" t3 a - USART_InitStructure.USART_WordLength = USART_WordLength_8b;
/ Z+ x4 X0 X" }6 a1 u6 p/ g3 g3 E4 t - USART_InitStructure.USART_StopBits = USART_StopBits_2;
4 p r8 I# t; E9 R4 K% f" @. G0 W1 \ - USART_InitStructure.USART_Parity = USART_Parity_No;
0 f7 O; u2 A/ T% X4 {1 H8 j - USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
9 A$ w) H3 `$ S) Z! i* O% u' T; ~ - USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
! t# r8 ^9 h7 p5 ~ h% w+ g3 c. \ - USART_Init(USART1, &USART_InitStructure);
复制代码 # | b7 z, y1 a# v" r. m
& ^/ u v7 U8 I% X6 G2 p0 b0 I, H4 j5 v
发送DMX512信号过程如下,先把UART的TX脚配置为普通的GPIO并输出低电平,然后启动定时器计时88us, 时器到后把TX脚置为高电平并计时8us, 时器到了后在配为UART模式用DMA方式把数据发出。4 g' E: T( t" y( I) O% A& q
DMX512信号的接收是个难点,一般直接配为UART接收就行,不需要在UART模式和GPIO模式间切换,但需要在接收过程中检查接收到“Break”信号时的状态是有帧错误出现,并且接收数据全为零,这样的话可以确认已经收到“Break”信号,随后数据正常DMA接收就行了。
7 ~0 a; [) z9 ?( B( I4 @; ^- K3 L8 T% F; H% G0 K/ t
|
1. 使用已经调试好的例程,特别是参考官方例程包。
2. 使用KEIL的RTE配置串口,很好用。
3. 使用CubeMX配置串口,也很好用。