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

【经验分享】STM32串口通信UART使用

[复制链接]
STMCU小助手 发布时间:2022-2-7 21:16
uart使用的过程为:
  • 1. 使能GPIO口和UART对应的总线时钟
  • 2. 配置GPIO口的输出模式
  • 3. 配置uart口相关的基本信息
  • 4. 使能uart口的相关的中断,如接收中断、空闲中断等
  • 5. 编写中断接收函数

  • # g$ y, O" t4 B' N4 B5 S
配置对应的GPIO口
对于STM32F4_Discovery开发板而言共有五个,选择UART5作为实验串口,其对应的IO口为PC12、PD2。
  • UART5_TX: PC12
  • UART5_RX: PD2. n% v' Q' D5 p& |- _
首先需要将对应的GPIO口配置为复用功能,如下所示:
  1. GPIO_InitTypeDef gpioInitStructure;
    , O8 J' a9 {2 ~4 j
  2.         //
    ' [1 Q' V6 e' I1 L, G6 J# n4 A
  3.         // 使能对应的GPIO口时钟
    7 B9 q+ C2 P7 z1 M
  4.         RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD, ENABLE);
    3 k* R  I3 d- H" p* p. I
  5.         //4 \2 \% @3 P9 L3 L
  6.         // UART5 TX:PC12  RX:PD2
    + X+ P' o4 w0 X2 }* X) p2 {
  7.         //4 M& D% V2 x# @4 J' z
  8.         GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_UART5);
    5 s$ w2 e) d8 d* ~
  9.         GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_UART5);3 j: o3 x: Z; T, _# U8 k3 V) K
  10.         //
    ! B$ l; _3 \- F. W) X
  11.         // PC12       
    0 U9 w6 C( A4 {! D
  12.         gpioInitStructure.GPIO_Pin = GPIO_Pin_12;2 H) m, |/ G: z8 {: Y; R5 ~2 T8 C
  13.         gpioInitStructure.GPIO_Mode = GPIO_Mode_AF;
    ( C0 o: R5 p$ w
  14.         gpioInitStructure.GPIO_OType = GPIO_OType_PP;' ^- Q- h" A0 W) F
  15.         gpioInitStructure.GPIO_PuPd = GPIO_PuPd_UP;: ]" j& Z; ]! R3 |: M+ M1 R6 `6 W& j
  16.         gpioInitStructure.GPIO_Speed = GPIO_Speed_2MHz;        9 o3 @4 C+ s( n; g- ]
  17.         GPIO_Init(GPIOC, &gpioInitStructure);       
    7 m7 U2 s/ J8 W; [! L
  18.         // PD29 f, Q# w, W, h+ A6 o9 X$ h/ p
  19.         gpioInitStructure.GPIO_Pin = GPIO_Pin_2;
    , F1 M, t/ `3 S6 ?# l( I1 g
  20.         GPIO_Init(GPIOD, &gpioInitStructure);
复制代码
6 ]  ^- g/ y+ {
对于GPIO口的配置,实际上是对GPIO各个寄存器的配置。GPIO_PinAFConfig()函数作用是配置GPIOx_AFR寄存器,每个口的复用功能选择由四个位来配置(具体参考STM32F4XX参考手册),因此16个GPIO空需要两个32位寄存器,在STM32F4处理器中,分别是GPIOx_AFRL、GPIOx_AFRH。而在库函数中,将寄存器的地址对应到相应的结构体上,与这两个寄存器放在一个AFR[2]数组中,如下所示。
  1. typedef struct
    " y$ E4 J4 k3 L% p7 g6 {
  2. {9 c7 }, _2 Q: y; F5 ]/ ?, M
  3.   __IO uint32_t MODER;    /*!< GPIO port mode register,               Address offset: 0x00      */, H, R2 ]6 m) {  B
  4.   __IO uint32_t OTYPER;   /*!< GPIO port output type register,        Address offset: 0x04      */+ N8 Q" C/ [0 P7 R- Z
  5.   __IO uint32_t OSPEEDR;  /*!< GPIO port output speed register,       Address offset: 0x08      */! O( f1 O: F9 l6 R0 @; @
  6.   __IO uint32_t PUPDR;    /*!< GPIO port pull-up/pull-down register,  Address offset: 0x0C      */
    ; i* G1 ~1 j# I* j! y9 G
  7.   __IO uint32_t IDR;      /*!< GPIO port input data register,         Address offset: 0x10      */+ {( A- u1 @4 t1 _7 T
  8.   __IO uint32_t ODR;      /*!< GPIO port output data register,        Address offset: 0x14      */% a& E5 x( @, l/ U* T6 X
  9.   __IO uint16_t BSRRL;    /*!< GPIO port bit set/reset low register,  Address offset: 0x18      */
    2 R) g" M( i' K* B' ?& n5 f
  10.   __IO uint16_t BSRRH;    /*!< GPIO port bit set/reset high register, Address offset: 0x1A      */& |  K9 [$ }7 o, j
  11.   __IO uint32_t LCKR;     /*!< GPIO port configuration lock register, Address offset: 0x1C      */# _  ?& _7 u9 K8 }2 T. `
  12.   __IO uint32_t AFR[2];   /*!< GPIO alternate function registers,     Address offset: 0x20-0x24 */+ J( Z2 p! O1 I5 R- l& Z  z$ O
  13. } GPIO_TypeDef;
复制代码
% s5 J2 Y( `) w' H
GPIO_Init()函数作用是配置GPIO口的输出输入功能,将GPIO_TypeDef结构体中的寄存器依次配置为相应的模式。
GPIO口配置完成之后,需要配置UART口。
# S! Z3 x" O, h8 i
UART口配置
配置UART口的同时,需要配置对应的接收中断,对应代码如下:
  1. NVIC_InitTypeDef nvicInitStructure;
    $ D+ h8 ?3 V/ k" ~
  2.         USART_InitTypeDef uartInitStructure;
      Z6 n! [9 R; n+ r/ q; J' M  |9 N
  3.         //使能uart5时钟
    3 l; {( ]* n8 e
  4.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5 , ENABLE);1 ~: N& W5 o, y$ e/ [
  5.         //
    5 f# w3 E6 e8 A; @. e% W. i
  6.         // 配置UART5
    / i8 ?, W& D; P. t4 C
  7.         uartInitStructure.USART_BaudRate = 9600;
    ; S9 s9 q5 |/ i. `
  8.         uartInitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;% |% h3 C: ?  k! N3 ~, U
  9.         uartInitStructure.USART_WordLength = USART_WordLength_8b;- W& E3 g, B8 L4 \, M# Y& H! i
  10.         uartInitStructure.USART_StopBits = USART_StopBits_1;8 a8 R/ X6 V% ~1 J4 w9 a' k$ ?
  11.         uartInitStructure.USART_Parity = USART_Parity_No;8 B3 _5 z; @; g1 S& G: B
  12.         uartInitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    8 R' y0 s: T. ?! z
  13.         USART_Init(UART5, &uartInitStructure);3 P3 q1 M8 Z8 @7 g2 I
  14.         //
    3 e& k% V( I1 h1 z" ]) `
  15.         // 配置外设接受中断
    0 c" D) o% M- b$ @5 E0 w( {1 _
  16.         nvicInitStructure.NVIC_IRQChannel = UART5_IRQn;        ' y- ]/ A/ T  u! Z% {
  17.         nvicInitStructure.NVIC_IRQChannelPreemptionPriority = 0;8 J9 J* ~! b! Q2 n: {! n  D! O
  18.         nvicInitStructure.NVIC_IRQChannelSubPriority = 0;
    0 i3 h3 r, U' [3 U- R$ J
  19.         nvicInitStructure.NVIC_IRQChannelCmd = ENABLE;
    & T& h1 s1 m7 `8 F0 T  J" P0 c- U
  20.         NVIC_Init(&nvicInitStructure);
    1 f: y6 z3 y( ?' O" c. S6 Q$ {  T
  21.         //& X3 y& t1 A' h( ]+ ]+ C* }0 t
  22.         USART_Cmd(UART5, ENABLE);
复制代码

- w1 [. y; Z' A" e4 H) N9 ^3 z
配置UART5的过程主要由USART_Init()函数实现,该函数完成对UART寄存器的配置。在库函数中,UART寄存器如下所示:
  1. typedef struct
    & J: m$ O6 f0 m) ~
  2. {
    7 |; g+ s: e( G0 o
  3.   __IO uint16_t SR;         /*!< USART Status register,                   Address offset: 0x00 */
    * p4 g& u6 \* Z: e, |5 Y2 B) G
  4.   uint16_t      RESERVED0;  /*!< Reserved, 0x02                                                */  }) y0 P: K* u/ i
  5.   __IO uint16_t DR;         /*!< USART Data register,                     Address offset: 0x04 */% w& E: k9 a* x( {/ j! A3 x
  6.   uint16_t      RESERVED1;  /*!< Reserved, 0x06                                                */
    / k6 E. E- V1 s  m. d" S
  7.   __IO uint16_t BRR;        /*!< USART Baud rate register,                Address offset: 0x08 */3 l2 Y- U% K7 G
  8.   uint16_t      RESERVED2;  /*!< Reserved, 0x0A                                                */' ?9 P  P! M7 c
  9.   __IO uint16_t CR1;        /*!< USART Control register 1,                Address offset: 0x0C */8 B+ M% r& }+ L" g* J
  10.   uint16_t      RESERVED3;  /*!< Reserved, 0x0E                                                */$ g2 f' Y% o2 J! H$ J% ~
  11.   __IO uint16_t CR2;        /*!< USART Control register 2,                Address offset: 0x10 */
    2 ]4 M# y8 O8 p  \% J
  12.   uint16_t      RESERVED4;  /*!< Reserved, 0x12                                                */
    2 y! W4 J. Y7 Y4 o) v, v
  13.   __IO uint16_t CR3;        /*!< USART Control register 3,                Address offset: 0x14 */% R- ]. n4 h, f5 \% g* n
  14.   uint16_t      RESERVED5;  /*!< Reserved, 0x16                                                */% ^1 A* F0 ?( c0 R
  15.   __IO uint16_t GTPR;       /*!< USART Guard time and prescaler register, Address offset: 0x18 */
    * H0 k5 ?; z' x% c' S# v8 O
  16.   uint16_t      RESERVED6;  /*!< Reserved, 0x1A                                                */
    & I$ j2 _# b  h, V
  17. } USART_TypeDef;
复制代码

8 u# o$ h, m# C, G
UART寄存器详细内容可以参考STM32F4中文手册,这里简单介绍下以下几个寄存器:
  • SR寄存器:状态寄存器,包含了一些标志位,如TXE(发送数据寄存器为空)、TC(发送完成)、RXNE(读取数据寄存器不为空)
  • DR寄存器: 数据寄存器,只用其低9位(DR[8:0])。当发送数据时,将数据写入该寄存器,该寄存器将数据发送到TDR或者移位寄存器发送,当数据写到移位寄存器时,TXE标志置1(数据写入时置0)。TXE为1时可以继续写入数据,否则新写入的数据会把原有数据覆盖。读取数据时,也是从该寄存器读取数据。
  • BRR波特率寄存器:波特率寄存器,用来设置波特率的值。
  • CR1寄存器:包含使能位UE、字长M、过采样倍率、奇偶校验、接收使能、发送使能等控制信息。
    4 W$ ]% p! s9 y: f
数据收发单字符发送        & ]2 v5 q  N# {6 c% F
  1. //发送一个字符,USART_SendData函数实际就是将字符写入USART_DR寄存器
    $ U0 p! m, ^$ H& U
  2.         USART_SendData(pUSARTx,ch);5 m- i! V/ m0 u0 g2 x& b( I
  3.         //
    / D( H$ D* u2 p% b4 l
  4.         //等待发送寄存器为空,只有当USART_FLAG_TXE == 1 时才可以继续想DR寄存器写入数据,否则会将上一个数据覆盖掉。) u# T8 T+ m! {# {3 `
  5.         while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET)
复制代码
" u% f  c: t" z4 M: E$ B* i( L

3 M6 L, l* |, X" Y. O, |字符串发送 2 S; i+ `$ U* S$ e5 B! t7 I, c" q6 s
  1. /***************** 发送字符串 **********************/' w$ M0 M/ `. i# W4 H
  2. // 发送字符串是每个字符依次发送,相当于循环执行单字符发送函数。
    4 j' v& h# A) A
  3. //
    & d4 ?" [" P3 N! @
  4. void uart_send_str( USART_TypeDef * pUSARTx, char *str)
    6 }. U4 B$ q/ H2 Q. @# b7 ~: b
  5. {1 g' s) q5 x1 \8 N
  6.         unsigned int k=0;
    9 o# ^/ e: _$ n& w7 _- D/ H
  7.         //
    * u/ `. W1 v2 _0 z! a
  8.         do {
    3 v5 O6 B7 I8 v3 @1 q+ B+ B
  9.                 uart_send_byte( pUSARTx, *(str + k) );
    ; R4 R- n' V/ g  _
  10.                 k++;
    4 e: X& I! h* p5 e9 b# ?: B, ^2 `. p
  11.         } while (*(str + k)!='\0');- ?6 N' {! G& I, C# s: V% N; C: F
  12.         //  R4 E- Q' a; ~
  13.         /* 等待发送完成 */
    / z- x$ I7 [% `: E1 n8 x, |
  14.         while (USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET) ;
    1 F  [$ O* v, D% M; V9 c
  15. }
    ( _" K" ^& F3 Q. z
  16. //3 ~; h' G! l# z, t6 I7 }
  17. // USART_FLAG_TC为1的条件是,DR寄存器为空并且以为寄存器也为空。相当于所有数据都发送完毕1 D; }6 {, `% Y9 c% k
复制代码
字符接收
0 Y! C/ l7 o- K' V9 q; c* i
  1. uint8_t ucTemp;        4 J* d6 p9 d6 k" L0 `3 q
  2.         if (USART_GetITStatus(UART5, USART_IT_RXNE)!=RESET){
    3 d! r2 s) I# R& B! `
  3.                         ucTemp = USART_ReceiveData( UART5 );5 b+ P/ e5 w  W8 t$ i
  4.                         // USART_SendData(UART5,ucTemp);
    # a- u, y% h! C( Z% W7 l3 X
  5.                 }+ m/ [9 @1 ~+ b  ?3 M
  6.         // USART_ReceiveData()函数是将DR寄存器读取并返回; ^$ m4 t, T  T" x
  7.         // USART_IT_RXNE不为0表示数据寄存器中有数据,需要将其读出。$ o: [! J/ c7 E0 X3 j
  8.         // 每次收一个字符,USART_IT_RXNE会被设置为1,直至数据被读出,USART_IT_RXNE再次被设置为0.
    7 a1 R2 y- j6 ]
  9.         // 同时,USART_IT_RXNE也被设置为中断的标志,即接收到数据时,进入中断。
    ! A0 ^$ E+ }4 ^* `0 T5 d' Y
复制代码

$ q" n7 S# N/ o8 i5 i# [, }& Z- f0 e& u5 u, z- p: T
  \/ N& w. t( h
收藏 评论0 发布时间:2022-2-7 21:16

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版