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

STM32F103之UART上位机通信

[复制链接]
flyingstar 发布时间:2025-8-14 18:09
一、USART简介
8 M  ~* R4 c6 S. I1.1 UART 简介
1 O% v- {, o& U" \% r9 i0 I通用同步异步收发器(USART:Universal Synchronous/Asynchronous Receiver/Transmitter)# Q# |% T7 ~% y3 W& E  T3 b3 O
特点:串行、全双工、同步/异步通信(USART可支持同步通信,UART只支持异步通信)
/ \/ b0 m7 r/ ]0 v$ _/ j0 A
# X0 y% _2 w$ u发送和接收共用的可编程波特率$ z* x. S5 k4 ?8 q4 c
可编程数据字长度(8位或9位)(常用8位)
2 r! |, y! N/ `  u可配置的停止位-支持1或2个停止位(常用1位停止位)2 l; I/ w) O* ~" T5 Q- v5 s$ d! Q
可配置奇偶校验位(一般不用)
' }5 e0 t+ W7 C& |3 q; O
5 i+ U3 i' W" \! I7 R; u2 l1 o1.2 物理拓补图
- J: i# A! }( }: f2 e8 f接口通过三个引脚与其他设备连接在一起。任何USART双向通信至少需要两个脚: ]) S5 h9 v2 c+ P
RX:接收数据输入
/ ?7 k& M" ^3 k0 R; ZTX:发送数据输出
; H+ _8 I) }2 c# i$ ^GND:双方要共地,双方通过USART进行通信,两个设备必须要共地,因为逻辑1---3.3V电压(对于地的电压),如果两个设备不共地则对地电压的高电平(3.3V就可能不太一样)。共地的意义是让两个设备的通信电平对地电压相等7 g; Z& L4 b5 n) w
. @9 }/ V- Z% y( y! O! O8 Z% B
143313vbrrl0ybxaap3skz.png.thumb.jpg / G7 V* q6 |% }: T3 F2 j, }
% n( x7 c$ c2 ]6 j# k9 J
1.3 数据帧格式+ R; D2 z. k7 G
一帧数据=1bit起始位[低电平]+8bit数据位+1bit奇偶校验位[可以不用]+1bit停止位[高电平]+ i7 Y5 i1 ~- _! V
) O/ C  ~- l" ]7 [) @, \# ^
USART总线空闲,即没有数据发生,TX线为高电平# N* i& z! a5 i2 |; |/ s

2 m; P' R5 {# {  U* ?3 X; M4 s<1>数据位:USART发送的1次数据量是1Byte=8bit;[5、6、7、8]
/ o3 e8 t8 C, |$ T<2>数据字:数据位+奇偶校验位;如果不用校验位,数据字=数据位=8bit;如果使用校验位,数据字=数据位+校验位=9bit, [) M6 x! g' A& Z( o+ I0 J7 F
                    奇校验:数据位中的1的个数+校验位中的1的个数为奇数
9 m- m& g6 X' k8 z" l                    偶校验:数据位中的1的个数+校验位中的1的个数为偶数6 F$ D  j( |% x5 S6 c; U: Y
<3>停止位:可以被配置为1bit(默认);2个停止位(可用于常规USART模式、单线模式以及调制解调器模式);0.5个停止位:在智能卡模式下接收数据时使用;1.5个停止位:在智能卡模式下发送和接收数据时使用+ Y. E# z5 m  b8 K! J$ b( n  b
<4>发送顺序:先发送低位,再发送高位. D+ U7 a) t" o3 J

4 n* ]% S6 W* P8 J1.4 框图2 Q3 Q$ e. A, o" M) W9 L( _

; E3 U1 o. k. o% X. d/ O 143305ex594sdg0xa59ahj.png.thumb.jpg 8 z  t( x$ l" L# O6 a9 @+ ~

% O5 w* j/ }' V' E+ G, ~对于这个框图,最关键的是两个标志位TXE(发送为空标志位),RXNE(接收不为空标志位)
: S4 ~8 {6 j2 y数据通过RX端口进入MCU的UART的接收移位寄存器,随后进入接收数据寄存器(RDR),进入后RXNE被置1,表明可以读" c4 g! D. }7 h7 {) n
MCU通过数据总线获得数据,数据再到发送数据寄存器(TDR),若TXE=1,说明数据已经被转移到移位寄存器,表明可以发送- f. a/ J( }$ \7 Y& V+ V- ]
2 g1 X: Y$ {' b3 d$ \' A
二、串口通信' f! s5 w9 b7 O4 E) x# `
配置UART+ x2 f  u( D: c9 I$ k# f3 G

8 c3 i4 M0 Y" i& c7 d8 a开启了接收中断和空闲中断3 e( s% A1 v# v+ t. b

% o8 G6 L# w' P* }& X% n/****************************5 @3 ^4 Y$ V+ d8 G4 {
*@brief    uasrt1端口配置函数, l) l9 p8 H/ _/ J
*@param     void9 m7 O  |: L- O. ?8 `8 H
*@return    void
) b. p1 P8 y4 R*@NOTE      PA10->RX PA9->TX
  M: J1 Y% b) g; V- O            PA10,PA9位于APB2上+ m! w" x: S- j7 D7 l- c
*@time     2025-6-3
2 y. a- [3 Z, h. z! U* [. K- g" i******************************/
' ^' |& l: ]& s! Q* Fvoid usart1_Init(uint32_t Baud_Rate)
3 i  a' V5 ?9 X/ N, [8 }4 @{
, ?3 ?7 J; w& N* b7 S        //1.打开引脚时钟PA/ b) N6 ^# x) f
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE)      ;
: `" X9 j  F* z4 B2 e& q      
: u( l) d9 W! Z; }+ F3 V" ?, j3 y        //2.打开usart1时钟
' m+ \% @2 G2 x: Z  X        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE)    ;
0 K: h) i2 r( }8 ]" n: C       ! ]( P; N- M+ Z: z: w( ?  f; W
        //PA9->TX推挽复用输出
