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

STM32 串口详解

[复制链接]
STMCU小助手 发布时间:2021-2-2 09:45
STM32 串口详解
1.     USART的特点
USART是通用异步收发传输器(UniversalAsynchronousReceiver/Transmitter),通常称作UART,是一种异步收发传输器,是设备间进行异步通信的关键模块。UART负责处理数据总线和串行口之间的串/并、并/串转换,并规定了帧格式;通信双方只要采用相同的帧格式和波特率,就能在未共享时钟信号的情况下,仅用两根信号线(Rx和Tx)就可以完成通信过程,因此也称为异步串行通信。

% `" E) U. g: u$ ?3 A
(1)    全双工异步通信。
(2)    小数波特率发生器系统,提供精确的波特率。
(3)    可配置的16倍过采样或8倍过采样,因而为速度容差与时钟容差的灵活配置提供了可能。
(4)    可编程的数据字长度(8位或者9位);
(5)    可配置的停止位(支持1或者2位停止位);
(6)    可配置的使用DMA多缓冲器通信。
(7)    单独的发送器和接收器使能位。
(8)    检测标志:①接受缓冲器  ②发送缓冲器空 ③传输结束标志
(9)    多个带标志的中断源。触发中断。
(10)  其他:校验控制,四个错误检测标志。
0 @  |' ]- z6 j/ |. a
通信结构
1.1.png

- @7 E/ _4 \6 i3 r6 J5 t. ]
2.     USART简介
2.1、数据传输模型
1.2.png
* l8 s% s  @3 q% O
2.2、帧结构
串口异步通信需要定义的参数
① 起始位
② 数据位(8位或者9位)
③ 奇偶校验位(第9位)
④ 停止位(1,15,2位)
⑤ 波特率设置
带奇偶校验的数据为就是9位
1.3.png
9 Z8 I( P  r3 r
(1)   数据包
串口通讯的数据包由发送设备通过自身的TXD接口传输到接收设备得RXD接口,在协议层中规定了数据包的内容,具体包括起始位、主体数据(8位或9位)、校验位以及停止位,通讯的双方必须将数据包的格式约定一致才能正常收发数据。

1 b8 S  Z- q2 P( |- Y7 N, K
(2)   波特率
由于异步通信中没有时钟信号,所以接收双方要约定好波特率,即每秒传输的码元个数,以便对信号进行解码,常见的波特率有4800、9600、115200等。STM32中波特率的设置通过串口初始化结构体来实现。

# u, q7 A+ l' U
(3)   起始和停止信号
数据包的首尾分别是起始位和停止位,数据包的起始信号由一个逻辑0的数据位表示,停止位信号可由0.5、1、1.5、2个逻辑1的数据位表示,双方需约定一致。STM32中起始和停止信号的设置也是通过串口初始化结构体来实现。

$ q7 f7 j/ o2 F" N3 S8 o' \
(4)   有效数据
有效数据规定了主题数据的长度,一般为8或9位,其在STM32中也是通过串口初始化结构体来实现的。
1 I' o3 J( O. R% [
(5)   数据校验
在有效数据之后,有一个可选的数据校验位。由于数据通信相对更容易受到外部干扰导致传输数据出现偏差,可以在传输过程加上校验位来解决这个问题。校验方法有奇校验(odd)、偶校验(even)、0 校验(space)、1 校验(mark)以及无(noparity)。这些也都可以在串口初始化结构体中实现的。

- [. v6 _6 H+ j) ^3 L/ J
2.3、波特率
1.4.png

! C: o/ u( f( n/ J
OVER8,用于配置过采样,通常情况下,OVER8设置为0。
1.5.png

) p% {1 N& A6 M: [" P
如果时钟时84M
USARTDIV = 84000000/(115200*16) = 45.572
那么得到:
DIV_Fraction = 16*0.572 = 0x09;
DIV_Mantissa = 45 = 0x2D;

/ \: w  E$ j! r0 T: {( B. F
3.     STM32的USART
根据STM32F207数据手册,STM32F207一共6个串口
1.6.png
2 P6 a1 f: `& F1 `
下文我们以USART1为例讲解
从STM32F207数据手册的Table10.Alternate functionmapping图中看到USART1的对应管脚,下文我们选择PA9和PA10作为USART1的管脚。
1.7.png

/ |; N- ~" X8 @* V  q* c
4.     代码配置
配置中断优先级。
  1. /* Enable the USARTx Interrupt */+ c' B! W. o$ `7 ?! P6 B
  2.   NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    3 }# z4 i/ ]; u5 A, d$ _5 \, K
  3.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =1;
    7 U- B0 D0 @6 _; R
  4.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;1 q) X$ D. b, \+ g
  5.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    ( y" M, y- ^1 M$ f; G1 h
  6.   NVIC_Init(&NVIC_InitStructure);
复制代码

- Q3 L1 w1 ?) ?1 {
打开串口与相应的GPIO引脚,配置好相应串口信息与GPIO引脚的工作模式。
  1. /* Enable GPIO clock */
    3 d7 ], W* ~8 o8 ]1 x) B
  2.   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);/ @' B- \+ X- U4 [
  3.   /* Enable UART1 clock */
    $ m+ u2 J" V3 Z$ v
  4.   RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);% F# o; T- _! x& E
  5.   /* Connect PXx to USARTx_Tx*/
    ( I& C+ F, I+ o! ?' m$ Q
  6.   GPIO_PinAFConfig(GPIOA, 9, GPIO_AF_USART1);# L( j& e2 H1 F; F) o
  7.     p1 w4 {( W) J+ V4 ?' B
  8.   /* Connect PXx to USARTx_Rx*/+ s) m* |6 x& b$ v
  9.   GPIO_PinAFConfig(GPIOA, 10, GPIO_AF_USART1);
    7 Q8 f. Q+ C1 Y* \8 K
  10.   ) P) D1 \+ ^( b) o
  11.   /* Configure USART Tx as alternate function  */- t& ]. r  B9 ?" G0 m  V1 S
  12.   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;8 D/ b' E8 p' d% ?, y% J
  13.   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;/ ?, h& g$ X8 j" E* [+ o
  14.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    - ]1 t( n2 t7 Y, b7 v6 e$ Y
  15.   
    6 C/ u1 {4 S* W
  16.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;, _: [6 W1 I$ g; p& @* C# ]3 w
  17.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    / l0 |$ a% X4 T) ?
  18.   GPIO_Init(GPIOA, &GPIO_InitStructure);2 ]! y8 ~9 X! _8 `1 O1 m4 j
  19.   ( X% m- l! X2 R- k  f
  20.   /* Configure USART Rx as alternate function  */
    % _  r4 S7 B; J* C
  21.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;0 _! u8 a" G" j
  22.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    1 u9 m/ m, ~+ w
  23.   GPIO_Init(GPIOA, &GPIO_InitStructure);
复制代码

+ M1 v3 r7 s9 Z; d9 ?# A
配置USART1。
  1. USART_InitStructure.USART_BaudRate = 115200;//配置波特率& B4 y. n+ d0 q+ V* N
  2.   USART_InitStructure.USART_WordLength = USART_WordLength_8b;//配置数据字长4 _( G4 r& i+ g
  3.   USART_InitStructure.USART_StopBits = USART_StopBits_1;//配置停止位
    ( u+ K- j* l6 u8 }" y% F. w# u8 V
  4.   USART_InitStructure.USART_Parity = USART_Parity_No;//配置校验位: A8 v% d* v2 k
  5.   USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//配置硬件流控制
    ' p* M1 @# H4 A/ j5 h
  6.   USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//配置工作模式,收发一起
    / e* m- s! m, d
  7.   
    6 H( Q% N% q8 y# o- i7 I7 ~9 D
  8.   /* USART configuration */
    ' o( U8 {$ v9 L0 `0 e2 I
  9.   USART_Init(USART1, &USART_InitStructure);// 完成串口的初始化配置
复制代码

! [) D. L& q/ F6 B: }  y& t
使能中断配置。
  1. USART_ITConfig(USART1, USART_IT_TC, ENABLE);' `$ A5 R) u" e. s2 q
  2.   USART_ITConfig(USART1, USART_IT_RXNE, ENABLE)
