前几天参加论坛活动人品小爆发抽中了一个NUCLEO-STM32F030和一个移动电源,感谢与非网,ST,沐紫和苏柚,特别要感谢苏柚的不辞辛劳。 % J6 m- c4 s* U# N
NUCLOE-STM32F030:( G( O$ c7 b6 \
为了避免板子一到手就沦落到吃灰的命运,趁着新鲜感和热乎劲先写个测试程序,也是为继续给自己攒人品。$ Z) o" P9 ^1 @- f$ V
ST的很多ARM系列的串口都有个自动检测波特率的功能,比如这个STM32F030,还有前端时间论坛搞活动送的STM32L476。
1 O, l5 a9 t" ?4 `+ X4 A使用自动识别波特率主要有2个方面的原因: 8 D1 l; } ?& r( J. _9 e
●:通信之前并不能确定波特率或者波特率可能不固定9 ^7 S% M# k, @0 V. N# u8 A; \3 K
●:系统的时钟准确性较差,计算出来的波特率可能不准确
7 {: t. D# l2 ]$ h2 P/ D! |: j. P自动识别的原理是MCU内部检测一个下降沿到上升沿的时间间隔进而算出来波特率,STM32030有2种模式:
O& a4 h a4 O+ N6 g4 x
STM32L476有4中模式:
$ V. }% d$ D0 Q/ A5 w4 g% K
+ n/ _' B% ~( y2 |! x
# P* L( n8 x0 C/ Y这些模式的原理基本是上面说的那样测跳变沿的时间来计算波特率,下面我们使用模式0来测试。模式0的要求是发送的一个字节的第一个bit是1,比如: x+ N" H* R0 T* F
小写的a(0110 0001),MCU在接受到这个字节后会根据这个字节算出新波特率并更新相应的串口的波特率,下面的通信就使用这个波特率进行通信。' t( i K1 u$ ~5 c
使用这个功能时要注意有的串口可能不带这功能,比如STM32030只有串口1带有自动识别功能,串口2并不到自动识别,有的单片机不同串口支持的模式也不太相同,下面是STM320X0系列的一些支持:
; K; w+ s. d# ^) E/ A- |' w
& g5 c0 _; y X4 G6 S( C @4 @8 j& O在初始化串口是默认设置波特率为为9600,然后用不同的波特率向MCU进行通信测试自动识别功能。NUCLEO测试时可以使用杜邦线将串口1的PA9/PA10连接到STLINK上面的TX/RX引脚,这样就可以借助STLINK的虚拟串口和串口1进行通信了,NUCLEO板子上默认STLINK虚拟串口是和串口2物理想连接的。STM030有标准库,所以我先使用标准库测试。
; X7 y( w; `# C6 Q5 J4 M串口的初始化和平常一样:- q& }* W3 P+ i: U9 n
- void USART_Config(void)% V0 z! H( q$ v7 n! t
- { 4 H3 ]9 ^, k; }/ @8 y8 j
- USART_InitTypeDef USART_InitStructure;; U2 U# }* W7 G
- GPIO_InitTypeDef GPIO_InitStructure;
0 a& L5 h" k- `6 a: _* I - RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);
, ^9 n i; |3 D2 }2 f1 o/ |) i( \ - RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);1 }5 M6 ^2 J- A2 D, E* @
-
' E9 p) a( \9 U, b/ n) {" |- w/ S" ` - GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_1);
# Z( [: h, W$ ]) ^- T - GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_1);7 t2 n, X/ F9 l5 V( B$ j
- //U1_TX :PA9
q3 \: r4 t: [( ]5 s; Z3 G+ h! M; s - //U1_RX :PA108 v* ?& v3 g+ N
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
. q: Y. e8 X! o& s \ - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
0 G9 a" V* M- n! o/ S% o7 g1 ^' H - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;2 a& n, a2 B/ y. C, D, E
- GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
7 q/ f& v" I+ ^% y' Q6 H+ i' \1 K6 N - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
! D- f K6 `; }' Q; r" ?" ] - GPIO_Init(GPIOA, &GPIO_InitStructure);# h7 e# z; N* X
- & v4 o8 i6 k0 q! d) T3 d& L% T! c! L
- USART_InitStructure.USART_BaudRate = 9600;1 P: h( F7 U+ R( p! _4 J" O8 {
- USART_InitStructure.USART_WordLength = USART_WordLength_8b;
' o: \/ {: L/ Z9 ?/ k q - USART_InitStructure.USART_StopBits = USART_StopBits_1;
* m4 ?- M) Z6 a! p& ] - USART_InitStructure.USART_Parity = USART_Parity_No;! f0 x: I8 @1 W. E
- USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
& W9 }( G( w) Z5 {, D8 D - USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;. w" p9 W1 b6 Y
- USART_Init(USART1, &USART_InitStructure);0 D2 k' {0 P0 q7 E
- USART_Cmd(USART1, ENABLE);' @5 @+ F$ r' i
- 4 v5 x6 H9 f% B' e
- }/ a3 U' u" X" y( _2 f
复制代码 然后打开自动识别功能,等待接受字符进行识别,然后计算识别出来的波特率;
" ~+ p" y G8 r6 z6 W0 k6 B- void AutoBauRate_StartBitMethod(void)
S9 e$ e5 ?( D - {
9 M7 z9 L8 E: R" B - uint32_t baudrateval = 0;" X# a; o% K; H9 m$ o, q8 C
- uint8_t tmp[25];( w! r0 U7 ^: Q+ Y* Q
-
; c, J9 G! Y0 e# I# j O - USART_AutoBaudRateConfig(USART1, USART_AutoBaudRate_StartBit); % g6 C2 q8 y9 w+ G3 a7 D
- , C$ O% R( S, M5 P
- USART_AutoBaudRateCmd(USART1, ENABLE); 8 z. n3 ~9 u# y
-
6 M& [ c/ j6 q! {2 l. I' o - while(USART_GetFlagStatus(USART1, USART_FLAG_REACK) == RESET)7 q" h/ f A7 C3 c- v
- {} * s8 X4 v k+ c8 n
-
% ~ \' v/ M: N5 g: X; n/ G - while(USART_GetFlagStatus(USART1, USART_FLAG_TEACK) == RESET)$ `! j' W. u+ Q( i
- {} ; N# d; R9 O2 A {' f' {9 K
-
8 Y7 c3 l4 w% d - /* Loop until the end of Autobaudrate phase */+ C2 r/ b* l3 `8 i' I3 d
- while(USART_GetFlagStatus(USART1, USART_FLAG_ABRF) == RESET)* z4 |4 P3 P- j3 v, @) z% Y
- {} 9 ?4 ]8 M& A2 Z- @9 S
- ( P0 h& }) T9 M2 A$ L& w
- /* If AutoBaudBate error occurred */3 R _- j' M) Y9 v
- if (USART_GetFlagStatus(USART1, USART_FLAG_ABRE) != RESET)0 e' }/ g* w" U9 c& l) T( y: H
- {
/ U0 `1 ]8 K# G - }
, d7 e: ~2 F( y% ^/ u4 | - else
$ y5 p4 m; n& `6 |& p b4 H( X( b - {
, E Y8 o- U5 l& z3 T - . U& I, S6 G% z# g5 K+ ?5 l! J
- /* Wait until RXNE flag is set */
0 M9 {& C2 g3 v1 U: p* S - while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET)4 w3 V: T7 p; Y0 l. l2 B, _
- {}
9 A; i6 I9 D. J( I; h* q6 Z - 8 g3 ]: x4 ?* u& o& o3 N
- /* Wait until TXE flag is set */ 5 H" S% `* d/ q: R! ~
- while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)
s S( \& w1 C- d - {}
! {: u# C6 o4 y( g/ m2 v -
. O( f) t% M% F$ g5 h/ ^( B+ e0 x, T - //将收到的数据发送到串口( z8 @4 k( V( I4 p j5 b
- USART_SendData(USART1, USART_ReceiveData(USART1));
- S0 ]8 c& x0 Q4 f7 n% p - while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
7 q6 v/ L6 K$ r. W - {}6 g3 v G" F. ~5 M% q- f" K
- ; N3 P& G6 h' T7 S' r0 I3 I' B- u
- //计算波特率* M0 w0 @# g6 Y- o) J9 |
- baudrateval = RCC_Clocks.SYSCLK_Frequency / USART1->BRR;
2 z- G( K+ D+ n$ p3 F1 z - sprintf((char*)tmp,"\r\n检测到波特率为:%d\r\n",baudrateval);
, w. i# R* y* C9 \2 G" h( f - USART1_Send(tmp,25);
# D/ Z" M, L# C v K; P - } 8 S3 t R! N9 k( w+ A9 e
- }
3 i# O1 A, h* R; Y# C* c
复制代码 分别测试几种波特率向MCU发送数据a:可以看到识别计算出来的波特率和实际有差别,因为这个差别在串口波特率的接受范围内,所以并不影响实际的通信。
( N# W3 i# E/ V7 L' H! ^
7 F1 o; L- E _
. i( Q2 n- i1 e5 Z( y6 \4 x
# v E; K0 W+ p
N! p# C" R4 Q
$ V- E% P( `4 D/ f# HNUCLEO-STM32L476:
$ v4 S$ b* j4 `- U% F上面使用的STM32F030可能很多小伙伴没有这个板子,下面用NUCLEO-STML476测试下,相应的使用的HAL库。使用HAL设置比较简单,在初始化串口时顺便打开自动识别高级功能即可。, V& N) N8 i1 ^
- void USART1_Init(void)/ C0 J+ Q) b% K; D3 c
- {
" M& @/ _/ S8 k$ s) M - UartHandle.Instance = USART1;
& ~/ {7 l& l' J" Q - UartHandle.Init.BaudRate = 9600;
6 ]. _5 |* E8 a6 D - UartHandle.Init.WordLength = UART_WORDLENGTH_8B;
0 a" o5 l/ o* z - UartHandle.Init.StopBits = UART_STOPBITS_1; |% ?' x! ]/ p
- UartHandle.Init.Parity = UART_PARITY_NONE;
# a& _+ Q5 ~) _$ x, ?2 x2 H5 }6 @ - UartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
: e, @; I5 z; Y1 } - UartHandle.Init.Mode = UART_MODE_TX_RX;$ s$ w3 t# v4 a2 {# v2 F
- UartHandle.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_AUTOBAUDRATE_INIT;8 m. a+ i' y B1 b( a1 Z9 I6 l
- UartHandle.AdvancedInit.AutoBaudRateEnable = UART_ADVFEATURE_AUTOBAUDRATE_ENABLE;
t( B8 _+ ?: M* Q - UartHandle.AdvancedInit.AutoBaudRateMode = UART_ADVFEATURE_AUTOBAUDRATE_ONSTARTBIT;
9 w, L, Z) Z) [ - USART1_MspInit();
! o4 Q; P2 h4 @, z$ S O- C H7 \ - if(HAL_UART_Init(&UartHandle) != HAL_OK)
- P- @' w$ h3 Q; F2 v, q. y* P' L) I - {1 {! s' [( R# o- X
- while(1);9 A$ q6 s5 F* }8 b& f
- }
! m3 Y# b4 i; g) s - }
复制代码 波特率初始化为9600后BRR的值为0X208D(8333),此时的波特率为80000000/8333 = 9600.此时MCU主频为80MHZ+ u. {7 |' [+ X- l. B- F. }
0 m* r1 x5 R* _" v. y1 D( `使用460800的波特率和MCU通信后BRR的值为:0xAE(174) ,此时的波特率为 80000000/174 = 459770.误差率为0.22%! }% J, B' L, p, l5 ~7 W$ m
: _; R$ A3 ^* V. d" Q+ u* ^! p总体来说波特率自动识别还是很实用的,识别一次后就可以一直使用,如果有需要还可以继续识别。/ {4 U3 o" i! z/ R! P
测试代码:
2 y* R1 L+ L' j" N) \: x( ?
USART_AutoBaudRate_STM32F030æ ååºæ¨¡å¼.rar
(232.69 KB, 下载次数: 464)
|
你在每次测试的时候,UART有复位吗??
或者说改变波特率的时候,UART不需要复位就可以自动适应这次的波特率吗??" f. c" t) ^9 T5 Z* t9 e0 \
(我的问题是通信过程中,改变主设备波特率的时候,从设备都可以自动适应吗?还是只有再上电后那一次能适应?)/ f1 G4 D3 N1 i5 K2 _
不知道有没有问的清楚。有时间请帮忙回答一下。 L' ]! Q/ M% _/ T/ T
因为我想不明白,波特率降为一半时,从设备(stm32)怎么知道收到的约定字符是所谓的约定字符还是有效data。
非常规波特率指的是那些不是常用的波特率吗,一定的范围内应该可以支持,MCU只是简单的测试外部发送的数据的波特率然后就设置为自己的波特率。有空我测试下你说的这种情况看行不行。
0 b3 P/ _" Z* L/ I# J
while(__HAL_UART_GET_FLAG(&huart5, UART_FLAG_ABRF) == RESET)
{}
我也只会玩这种小儿科的东西,太复杂的玩不了