! H$ P) Y7 Y- x. w0 u5 I        GPIO_InitTypeDef GPIO_InitStruct_TX                      ;/ z! x- q* N0 ^- Y1 k! m' K9 p( G$ A3 G
        GPIO_InitStruct_TX.GPIO_Mode  = GPIO_Mode_AF_PP          ;
! i/ P) w) m8 x: [        GPIO_InitStruct_TX.GPIO_Pin   = GPIO_Pin_9               ;7 V* Z  J# ~9 x& ?/ n& Q8 c0 g" C# j1 @$ u
        GPIO_InitStruct_TX.GPIO_Speed = GPIO_Speed_10MHz         ;
9 }: M+ b! K5 g: J& Q! c; c+ W/ c        GPIO_Init(GPIOA,&GPIO_InitStruct_TX)        ;
" F( G* i8 p" D" C      
4 W& r7 F0 g9 g' }9 l4 Y& q      
+ f8 \8 `5 e6 y* U/ p        //3.配置,PA10->RX浮空输入
3 c  o! _7 j/ X        GPIO_InitTypeDef GPIO_InitStruct_RX                      ;
, h! E4 b+ S7 ?: }9 C, A1 A        GPIO_InitStruct_RX.GPIO_Mode  = GPIO_Mode_IN_FLOATING    ;5 U7 @% \& }( t7 W( Z8 p, y
        GPIO_InitStruct_RX.GPIO_Pin   = GPIO_Pin_10              ;7 O6 D2 ^: |& O1 F6 Y' F2 }$ V( i
        GPIO_Init(GPIOA,&GPIO_InitStruct_RX)        ;
7 z/ d$ Q$ I  j* [; O       ! P2 s$ d4 R7 R$ \1 N: B8 N
        //4.配置usart1,, M7 i. D- B) Q' O. V
        USART_InitTypeDef USART_InitStruct                                           ;7 Q7 c; }5 B0 n) F7 P7 U2 X
        USART_InitStruct.USART_Mode                = USART_Mode_Rx|USART_Mode_Tx     ;6 h5 g. v. r0 Z3 _7 Z( P/ ?
        USART_InitStruct.USART_Parity              = USART_Parity_No                 ;& X, L9 _- t( r2 o7 T
        USART_InitStruct.USART_StopBits            = USART_StopBits_1                ;
. ?7 y; q2 y' a$ c        USART_InitStruct.USART_BaudRate            = Baud_Rate                       ;       ) I. q- T2 {$ N& d% a! }3 r4 g- E
        USART_InitStruct.USART_WordLength          = USART_WordLength_8b             ;
# I% x$ [$ ~% t) Y        USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None  ;
/ u6 a& @$ X; S" G# m        USART_Init(USART1,&USART_InitStruct)                                         ;$ ~9 l  `: r% G# y
" U. m5 @" e6 \! j, r+ i, p1 N2 {
                  
) y0 P9 H6 c+ `9 O, f6 G                  USART_ITConfig(USART1,USART_IT_RXNE,ENABLE)                     ;//开启接收中断 RXNEIE=1" B2 n: J: I& w$ i
                        USART_ITConfig(USART1,USART_IT_IDLE,ENABLE)                     ;//开启空闲中断 IDLE=1
+ Z- C8 _5 ^* z$ g                  //初始化NVIC
+ v5 [2 y0 U6 v                  NVIC_InitTypeDef  NVIC_InitStruct                               ;( `+ |' P5 v& x7 U
                  NVIC_InitStruct.NVIC_IRQChannel                   = USART1_IRQn ;//中断通道