复制代码
7 g8 b" H" a$ r! G& B. B2 d4 ], D
我们配置了发送传输完成中断和接收数据寄存器非空中断。我们可以配置很多类型中断,在ST提供的标准库函数中看到。
  1. /*** S% v  T' s, [& s, u
  2.   * @brief  Enables or disables the specified USART interrupts.' o4 I( f, n) o- l5 x
  3.   * @param  USARTx: where x can be 1, 2, 3, 4, 5 or 6 to select the USART or
    2 t: z9 e: D; r1 U
  4.   *         UART peripheral.
    * [9 R. }2 I+ p: X6 Q% l3 w4 m
  5.   * @param  USART_IT: specifies the USART interrupt sources to be enabled or disabled.
    4 D5 }" M# X: t# V( G
  6.   *          This parameter can be one of the following values:
    5 M( t) \; V  j+ Z/ {
  7.   *            @arg USART_IT_CTS:  CTS change interrupt
    * a# X1 W. H, t2 f
  8.   *            @arg USART_IT_LBD:  LIN Break detection interrupt; ]* @* U- X, I2 c
  9.   *            @arg USART_IT_TXE:  Transmit Data Register empty interrupt
    $ F2 r2 |* m# {1 _' \$ V
  10.   *            @arg USART_IT_TC:   Transmission complete interrupt
    8 p. x) \$ L4 @4 a8 N
  11.   *            @arg USART_IT_RXNE: Receive Data register not empty interrupt& g7 m( T8 B; ~6 @
  12.   *            @arg USART_IT_IDLE: Idle line detection interrupt
    ( y8 W0 E! H6 A# a
  13.   *            @arg USART_IT_PE:   Parity Error interrupt
    * H& M' O( A+ Y+ t4 e
  14.   *            @arg USART_IT_ERR:  Error interrupt(Frame error, noise error, overrun error)
    % D+ u) X8 W) c/ A
  15.   * @param  NewState: new state of the specified USARTx interrupts.
    3 S9 f# q( X. y$ X" A
  16.   *          This parameter can be: ENABLE or DISABLE.% n/ s. O/ k& F! l3 \8 L( b9 O% m5 C
  17.   * @retval None
    + \* j9 n- y8 ]
  18.   */
