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

STM32F103之UART上位机通信

[复制链接]
flyingstar 发布时间:2025-8-14 18:09
一、USART简介
- K9 a: V( [9 b. e, l1.1 UART 简介
* [" U2 |7 Y7 s9 R3 i# m! k9 z通用同步异步收发器(USART:Universal Synchronous/Asynchronous Receiver/Transmitter)1 R4 F! V; H( y" ]4 d7 A  I
特点:串行、全双工、同步/异步通信(USART可支持同步通信,UART只支持异步通信)
) o0 J' Q* @& ^8 k# f# L+ d9 e( g1 w2 z: G4 K: K8 v
发送和接收共用的可编程波特率
1 T9 p2 J6 l. u. R3 C+ q7 ~/ ^' e, \可编程数据字长度(8位或9位)(常用8位). C: Y4 n* s- H4 u5 Y" E2 q% [
可配置的停止位-支持1或2个停止位(常用1位停止位)
0 B( [( i  J5 j. M% \7 I可配置奇偶校验位(一般不用)
5 z) \$ P& m3 X* e
. B% Q$ O# L0 ^1 V3 b1.2 物理拓补图
5 \; q+ z- y0 |0 |接口通过三个引脚与其他设备连接在一起。任何USART双向通信至少需要两个脚
% j! d) }% o2 M, a  e% y" u- SRX:接收数据输入
+ r9 m) s2 b0 A, o  F4 lTX:发送数据输出
& ?4 t5 d3 w1 lGND:双方要共地,双方通过USART进行通信,两个设备必须要共地,因为逻辑1---3.3V电压(对于地的电压),如果两个设备不共地则对地电压的高电平(3.3V就可能不太一样)。共地的意义是让两个设备的通信电平对地电压相等
: l  r9 s* U9 J7 _- {9 W. M$ W
4 |! `0 k' I0 j, i 143313vbrrl0ybxaap3skz.png.thumb.jpg 5 v. D& E. _' z4 O6 o
( |0 h2 {5 N% I/ w/ }* o
1.3 数据帧格式
3 q. U, ?7 j) I& U: I, a( N一帧数据=1bit起始位[低电平]+8bit数据位+1bit奇偶校验位[可以不用]+1bit停止位[高电平]
& j" L- d" Z; E' Y. U: X9 v# v% f
& v( ~9 s0 P# J: f! @USART总线空闲,即没有数据发生,TX线为高电平
( V4 u* o2 A5 b; n8 B; A
: v9 Y, b  p7 {: l! M5 }! z<1>数据位:USART发送的1次数据量是1Byte=8bit;[5、6、7、8]4 l% B( T* [% U) B
<2>数据字:数据位+奇偶校验位;如果不用校验位,数据字=数据位=8bit;如果使用校验位,数据字=数据位+校验位=9bit! B# I! {7 M3 z* \9 a5 @1 U% g6 G
                    奇校验:数据位中的1的个数+校验位中的1的个数为奇数
5 Q2 o) Q9 |/ L1 R: q: g                    偶校验:数据位中的1的个数+校验位中的1的个数为偶数. x1 B/ o8 `+ o0 j
<3>停止位:可以被配置为1bit(默认);2个停止位(可用于常规USART模式、单线模式以及调制解调器模式);0.5个停止位:在智能卡模式下接收数据时使用;1.5个停止位:在智能卡模式下发送和接收数据时使用, V6 c' Z& f2 z
<4>发送顺序:先发送低位,再发送高位  j$ }# L8 Y2 q4 H- k! a8 N* v" H

4 q8 z/ ]9 b. b5 K. z- K0 A# S! ?1.4 框图
2 i" C6 K: e& X; Z* d! b3 I7 c4 p1 p2 g5 f6 e
143305ex594sdg0xa59ahj.png.thumb.jpg - F) s; O+ E/ i- Q
, P" b3 I" W, M$ _% T) s+ P0 g5 a
对于这个框图,最关键的是两个标志位TXE(发送为空标志位),RXNE(接收不为空标志位)4 q" V) f+ ]( o6 g
数据通过RX端口进入MCU的UART的接收移位寄存器,随后进入接收数据寄存器(RDR),进入后RXNE被置1,表明可以读- V, ~$ ~& Y6 V$ Y" X) a8 K# V+ c
MCU通过数据总线获得数据,数据再到发送数据寄存器(TDR),若TXE=1,说明数据已经被转移到移位寄存器,表明可以发送
  v& P4 q- T3 n! ~) R