& ~7 X8 d' y, X' T                  NVIC_InitStruct.NVIC_IRQChannelCmd                = ENABLE      ;//中断使能
6 E6 W0 K' b6 \. R                  NVIC_InitStruct.NVIC_IRQChannelSubPriority        = 2           ;//响应先级$ K& e& k9 j! n5 R* t8 O
              NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2           ;//抢占优先级
7 R$ o3 Z* V: Q, y# F  B4 h              NVIC_Init(&NVIC_InitStruct)                                     ;( x$ ~' K3 a. D5 u# o+ T! v- b
      
: e1 n+ N2 _8 F6 D" W' B' b, {) K        //5.使能usart1
7 \$ f6 Q( o4 j1 W  B        USART_Cmd(USART1,ENABLE)                                                     ;
- x+ n0 U2 {. a, q}  
5 G* a/ Y7 r; c% x  z' r* `  Z$ |6 Q

5 b! A8 \, B* K- a接收发送函数5 q3 ]1 Y" b4 D7 |* H7 V
$ W' ?. Q/ z. W) X
/****************************
* v: i5 F+ Q& m0 P' X*@brief     发送字符函数) q2 }* `$ c" n( H
*@param    void1 E2 V6 M2 E" ~/ ]) D
*@return   void2 ~5 g) o8 V+ e. Q- c) q
*@note     MCU会将数据发送到DR寄存器中的TDR寄存器中,
1 m3 |, }  k; V( ?1 v当TXE==1时,TDR寄存器会将数据加载到移位寄存器中,可以发送
/ u9 P/ z! H' {3 {( |0 q# ]9 j*@time    2025-6-33 ~8 L7 Q( V+ P5 B8 U
******************************/+ O6 `. T& L& V8 {
void usart1_sendbyte(uint8_t str)
6 I4 j) V) i% j3 n{+ N! R- }( r. [7 g6 {
        while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==0);
* R  O5 _# q  s& T, f$ y        USART_SendData(USART1,str);. a0 K, O0 t4 T& N- j, `8 g4 s
}+ u& S% r& a$ f
% L; O; Q6 F, a- r: D
/****************************
! H0 d' v# G* d, y*@brief     发送字符串函数
- ~8 ^! x7 [0 ]( D8 `# K2 k*@param   uint8_t *str
$ \7 N3 [) t+ p3 i  M*@return  uint16_t len3 O/ Q9 P5 c/ L5 \8 Z
*@note    发送字符串本质上就是发送字符
* ?/ d  z2 r$ v  D) U3 ]' p( c# r; y*@time    2025-6-3
6 q7 Z" V3 h* G4 X7 G+ A4 n6 n******************************/
3 \4 Z% e) A$ E* K# {8 c$ @void usart1_sendstr(char *str,int len)
. ]3 i6 H$ h$ P7 O{
8 ?) w: w8 {. A2 B) f        while(len)) v! R4 [( p" T- w
   {: M8 o* y+ b% w4 r  S
                 usart1_sendbyte(*str++);
1 j% _+ ?- w% I% O                 len--;
: Q- A# b7 P' ]0 Y& \4 U% V         }2 Y2 X" }% {! _
}+ ~' g8 u# U  b" e3 W2 a
! n! _+ A7 s* a: ?
/****************************9 Q+ J8 ^5 Z9 V- p; c8 M. {- c
*@brief    接收字符3 C7 k0 L7 |; K/ T6 Z/ p0 f; Y
*@param    void; h# A/ t4 I% l
*@return   void  |0 @, k8 e8 M9 A5 ?
*@note    MCU接收到数据后先放在DR寄存器的接收移位寄存器
% R9 A8 o6 }, K) W          数据会到RDR寄存器中,当RXNE==1时,说明RDR有数据,可以读0 h. \' \+ O" m. C  N# y
*@time     2025-6-3! q2 \) d# @- s
******************************/# ]( H7 Z  ^* K/ ~. Z- p2 A
uint16_t usart1_receivebyte()
% r/ \. I' y* L9 ~  a, z1 e8 Q& o{
2 l( X8 Y; I3 B5 }$ L        while(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==0);
" u5 `/ ^' U: v% N  z6 L        return  USART_ReceiveData(USART1);
! ]" s. i; t) r  B+ W/ {" b}: I: Z. W1 P% }5 ^* P
/****************************+ A5 e/ m8 T. I
*@brief    接收字符串函数(idle标志位)
. W& D; h3 h9 B+ f, b6 u*@param  void6 P7 m( B3 v. M2 \: U! i
*@return   void" M4 R  B" ~) a; b9 i' P
*@note     void% I: a9 N. O2 r, J3 C- ?5 ~
*@time    2025-6-3" \! Z# ~: c* W, X2 I) G
******************************/
6 C- z9 d. ~6 x! T/ c0 rvoid usart1_receivestr(char*buff)
: D* k5 \$ D8 k4 }" U{: Q6 g0 ~. P7 B; o: p" Y. i5 ]
        uint8_t flag;
