你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【STM32F030开发】波特率自动识别 精华  

[复制链接]
creep 发布时间:2015-12-1 22:57
前几天参加论坛活动人品小爆发抽中了一个NUCLEO-STM32F030和一个移动电源,感谢与非网,ST,沐紫和苏柚,特别要感谢苏柚的不辞辛劳。
) `' `, D$ [8 N& G4 Q QQ图片20151126215320.jpg QQ图片20151126215856.jpg QQ图片20151126215330.jpg NUCLOE-STM32F030:3 F0 E4 Z2 X9 m* I% h
为了避免板子一到手就沦落到吃灰的命运,趁着新鲜感和热乎劲先写个测试程序,也是为继续给自己攒人品。
: k% W; A" d5 X. I% Y6 X3 ~ST的很多ARM系列的串口都有个自动检测波特率的功能,比如这个STM32F030,还有前端时间论坛搞活动送的STM32L476。9 |" s6 e+ o% }2 e$ n( _2 K6 d
使用自动识别波特率主要有2个方面的原因:  2 z6 l& d, ?; d& Z1 C; D) W. D0 N  I! w
       ●:通信之前并不能确定波特率或者波特率可能不固定
9 }1 F4 f. S1 x2 }" _       ●:系统的时钟准确性较差,计算出来的波特率可能不准确& G* e  x. b! h) _/ S  X; t
自动识别的原理是MCU内部检测一个下降沿到上升沿的时间间隔进而算出来波特率,STM32030有2种模式: 1.png
+ |: l: N2 M2 L5 V1 y* eSTM32L476有4中模式:+ n3 U# H# G: O8 H! L
2.png
! i9 u- e: z: t5 ?# i! ]/ P 3.png
7 \2 y! @' t  r- p1 h3 Y% G这些模式的原理基本是上面说的那样测跳变沿的时间来计算波特率,下面我们使用模式0来测试。模式0的要求是发送的一个字节的第一个bit是1,比如. s& F& o' D8 l
小写的a(0110 0001),MCU在接受到这个字节后会根据这个字节算出新波特率并更新相应的串口的波特率,下面的通信就使用这个波特率进行通信。
4 c) `; _- w% G9 h$ L9 |) J* P1 b1 g使用这个功能时要注意有的串口可能不带这功能,比如STM32030只有串口1带有自动识别功能,串口2并不到自动识别,有的单片机不同串口支持的模式也不太相同,下面是STM320X0系列的一些支持:- |4 E: }+ P- A' Z
4.png
$ Q8 B+ c. e) ?0 d+ J! @在初始化串口是默认设置波特率为为9600,然后用不同的波特率向MCU进行通信测试自动识别功能。NUCLEO测试时可以使用杜邦线将串口1的PA9/PA10连接到STLINK上面的TX/RX引脚,这样就可以借助STLINK的虚拟串口和串口1进行通信了,NUCLEO板子上默认STLINK虚拟串口是和串口2物理想连接的。STM030有标准库,所以我先使用标准库测试。
$ _# \2 f- l' b& e- T, \; E串口的初始化和平常一样:
2 J' O1 Y, g2 F* Q, N
  1. void USART_Config(void)
    8 W3 v; ]0 g" J9 F  _# X
  2. {         ) Y9 i6 ]5 i9 {0 t/ ^
  3.   USART_InitTypeDef USART_InitStructure;) j* W! I8 s4 }$ h0 f
  4.   GPIO_InitTypeDef GPIO_InitStructure;
    1 ^$ g! W+ d, V8 n( g) J% V
  5.   RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);
    4 }/ ^. ~$ }- p1 t$ B6 f$ M
  6.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
    ( w, z8 ^3 l% f6 L
  7.        
    # V4 b8 p. Y& l4 K+ r9 T1 ?; Q
  8.         GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_1);
    % |; v2 H4 A+ J% I
  9.         GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_1);- C' I( Q1 }# [1 y# s: B0 A
  10.         //U1_TX :PA9: P3 ?/ s) W4 O. {4 |
  11.         //U1_RX :PA10
    ! J' g  K  i6 ?5 s" F) Y
  12.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
    % B5 E5 p: c  B" |* }  W. L
  13.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    3 O; h1 r8 f4 s) l# q' f
  14.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;; C7 p/ B! {/ i$ ?1 [
  15.   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;, H. d9 ?3 P* ]& }: Y! n. T4 ]
  16.   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    & V$ d/ |7 N( T6 @- l! n7 H- X
  17.   GPIO_Init(GPIOA, &GPIO_InitStructure);
    ; j3 S+ i, L- r' N
  18.        
    6 `/ E9 s% l. B) e1 V
  19.   USART_InitStructure.USART_BaudRate = 9600;
    ' L' x' @4 p! }' f
  20.   USART_InitStructure.USART_WordLength = USART_WordLength_8b;9 _7 G0 o. }, Z0 B2 K2 q3 Q& L3 }. g
  21.   USART_InitStructure.USART_StopBits = USART_StopBits_1;
    0 p$ l, ^6 ^9 M& e3 O5 |7 d/ w
  22.   USART_InitStructure.USART_Parity = USART_Parity_No;
    : D% y' W0 `' T, m6 m) W
  23.   USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    . J, w& o; F7 W, w/ B( y' k3 E+ T
  24.   USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;, U, W( |& T' V" ~  [+ z/ q; I
  25.   USART_Init(USART1, &USART_InitStructure);
    6 T& T4 ^+ T' H2 ]+ Q3 m' E# }
  26.   USART_Cmd(USART1, ENABLE);! D* U7 |1 Z  w0 v6 h
  27.        
    4 h! f: l* s3 e/ I2 i
  28. }% e$ {* C6 M: h% w6 U
复制代码
然后打开自动识别功能,等待接受字符进行识别,然后计算识别出来的波特率;6 x. }, Y8 O) Q) V
  1. void AutoBauRate_StartBitMethod(void)
    4 [& ?6 G: T6 V0 L$ n3 D# J; x: B
  2. {   
    4 y7 D; Z5 J1 G1 o8 K. F  h; \8 @
  3.         uint32_t baudrateval = 0;
    $ D( v. |( r6 x4 L8 P8 c" y
  4.         uint8_t  tmp[25];
    * s0 Q. R$ k+ \1 d. Y
  5.        
    9 d5 k# e" a! q; {, S/ o7 |+ b
  6.   USART_AutoBaudRateConfig(USART1, USART_AutoBaudRate_StartBit);  ! q! ?, Z! B" {5 T
  7. ' o6 \' ]& d2 m  `. y" b
  8.   USART_AutoBaudRateCmd(USART1, ENABLE);  " E4 b* Z2 V1 J. v4 Y0 q

  9. $ J& C, L  D# G/ u+ r
  10.   while(USART_GetFlagStatus(USART1, USART_FLAG_REACK) == RESET)
    * G' ?) U) F& c" O' @
  11.   {}   
    ) U! C" A, C5 }9 ?7 D

  12. % T; E' s$ q& ^6 g) `: Y
  13.   while(USART_GetFlagStatus(USART1, USART_FLAG_TEACK) == RESET), G) K+ q( G- h0 T, E
  14.   {}  # E% R2 {5 W; ]7 Y  B' @3 N
  15.   . H: ]/ n$ h4 Z
  16.   /* Loop until the end of Autobaudrate phase */
      w$ e' |) y1 w- t( B
  17.   while(USART_GetFlagStatus(USART1, USART_FLAG_ABRF) == RESET)
    # @* N+ @$ j  R3 Z
  18.   {}  5 m0 T0 v' q+ |8 G
  19.     V) d# W5 V% L7 {! ~1 b
  20.   /* If AutoBaudBate error occurred */* G* z0 O- {" R# r, }! W
  21.   if (USART_GetFlagStatus(USART1, USART_FLAG_ABRE) != RESET)
      P' j5 k- g2 `+ C! s- c
  22.   {# a# B# R0 i7 T/ ?: ^  f
  23.   }: |0 f! ]8 _' h) G9 G
  24.   else
    2 H4 |; w# z' E% C0 R
  25.   {
    2 ]; r/ O; ^8 b% s1 n# s. u" a$ w
  26.     & Y% }, E: P( A; M' Y
  27.     /* Wait until RXNE flag is set */9 e* B5 F$ D. V" M0 W* u
  28.     while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET)
    + ~0 |" w. {2 x, p
  29.     {}) G( t; x6 J. T% N) u
  30.     / ^, V7 D3 n$ s9 a' l4 M( ?
  31.     /* Wait until TXE flag is set */    . L- B; s4 a3 `
  32.     while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)1 A: e7 T  \6 |- ]
  33.     {}
    , @  `/ o' R! p  I& w
  34.    
    8 M+ V% ?$ X3 K2 f" r1 U, ]
  35.                 //将收到的数据发送到串口. J/ G- M* T! U! [% B; U
  36.     USART_SendData(USART1, USART_ReceiveData(USART1));
    ' c" \: \) w4 m9 S: {) R5 D
  37.     while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
    % y! }# R% R8 E
  38.     {}
    0 ^* Q5 R7 ?3 G/ o8 P$ o

  39. & ]2 o8 e& D! o8 C7 Q% O$ ^
  40.                 //计算波特率+ {5 y7 b- f" y7 @6 F2 Z" H3 [
  41.     baudrateval = RCC_Clocks.SYSCLK_Frequency / USART1->BRR;
    / M1 C7 B/ l7 e) n
  42.                 sprintf((char*)tmp,"\r\n检测到波特率为:%d\r\n",baudrateval);
    : ^. S: a' ~1 R4 \/ p* y/ Y
  43.                 USART1_Send(tmp,25);    , q  W( `# ?# H& x
  44.   }  3 ]6 ~* m/ U2 D; r7 P2 p  {, ]
  45. }
    0 ^/ _  V/ g( \& b: Z( `( U
复制代码
分别测试几种波特率向MCU发送数据a:可以看到识别计算出来的波特率和实际有差别,因为这个差别在串口波特率的接受范围内,所以并不影响实际的通信。
. h7 ]' r; ]8 R9 ~- X9 {
# w2 q' D# H4 }) K/ p5 d 9600.png 15200.png 19200.png & q; ?  D* Z+ M9 p, Q
, V% d6 E  P  {1 d# n( l4 w7 @, l
460800.png 921600.png
- u3 R4 ]7 n9 U, J- }$ x
! Q) k/ B. F$ _NUCLEO-STM32L476:5 @! q: w: n2 Y. F
上面使用的STM32F030可能很多小伙伴没有这个板子,下面用NUCLEO-STML476测试下,相应的使用的HAL库。使用HAL设置比较简单,在初始化串口时顺便打开自动识别高级功能即可。' |9 j6 L( k6 Z# d3 p
  1. void USART1_Init(void)7 |% s$ x0 J: F4 ^1 O3 s6 m
  2. {
    7 q0 E0 V9 D9 N9 h  R& D$ z
  3.   UartHandle.Instance        = USART1;  @# I- k$ W; k- g% R9 _
  4.   UartHandle.Init.BaudRate   = 9600;) ^, Q7 |5 j8 d4 Z% l
  5.   UartHandle.Init.WordLength = UART_WORDLENGTH_8B;
    3 E2 c0 {+ V  u
  6.   UartHandle.Init.StopBits   = UART_STOPBITS_1;
    9 x) e4 ?4 A! c3 r* q* B
  7.   UartHandle.Init.Parity     = UART_PARITY_NONE;  {" U% B4 Q  e  m
  8.   UartHandle.Init.HwFlowCtl  = UART_HWCONTROL_NONE;
    1 [$ |1 P. Y5 U- m6 E, G
  9.   UartHandle.Init.Mode       = UART_MODE_TX_RX;
    7 D1 e! r) X- c# s. }
  10.   UartHandle.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_AUTOBAUDRATE_INIT;$ \9 U" a  h; V! P
  11.         UartHandle.AdvancedInit.AutoBaudRateEnable = UART_ADVFEATURE_AUTOBAUDRATE_ENABLE;. W' I: N& Q1 q. i% A- _, E
  12.         UartHandle.AdvancedInit.AutoBaudRateMode = UART_ADVFEATURE_AUTOBAUDRATE_ONSTARTBIT;
    ; W1 Q! ~7 D6 R- {& A* C2 X
  13.         USART1_MspInit();* C9 C! e. o( D) J  X) J; U% [
  14.   if(HAL_UART_Init(&UartHandle) != HAL_OK)
    * W9 n  r: X* O/ e& f
  15.   {1 S9 F& t/ ~5 o; f' Z
  16.     while(1);
    1 [. R3 I# h) q7 y; g+ k2 V
  17.   }               
    ) [1 H3 s, O3 T
  18. }
复制代码
波特率初始化为9600后BRR的值为0X208D(8333),此时的波特率为80000000/8333 = 9600.此时MCU主频为80MHZ% t9 x/ V6 `# W: p  L) T
5.png 2 z* O3 i1 Y' z- ]! i0 x7 ^
使用460800的波特率和MCU通信后BRR的值为:0xAE(174) ,此时的波特率为 80000000/174 = 459770.误差率为0.22%% c7 o9 i* K  w, f  W8 l
6.png
4 @  p# b3 K) }: u5 R! S总体来说波特率自动识别还是很实用的,识别一次后就可以一直使用,如果有需要还可以继续识别。8 Q" C2 q% n9 n/ q0 t. C; ^. z
测试代码:
: R9 t! k  e. k$ w& | USART_AutoBaudRate_STM32F030标准库模式.rar (232.69 KB, 下载次数: 449)

评分

参与人数 1 ST金币 +30 收起 理由
沐紫 + 30

查看全部评分

收藏 27 评论64 发布时间:2015-12-1 22:57

举报

64个回答
kissrose 回答时间:2020-2-10 12:29:00
hi,请教一个问题。
: w4 n" e( p. Z) W2 `& j3 [/ C1 `0 c$ ~你在每次测试的时候,UART有复位吗??# B  B+ g6 E1 r+ c0 q0 K
或者说改变波特率的时候,UART不需要复位就可以自动适应这次的波特率吗??# s/ O. r1 E4 S7 ?$ Z3 S) R0 `3 {
(我的问题是通信过程中,改变主设备波特率的时候,从设备都可以自动适应吗?还是只有再上电后那一次能适应?)% f1 T7 s- L6 g7 D
不知道有没有问的清楚。有时间请帮忙回答一下。
# m0 h7 N+ i! v
0 w( t! ?% U' y' h6 [: J; A因为我想不明白,波特率降为一半时,从设备(stm32)怎么知道收到的约定字符是所谓的约定字符还是有效data。
creep 回答时间:2015-12-2 16:28:14
Endless. 发表于 2015-12-2 16:107 Y% y- w3 X( U  h" B
这个技术很实用  不知道是否支持非常规波特率

1 `4 A# J3 S/ S7 P, b- a- H非常规波特率指的是那些不是常用的波特率吗,一定的范围内应该可以支持,MCU只是简单的测试外部发送的数据的波特率然后就设置为自己的波特率。有空我测试下你说的这种情况看行不行。
回答时间:2019-6-19 18:01:24
你好,正在测试,这个识别完成的标识 UART_FLAG_ABRF一直不置位,请问可能是什么原因?( E( k, o. f& ~( K2 a, x  j
+ I, t# b8 G5 g( s& H- L
  while(__HAL_UART_GET_FLAG(&huart5, UART_FLAG_ABRF) == RESET)( F- F5 t# n1 @1 _
  {}
kingsings 回答时间:2015-12-1 23:26:19
ST的芯片还有这功能,学习了
风子 回答时间:2015-12-2 00:30:16
学习了,大神出手就是不一样
Paderboy 回答时间:2015-12-2 08:05:46
大神出手就是不一样,学习啊。。。
: j0 \# [# N5 k% H& X- r STMCU-Logo.png ) L7 e1 v- r) A5 ^* t" W- u
foxglove 回答时间:2015-12-2 08:07:03
波特率自动识别
slotg 回答时间:2015-12-2 08:29:08
很不错,感谢分享。
liuyu-419812 回答时间:2015-12-2 08:44:11
挺好的,学习了
disheng4688 回答时间:2015-12-2 08:44:13
学习                  
zhangdaijin 回答时间:2015-12-2 08:47:50
alvin_ 回答时间:2015-12-2 08:52:38
一次中两个奖!这真是人品爆发了!
JackieLaura 回答时间:2015-12-2 08:56:37
多谢橙子兄弟的分享
stmcu.org.png
JackieLaura 回答时间:2015-12-2 08:57:18
先收藏了。。。橙子兄弟的又一精华帖啊
stmcu.org.png
creep 回答时间:2015-12-2 09:13:07
JackieLaura 发表于 2015-12-2 08:577 d+ s- L2 W. l5 y4 Q
先收藏了。。。橙子兄弟的又一精华帖啊
! V+ p' Q( c) l9 c' y9 o
我也只会玩这种小儿科的东西,太复杂的玩不了
wamcncn 回答时间:2015-12-2 09:23:16
谢谢分享         
wolfgang 回答时间:2015-12-2 09:48:30
不错,好东东!!
12345下一页
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版