. s' e2 j' l4 ]1 x二、串口通信
, p& j# E& ?% u2 ~4 J配置UART
; T5 z" [) {& l- t& `) T9 T2 a5 W$ D" V
开启了接收中断和空闲中断
% S! t" ]; T! N( R  U6 S, [8 c
! b4 q/ C8 _+ `7 s* b  D* K, p9 k/****************************
1 e9 E1 ?' Q. j*@brief    uasrt1端口配置函数
2 ?  l4 n* v" e' l*@param     void7 x* N/ X6 C" |* u! n( g( f. O  [
*@return    void$ P' a* D/ S* m9 g( r8 R) v% v  ~
*@NOTE      PA10->RX PA9->TX7 s. ?7 |5 R* L7 w2 E. i$ w
            PA10,PA9位于APB2上
% K; Y% v% y& w*@time     2025-6-3
6 k) c+ L- [; P: G2 q( L, c******************************/  X4 D9 H  U/ G6 |$ U* E6 Z3 G& V
void usart1_Init(uint32_t Baud_Rate)( X+ ^1 j' E) p# f! `' m8 ]
{5 Q* e5 {. N+ z/ j' N# L
        //1.打开引脚时钟PA$ B* ?. u% Q. z) D) H& Y
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE)      ;0 C' i+ k. \( i) I3 i! Z3 q. P+ c* S' B
       1 D1 R, r8 B# F* y( q2 t# i
        //2.打开usart1时钟8 K  O) j8 L) H; _1 Y: M
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE)    ;5 s8 e% n! L- `; J& P4 R' Q( \6 ?
       + i5 f2 y7 K, l9 l$ P
        //PA9->TX推挽复用输出
& G' v$ f6 Z2 e8 ?* p" @+ \        GPIO_InitTypeDef GPIO_InitStruct_TX                      ;3 k/ e7 c) h/ f, y) |& ~" @
        GPIO_InitStruct_TX.GPIO_Mode  = GPIO_Mode_AF_PP          ;
% x! T+ o' ?' ?! D2 f6 z        GPIO_InitStruct_TX.GPIO_Pin   = GPIO_Pin_9               ;' T' m" ^  h1 c% X3 ]
        GPIO_InitStruct_TX.GPIO_Speed = GPIO_Speed_10MHz         ;# Q2 |0 B1 L# I* G+ j1 O
        GPIO_Init(GPIOA,&GPIO_InitStruct_TX)        ;
2 L: W3 A9 _6 w7 d       & y) D6 l- \+ h# {4 Q0 ^
      
! A$ d* D/ N0 X% d/ e        //3.配置,PA10->RX浮空输入3 f* [6 Z* Y0 l. ^. U7 M
        GPIO_InitTypeDef GPIO_InitStruct_RX                      ;* \5 B# w; E4 I- v
        GPIO_InitStruct_RX.GPIO_Mode  = GPIO_Mode_IN_FLOATING    ;
3 j+ c2 y3 ?  U4 [8 F2 J- n7 o% S) }" O        GPIO_InitStruct_RX.GPIO_Pin   = GPIO_Pin_10              ;
2 M3 k7 S7 M* Z- f        GPIO_Init(GPIOA,&GPIO_InitStruct_RX)        ;
* y; P# f! x( P& Q8 [, u- L      
# `7 ]5 \: C+ S! @( ]6 {9 Y        //4.配置usart1,
+ i) R, ?& y+ V& ~! ]5 \        USART_InitTypeDef USART_InitStruct                                           ;
% [9 |# }0 W" r/ t- M8 A; N        USART_InitStruct.USART_Mode                = USART_Mode_Rx|USART_Mode_Tx     ;. i* d+ c5 C2 k8 l
        USART_InitStruct.USART_Parity              = USART_Parity_No                 ;
* ^; T/ u' e0 m; a: R  s1 {        USART_InitStruct.USART_StopBits            = USART_StopBits_1                ;
6 u7 z6 c5 }% U1 e        USART_InitStruct.USART_BaudRate            = Baud_Rate                       ;       5 |; X: Q3 ^9 [
        USART_InitStruct.USART_WordLength          = USART_WordLength_8b             ;& R5 Y' \& {6 I" A$ n
        USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None  ;! r$ a% J8 a: G9 e6 `& k1 A  x
        USART_Init(USART1,&USART_InitStruct)                                         ;
" O% E* {1 R) P! o' N8 D4 r
( x! @$ L2 b8 e7 b! J* Y2 h                  
9 U, f/ {& U) ]. J                  USART_ITConfig(USART1,USART_IT_RXNE,ENABLE)                     ;//开启接收中断 RXNEIE=1
) h7 q( N, n; l/ m2 _                        USART_ITConfig(USART1,USART_IT_IDLE,ENABLE)                     ;//开启空闲中断 IDLE=1
$ I; d- N/ o/ T4 U* w                  //初始化NVIC
( c9 V) t0 Y5 l/ w& L                  NVIC_InitTypeDef  NVIC_InitStruct                               ;4 x% S8 y4 i7 E9 c
                  NVIC_InitStruct.NVIC_IRQChannel                   = USART1_IRQn ;//中断通道
6 v- q, T: e( Y; E" y                  NVIC_InitStruct.NVIC_IRQChannelCmd                = ENABLE      ;//中断使能0 E1 p! H7 x8 \4 n8 o3 z) ]
                  NVIC_InitStruct.NVIC_IRQChannelSubPriority        = 2           ;//响应先级
# ?0 h4 {: k% B6 V& P6 \7 S4 n$ D              NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2           ;//抢占优先级) ]6 j! T0 p& \: m' U
              NVIC_Init(&NVIC_InitStruct)                                     ;% S. N, C0 L; Y$ o% ]
      
* A2 F6 Z' R. f, Q        //5.使能usart17 d' a  C. O( _' _
        USART_Cmd(USART1,ENABLE)                                                     ;9 x" j2 D; V# g/ E
}  
  K% F7 [/ Z: Z8 h+ |# w) j" J( U
8 O! X8 Q  m- S& K4 R# u, q6 i+ M/ T7 a; y- t8 H+ o; b
接收发送函数1 p  R3 }8 {4 f8 L+ R

3 h8 H) P( ~8 w) R- p) ~% L$ e/****************************! n; G! q  q/ M1 r* p
*@brief     发送字符函数& ~- A' b5 d' l/ H
*@param    void5 H& S0 u+ m# g! N7 `- u' W
*@return   void
. R6 J( ?1 s7 e*@note     MCU会将数据发送到DR寄存器中的TDR寄存器中,
4 L$ L  b2 r. j! Z+ T当TXE==1时,TDR寄存器会将数据加载到移位寄存器中,可以发送" W1 Z" Y) y6 @* v1 m
*@time    2025-6-3
- P0 ?; `1 C- X! _7 {4 b8 K; |******************************/
. m" M; R9 d. l- `1 F7 kvoid usart1_sendbyte(uint8_t str). [) H1 M! x$ Y  B- D/ z* |
{* _5 Q: P6 Q5 y: k( M- j% r
        while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==0);
- }2 |; t4 j/ x* q  h        USART_SendData(USART1,str);
0 b: D! }% F4 b" N$ h% a# B3 \( Y; \- u}
5 X; W# e# V" U4 a6 a$ U1 E, |& k0 S+ N1 d3 R
/****************************6 D6 p8 C5 l; k
*@brief     发送字符串函数% D5 c; ?1 p3 Y
*@param   uint8_t *str
- [! a& _; u6 |*@return  uint16_t len9 @( |& S# d! X% A
*@note    发送字符串本质上就是发送字符
% q* b, q, N8 A$ C. h5 z*@time    2025-6-3
' L) w% K2 c8 |% p% B- r0 I, A******************************/
+ ~8 ^+ I9 u/ n$ fvoid usart1_sendstr(char *str,int len)& U5 Q0 t7 K$ k
{8 x3 D& Y, u+ G; v" c
        while(len)
# i5 U( g' R* h4 e) v$ x- f4 B   {
" V+ N; F" T3 c( r( r; z                 usart1_sendbyte(*str++);' K" [) }% Z! p& n& O
                 len--;2 {% F4 V  T  S7 ]" a3 u8 A
         }6 H# D7 Z# {# z# m; @5 _2 |" W$ v
}3 N. P% n  \( b8 E4 v

$ d" Q4 |' D! O, w/****************************5 A- J3 u  a) b
*@brief    接收字符. X: `- d( r( C" _4 ?: j) @
*@param    void5 I- W! y, x7 ~' q6 v) s1 {
*@return   void( {* S7 L% _1 I
*@note    MCU接收到数据后先放在DR寄存器的接收移位寄存器+ ^0 r1 o: S( i
          数据会到RDR寄存器中,当RXNE==1时,说明RDR有数据,可以读( {, O9 ]2 v  `$ |
*@time     2025-6-3
* m: y. h7 e1 r5 f) c******************************/5 n4 E/ f3 \4 E* N( y2 e% t- Z0 S
uint16_t usart1_receivebyte(). d$ a$ P9 w" A3 ?& e
{: K7 w+ Z- X. e1 ^* v
        while(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==0);
. L. E& V+ Y! U5 T0 g        return  USART_ReceiveData(USART1);$ m- P8 q9 s) x1 j% F8 n+ h: v
}1 }- q* Z  P/ i6 g
/****************************
/ i! x+ O, z$ K! p3 U9 Z/ K*@brief    接收字符串函数(idle标志位)
' H  a3 h0 e: t1 z0 L*@param  void+ z7 F$ m* I3 P  {7 j+ y
*@return   void# o1 A- C* g& a, C* o
*@note     void
( {# }+ X$ M) k% J) l2 v, j*@time    2025-6-3$ h- F% J, M# W: X9 k- \
******************************/
! h/ l* ~& ~; S3 a! R1 qvoid usart1_receivestr(char*buff)4 U( T7 S( B6 m7 A/ ]' \3 M) X
{- j7 ^5 C' F$ R9 I
        uint8_t flag;, F9 ]! p, @. I9 ?# ^6 G
        while(1)
+ g  Z, p7 s8 x" c, p+ i0 z   {
, S0 J& v% E, z7 N  b% f# f4 e1 q3 l                 if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==1)
/ |- S: k5 a( E  r4 ]       {
- m8 Z' C$ f( k0 X8 ?3 `+ h                                 *buff=USART_ReceiveData(USART1);
( V5 o0 z7 }6 ^1 Q3 y4 b; @7 \                                 buff++;  ~: h% i, _, ]# C0 D& R
                                 flag=1;# \9 \4 Z7 A" N
                         }