/ x& n1 Y2 O. J4 h# t; v1 ^# G        while(1)
* y3 @, F$ O+ S) \2 H9 X   {+ q( i- e) f+ D7 j
                 if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==1)
8 h$ u5 [) K& \       {
# j" v* p$ u6 I. A3 I                                 *buff=USART_ReceiveData(USART1);
* e4 l4 b$ t; Y& U1 c3 c. J/ Z                                 buff++;9 U' t# Y/ v; j; G# A
                                 flag=1;
/ G, h/ ?% [* q+ Z5 l0 Z$ J                         }% F0 }1 I6 o  Y0 ?! x
                        if(USART_GetFlagStatus(USART1,USART_FLAG_IDLE)==1&&flag), J% v4 Z' h2 W2 E: M
       {
& q0 F1 u. L4 r3 e                                 *buff='\0'; //当发送时 发送结束标志# X% l+ R1 S* ]9 K& u4 C- y
                                 //先读SR,再读DR将置IDLE位置0
" g  Z5 l  y; P: h5 N3 w                                 USART1->SR;
* {5 z% C, i& ?; K6 g: I! q6 J2 s! }                                 USART1->DR;) X9 B9 M  e- p8 D, t, z  R
                                 break;
7 ~7 h. ^" z' M& l                         }! M- K- Z3 ~$ r
         }
