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

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

[复制链接]
STMCU小助手 发布时间:2022-4-5 20:21
14.1 USART定义* \) z9 y/ I; N! d8 S- w5 N

: P4 I* p% {2 e; g1 Z$ x0 j& LUSART(Universal Synchronous/Asynchronous Receiver/Transmitter,即通用同步/异步收发器)串行通信是单片机最常用的一种通信技术,通常用于单片机和电脑之间以及单片机和单片机之间的通信。( Y: z3 R4 U7 ?5 k. i2 u
# T! w9 _  c' U3 D1 [
( x% _6 n& W0 g' ^
14.2 USART串行通信协议

! X: x1 s5 w' m/ Y8 p6 \: m" q9 y% d5 [2 v3 Q
14.2.1 波特率和数据格式: _, T  b6 v7 E* a( E" z
- z' {4 [7 U; ~4 D: t
USART通信中的同步通信功能很少用到,大多情况下只采用异步通信,只能实现异步通信功能的接口就称之为 UART。UART 通信通常以字节为单位组成数据帧,由通信收发双方根据预先约定的波特率(传输速率)进行通信。
3 {" y5 [5 X- P( y9 h, @" A6 T4 L/ D8 O0 [/ O+ N, l" c( a2 P
波特率表示每秒发送二进制数据位的速率,单位是 bps,即 位/秒,波特率越高,传输速度越快,常用的 UART 通信波特率有2400,4800,9600,115200 等等。在进行串行通信之前,通信双方需要设置波特率保持一致,否则不能正常通信。
/ }% b, h) Q1 [# ^3 ~
2 F4 e# I" W( F" o( |单片机标准串口进行通信时,没有数据传输时通信线路保持高电平状态。当要发送数据时,先发送一位0,用以表示开始发送,叫做起始位。然后再按照低位在前,高位在后的顺序发送8位数据。当8位数据发送完毕时,再发送一位1表示停止位。' F% h2 A, u) w$ C2 e

( K+ d' U/ ?, W% u# p对于接收端而言,开始时传输线路一直保持高电平,一旦检测到低电平,便准备开始接收数据。当接收完8位数据时,便检测停止位,检测完毕后,表示一帧数据发送完毕,开始准备接受下一帧数据。为了确保数据准确性,通常会在数据位之后设置校验位。
, W! g1 U& j3 w- h0 w7 W* t& p; a+ j: K7 e# T1 S
串行通信的数据帧的格式由起始位、数据位、奇偶校验位(可选)和停止位等部分组成,如图:
# q" S8 k- b' \1 \  K% z5 M5 z4 N0 K  v2 _' W. |
{)ATF(8AY8U]A{D8M}I(GUB.png : ^5 y& d* I5 o/ ~& A
) ]5 |. P& c/ K1 ~  [3 _; B* c9 `

8 c" v, C% H5 D( L& S14.2.2 TTL通信接口和RS232通信接口
! x. {6 V6 g( q+ T' n! t/ n, p! o% x; V7 X
电脑和单片机之间进行串口通信,通常使用USB转UART芯片,将USB通信协议转成UART协议和单片机通信。
/ ^7 r+ [+ `  [/ k4 u" p* D$ d- j' Z3 L, t4 D
" W8 O" o9 Q& J
& h* j- C' F# E( A$ i0 h7 c
14.3 USART配置步骤
; ~# O" l: J; n! ]
/ ~1 X% ~/ t& v4 ^; [1.时钟使能! D9 W. C' O7 e
2.设置中断分组* Y9 d6 L/ s. ]
3.串口复位
7 v3 a# ^$ W0 z% V6 u) u. V$ v4.GPIO初始化(TX,RX引脚)
& u& {+ w- {" ^' a9 Y5.设置中断分组" ]5 x8 U+ X* x5 X) S/ q% i* M, Q
6.串口初始化. ]/ K! X7 ~# P6 T' I7 \
7.开启中断  m+ j8 h1 m- R: L" M& \9 q
8.使能串口
% V* E( w  h) i$ O
, h1 C* g  }8 n* e
) H1 o( ~. O  m6 [# W5 A+ C2 y' \  w1. 新建两个文件,usart.c 和 usart.h" G( K9 ^/ @& B/ N9 i5 D

3 Z6 n' R9 |/ s []OJ]~{CGB[$T27T%H}1@N3.png ( L1 L. O- _1 H6 N
- M! K- o9 R0 l0 q! D

* \" V7 @. f9 {. _) E* Q  m2. 在头文件 usart.h 添加下面代码:
  1. #ifndef _USART_H
    1 a4 [- x) v1 ~
  2. #define _USART_H1 A- a! L$ h- x( u1 ?
  3. #include "stdio.h"; S# L6 g+ J4 ~* [) R- Q
  4. #include "stm32f10x.h" 4 f9 s. E9 t) w$ B" Q$ O" [4 R
  5. , D  U0 U* ~$ q& ~
  6. #define USART_REC_LEN        200      //定义最大接收字节数 200" P; g8 Z% @1 {; `' p# ?( Y3 m
  7. #define EN_USART1_RX         1        //使能(1)/禁止(0)串口1接收1 a! d# ?1 [% o2 o! B, ~
  8. 5 E% E  W( \5 ^- F6 O1 I  b! E! M
  9. extern u8  USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 ' u- S& w' R0 e$ P; \! @6 `% @
  10. extern u16 USART_RX_STA;                //接收状态标记) W9 e* d4 d) W& z
  11. 7 C7 q: ^) I, N) I, L- J  ^. k, A# @- V% ?
  12. void usart_init(u32 bound);4 b6 E2 h4 \7 q0 A& d: u

  13. 7 Q% T/ ^$ c; _. ^
  14. #endif
复制代码

; N; f, b$ t5 I; o% V( o& _3 X3 n& k [4BJGRON~`JX8%H)Q8]0UUR.png
& t3 w* N7 E( t) X7 L
  d$ s; C8 B5 G- {- v( Q; g
8 w9 a$ o- [' W3. 把 usart.c 添加到工程中1 y+ @$ v1 `6 }) d3 K- B9 W

. w1 ^- `4 l, c) r# x6 M& U% z$ C {H%V(28~w4HYQRQF$]K8C.png ! U1 j& u/ n( q& F# [
% x: f1 ~% r9 N/ ~5 ~/ e/ |8 \; B2 u- H
4. 在 usart.c 中添加以下代码:
, {& W* a2 `  K. K! W. x* H3 d( O7 M' i: |5 Z
  1. #include "usart.h"
    $ T, t& z  G: e
  2. : E$ G. C2 I# H0 X
  3. #pragma import(__use_no_semihosting)
    & G4 |, Q6 t, B, ^
  4. //标准库需要的支持函数0 h3 a, O$ e1 }  B. k" }
  5. struct __FILE9 J! J0 H7 H" L* |. i  g
  6. {3 B# o; \& H* a0 U9 L  K
  7.     int handle;) p2 `5 h4 O( I5 H* B* K/ _
  8. };# p* ]. ^0 q& j  u# l- I

  9. , O7 P( z' O4 I' H
  10. FILE __stdout;$ N4 |. q5 O* b( q7 R& ?

  11. 6 [/ M& z- n6 M) w
  12. //定义_sys_exit()以避免使用半主机模式
    . [. n9 p) |! D' s7 k4 i& _
  13. void _sys_exit(int x)
    ; b7 V1 L& w' q
  14. {
    $ H8 ?2 b! H. @; v9 q0 b  D6 n4 T" `
  15.     x = x;
    $ s1 `. D8 U. s2 u, A
  16. }
    0 Z9 V% U2 u0 D# r
  17. 2 y5 E$ K7 q# Z7 B. m+ o
  18. //重定义fputc函数( ~9 [+ b3 o; l7 q  ]/ e
  19. int fputc(int ch, FILE *f)
    / E( F. y5 k' v5 s5 M
  20. {- S5 v  @* }$ e/ ~
  21.     while((USART1->SR & 0X40) == 0); //循环发送,直到发送完毕
    ) C+ p9 m$ }! E
  22.     USART1->DR = (u8)ch;# C# s8 p5 @3 ~
  23.     return ch;0 _8 F& K) X5 H, y
  24. }
    * }: R$ j5 @$ @; p
  25. ) Z+ r; g1 X& F2 a, y
  26. #if EN_USART1_RX                    //如果使能了接收' M) i5 ?; d7 N5 p
  27. //串口1中断服务程序
    9 ~1 h$ z9 d6 L. _6 d
  28. //注意,读取USARTx->SR能避免莫名其妙的错误
    2 X5 L' U& L% \* y4 }2 r
  29. u8 USART_RX_BUF[USART_REC_LEN];     //接收缓冲,最大USART_REC_LEN个字节.
    / j( E+ i. x! [
  30. //接收状态- p) k6 z4 T: h; C, O3 [+ I
  31. //bit15,    接收完成标志, r1 y) d) {  |4 y/ Q$ b
  32. //bit14,    接收到0x0d
    / k# ?5 \7 K1 x2 r# M& D
  33. //bit13~0,    接收到的有效字节数目
    2 w+ ^( D- k* A) J0 e
  34. u16 USART_RX_STA = 0;                //接收状态标记
    6 l9 h: t( N- K

  35. - @* }4 v7 N% W. Z# k1 L
  36. void usart_init(u32 bound){+ u) l" \: x) {0 \/ Y

  37.   I/ d. |/ `( R6 {# g4 \( c
  38.     //GPIO端口设置/ y7 c% `0 w0 Q3 _
  39.     GPIO_InitTypeDef GPIO_InitStructure;
    - Z' x3 E: A* f2 \& ?
  40.     USART_InitTypeDef USART_InitStructure;' o8 E* E# A* I$ E( [
  41.     NVIC_InitTypeDef NVIC_InitStructure;4 j" a9 S7 M+ {2 J& d6 M4 M

  42. + a  l! j* |" W. e8 C. _: d
  43.     //使能USART1,GPIOA时钟
      I( n, F4 i8 P6 {* h
  44.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA,ENABLE);/ N9 F, |3 i  [' d  v. k0 @+ m" U2 i
  45.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);   //配置中断优先级分组' @4 d$ M! {6 J; V3 J% `! c

  46. 2 y& I8 I: I8 P0 D0 h
  47.     //USART1_TX   GPIOA.9* T: _* b8 m" n! f- M$ L8 }
  48.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;         //PA.9
    * `. O; D" y& E) q% v# X# i
  49.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    + A* m9 E. L) o. u6 r
  50.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;   //复用推挽输出& p, y5 Z$ F9 G  m* Z6 t! o: [* |
  51.     GPIO_Init(GPIOA,&GPIO_InitStructure);             //初始化GPIOA.9" r' B7 i, f3 r5 h0 V$ O
  52. 1 R- z& D6 N7 [3 j
  53.     //USART1_RX      GPIOA.10初始化
    ' W  J- h6 Q$ a
  54.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;               //PA.10& M8 G- E0 }$ r) O; H
  55.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;    //浮空输入
    + I0 C: R2 O' v; Z! w( V
  56.     GPIO_Init(GPIOA,&GPIO_InitStructure);                    //初始化GPIOA.102 _7 H# _) q' M

  57. 7 h6 `/ Z  I) L, y* \
  58.     //Usart1 NVIC 配置
    8 m8 h% q3 }0 q
  59.     NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    - [2 a: u( p; e* y) o* v9 ^! K* v% C
  60.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3 ;  //抢占优先级3
    . Q7 k2 i- y1 M8 [, f
  61.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;          //子优先级3
    % ]- p- s- y* q6 e1 @+ k2 r  C, u
  62.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;             //IRQ通道使能
    * ?4 l( I( I2 }6 D* c6 K7 |  p
  63.     NVIC_Init(&NVIC_InitStructure);            //根据指定的参数初始化NVIC寄存器' j' m) |5 h  K4 o, [1 C
  64. 4 [! E3 h  {3 N$ O$ v
  65.     //USART 初始化设置) b) l, s+ H, ]$ W
  66.     USART_InitStructure.USART_BaudRate = bound;                    //串口波特率. M; M4 }0 t% K" J
  67.     USART_InitStructure.USART_WordLength = USART_WordLength_8b;    //字长为8位数据格式
    ' `& D. J& p+ t$ j' B% z
  68.     USART_InitStructure.USART_StopBits = USART_StopBits_1;         //一个停止位4 I" ~9 O: }- ]5 h: ?$ b7 R# p% u
  69.     USART_InitStructure.USART_Parity = USART_Parity_No;            //无奇偶校验位
      |7 |+ C- j% W8 ^" c3 u! m
  70.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
    2 {1 M% i8 V. o
  71.     USART_InitStructure.USART_Mode = USART_Mode_Rx|USART_Mode_Tx;  //收发模式
    8 ?1 g! W1 F6 s
  72.     USART_Init(USART1,&USART_InitStructure);        //初始化串口1
    6 K8 e& p" ^8 R+ q* b

  73. & e" P0 \+ `. ^7 p6 {+ y
  74.     USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);    //开启串口接受中断/ d6 B# U' b5 Y0 }2 s0 ~. D
  75.     USART_Cmd(USART1,ENABLE);                       //使能串口11 T8 ^' W, z; E! s) l) N2 n2 q
  76. }
    / \  h% F5 z9 `% s" n. G) M% M
  77. ( ?% S1 n; m. [; @; w0 ~
  78. void USART1_IRQHandler(void)         //串口1中断服务程序- U9 Z& R" d0 d" R; R( X: b. b/ `
  79. {' D, r) R7 j& Q( O
  80.     u8 Res;0 ~5 _+ L) n6 y6 A3 \- _! d

  81. & [7 z" M& _5 M  t/ l0 P3 |
  82.     //接收中断(接收到的数据必须是0x0d 0x0a结尾)3 f+ `% t: p* t, A' @  \! m
  83.     if(USART_GetITStatus(USART1,USART_IT_RXNE) != RESET)7 X& Z+ P. ~) D! S
  84.     {2 G" Q8 ~% j" D( V& r: L
  85.         Res = USART_ReceiveData(USART1);            //读取接收到的数据
    $ ~8 C; F: A4 r0 H6 _/ B# N
  86. * c$ g7 K- r0 Y" f' M  T1 ?. H
  87.         if((USART_RX_STA & 0x8000) == 0)            //接收未完成
    & k; N/ ^. }7 N3 k7 H0 K
  88.         {8 d/ c# [7 N4 e% Q6 x4 t1 p! m
  89.             if(USART_RX_STA & 0x4000)               //接收到了0x0d' S5 H# n8 n! p. Z# T
  90.             {
    + M. C7 ^8 Y, O1 F0 m6 t
  91.                 if(Res != 0x0a) USART_RX_STA = 0;   //接收错误,重新开始
    ( y+ q9 j; O2 v: W4 Y; o5 l
  92.                 else USART_RX_STA |= 0x8000;        //接收完成了
    ' B8 ?. H, n: f9 D- i6 G$ U
  93.             }) h5 e6 U0 ?+ G/ r6 F, y5 L5 t
  94.             else //还没收到0X0D( s5 A& w8 F7 |$ b$ F* S
  95.             {2 a7 d0 z+ s$ m  _( U
  96.                 if(Res == 0x0d) USART_RX_STA |= 0x4000;' \; |7 l. c5 \1 z2 S9 g# w8 F
  97.                 else2 `0 U9 Z% O0 M
  98.                 {
    : n, z& v! h- ]# q8 c$ S- F
  99.                     USART_RX_BUF[USART_RX_STA & 0X3FFF] = Res;
    0 H, H' Z* R* b& \. \) T
  100.                     USART_RX_STA++;  v! Q3 g/ F# @  E9 T
  101.                     if(USART_RX_STA > (USART_REC_LEN - 1))USART_RX_STA = 0; //接收数据错误,重新开始接收
    " ]! v5 Y  |; H
  102.                 }
    , i: }, F5 v- H  P
  103.             }! ]) a2 w& p: P0 e
  104.         }8 M/ m' Z- ~/ U. V" ^
  105.         /*---- User Code Begin ----*/
    0 z2 g8 E% d* ?9 P" `& C( ^. g3 }
  106. 7 @2 k- r5 G# ^, c8 v) x
  107.         /*---- User Code End ----*/) T+ n+ y. N' c+ ~
  108.     }7 D+ G3 `8 A. q+ M4 B
  109. }
    6 k4 |! r1 t, Y3 _5 L
  110. #endif
复制代码
: d1 Q. G( \- a* A
3XKR98{IF1ODKV}1PQNCG53.png . Y1 b! X/ y* B# j/ Q
1 d! ~  L- O  v+ X
QL}VQ#A`~~12`MZKX]38O.png , D- c8 f" V9 n: T  l; q

  I( i4 U  t1 z. C+ Y5 T5 l/ O _WQ@[ZKGE3$OF}}(C{RFQBP.png , i/ b) G5 D, k  [; x( W+ p
& B+ X: z8 w& ?9 Q+ Q
QM1]1J[_0]IYJ{Q`MHFC@LW.png # q  ~1 s3 |# s5 l0 Y( a
0 z3 o8 Q" _! f0 b
QN_DV9@TL@A{CTD)NTED2.png + N3 v9 H% a/ H$ |

5 M0 g/ B7 [  ]3 A* a, z2 |& W
7 r5 C$ g# @! ?5. 实现USART串口通信(以printf函数为例)
4 J. B4 q9 B( n1 J, i6 I' B+ h) K, f& u+ u; r7 k4 j
  1. #include "stm32f10x.h"
    ) f/ a  @: z" U2 |
  2. #include "delay.h"( m9 M1 w$ i+ C/ c. ^/ |
  3. #include "led.h"; w2 F/ i* m9 k7 H; |
  4. #include "tim.h"( _4 h) |/ b1 J9 u, b5 w
  5. #include "key.h"" X) }# Y: H8 V. g. o' J9 C8 I
  6. #include "pwm.h"% Z- {, Z! k( P! X/ B3 O6 z
  7. #include "usart.h"' \7 A* E* |+ e. y& p5 y
  8. 5 G$ ]. U0 [# |  J2 i, ?% D; i: g
  9. int main(void)% R5 X( ~7 j( _* k( `) l
  10. {, O. F3 @/ `6 z
  11.     delay_init();
    ) T2 m, Y, t8 A( G2 _! o0 F7 O0 O
  12.     usart_init(115200);
      w* U/ \# E% I2 H1 F1 ^4 N

  13. ' f. a2 m- `1 m
  14.     printf("USART Init Complete.\r\n");' u# O5 x! J7 i
  15.     while(1)1 P8 _4 H( \- @4 s0 v: S
  16.     {
    9 }" n  R8 W# }2 Y+ Q
  17.         printf("Hello World !\r\n");
    % C$ Y4 z( e) K% a  j% T; w5 @0 [, M/ [
  18.         delay_ms(500);* |8 ^2 s4 J( _( Z! N8 C1 j# X- T
  19.     }$ j* u$ Q; l( }# k0 _9 y
  20. }
复制代码
5 R1 f/ N$ E* E: C7 i
~F@@88S8U0SOG6K(CBHFF]8.png
2 }( K2 l8 \3 f) y) e
9 N( U  t( H( k! F' |- ~& B+ O& ?$ E8 p) T6 M5 v) D5 {) f
测试结果:
; v7 m+ d7 J) [- h6 b! J9 _; y  @3 k8 E6 @4 f: t# C/ Z
%ZT}C0)X@J{4TBY8M27MW{F.png
) \- w& l0 q  u7 C: C+ k8 L2 q+ D  z  i

  J- t: |1 `) d, k+ i* W
收藏 评论0 发布时间:2022-4-5 20:21

举报

0个回答

所属标签

相似分享

官网相关资源

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