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

STM32F103之UART上位机通信

[复制链接]
flyingstar 发布时间:2025-8-14 18:09
一、USART简介; Q: G- b- }( X, o+ k
1.1 UART 简介
8 _. d! [8 ?$ i3 ]+ u, o% j通用同步异步收发器(USART:Universal Synchronous/Asynchronous Receiver/Transmitter)
5 G. s% t+ U: ?  A8 g6 I5 U特点:串行、全双工、同步/异步通信(USART可支持同步通信,UART只支持异步通信)
! s0 E) P" C. X/ m' S% L/ }% K- W" g& L* _6 H, ~& D
发送和接收共用的可编程波特率2 s% k/ b# z/ G  _% n0 W# m( [
可编程数据字长度(8位或9位)(常用8位); q0 V& l) J3 T+ x
可配置的停止位-支持1或2个停止位(常用1位停止位)1 P" Z  u1 k! g4 w
可配置奇偶校验位(一般不用)
! u2 _3 M4 z& A+ H0 d3 A: X9 d2 N7 `8 X
1.2 物理拓补图7 b; [3 l! @% ?" ?' N& N. O
接口通过三个引脚与其他设备连接在一起。任何USART双向通信至少需要两个脚: a6 P- n( v5 Z8 |" a  }/ r) T. }
RX:接收数据输入
7 |# c: P% R  |( S% MTX:发送数据输出* J/ d7 O1 b4 c& v0 y8 A
GND:双方要共地,双方通过USART进行通信,两个设备必须要共地,因为逻辑1---3.3V电压(对于地的电压),如果两个设备不共地则对地电压的高电平(3.3V就可能不太一样)。共地的意义是让两个设备的通信电平对地电压相等" G6 T/ Y9 }3 W& P" {1 R+ E
3 ?' W  B, x8 S0 S" q$ ]- P
143313vbrrl0ybxaap3skz.png.thumb.jpg / L2 n) e- T3 c3 o: ?/ a5 O
. a8 p+ X. l" ~, V
1.3 数据帧格式# O8 D9 K2 r3 Y3 J
一帧数据=1bit起始位[低电平]+8bit数据位+1bit奇偶校验位[可以不用]+1bit停止位[高电平]- B' l# x3 I: B+ @
4 d* c% m9 U0 I' Q; d
USART总线空闲,即没有数据发生,TX线为高电平
+ f1 d. {  o& W, X3 g+ X& g
6 i& V6 L9 ?6 a4 [0 _<1>数据位:USART发送的1次数据量是1Byte=8bit;[5、6、7、8]& p( B8 ?0 r! f: u
<2>数据字:数据位+奇偶校验位;如果不用校验位,数据字=数据位=8bit;如果使用校验位,数据字=数据位+校验位=9bit
# j' x2 i) p. {                    奇校验:数据位中的1的个数+校验位中的1的个数为奇数: ?5 F8 T4 @; J) C9 j" L% g
                    偶校验:数据位中的1的个数+校验位中的1的个数为偶数
0 W9 V9 _1 a% |" ?0 }<3>停止位:可以被配置为1bit(默认);2个停止位(可用于常规USART模式、单线模式以及调制解调器模式);0.5个停止位:在智能卡模式下接收数据时使用;1.5个停止位:在智能卡模式下发送和接收数据时使用+ O0 k- `2 q" Y% n9 Q
<4>发送顺序:先发送低位,再发送高位' s8 g0 W" }  G* {( k- Z8 F% l
4 v! Z' ?4 u+ C1 w" h# @) }- Q
1.4 框图2 k8 L/ t- A# ~7 t4 a$ E