' S. X( L5 i( o}: ]* U7 H$ b* ?: c" p. [
! V3 L( Q8 T6 I0 _- p$ M) {
6 O' K* _% o; u- C- v4 K
打印函数
3 H* p) P8 b# \. }& I# S  O
& {- n  E. B) s% _4 W' A记得勾选微库,printf函数不涉及到中断,它是将内存中的数据输出到上位机
& f- n$ W, A6 A" K0 `7 b8 g5 ?3 H0 i/ c* F+ b
//printf()的底层借助fputc函数进行输出* F, J& o* ^4 A! u
int fputc(int ch,FILE*stream)+ b% d$ P+ e% }( ^! X7 e
{' M! |7 w. h- [* `9 [0 a
        usart1_sendbyte(ch);" v6 l9 V5 X0 i+ h, N: [4 {  \
        return ch;
1 H1 B6 o5 M' m- ~! ~}- n9 c) O1 S" l, ^; s& G
5 J; s% |! K* J5 }8 w
5 i2 u; k; m+ u
143243jrwwvnvkww4wvrto.png   G* \. q+ V! e; T) q; X

& L9 s( U7 X' l0 `! b+ s' o中断函数
; @! r- H( [' ]4 k. x  S) g  ~: X* gMCU接收到数据时,进入接收中断函数,将数据存到rx_buff[100]数组里;当上位机不发送数据时,说明空闲状态,进入空闲中断,将 rx_buff[100]数组里面的数据发到上位机6 [& g  ?7 i, k  M1 |; H: d, D
, F% l5 p  \+ P
/****************************6 M6 r: v4 i4 s+ ~
*@brief    usart1中断实验
$ C* @  w, E! A" K6 O  Q2 ~" A*@param  void
2 h$ w) E2 c" h/ ~*@return   void
* ^5 o; W- b5 p' f( l- ^*@note     void1 d/ d6 }' D' D# m5 y
*@time   2025-6-4
4 J; y" h& t( s. g! D7 \  Q; d******************************/
) S% g  \( Z# A: y+ T: P5 Lchar rx_buff[1000]={0};
0 |/ ~: h& C( T1 Z! bchar cnt=0;" V& z. \1 ^  E: P. w/ |) x
void USART1_IRQHandler(void)+ p/ v+ g" K* f( E0 V: u9 z
{0 Z. e0 ^5 g( E: J( \) R, c: F
   //当RXNE=1时,有数据接收/ U$ x/ I& a. `# n7 y; Q  U
        if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET)0 M4 k) G( J9 @- q  M: L
   {" a/ p' f& c! ?1 r: N* Q, z. Z& n
                 rx_buff[cnt++]=USART_ReceiveData(USART1);
+ ]" z- P, E  ?" p* F                 USART_ClearITPendingBit(USART1,USART_IT_RXNE);//清除标志位
6 j* w' X" Y$ E/ E         }
1 |4 x1 B$ J+ i* ?5 U! {         ) }9 }: V) _8 I7 y6 Q
         //当IDLE=1时,
7 ]! h3 J4 y* t- R$ Z2 }: P  R& T8 b        if(USART_GetITStatus(USART1,USART_IT_IDLE)==SET)8 ?1 X9 h# y$ Q. ]0 `
   {" z2 k8 @, T( K; j4 s/ r" S
                 usart1_sendstr(rx_buff,strlen(rx_buff));, j; T+ Q( t8 Q1 _
                 cnt=0;
  V6 s" ^6 {3 ?5 E, \/ C$ C                 USART1->SR;
! X% x6 e# M" M/ ?0 c                 USART1->DR;                                  //清除标志位' {& S8 s" D/ Y6 P+ @1 B0 e
         }
8 h. M3 X4 K0 r8 h, ^}& R% X1 @6 B4 R* s- [

, l& u, B% V" W" z2 z+ ~) k7 y0 O7 g0 h& D2 e) e* H
————————————————
5 `3 G" T+ q# {2 n
赞 收藏 评论0 发布时间:2025-8-14 18:09

举报

0个回答

所属标签

相似技术帖

官网相关资源

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