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

【经验分享】STM32F103 USART串口通信

[复制链接]
STMCU小助手 发布时间:2022-4-5 20:21
14.1 USART定义$ Y7 u$ K  X+ M4 y  H* E# z$ y

8 @( p* e" O$ Q8 \" ]3 s! D( VUSART(Universal Synchronous/Asynchronous Receiver/Transmitter,即通用同步/异步收发器)串行通信是单片机最常用的一种通信技术,通常用于单片机和电脑之间以及单片机和单片机之间的通信。6 j7 O! b9 Y  w0 s
5 [0 r) t' m- H# B* [

8 N8 x' m$ K$ x2 c14.2 USART串行通信协议

2 h: Y  K6 x* ]3 N
# f" H+ C) X4 C. `( Z$ Q2 G$ A, g14.2.1 波特率和数据格式
6 U+ Z2 @, _- {- Z5 A$ D' _  s0 d6 ?
USART通信中的同步通信功能很少用到,大多情况下只采用异步通信,只能实现异步通信功能的接口就称之为 UART。UART 通信通常以字节为单位组成数据帧,由通信收发双方根据预先约定的波特率(传输速率)进行通信。
; k5 q% S2 ?0 g" V, A
+ {& |6 _, R% Q4 M波特率表示每秒发送二进制数据位的速率,单位是 bps,即 位/秒,波特率越高,传输速度越快,常用的 UART 通信波特率有2400,4800,9600,115200 等等。在进行串行通信之前,通信双方需要设置波特率保持一致,否则不能正常通信。
( R1 A  P% r' g9 b& U
1 }6 n" x8 J6 b. t1 [单片机标准串口进行通信时,没有数据传输时通信线路保持高电平状态。当要发送数据时,先发送一位0,用以表示开始发送,叫做起始位。然后再按照低位在前,高位在后的顺序发送8位数据。当8位数据发送完毕时,再发送一位1表示停止位。3 P4 _1 W2 n  q4 _7 Q/ a

6 J& r4 I2 K; _, U- g5 W' ]4 x6 X, j: X对于接收端而言,开始时传输线路一直保持高电平,一旦检测到低电平,便准备开始接收数据。当接收完8位数据时,便检测停止位,检测完毕后,表示一帧数据发送完毕,开始准备接受下一帧数据。为了确保数据准确性,通常会在数据位之后设置校验位。
4 k/ A* S5 t2 s
: N( @% ?5 \* T$ a% c, m( m串行通信的数据帧的格式由起始位、数据位、奇偶校验位(可选)和停止位等部分组成,如图:1 K5 J7 x2 U: B8 j
) F3 p7 H- i, x0 h9 w7 m- T
{)ATF(8AY8U]A{D8M}I(GUB.png
8 {& Y; k) [  d3 B' A: q
' `( \* j+ h, n9 _3 e+ O
) s; W, Q$ y. n14.2.2 TTL通信接口和RS232通信接口
; ]/ f" }0 K$ B8 a% D
3 z. f6 _' T- p电脑和单片机之间进行串口通信,通常使用USB转UART芯片,将USB通信协议转成UART协议和单片机通信。
# }4 q9 H; m" [$ F* d+ h3 ?1 P
' ~0 V- D2 ^4 O$ C$ [0 n1 Q, K$ [
3 c6 m7 P0 q' B6 p- w; J
# `/ x+ N/ [0 `1 M14.3 USART配置步骤: H  M2 L0 v7 \3 \1 ]
" K9 P8 @5 y% {4 p
1.时钟使能
" h$ m) W8 G: N3 Z! p2.设置中断分组
; l, V0 F7 r) n2 V. O3.串口复位2 |, a, A$ ~1 T% _
4.GPIO初始化(TX,RX引脚)
! m( v. n' _  F) `" t5.设置中断分组7 o: D. l# l9 g; e, p# n6 L
6.串口初始化8 W' Y' i7 F6 T
7.开启中断
; g8 ~$ W9 M: A' }8.使能串口% _" x& e+ w8 F. D

2 C8 {# S! w, [7 L' m
6 O. M8 m0 `6 h1 T1. 新建两个文件,usart.c 和 usart.h
2 V0 z' ?' d/ u" e3 W1 R' q0 G- d$ G
4 r' L3 \* l! J, L7 A []OJ]~{CGB[$T27T%H}1@N3.png . F1 C6 o5 ?3 @

  s1 a3 U4 Z  X- ?5 A& V: o$ z) M
3 m0 O$ m) F! R0 L2. 在头文件 usart.h 添加下面代码:
  1. #ifndef _USART_H! m  O+ Z! O$ j* }! g% R6 g4 A1 a4 B
  2. #define _USART_H
    : a+ u9 Y4 O$ @+ l! b
  3. #include "stdio.h"2 A1 W' v" c( c5 k* D( w4 S
  4. #include "stm32f10x.h"
    / ?/ z( s& i; @( }+ Y7 ]5 W
  5. " V8 J1 [' o/ Q+ {4 \
  6. #define USART_REC_LEN        200      //定义最大接收字节数 200* x1 ^8 u2 g" v! w/ e, Q  _
  7. #define EN_USART1_RX         1        //使能(1)/禁止(0)串口1接收7 C; D5 s  y/ `* o- m
  8. ! |! x7 `; B% I. u- j0 f. s) `3 ?9 M
  9. extern u8  USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
    2 a$ t) W  i6 A( r6 O& Q* z# n
  10. extern u16 USART_RX_STA;                //接收状态标记
    1 a" M2 `% ?! [: J, ^* V

  11. / ?' e8 @! [9 r1 G# i" \
  12. void usart_init(u32 bound);/ ]8 n) ?" D- P/ b

  13. % {8 Q- ~8 Z* W) D- @5 s
  14. #endif
复制代码
/ p+ v8 K8 `" D
[4BJGRON~`JX8%H)Q8]0UUR.png
3 U) I. e8 w, Z% x3 j. ~8 M
9 k1 w/ ~. U! O% X. ?5 |3 @% e5 g3 Z
3. 把 usart.c 添加到工程中  B. P# m) E' T: @
" Q0 ^: j9 }; e) U
{H%V(28~w4HYQRQF$]K8C.png # N3 m, t9 L) Y3 H
0 Q) K# i8 U) L/ X
4. 在 usart.c 中添加以下代码:
+ h# f, ^' N2 K* m/ V7 V9 J+ i9 r: Z( l1 r/ T8 `
  1. #include "usart.h"+ Y' j8 T3 x  |+ R- L# ]
  2. # I$ q+ O' X, W6 v! b" f4 [- y) n
  3. #pragma import(__use_no_semihosting)
    0 L) ~2 U: J/ g& L) d8 l
  4. //标准库需要的支持函数. X; Q& S5 q+ u- l; X
  5. struct __FILE
    : ?" N! l- \" \7 d/ t
  6. {; p7 X! C! v1 e8 p' P" S
  7.     int handle;/ }0 t, \  V' m( d9 Q& T
  8. };
      B3 a, i+ L2 [6 f/ c) s
  9. ' L" [, f& K3 w- [
  10. FILE __stdout;
    ! e9 B9 L' A; g" n7 V

  11. 1 d. x' A. Y" p9 u5 T$ T/ V" u3 u% l
  12. //定义_sys_exit()以避免使用半主机模式+ S8 h: t/ P- ]' t5 o" B4 Y/ @
  13. void _sys_exit(int x)
    ' m! e) l- h) J" x1 i
  14. {7 @7 u8 P% w5 v" G6 e( s( O  c
  15.     x = x;* y$ @9 v: v5 B) D0 V3 T$ T
  16. }1 }- C( s3 \2 V$ b. K

  17. ' h2 B. k; g2 U. C
  18. //重定义fputc函数
      c1 Y$ z8 Q- j& O
  19. int fputc(int ch, FILE *f)3 }: e& z. `# ]1 H) ^: k& S2 k
  20. {
    + i( ~- r" [" r7 t6 A
  21.     while((USART1->SR & 0X40) == 0); //循环发送,直到发送完毕
      g! h% k. ]2 f. @
  22.     USART1->DR = (u8)ch;
    2 [3 {4 ?/ q2 B' k/ `
  23.     return ch;
    * G( h- e- i* K& l( r) h* e6 }
  24. }
    " Y/ ?: R4 u! u5 V; ~
  25. 7 C2 }+ J3 P0 J- ^
  26. #if EN_USART1_RX                    //如果使能了接收
    / P; _, j) q( G; ^7 o
  27. //串口1中断服务程序' @( k' G2 p4 [
  28. //注意,读取USARTx->SR能避免莫名其妙的错误3 S! ]7 }, c6 [0 f* T* I. ~+ O! K
  29. u8 USART_RX_BUF[USART_REC_LEN];     //接收缓冲,最大USART_REC_LEN个字节.* h  b' T/ x1 ]6 X( C8 `. W+ U  d! |
  30. //接收状态; @+ v# [  l9 v3 }2 l% w6 @
  31. //bit15,    接收完成标志1 i$ n# M- H6 J# t
  32. //bit14,    接收到0x0d, M2 K. l2 {" Q4 Y7 Y+ D6 Q
  33. //bit13~0,    接收到的有效字节数目: [9 D3 \4 B  D* h
  34. u16 USART_RX_STA = 0;                //接收状态标记
    1 G: [- `# I  }$ I8 t

  35. % H! P7 z" d6 z: j1 `
  36. void usart_init(u32 bound){
    ! }4 ~1 x1 a' F7 {5 q

  37. 7 _, ?: l  R0 Q
  38.     //GPIO端口设置  c# d: N9 L: N3 H" b& V! }
  39.     GPIO_InitTypeDef GPIO_InitStructure;
    6 d9 F9 K0 z( K
  40.     USART_InitTypeDef USART_InitStructure;
    $ H1 j% O* w9 m: ~6 |
  41.     NVIC_InitTypeDef NVIC_InitStructure;" Z+ M! y; r( V- d/ @( s  F
  42. ! F" I% l+ S; a* j) T
  43.     //使能USART1,GPIOA时钟
    0 D) ~1 p& `( n& j) K$ Y9 n8 \
  44.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA,ENABLE);- O! x, B4 N' h7 b- u
  45.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);   //配置中断优先级分组& }( v9 _9 `2 y8 k/ A

  46. ( n9 h* M: `8 v
  47.     //USART1_TX   GPIOA.9
    / B9 q2 ^( T& N' _: t6 U% |
  48.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;         //PA.9
    2 Z* P" f  X3 C9 z) a: O. ]6 c+ B5 S0 ~
  49.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;9 ~1 K# S, N4 B; J) {
  50.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;   //复用推挽输出5 k1 J+ V) V9 R8 B6 ~5 g
  51.     GPIO_Init(GPIOA,&GPIO_InitStructure);             //初始化GPIOA.9
    , L- B: |( A7 v8 Y+ b$ l
  52.   @1 r% ]% K( x5 m2 k6 q) W- Q
  53.     //USART1_RX      GPIOA.10初始化2 [' O8 }" h( P% h0 X
  54.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;               //PA.10; O0 F9 w" z) Q
  55.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;    //浮空输入/ j9 A$ ~9 N3 P/ G3 y1 S
  56.     GPIO_Init(GPIOA,&GPIO_InitStructure);                    //初始化GPIOA.10
    7 S/ Y. Q5 y( }9 B0 l: X
  57. " U1 v+ N5 W/ L2 o
  58.     //Usart1 NVIC 配置* c- {) `& }' D8 `1 e8 M
  59.     NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    " _$ c0 l* a1 O$ `
  60.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3 ;  //抢占优先级3
    & f# @$ X; L  L
  61.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;          //子优先级36 i  f* ^! U6 [* ^
  62.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;             //IRQ通道使能
    . n+ c% Z$ C/ Y2 W1 ~% j7 W; w
  63.     NVIC_Init(&NVIC_InitStructure);            //根据指定的参数初始化NVIC寄存器' }, [+ ~' ?9 b# K' S9 e
  64. 8 Q4 c% c% T9 ?6 A% o
  65.     //USART 初始化设置
    0 R- B- n4 ?+ w8 x& u0 j$ v
  66.     USART_InitStructure.USART_BaudRate = bound;                    //串口波特率: e6 k! ]' G8 a0 c
  67.     USART_InitStructure.USART_WordLength = USART_WordLength_8b;    //字长为8位数据格式
    / U! f- N, d' F& N
  68.     USART_InitStructure.USART_StopBits = USART_StopBits_1;         //一个停止位
    4 K- X4 C# N( e, |7 u7 O
  69.     USART_InitStructure.USART_Parity = USART_Parity_No;            //无奇偶校验位$ [) y; t7 `6 b) U
  70.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
    * T, P! E, B. i. x9 N5 S& s
  71.     USART_InitStructure.USART_Mode = USART_Mode_Rx|USART_Mode_Tx;  //收发模式) f* }8 R; Q4 X. T. T7 @8 u
  72.     USART_Init(USART1,&USART_InitStructure);        //初始化串口1
    % i3 P* P0 u5 I( _* \6 B# y
  73. , n$ R% [" T) m9 P  l
  74.     USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);    //开启串口接受中断  h2 v3 X! U* L; i" S' V1 L
  75.     USART_Cmd(USART1,ENABLE);                       //使能串口1
    ' d- @' a8 c8 Z0 |2 g  J
  76. }
    # J  {3 N4 k7 o) X8 O

  77. " t) }" A) R5 O: s  G$ h8 u% z
  78. void USART1_IRQHandler(void)         //串口1中断服务程序
    ) U# Y' h: F0 \
  79. {
    5 o# V2 P" C3 {8 Y# V
  80.     u8 Res;/ D" ]$ I4 f! V

  81. ) b. i! ]% Y4 w& e" [; {
  82.     //接收中断(接收到的数据必须是0x0d 0x0a结尾)  ]/ w. K  l2 m: m6 @2 l+ W3 n
  83.     if(USART_GetITStatus(USART1,USART_IT_RXNE) != RESET)
    6 \- r0 w) t% n+ g/ d
  84.     {
    - P, ]8 x8 a/ k4 B1 i0 p
  85.         Res = USART_ReceiveData(USART1);            //读取接收到的数据
    6 C* f% k; A6 o8 d8 @
  86. # P( @  g) v" U$ `
  87.         if((USART_RX_STA & 0x8000) == 0)            //接收未完成3 Z+ I0 s2 w; \3 t
  88.         {. T- K7 s+ W$ i4 o/ a' y3 x. C
  89.             if(USART_RX_STA & 0x4000)               //接收到了0x0d6 ?; E! Q# h' B. V+ l
  90.             {$ e" S( g$ O7 a8 ~4 I2 H5 R
  91.                 if(Res != 0x0a) USART_RX_STA = 0;   //接收错误,重新开始5 _. q/ g  l5 g# _
  92.                 else USART_RX_STA |= 0x8000;        //接收完成了
    8 v+ W0 r/ W+ B& p0 m3 S
  93.             }
      g2 r5 n! j# `; \# q& ~
  94.             else //还没收到0X0D3 _/ K, W# r3 V; S. h- ^, B' j* j* z: e
  95.             {. X/ b2 w; n! Q  d1 e
  96.                 if(Res == 0x0d) USART_RX_STA |= 0x4000;: }2 I7 M& W( {; R$ h5 R9 d4 d
  97.                 else! P/ b  I( t" y9 {
  98.                 {0 z9 W# S  h% D
  99.                     USART_RX_BUF[USART_RX_STA & 0X3FFF] = Res;) m9 M- g/ `2 _9 y
  100.                     USART_RX_STA++;2 \( i3 H$ ~9 X0 K
  101.                     if(USART_RX_STA > (USART_REC_LEN - 1))USART_RX_STA = 0; //接收数据错误,重新开始接收7 }- z" B0 Q7 o3 r% d5 w
  102.                 }
    : T7 S, h" l4 ]0 V1 ?9 n
  103.             }
    7 |' q, v4 {- F6 E
  104.         }
    , U  I- x' b0 ]$ x; a* a' B
  105.         /*---- User Code Begin ----*/8 C" V& P# a5 w7 L0 u

  106. & N- |0 F9 u! ^8 {. a3 x: d; @+ j
  107.         /*---- User Code End ----*/
    9 \: D3 m$ A4 c0 ?
  108.     }0 t4 f% G8 ~, `9 K
  109. }7 ]$ d' G! Q6 _2 D$ [
  110. #endif
复制代码
* \* L0 ~# M& }$ X) @5 q( Q( Z
3XKR98{IF1ODKV}1PQNCG53.png
9 ]% s! l" d) a  {0 F. B1 r
1 l% z, c+ F9 m1 j; Q QL}VQ#A`~~12`MZKX]38O.png 3 e% L% r1 ~9 V* {0 ~
, f. Z; F( H/ Z
_WQ@[ZKGE3$OF}}(C{RFQBP.png
& u5 u0 E! J& r
4 C. C! J; O+ J) ~+ T QM1]1J[_0]IYJ{Q`MHFC@LW.png 3 s. _* B) `! L" a8 l6 T7 W

6 J& X* W4 L- E: I QN_DV9@TL@A{CTD)NTED2.png
/ x$ b9 }: t( ]3 v- x6 C
! C5 N! i9 f9 W0 Z
6 K4 [4 D0 i2 j' o1 F- W5. 实现USART串口通信(以printf函数为例)
2 n) \+ w8 |/ n0 {- r5 A9 V
* B/ n. W1 q5 K1 d
  1. #include "stm32f10x.h"
    # U1 _4 I9 ]6 p8 h1 X
  2. #include "delay.h"1 ~* N8 G, y/ \& R' a: g
  3. #include "led.h"# c- R! I' G, H. \
  4. #include "tim.h"
    0 v) Q1 Q+ o( W8 |! O
  5. #include "key.h"
    & I1 b. y8 l& p
  6. #include "pwm.h"# `4 e- G, |9 V: W: b* o) G
  7. #include "usart.h"1 E4 Z8 L) ?; b! N
  8. + r: ~8 ^: ]9 @9 i! f
  9. int main(void)# p# \) Q% Y/ Z/ _7 \5 U
  10. {
    " V9 T4 g$ R( r: U& x
  11.     delay_init();
    4 }7 z  L) z) s" V* A/ x
  12.     usart_init(115200);
    5 H& G& _  G3 h  u) B, b

  13. " L- a$ v% }" r6 M) `- m
  14.     printf("USART Init Complete.\r\n");' \  q: T& S: d7 _
  15.     while(1)
    * c' C+ g# B* p8 ~0 C; J
  16.     {
    2 J2 r4 N( F9 D9 d, a# x
  17.         printf("Hello World !\r\n");
    5 m$ y/ T6 `4 k8 O
  18.         delay_ms(500);0 U4 k. j3 B& G4 F  X/ ^5 Z8 o( Y
  19.     }/ a6 q; V- {( c$ u
  20. }
复制代码
7 @4 [- C) X( c. V2 d
~F@@88S8U0SOG6K(CBHFF]8.png
9 `4 h5 X; d8 Y- O- O" b% x, L: N" N- M) W

4 K) V# Y0 {; m: g/ O/ _5 l7 e测试结果:
8 J0 Q. L! x( {3 p7 P- L
/ r8 p) Y! i7 Q %ZT}C0)X@J{4TBY8M27MW{F.png
. B2 L! \7 N. U$ |" U: E0 x; D! `* Z( f! y! c& w
& w: l0 ?6 q9 D+ P
收藏 评论0 发布时间:2022-4-5 20:21

举报

0个回答

所属标签

相似分享

官网相关资源

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