; `# z& P6 L: I3 G0 ^                        if(USART_GetFlagStatus(USART1,USART_FLAG_IDLE)==1&&flag)( c6 c5 k  z/ e, A2 Q& y2 j' Z
       {( j& h0 p2 ~6 S7 d
                                 *buff='\0'; //当发送时 发送结束标志" W. L* y2 `2 a! O7 |
                                 //先读SR,再读DR将置IDLE位置0
) x$ z* Y' O% q                                 USART1->SR;: z8 E5 ~" Y% t5 U- m" I
                                 USART1->DR;
! l$ ], H8 q( l4 y; H                                 break;' m3 _; c- I. |. \6 x( S" J% I
                         }
4 D+ g! T% J" P/ x! X         }
( R1 H) K% p+ [% K$ l}8 P- \1 n( }3 w
1 D+ T. p/ k- c1 A# K) \$ o
( f3 k, r- K- D' L0 W+ E; _  F
打印函数, S; ?4 ^$ H! z$ n+ s* Y

/ I& W, p0 X8 J* Q; e1 X记得勾选微库,printf函数不涉及到中断,它是将内存中的数据输出到上位机
% n/ l, m) K- A. F/ g3 n7 s
0 l) ?5 n- b: K9 X  ^' M//printf()的底层借助fputc函数进行输出
$ F$ t. d& s1 L: f: Oint fputc(int ch,FILE*stream)' }6 h& c5 |8 V6 e  Z( v
{; o2 l- [9 U1 w1 e5 ~, B! F4 k% b
        usart1_sendbyte(ch);4 j( ~6 }/ V0 P* x6 t
        return ch;
( m/ {( F# F6 ^}4 z" E- D7 j  p; j* y$ o4 R) y

* A/ ~6 w! p5 D0 [
8 s9 G* x7 c# P6 F0 F  ? 143243jrwwvnvkww4wvrto.png 0 G- _; y# {# ~, z

2 \3 {, o3 P# H7 `! w中断函数' ^) M+ z5 B+ R( q
MCU接收到数据时,进入接收中断函数,将数据存到rx_buff[100]数组里;当上位机不发送数据时,说明空闲状态,进入空闲中断,将 rx_buff[100]数组里面的数据发到上位机
# s9 B& k$ u+ H) `; |% `. X" r6 a
/****************************) ~. s4 K3 u( x' c) }
*@brief    usart1中断实验+ m- E# ], X' H7 n
*@param  void
# h6 J2 m. J" o: Q  M% b) {8 Q. b*@return   void
( B, o; j. F$ X9 J) e*@note     void
- {% N9 u' {. @- @! w; F*@time   2025-6-4
# X6 H5 ~6 r0 F5 U7 M******************************/, B6 Z" \7 h  R% h6 W# f
char rx_buff[1000]={0};5 }% U' k2 l( h9 V
char cnt=0;
) ?) i' W+ y3 E0 |void USART1_IRQHandler(void)
* `/ }' b4 E$ l6 K) {( P9 q/ \% j{/ ]9 x8 N5 }& @+ B
   //当RXNE=1时,有数据接收# `0 i4 Q, m* P7 Q* X
        if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET). r8 F- a8 _0 \/ ^. |& ?; {- G
   {  J+ J: H. |2 P' @' ^
                 rx_buff[cnt++]=USART_ReceiveData(USART1);
! C+ [8 V# Q1 v7 p                 USART_ClearITPendingBit(USART1,USART_IT_RXNE);//清除标志位( ]( i. L2 i% d8 Y
         }. C" M# Y/ _7 l' Z, Y% i) n0 |
         & l3 N) V5 i8 g% M" Y
         //当IDLE=1时,; A0 f6 ], l8 R/ Z6 S
        if(USART_GetITStatus(USART1,USART_IT_IDLE)==SET)
+ o6 U2 P$ k* ~% f8 O' J1 n7 F4 ~   {
8 ~  c' U* u6 s( k$ _7 @8 ^                 usart1_sendstr(rx_buff,strlen(rx_buff));/ D9 G, Z) B! G: c: N! _% U
                 cnt=0;
7 }- v8 N) y1 t9 C2 N! @                 USART1->SR;7 V6 p+ h) E6 D$ ?6 W) `7 k8 M! ^3 j
                 USART1->DR;                                  //清除标志位
4 d# r! z* z# v* |5 L" o         }
9 k: A/ P% h) N7 B3 ^: A; B0 [}
5 z2 s# j; w  _5 h  B/ _6 a
) D- j& j) }' S  e! G. L, m6 {
$ K4 {, y+ M; `7 `————————————————
; a% \) X- [8 o. i9 \4 F
赞 收藏 评论0 发布时间:2025-8-14 18:09

举报

0个回答

所属标签

相似技术帖

官网相关资源

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