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

STM32F103之UART上位机通信

[复制链接]
flyingstar 发布时间:2025-8-14 18:09
一、USART简介$ Y& \; [# C% }
1.1 UART 简介
  y: B2 \- o& k3 Y2 P! F5 s通用同步异步收发器(USART:Universal Synchronous/Asynchronous Receiver/Transmitter)) A; X! ~5 v; i! Z" ^
特点:串行、全双工、同步/异步通信(USART可支持同步通信,UART只支持异步通信)
; l$ h; z: w  I( |  D
7 ^# w8 U( ]1 X2 K( y* _, i发送和接收共用的可编程波特率0 @) L; M0 |7 C: _
可编程数据字长度(8位或9位)(常用8位)
2 Y. b* z6 I# W8 L2 {& ]# I可配置的停止位-支持1或2个停止位(常用1位停止位)
: N; Y6 O! M' P* ^! I0 U1 i可配置奇偶校验位(一般不用)# J0 @. Z7 Q& N( A$ Q3 I- Z* d: ^3 N
8 O* [4 l* @" ]1 @; @! b0 \
1.2 物理拓补图
- m  K* U, m  _7 x, ?2 p8 i接口通过三个引脚与其他设备连接在一起。任何USART双向通信至少需要两个脚
! [- s; E0 O0 p( Y/ v! W2 h$ eRX:接收数据输入
8 O% P* c8 d; q. bTX:发送数据输出
* |- `/ F: h5 wGND:双方要共地,双方通过USART进行通信,两个设备必须要共地,因为逻辑1---3.3V电压(对于地的电压),如果两个设备不共地则对地电压的高电平(3.3V就可能不太一样)。共地的意义是让两个设备的通信电平对地电压相等+ f) T. _: V  q; i' T
3 d& h0 n& t; C  q: S; Z2 M4 d+ H* Z
143313vbrrl0ybxaap3skz.png.thumb.jpg
8 b) C# @' d% W1 R) g/ K+ ]( u& e" [! G- _% J
1.3 数据帧格式
# t3 m( |. {7 h# c1 w+ h' ?* h一帧数据=1bit起始位[低电平]+8bit数据位+1bit奇偶校验位[可以不用]+1bit停止位[高电平]4 [! E9 c% V0 W- }; k+ \" u

. ^; D! M# d9 @- `1 W* u) l4 `/ G9 ]USART总线空闲,即没有数据发生,TX线为高电平7 D9 Z& j6 ]. K* Z7 I  r
$ V0 e% x& x8 q/ O  K9 q, Q
<1>数据位:USART发送的1次数据量是1Byte=8bit;[5、6、7、8]
) H  k: _+ y" L  W' _1 v$ r<2>数据字:数据位+奇偶校验位;如果不用校验位,数据字=数据位=8bit;如果使用校验位,数据字=数据位+校验位=9bit1 o$ {3 C; J! a7 x' |3 z: ?7 e# z
                    奇校验:数据位中的1的个数+校验位中的1的个数为奇数+ O# S% i2 ~. z5 ], \! N8 Z6 K( D7 f
                    偶校验:数据位中的1的个数+校验位中的1的个数为偶数
  V$ X1 q% j5 T/ \: Y<3>停止位:可以被配置为1bit(默认);2个停止位(可用于常规USART模式、单线模式以及调制解调器模式);0.5个停止位:在智能卡模式下接收数据时使用;1.5个停止位:在智能卡模式下发送和接收数据时使用5 t6 t% N; ~* N+ ~7 ?
<4>发送顺序:先发送低位,再发送高位
& L. j' `% I$ J( @
5 v( ~# H! F5 q+ j) g7 h6 }1.4 框图
& j( n8 ?# }2 ~, Y
( f- ?4 h% [3 {7 T5 a  p3 O 143305ex594sdg0xa59ahj.png.thumb.jpg ; z4 w& s9 g; C$ q* L* n! b
( F! c! ]. @) g5 b$ J' h) h
对于这个框图,最关键的是两个标志位TXE(发送为空标志位),RXNE(接收不为空标志位)
; S5 v# f4 E; A数据通过RX端口进入MCU的UART的接收移位寄存器,随后进入接收数据寄存器(RDR),进入后RXNE被置1,表明可以读  f: ^$ c5 a/ R( ]8 a. J1 _
MCU通过数据总线获得数据,数据再到发送数据寄存器(TDR),若TXE=1,说明数据已经被转移到移位寄存器,表明可以发送5 ]& e* h1 O" h

; y7 j/ s! \! R( _6 T二、串口通信
1 C$ K' G4 x: Q配置UART
) {) b# F! S- {) Y
8 p' l, n- i! ?2 `) t+ R开启了接收中断和空闲中断) |3 W4 I& I  s3 H6 a
0 [; c2 y' }# t* W
/****************************7 C  E+ u! ]2 |/ w! ^7 v5 L8 ?$ ?# N
*@brief    uasrt1端口配置函数( |, j+ E% V; ]; d" s
*@param     void2 Q2 R: C# ~# S  z
*@return    void
' }* t  T) ?: `4 L$ f$ b& u4 H7 G*@NOTE      PA10->RX PA9->TX
4 |  @" D% `$ r, X. G% X, B" f            PA10,PA9位于APB2上% B5 g5 j( |. A; b1 }. ^  y
*@time     2025-6-3% w+ n2 k4 r+ a1 r* D4 d3 y+ d: Q
******************************/
! x" W" {: b! g- [" Zvoid usart1_Init(uint32_t Baud_Rate)* h' d+ C2 I  P$ r! I6 ~
{
) h- [# t$ C4 U0 l- D% E, Q        //1.打开引脚时钟PA4 Q+ `( e8 B( e" @& R. g3 u* X7 [2 X
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE)      ;! ^+ z4 K) B9 |  t
       $ e) V; j" C) d
        //2.打开usart1时钟( W- B+ T5 f/ z9 s/ H4 s8 \
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE)    ;
% @" K7 t( }3 B       9 q0 S0 }2 s9 M+ O) C, U* z! M
        //PA9->TX推挽复用输出
; A7 j$ a/ @0 E% T% w6 b        GPIO_InitTypeDef GPIO_InitStruct_TX                      ;& y' @* [, W3 y
        GPIO_InitStruct_TX.GPIO_Mode  = GPIO_Mode_AF_PP          ;. P1 E+ c' r( o7 y# R
        GPIO_InitStruct_TX.GPIO_Pin   = GPIO_Pin_9               ;
; V5 T  `6 @; j9 v0 y        GPIO_InitStruct_TX.GPIO_Speed = GPIO_Speed_10MHz         ;
! s# k$ Z0 q+ K% }" u        GPIO_Init(GPIOA,&GPIO_InitStruct_TX)        ;
. r8 `8 k& G+ [       4 _/ {0 {- j' n! Q. R
      
( l# ~# R5 }6 F        //3.配置,PA10->RX浮空输入
3 o& `: z8 k# b. e' O        GPIO_InitTypeDef GPIO_InitStruct_RX                      ;
% J8 S$ ?2 ^! ]* M" N' a2 r        GPIO_InitStruct_RX.GPIO_Mode  = GPIO_Mode_IN_FLOATING    ;
; D: [$ g/ J3 [* `! ]) Y        GPIO_InitStruct_RX.GPIO_Pin   = GPIO_Pin_10              ;
5 k0 @/ F% Z9 i* V        GPIO_Init(GPIOA,&GPIO_InitStruct_RX)        ;
; [7 P& l% Y( z; r* M3 M0 P      
4 b- ?% u* I: Y, H$ K* {! x' c        //4.配置usart1,
' S9 r: M& j' U2 R8 w& Q        USART_InitTypeDef USART_InitStruct                                           ;
" I5 z4 d4 V( K) E9 R; r$ u        USART_InitStruct.USART_Mode                = USART_Mode_Rx|USART_Mode_Tx     ;: G: _! U4 s2 a2 F
        USART_InitStruct.USART_Parity              = USART_Parity_No                 ;& }& l: c7 B  y' }& h
        USART_InitStruct.USART_StopBits            = USART_StopBits_1                ;
0 y- d- X3 o: g) C        USART_InitStruct.USART_BaudRate            = Baud_Rate                       ;       9 u9 m3 F& j5 Q8 d$ a& h: K
        USART_InitStruct.USART_WordLength          = USART_WordLength_8b             ;6 ~4 A8 B: N% Q: {
        USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None  ;/ I4 i9 t5 h/ [; Q( O! G
        USART_Init(USART1,&USART_InitStruct)                                         ;3 g. ?: {) B! K- b7 S

0 V5 P- n8 o. t  A" v& M                  
3 g* K3 Z; ~6 R; C                  USART_ITConfig(USART1,USART_IT_RXNE,ENABLE)                     ;//开启接收中断 RXNEIE=1
- _/ ~7 x0 f: E  O* b1 C                        USART_ITConfig(USART1,USART_IT_IDLE,ENABLE)                     ;//开启空闲中断 IDLE=1
) F* h1 y$ H% {0 i, @                  //初始化NVIC& C5 S$ f8 i3 t5 w
                  NVIC_InitTypeDef  NVIC_InitStruct                               ;8 ^- |7 T! y0 ?( i
                  NVIC_InitStruct.NVIC_IRQChannel                   = USART1_IRQn ;//中断通道0 ~" _6 s6 E% B
                  NVIC_InitStruct.NVIC_IRQChannelCmd                = ENABLE      ;//中断使能
' s1 K, ~- ^8 H3 f                  NVIC_InitStruct.NVIC_IRQChannelSubPriority        = 2           ;//响应先级
9 {$ y4 l. S! q1 e/ e              NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2           ;//抢占优先级
$ d$ b2 A& r" `              NVIC_Init(&NVIC_InitStruct)                                     ;3 x5 \* u/ W" H# D; {# m8 e
       ( F9 F. o$ Q- M: S2 q
        //5.使能usart1
* L% ^- K3 F* ~* Z1 Q6 s- g2 X% `6 R        USART_Cmd(USART1,ENABLE)                                                     ;6 A: ?3 I2 d: O+ H0 Q2 q
}  
" Z4 ~& m- Z- |/ @6 ]
3 C/ O: m9 }) T9 I# e; f5 {  K
$ u- E" e  P! E接收发送函数- b" ^* K1 P7 d+ P0 L
/ d- C7 w: Q% e0 G! D" M6 y
/****************************2 n4 K* ?% h: h  C) N
*@brief     发送字符函数" ~( q5 a/ F% a
*@param    void
  u+ d7 I, F7 n4 H" c*@return   void
; ?* ?6 Y& q! U/ u$ Z, @*@note     MCU会将数据发送到DR寄存器中的TDR寄存器中,
4 h9 J) ]& q1 A2 n当TXE==1时,TDR寄存器会将数据加载到移位寄存器中,可以发送
3 k3 R, c% v6 I5 e  ^*@time    2025-6-3) D7 a& ?4 {4 X! |
******************************/
, b  G  c2 X6 \8 e' H9 R9 gvoid usart1_sendbyte(uint8_t str)
  k9 w# [( x9 A{6 ?- V3 {) A  n5 K5 t& E! y
        while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==0);
# D  f0 V' |! O# V4 b        USART_SendData(USART1,str);
1 A; l2 }, e# R0 Q5 U}3 u; w/ P: @6 R1 h
% f) [1 M6 J) \+ H( v
/****************************
1 J, j5 ]5 D) {( i6 @  S*@brief     发送字符串函数
! U7 r5 a# l! @( C9 f*@param   uint8_t *str- r) O% H, c7 l. z5 K( ~3 f
*@return  uint16_t len0 G" r% v) u5 a/ [5 Y
*@note    发送字符串本质上就是发送字符' s. o; t* j! f0 C0 V) u  O: C
*@time    2025-6-3
: P2 v" N8 \' o# w3 Q: p******************************/* V/ M; x' J+ R0 ]( c2 D  V0 j
void usart1_sendstr(char *str,int len)" ^; i  a7 G8 g( S& Z
{7 N( h! q6 n, ]6 y5 p4 R
        while(len)
; K! t% S1 E: J   {+ [* K, W; N( C9 Y- f
                 usart1_sendbyte(*str++);
- t2 Y) O8 j9 i& @) Y5 X                 len--;
# J7 ^3 Q% e8 k         }
5 G; Y; m) z- O% s}: D# f" B8 \) n. ?; q5 \) L! @

6 H: C& s0 {. W7 v8 ^4 `2 e2 X/****************************
3 Y- x+ ~" f' b! d5 I9 u& `8 g& F*@brief    接收字符
1 j' X6 D& q' K! V6 ^8 N% p*@param    void1 h, {1 A9 ^% j" q
*@return   void3 ]1 h2 Z) t0 s: }  a2 o
*@note    MCU接收到数据后先放在DR寄存器的接收移位寄存器: ~4 s. x4 C$ [
          数据会到RDR寄存器中,当RXNE==1时,说明RDR有数据,可以读# p; n$ J- O* M0 s1 h' E
*@time     2025-6-3
/ ]. q4 C/ |6 \. c' ~: Z******************************/
' [( Z; {1 n5 s' L- huint16_t usart1_receivebyte()- j, x+ o* s7 H* [% I
{
& T& l! J+ v' T. C6 a6 R8 C        while(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==0);
* a) o- ^/ `# F3 U  H        return  USART_ReceiveData(USART1);
, A* B1 a; }& h  |: ?, v7 H" T}; K5 b8 c) m' K' Y1 C! O* n
/****************************
5 @& @8 K4 [, X* c*@brief    接收字符串函数(idle标志位)+ q% c; E* ?7 g- y
*@param  void
. S1 [8 E# c" \% O& x. N*@return   void
( \" f7 |7 l" N1 O*@note     void
6 P0 u# R, m4 D*@time    2025-6-3$ I8 r7 u: ]- C$ z. X
******************************/- G% P: |# l- X
void usart1_receivestr(char*buff)
7 f6 ^1 k  N( b/ S3 m{
( n$ Z# ?7 _: E        uint8_t flag;! t( M/ s' Z9 k
        while(1)3 ]9 [( K; d1 W. P3 o
   {
5 _( x/ t5 e" n; c4 X                 if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==1)
2 J! R& T4 Y- c' }0 o* g* [% C       {
* J8 y9 U) e1 F0 K; P/ [                                 *buff=USART_ReceiveData(USART1);+ \/ M( I% Y, z5 N% m# l" x+ A
                                 buff++;) L, z( O) ?* N& I' }
                                 flag=1;8 u+ T- q0 ?5 @/ z# q2 K& g
                         }. g! {; p6 A7 \' F. {3 q5 K2 `
                        if(USART_GetFlagStatus(USART1,USART_FLAG_IDLE)==1&&flag)" D. f& D/ E1 p2 ]# s9 m* M6 ~; N# c
       {; u, l5 u. _  q
                                 *buff='\0'; //当发送时 发送结束标志
& q( M+ m( F: Z7 \5 ]                                 //先读SR,再读DR将置IDLE位置0
% R% `) g/ y$ k. Z* H' t$ _& s5 ]                                 USART1->SR;
/ W5 o3 |' ~- b  h2 ~                                 USART1->DR;+ T* E' q# T+ w7 h$ a
                                 break;
7 c9 A$ t% |# E$ b+ I4 R( \3 G% m" k                         }9 S: b9 |/ L/ W
         }) n/ y" `! I! X: W+ B) o3 n) O. t
}/ F2 d( b  l9 S
! _- z  E3 c- @% [2 L
3 j1 [0 y0 T& a) v$ q. V+ K: T
打印函数
! k+ Y5 K0 ?, @8 q# K
. {% g; ~1 o9 r) F* j+ I记得勾选微库,printf函数不涉及到中断,它是将内存中的数据输出到上位机
& k) U6 W3 H( P( L5 X7 ?4 Z, j: W. n3 w4 s$ p& b
//printf()的底层借助fputc函数进行输出5 p/ C# \1 i1 ?# H: N
int fputc(int ch,FILE*stream)- H" H- e& Q# l5 D! g. k- g/ n6 j  L
{# A" f+ E" h7 K" s) u+ n; |
        usart1_sendbyte(ch);" g& s$ K+ M! g$ C+ {, S
        return ch;
/ z% j. z$ s/ b, |}5 G5 `, O/ S- h( |$ T& R' `

, l/ l0 A) T/ O' I2 V$ J! ~% M3 K5 D% x2 w: [6 f
143243jrwwvnvkww4wvrto.png 5 ~3 t: K' G0 J7 n

0 F4 q' w& W5 A  o5 `' _2 B8 E中断函数
) c9 d$ r$ K. W# DMCU接收到数据时,进入接收中断函数,将数据存到rx_buff[100]数组里;当上位机不发送数据时,说明空闲状态,进入空闲中断,将 rx_buff[100]数组里面的数据发到上位机; v! W. l. }8 J. Q, h8 {
% b: s- X! q, Q: R2 ]( Q. }
/****************************& h/ E/ A4 u& V, K9 c6 w; [
*@brief    usart1中断实验
. j# {& @' g4 f+ P*@param  void
: j" j% ?) A; D! w*@return   void
) i* q. @, K# ~: B3 P1 }: J2 e*@note     void0 h4 r$ ]" N+ C) c- Q. ~( l
*@time   2025-6-4- @$ l+ v0 y  e; }6 L; X
******************************/
+ g- e' f3 t( S8 Z- J3 echar rx_buff[1000]={0};. R4 o$ m4 u# _) E  J
char cnt=0;7 b- P$ N' [9 W
void USART1_IRQHandler(void)
1 T. a  A" t# H{
( ^. f" l; ]8 O5 j   //当RXNE=1时,有数据接收
( G6 H5 B: @" n, Z+ E( h        if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET)# `) l& ^( B0 n6 P
   {4 _; B1 H" f  {# w% k. X
                 rx_buff[cnt++]=USART_ReceiveData(USART1);
. H! j- _$ L3 J. z9 C# G                 USART_ClearITPendingBit(USART1,USART_IT_RXNE);//清除标志位) s+ q. R* z" a+ W$ c: o# j/ n
         }
' ?* m( o9 A4 X  H8 p         
0 l3 w, ]: I7 I: {) m1 z         //当IDLE=1时,0 C5 K  C( x: l  J
        if(USART_GetITStatus(USART1,USART_IT_IDLE)==SET)
9 g2 j# R. K- G' N' r   {" Q0 y& H5 B: Y: P5 [2 O
                 usart1_sendstr(rx_buff,strlen(rx_buff));- }- f" X7 \8 Z' ~) T
                 cnt=0;1 t: H6 \9 a- f. s
                 USART1->SR;# o, k' \- Q8 n# A7 A( s/ O
                 USART1->DR;                                  //清除标志位0 b! m! E2 s0 E/ w/ Y
         }
0 j( [) c- s, L, X7 S& S}% K0 a5 _! ^" N. b& @  F

! W* c$ w% a$ K0 N" X" K
3 v$ j& y1 m* h, \$ m( @————————————————3 z& |: ~+ H/ w) {0 Y- ~) L
赞 收藏 评论0 发布时间:2025-8-14 18:09

举报

0个回答

所属标签

相似技术帖

官网相关资源

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