1 l5 q1 N7 U( J7 n 143305ex594sdg0xa59ahj.png.thumb.jpg
# [% Y& }0 g6 V) F- X9 C7 t2 U5 E) r$ w' D; l- x+ y! A* p, G
对于这个框图,最关键的是两个标志位TXE(发送为空标志位),RXNE(接收不为空标志位)9 \3 _& A1 U1 R) _* b6 X% ]
数据通过RX端口进入MCU的UART的接收移位寄存器,随后进入接收数据寄存器(RDR),进入后RXNE被置1,表明可以读' f+ X3 P( k$ q/ P8 N
MCU通过数据总线获得数据,数据再到发送数据寄存器(TDR),若TXE=1,说明数据已经被转移到移位寄存器,表明可以发送
$ n) }  C% A/ }0 u1 C: Y1 z
0 T! _& F% w3 h; F二、串口通信' \$ Y& E- X& R$ l
配置UART  z* j2 Y7 k( k
. m7 l" F/ y% p
开启了接收中断和空闲中断
! ?& U3 h& |5 B$ D1 k0 W' {
3 x; G- M$ p' `6 M" b/****************************  }0 A  A! Y$ x/ y5 I! a$ V+ }
*@brief    uasrt1端口配置函数
4 U) e, d" u5 q' R. Y+ J8 n*@param     void
, K# G+ R% I' }$ z3 n5 q  d*@return    void
7 S! g! Z8 F. q7 H* q*@NOTE      PA10->RX PA9->TX
, ]7 G% n  f& Q. H1 N7 u) R! ~            PA10,PA9位于APB2上3 c5 u. }( c+ N/ u. c
*@time     2025-6-37 `. R% e% _5 Q
******************************/+ G( J4 n0 a& r3 ]9 u1 o' V
void usart1_Init(uint32_t Baud_Rate)
7 O  Q% g& V5 v: v" k- _{! D5 A2 }& G6 o; y# L% M0 \
        //1.打开引脚时钟PA
$ A3 g$ Z) b( h' t+ N( N# x; Z5 Y        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE)      ;
0 u; H& [; \' A      
' Z0 F" ]' s% Q        //2.打开usart1时钟
8 h7 l# \8 I, _0 l- y5 ~        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE)    ;* v, `4 S! |+ V! b8 H6 V$ ]2 U
      
, [& t, j1 B* |' E  K; Y        //PA9->TX推挽复用输出
7 f+ T: A% p/ @1 b8 [3 U$ X        GPIO_InitTypeDef GPIO_InitStruct_TX                      ;
6 v9 v/ t% U  j7 t1 h$ u% K2 \        GPIO_InitStruct_TX.GPIO_Mode  = GPIO_Mode_AF_PP          ;/ l, N4 b, Q' \: I
        GPIO_InitStruct_TX.GPIO_Pin   = GPIO_Pin_9               ;
& p& _* q1 h4 Q1 O5 \) a  W        GPIO_InitStruct_TX.GPIO_Speed = GPIO_Speed_10MHz         ;+ d+ \8 }' X+ A$ i
        GPIO_Init(GPIOA,&GPIO_InitStruct_TX)        ;
& h) Z5 o: Q: i7 @      
. Q. r  P4 }" S; `" n      
" I* k; E' O2 j: _$ p* c$ q        //3.配置,PA10->RX浮空输入: z) U; J8 T7 u" \1 I
        GPIO_InitTypeDef GPIO_InitStruct_RX                      ;
. r1 u  H: k  r5 X, l        GPIO_InitStruct_RX.GPIO_Mode  = GPIO_Mode_IN_FLOATING    ;
/ _) ^, h3 c" m: N: g        GPIO_InitStruct_RX.GPIO_Pin   = GPIO_Pin_10              ;4 J' V% R( w0 v, I' }' u5 x8 v- e
        GPIO_Init(GPIOA,&GPIO_InitStruct_RX)        ;