复制代码

$ g' e7 e" I% y' b3 y8 Q  z
最后使能串口。
  1. /* Enable USART */8 v9 x3 C& {% Z: H  w' w- K
  2.   USART_Cmd(USART1, ENABLE);
复制代码
1 m0 b  N/ S3 B6 r7 Q' |1 t* a
main主函数,功能是LCD显示串口接收的10个字符(如果不是ascii码则不显示),串口倒序返回接收到的10个字节。
  1. int main(void)
    ! `' o# b: U  a4 k2 V
  2. {
    * L& q0 G- R4 F' ~9 V1 ~
  3.   while (1)# z( O, T' ]  ?& r* I. d8 n
  4.   {
    5 l% K/ }4 E2 r( d- X
  5.     if(LCD_refresh_flg){
    . e: @* L1 E/ z. K
  6.       LCD_refresh_flg = 0;
    0 |4 m/ ^4 }4 D5 j$ k' q: p
  7.       LCD_ShowString(0,16,receive_data);5 c' i) Q& {9 i) N3 f4 `
  8.       receive_num--;
    1 @9 ]1 k  t! K% ^' a2 n- B$ U1 O
  9.       USART_SendData(USART1, receive_data[receive_num--]);
    & t9 s5 B& h6 A$ [/ q: O
  10.       send_flg = 1;
    * v: Y( l. A. R" r, m( g1 o- t: C
  11.     }- ~% z/ ?! U; M: y* j4 i( }
  12.   }% t* E! B9 J. [. C
  13. }
复制代码
' K6 m. J- K% W
因为使能了中断,我们还需要编写中断函数。
  1. void USART1_IRQHandler(void)0 m6 y+ Q; G8 H: n2 V8 W  x
  2. {
    6 a0 i1 `; R4 K+ D& S: `% F' J
  3.   if(USART_GetFlagStatus(USART1, USART_FLAG_TC))
    4 \6 L0 h1 v( V6 P+ `( `$ w
  4.   {
    : w1 z, P; }$ T( a5 x) X7 h% ^( b
  5.     if(send_flg == 1){: h9 i/ a: K5 N: g6 \
  6.       if(receive_num==0){
    + R5 U( q% h, }5 _9 t3 I- n  ^
  7.         USART_SendData(USART1, receive_data[receive_num]);
    % J% N- c  n/ l" z
  8.         send_flg = 0;2 e$ t1 n* a: K/ f# ?% _! @
  9.         receive_flg = 1;3 ]) {7 p* J7 f0 X' ~* d5 \% p
  10.       }else{3 r/ u. R9 Y7 @
  11.         USART_SendData(USART1, receive_data[receive_num--]);
    ' M/ B8 k, |. Z- F' ]: Z- O: H
  12.       }1 C* X' h2 O, j+ s) r- f) r
  13.     }
    & r: z/ O+ z8 Z( C
  14.     USART_ClearFlag(USART1, USART_FLAG_TC);8 n, ]8 j8 Z- Y: T; A
  15.   }& P- Z6 \% F' ?6 P: S8 K1 P+ L, G0 W
  16.   if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE))
    ' c3 V( D3 L2 `5 Z  E1 }) S
  17.   {! ]2 p1 p8 H1 Z$ q" f8 ?
  18.     if((receive_flg)&&(send_flg == 0)){- u% I& o% w, Q1 s5 [' `
  19.       receive_data[receive_num++] = USART_ReceiveData(USART1);
    5 }- `! ]2 Y/ N; r
  20.       if(receive_num==10){7 E, ^+ N# W/ h7 Y2 I
  21.         receive_flg = 0;$ E* m7 y) z" E6 x  a* {1 a
  22.         LCD_refresh_flg = 1;
    0 h" `* E/ v% n( ]$ T1 w3 e
  23.       }6 r6 Y8 H! g8 h# C6 F- B
  24.     }
    % x: T% `; j& V& ~7 V' b
  25.     USART_ClearFlag(USART1, USART_FLAG_RXNE);: r* f9 V7 v$ I
  26.   }4 {% v; L3 k, W
  27. }
复制代码

$ p) M- n; e3 |  o; \( a) _% e3 q' G
下载验证
LCD显示屏可以显示接收的10个字符,且PC以100ms为间隔发送数据,发送977包收到977包回复,测试demo就够健壮,没有出现丢包。
1.8.png
6 L" [7 Z  w: H2 S" x* ?
PCB和工程代码开源地址:https://github.com/strongercjd/STM32F207VCT6
" ^, b2 m- e6 h* [( O" B
文章出处: 知晓编程
" C1 ?3 I% I4 V5 J$ }' z
赞 收藏 评论0 发布时间:2021-2-2 09:45

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版