7 F& ?4 J' x. W$ Z" N4 v5 j      
: k, I$ U* C% S8 h  A1 g        //4.配置usart1,
: X/ N3 o! p. y" I        USART_InitTypeDef USART_InitStruct                                           ;4 @/ _9 T5 x& _9 a/ O, I% U# z) f
        USART_InitStruct.USART_Mode                = USART_Mode_Rx|USART_Mode_Tx     ;, k7 p, O4 S; E! d& N& P
        USART_InitStruct.USART_Parity              = USART_Parity_No                 ;% }2 I( K! n; b1 ~' K) j1 ?8 t& X9 V
        USART_InitStruct.USART_StopBits            = USART_StopBits_1                ;0 [( o+ \7 _8 }) U
        USART_InitStruct.USART_BaudRate            = Baud_Rate                       ;       6 u5 W' p2 D9 |% r
        USART_InitStruct.USART_WordLength          = USART_WordLength_8b             ;  n8 P1 I( |' C# m3 i2 j. r
        USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None  ;' d$ R! i: {' O2 L/ L% W( u
        USART_Init(USART1,&USART_InitStruct)                                         ;
  h& B0 Y* Y" `! H3 S, c! _* J* h( h/ y$ A* C! m
                  . ]! [$ Y" N. H" D$ T! ^, k7 E
                  USART_ITConfig(USART1,USART_IT_RXNE,ENABLE)                     ;//开启接收中断 RXNEIE=1: R) `! {. j) y% @
                        USART_ITConfig(USART1,USART_IT_IDLE,ENABLE)                     ;//开启空闲中断 IDLE=1
- U/ i, R( L; W' ~                  //初始化NVIC
. q+ s1 J: W, [% O' ~+ i- V                  NVIC_InitTypeDef  NVIC_InitStruct                               ;
* U6 u/ r2 o1 \& i* _                  NVIC_InitStruct.NVIC_IRQChannel                   = USART1_IRQn ;//中断通道0 g/ e; A! q" e0 ]" N* |; J$ B
                  NVIC_InitStruct.NVIC_IRQChannelCmd                = ENABLE      ;//中断使能
! v) g3 y& F; d; F( {. R                  NVIC_InitStruct.NVIC_IRQChannelSubPriority        = 2           ;//响应先级6 U: u* ^% ~3 F
              NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2           ;//抢占优先级
+ @0 K0 T. J& i! v3 j1 a+ v              NVIC_Init(&NVIC_InitStruct)                                     ;& L' J" E( J5 r' [: T
      
) x0 A7 }/ E  ?        //5.使能usart1
" k, Z! C- F/ g8 M4 r- Y* A; ~        USART_Cmd(USART1,ENABLE)                                                     ;8 w8 k; V9 t, [9 @: Y$ D
}  . O7 J: y: _/ C7 c4 j
4 f" T* x7 i0 n7 n- f
4 b! m6 o. f/ a& B  R
接收发送函数
. C. ^- a2 @/ t# w" A& C; J" O
  \' D' ]) ~; U  z/****************************
4 I$ c' Q5 o$ ^6 E2 o*@brief     发送字符函数. g: |/ Z9 C0 C# ]* H
*@param    void
3 s, @+ @7 C' n*@return   void
# z$ H" k( H1 R/ J*@note     MCU会将数据发送到DR寄存器中的TDR寄存器中,+ b5 R9 U; m: t, I: q
当TXE==1时,TDR寄存器会将数据加载到移位寄存器中,可以发送4 {: \# X9 A1 v1 l' v
*@time    2025-6-3: ]7 d. K/ p) q& L! x1 I
******************************/1 c: D! O7 J0 S* z
void usart1_sendbyte(uint8_t str)- ~0 U$ S$ H- s
{- s8 e2 O/ s1 N9 S( v" l
        while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==0);. }% }8 b  m$ v, B
        USART_SendData(USART1,str);- h2 j  x9 B2 a* f9 V
}9 A7 R3 T9 ]" v9 r4 j. J- D
" l& Y% b! n+ |; B- A' N: l/ C
/****************************
, H( k. Q: p) Z*@brief     发送字符串函数+ w: }1 b) T1 c+ p
*@param   uint8_t *str3 R8 y4 {3 ]: y( V( [! w+ P, D  ]) U
*@return  uint16_t len
( r3 _4 b4 i2 o' n- Q*@note    发送字符串本质上就是发送字符! t9 l5 x8 b/ h' |: U
*@time    2025-6-39 d6 A" k- l& R' q/ Q  m
******************************/
2 p* y6 C1 y# @  {: m4 \void usart1_sendstr(char *str,int len)
! \, {7 J- |5 \4 W% B- K{4 c2 R' r- O+ V* ~$ h$ }& u) ]
        while(len); O, F* N! q. T* ~0 G8 G4 S" t
   {
/ h' W5 ^7 ]2 V! r5 W% K                 usart1_sendbyte(*str++);8 @, A9 L. }7 i& V0 r; K4 `) H
                 len--;
# k* P& M7 p$ S8 W* w: ]; L         }
5 p% \! E+ Y. ]. J6 A4 t0 Q}
6 U) U) L7 w4 O! ~( x" z- t3 _( \, |( f5 ?( b
/****************************9 p; n6 i9 N( }, G
*@brief    接收字符
' x& g, u1 x& m6 e. A*@param    void' e3 y* S3 g1 f9 o
*@return   void9 G. i) {* u) v2 N
*@note    MCU接收到数据后先放在DR寄存器的接收移位寄存器5 M( Y4 c# M) E3 h2 z
          数据会到RDR寄存器中,当RXNE==1时,说明RDR有数据,可以读7 w5 m# k6 ?$ |/ }: \
*@time     2025-6-3, }! y! E% _, S  P( j7 Z  T
******************************/" |3 P* Q1 g1 `+ M
uint16_t usart1_receivebyte()7 _- b( y; H$ x9 C; |
{
( Z5 @. y+ W; w9 m        while(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==0);* i) t3 u% o) _
        return  USART_ReceiveData(USART1);
6 _6 e' \5 X/ X4 C" f}3 \% e9 {/ B& Q# v
/****************************
1 o( ~9 S) W. r# c# X( A% }*@brief    接收字符串函数(idle标志位)1 a1 T- V# w# H9 s
*@param  void! {8 w% h3 u4 s% v; H& c1 M7 x
*@return   void2 V. Q( p6 I) x/ u# a; K, N% n
*@note     void+ V7 S: Z: i2 h4 O, b6 H
*@time    2025-6-3! ~' g$ O, W- ?5 I4 k& U' w
******************************/5 @; c3 B# n1 v' \) e) I
void usart1_receivestr(char*buff)+ C- c( z  B5 Z9 j
{( i8 y7 F4 H5 M, @. R( G
        uint8_t flag;/ G! R% z) z: o3 ^( q5 }- M% x
        while(1)
- g/ _6 _: f# u5 x) d8 R& Z   {
) O6 {3 A7 G9 s; n, v                 if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==1)2 f- Q+ W3 E8 s. F
       {
! j( A6 N) X" ^8 K/ o                                 *buff=USART_ReceiveData(USART1);3 e! w. x" H+ E; Y& b
                                 buff++;
" v1 z" U1 R! r! X                                 flag=1;
! }) j2 g' z0 U4 G* I; s                         }
  \+ }, x" P+ Q1 J: n' \                        if(USART_GetFlagStatus(USART1,USART_FLAG_IDLE)==1&&flag)+ R- I' H) I8 B
       {
- x$ Y. o- M0 k  X                                 *buff='\0'; //当发送时 发送结束标志% C0 M/ a6 H2 ^" L3 y& W  B0 I  {
                                 //先读SR,再读DR将置IDLE位置0$ X% X, S$ B1 L
                                 USART1->SR;
8 a5 B- \2 Y" w% M( D                                 USART1->DR;
: c4 R, M& u3 y* S& Q                                 break;% H9 v+ P, b* S: z" M7 l# u
                         }- R  [  c' R% q4 m3 B7 t* I7 a; I
         }
/ b4 E) i& v! M% e2 @}
; L8 [9 c5 F* J  s, r# E& m1 z* Q  h

; I( N0 Q/ _; L6 }5 ^' X' b打印函数- }1 G9 D& j" \; c+ d

) N8 A6 E; _) w* z7 B4 B+ p记得勾选微库,printf函数不涉及到中断,它是将内存中的数据输出到上位机0 ]. ?) U  z' M
$ }9 T8 p" }( w: ]0 Y- `
//printf()的底层借助fputc函数进行输出  ?) e  B2 x1 @) b
int fputc(int ch,FILE*stream)3 r: Q; r6 t/ b, M! X: _/ m5 s& W
{
0 s) y( V; o' m# n, c/ |        usart1_sendbyte(ch);( p+ }( a4 b7 j! \4 d8 N
        return ch;
+ a8 o! s% b8 P+ @" o}
, l, z! B% `$ E& a; g& r
+ F* }! I: x3 ^3 J% m% _) o+ m: N0 P) I4 ^5 r/ w
143243jrwwvnvkww4wvrto.png
  m% c! s/ X$ Z$ d- Z9 g  E" ^
& @, W' u+ U8 _) j1 j6 `7 F中断函数
( Q* a/ g4 s- ?6 }MCU接收到数据时,进入接收中断函数,将数据存到rx_buff[100]数组里;当上位机不发送数据时,说明空闲状态,进入空闲中断,将 rx_buff[100]数组里面的数据发到上位机
% E5 d- K& G$ c  ~) m; m7 s' R; u
% ]8 `  O6 S( w: O& g% E' v/****************************
! ?" k1 `( D: r7 k9 ]) @2 i*@brief    usart1中断实验
4 ]. q  }% s( E% A0 ?+ S*@param  void
: v7 v$ ?# X3 k* |* ~*@return   void
9 m; G4 W& t9 S% P' ^*@note     void
! n) n4 }4 n* M, n# O  E+ ~*@time   2025-6-49 ^+ W' ?! j% U: N' H
******************************/8 V- \/ [* ]& I. x6 h7 d5 ]
char rx_buff[1000]={0};
4 y; b1 v, Z& m, i, ~6 Fchar cnt=0;
" f8 e! @- x9 }! nvoid USART1_IRQHandler(void)
/ J, V& s- J+ F0 M{/ D: ~% N2 Y, M! N/ u* A' E
   //当RXNE=1时,有数据接收
% r& \4 V0 f. p3 E, i        if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET); o6 q) {, q# N3 \8 [; V2 A4 P
   {
' \+ ?9 B# _' e& U1 _0 |. W" X! n                 rx_buff[cnt++]=USART_ReceiveData(USART1);
* c1 V( D& X3 A& X                 USART_ClearITPendingBit(USART1,USART_IT_RXNE);//清除标志位
% C- Y4 J. ^0 {+ D$ ]         }1 y! ~( G5 _# H# l, f
         
& [; @7 J, g# o# F, P         //当IDLE=1时," d- l( E+ m! J- t% N: o  s" ?8 n6 i
        if(USART_GetITStatus(USART1,USART_IT_IDLE)==SET)
* X& t' M! c* q# P7 U! ?   {
, k6 ^4 n" P9 |                 usart1_sendstr(rx_buff,strlen(rx_buff));) i! F9 d3 g" |( B( y
                 cnt=0;6 P3 w5 n3 y; x* B/ ^- c, E
                 USART1->SR;
( N9 z# I$ q# z                 USART1->DR;                                  //清除标志位
1 j: T/ O8 C( ]4 v         }8 N) X, d+ |; G$ c4 @
}
; q+ M+ c9 T; k2 h1 e, M
5 r; _' q- w& L2 M% l9 ?. ]2 p, V6 I: O/ M+ @4 T  ^0 `  `
————————————————( x$ Q* L, F: D$ u3 e( k) v
赞 收藏 评论0 发布时间:2025-8-14 18:09

举报

0个回答

所属标签

相似技术帖

官网相关资源

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