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

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

[复制链接]
STMCU小助手 发布时间:2022-4-5 20:21
14.1 USART定义4 {+ g) D. T. `+ X; [3 w& _7 d

( n8 |. t8 k0 l" bUSART(Universal Synchronous/Asynchronous Receiver/Transmitter,即通用同步/异步收发器)串行通信是单片机最常用的一种通信技术,通常用于单片机和电脑之间以及单片机和单片机之间的通信。* @9 q7 E$ O$ r  G1 r/ x. }
8 }! k! a/ s; \! D
" N( i3 S7 c' _: A$ T# e
14.2 USART串行通信协议
& V: L# h: f' o# s( R6 r
& C, B+ ?  R- s" d+ {
14.2.1 波特率和数据格式7 }6 J3 x" u4 ]: b
2 B& K; E; b$ Y( T
USART通信中的同步通信功能很少用到,大多情况下只采用异步通信,只能实现异步通信功能的接口就称之为 UART。UART 通信通常以字节为单位组成数据帧,由通信收发双方根据预先约定的波特率(传输速率)进行通信。$ I& T  I* r+ o' U2 ?) U% H3 S
; V- ]! U) @6 b
波特率表示每秒发送二进制数据位的速率,单位是 bps,即 位/秒,波特率越高,传输速度越快,常用的 UART 通信波特率有2400,4800,9600,115200 等等。在进行串行通信之前,通信双方需要设置波特率保持一致,否则不能正常通信。
9 Z2 e3 u: g5 n& G( ]
; s. O' F' u7 R4 P! q* {' g7 R单片机标准串口进行通信时,没有数据传输时通信线路保持高电平状态。当要发送数据时,先发送一位0,用以表示开始发送,叫做起始位。然后再按照低位在前,高位在后的顺序发送8位数据。当8位数据发送完毕时,再发送一位1表示停止位。- F8 \  v1 {! y
5 V- I% o$ G; g; c& I: Y! z
对于接收端而言,开始时传输线路一直保持高电平,一旦检测到低电平,便准备开始接收数据。当接收完8位数据时,便检测停止位,检测完毕后,表示一帧数据发送完毕,开始准备接受下一帧数据。为了确保数据准确性,通常会在数据位之后设置校验位。
' f6 Y  |. c1 x' m( u' v* x7 U
& s' B; Y! \4 |* }* m; V" x串行通信的数据帧的格式由起始位、数据位、奇偶校验位(可选)和停止位等部分组成,如图:
. V. J$ G8 ^! n# `* `
! E  Z0 d) U, C1 T: I" n: s0 a {)ATF(8AY8U]A{D8M}I(GUB.png
( m1 F. q& j9 v$ I! _+ _. ?! w5 A* ^: N

% {: [3 g- J; F' R; v14.2.2 TTL通信接口和RS232通信接口6 o8 s- K1 ?3 C+ V1 ^9 n7 L1 p

4 \- M  U# C& ]7 R! z; u电脑和单片机之间进行串口通信,通常使用USB转UART芯片,将USB通信协议转成UART协议和单片机通信。( F. w( {. z% \3 g
0 ~% ?3 ?" B$ J' K9 N9 w
( ]2 u3 L- L' V" ]2 Q9 Z% n4 [

. z1 `3 n* d* t3 x% y+ h: A6 u/ s& `14.3 USART配置步骤) @  v* ~. }2 P, v9 n

$ K+ K4 v& [, Z8 M# g1.时钟使能' U/ b3 o) S' z% A3 G8 t# [$ ^
2.设置中断分组
3 [3 O9 l; S8 V9 j9 t9 g* x  N) R3.串口复位) J2 Z. A$ y8 \1 U; s
4.GPIO初始化(TX,RX引脚)8 v$ ?8 _: i( m; _" d
5.设置中断分组
, N; |1 b6 P7 m& u0 n' ]8 p6 s6.串口初始化' ?' F7 {; [3 |6 C0 C
7.开启中断) A* I0 W7 g0 [5 e6 [. {
8.使能串口
( y8 h: f. e# d$ f1 m: I2 |8 v0 Z7 G( O
3 z( ~! M0 }8 v2 f
1. 新建两个文件,usart.c 和 usart.h
; x1 g8 J5 L+ C% b
+ _9 [0 [0 [4 s$ ~! {* \ []OJ]~{CGB[$T27T%H}1@N3.png
& D9 G3 y# [5 s% X+ S* Q( h- o8 A
$ Y* a( i. {2 T& f  }8 x2 t2 h3 E3 j( J$ t! E+ s3 f
2. 在头文件 usart.h 添加下面代码:
  1. #ifndef _USART_H
    2 O- i5 X3 Z" D1 [! V4 R( e/ E
  2. #define _USART_H
    $ |- H* `' A- i; @; h
  3. #include "stdio.h"  |1 r) z7 a! [2 ?3 {. t( H2 }
  4. #include "stm32f10x.h"
    - b, W& Z# ^5 u0 I

  5. " _7 c' x1 Q" U) g( ~- G
  6. #define USART_REC_LEN        200      //定义最大接收字节数 200
    * H  d3 g& K+ q4 @1 Q* ~
  7. #define EN_USART1_RX         1        //使能(1)/禁止(0)串口1接收
    + n" b0 z8 p- ^5 B# E2 j( K9 h3 [: G/ N

  8. , @* H. {7 f1 ~8 P! p# q' U- b4 K
  9. extern u8  USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
    / R$ I  S6 ?2 B0 L
  10. extern u16 USART_RX_STA;                //接收状态标记8 G5 {* b" U# O5 n2 E* a  |
  11.   R, K6 e- B: v' f
  12. void usart_init(u32 bound);* L) w+ I, d8 y, c/ o

  13. ( v' [, I+ L+ L% v! Z
  14. #endif
复制代码
8 e! r1 z3 P( X3 ]$ X7 z( n( ~
[4BJGRON~`JX8%H)Q8]0UUR.png
7 X" O, |' y) K; u* w. \! W* K$ x1 J6 Z+ W) b$ U( a

+ L6 A+ Z9 Q$ A) @. M% r3. 把 usart.c 添加到工程中
1 D4 Q8 d! x4 s! Q. n: G6 ]/ m0 |6 G# @8 ^
{H%V(28~w4HYQRQF$]K8C.png " J0 U3 V& W8 R  f' r1 n
! N! Z+ f: [+ f5 y2 h
4. 在 usart.c 中添加以下代码:
" v+ m! V* S$ G# c) v. J5 g2 y! f: o. i. S  Z! h
  1. #include "usart.h"& s9 S) l+ J8 t: \& v- g) F9 @
  2. & S) J& u9 L8 e6 f$ _
  3. #pragma import(__use_no_semihosting)# ~, G* w  x$ ]- M
  4. //标准库需要的支持函数
    & C; [( X: z( j% |2 {+ F0 N
  5. struct __FILE
    ! ?/ {. O5 S/ L
  6. {
    / |; s, t( K$ C0 |0 D
  7.     int handle;9 @3 D7 U! g( }0 R3 a( A$ |" e' X
  8. };; k4 x7 @7 [$ G8 t: B
  9. ; U2 x+ |. \9 N7 m$ w. s
  10. FILE __stdout;
    # w/ ]/ R5 }; m
  11. ( Z" b7 ]6 X! Y& A. f' M0 ~
  12. //定义_sys_exit()以避免使用半主机模式/ P! I0 ?) F4 s
  13. void _sys_exit(int x)
    5 H( ~8 k" O/ ?+ g) Y% N
  14. {1 }4 B" u- @' g2 ~( t
  15.     x = x;
    " j- Y& n+ q9 N+ U6 i
  16. }4 n# d+ c. v! s! y: L8 _
  17. 1 t6 v3 {1 N9 C6 E% `7 E' e
  18. //重定义fputc函数+ [" Q/ P; c8 l/ s$ ?0 w$ t: i
  19. int fputc(int ch, FILE *f)
    7 a# F- d8 g( R0 [& D, s2 W
  20. {0 F7 Q) q) ~" d5 u+ \
  21.     while((USART1->SR & 0X40) == 0); //循环发送,直到发送完毕) o0 @3 y6 {0 ]4 ?2 B, M+ f$ j
  22.     USART1->DR = (u8)ch;
    $ B2 e! E+ s" Y: ^# A9 {
  23.     return ch;
    7 b1 e! S; `- T  |/ i5 `2 c: U$ S' `
  24. }
    1 s4 }7 v( x$ O3 [" j. S
  25.   a0 ?! B: H8 k8 @+ D% w
  26. #if EN_USART1_RX                    //如果使能了接收+ c6 g/ F9 C# S, b9 u
  27. //串口1中断服务程序0 f* M8 }. g% V( O" K: Q3 x1 z
  28. //注意,读取USARTx->SR能避免莫名其妙的错误
    + i5 N) ?7 I( ^: W1 l3 N% y
  29. u8 USART_RX_BUF[USART_REC_LEN];     //接收缓冲,最大USART_REC_LEN个字节./ o+ `0 I3 Q9 ^# F( A2 F0 G
  30. //接收状态
    % |: H! H* @% C) b
  31. //bit15,    接收完成标志
    * F! e* D9 J! j1 j5 R# [$ g
  32. //bit14,    接收到0x0d
    # W; f# m5 i$ d* d$ j6 v1 R
  33. //bit13~0,    接收到的有效字节数目- a; @7 X6 S4 h
  34. u16 USART_RX_STA = 0;                //接收状态标记; c2 k! g2 a+ |3 h
  35. - N( R9 ^7 v/ g5 _
  36. void usart_init(u32 bound){
    6 K0 u7 G: I) [8 `. R$ b

  37. 1 x: v) w+ \& J2 M7 |
  38.     //GPIO端口设置
    / v7 y- ?+ Z) l( _# Y
  39.     GPIO_InitTypeDef GPIO_InitStructure;$ V1 {& m, D7 s. k/ R( L3 X) G
  40.     USART_InitTypeDef USART_InitStructure;, g, ?8 h6 W6 I; w: L* A, @
  41.     NVIC_InitTypeDef NVIC_InitStructure;
    ) n/ F% w. a, a* ^# i% l
  42. ; T# n( }9 c) |; P: H6 I
  43.     //使能USART1,GPIOA时钟
    " e. a) d1 l! f* v% }
  44.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA,ENABLE);+ T5 ^6 e5 f6 j# {# G* {  s
  45.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);   //配置中断优先级分组
    * `3 w/ I8 d3 g( p8 U
  46. 3 B! _2 R3 X, V3 d5 d, r3 z# s3 j4 J* m
  47.     //USART1_TX   GPIOA.9( J+ O/ D2 N: T
  48.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;         //PA.9
    . V* O, @# l% D
  49.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;) K4 i1 E# n4 w# C& ^7 t- j6 u) R* o8 Q
  50.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;   //复用推挽输出
      I! T6 x# S: W9 M) R: Z
  51.     GPIO_Init(GPIOA,&GPIO_InitStructure);             //初始化GPIOA.92 q# G# W3 F+ ~! J2 J. s

  52.   I; \2 E7 B$ U7 B1 U. ], c6 H5 _. K' x
  53.     //USART1_RX      GPIOA.10初始化
      p7 Y8 T9 {* ~, L( P
  54.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;               //PA.10
    9 Q; C% A- Z8 j& L9 ?9 D2 Y
  55.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;    //浮空输入3 l* b4 t' ?" t: n$ T- |, a
  56.     GPIO_Init(GPIOA,&GPIO_InitStructure);                    //初始化GPIOA.10
    4 B. Z/ r- n9 u, @

  57. 7 z4 g5 J  s0 v  G( t
  58.     //Usart1 NVIC 配置
    ! f6 h" L) p" \- Q8 I  W6 m. n
  59.     NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    $ q% z+ k* b5 K1 }6 z4 M# r; Y4 _
  60.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3 ;  //抢占优先级3
    " f  d- n- v1 H! ^# M  q
  61.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;          //子优先级3
    ; M3 e8 x" z2 k" k) o# F
  62.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;             //IRQ通道使能3 ~7 H/ a" ~  U' ]4 j7 y
  63.     NVIC_Init(&NVIC_InitStructure);            //根据指定的参数初始化NVIC寄存器
    ; Y# k' A# n- B  v/ N  z

  64. , B1 R' e3 E1 s& o8 T# l/ b- J( I
  65.     //USART 初始化设置2 L) p8 z$ Q  e! v& h5 |
  66.     USART_InitStructure.USART_BaudRate = bound;                    //串口波特率
      Z$ M) Z2 J. x) e, a* u3 M0 o6 ~
  67.     USART_InitStructure.USART_WordLength = USART_WordLength_8b;    //字长为8位数据格式
    + M* W3 E6 D: Q9 c$ y5 ?
  68.     USART_InitStructure.USART_StopBits = USART_StopBits_1;         //一个停止位: R9 C) U% M  e& W7 B
  69.     USART_InitStructure.USART_Parity = USART_Parity_No;            //无奇偶校验位4 I5 f" T! P4 d
  70.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制7 l& b4 }9 x, ^* t! @% |* S
  71.     USART_InitStructure.USART_Mode = USART_Mode_Rx|USART_Mode_Tx;  //收发模式' a# Q. t- P9 V( b  S2 C
  72.     USART_Init(USART1,&USART_InitStructure);        //初始化串口1
    - W5 {% w$ f% j& X5 [$ b
  73. , a' r. m" R) s- A( n4 x
  74.     USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);    //开启串口接受中断: a- h7 F8 u: M1 E3 p5 m
  75.     USART_Cmd(USART1,ENABLE);                       //使能串口1
    ) m, C6 L, h" S" E1 a
  76. }
    2 q7 Y! M1 a; V6 a

  77. & C& f$ I0 ^( D' B. f+ f( c5 r9 ]" K# z
  78. void USART1_IRQHandler(void)         //串口1中断服务程序% D0 _0 [+ w% D  F7 ~
  79. {
    & R) |$ @2 o; |: ~: b1 I1 c" o
  80.     u8 Res;
    8 {$ |! v, X+ |# \3 T

  81. - ~: ]+ g6 J+ V) e: R) J
  82.     //接收中断(接收到的数据必须是0x0d 0x0a结尾)+ _9 L( b% D; S' I
  83.     if(USART_GetITStatus(USART1,USART_IT_RXNE) != RESET)+ A+ L- P1 n8 a) A( J) U) g+ ?
  84.     {' g9 }8 q6 _& R" W2 E2 V8 I
  85.         Res = USART_ReceiveData(USART1);            //读取接收到的数据0 E. O! c9 v. u6 A+ g% f
  86. 1 {3 z9 Z( H' o* d; l' Z
  87.         if((USART_RX_STA & 0x8000) == 0)            //接收未完成
    5 j2 J" H1 B0 U, c- [% }9 X" I1 g
  88.         {' c' K; x7 r7 m4 v) X+ h
  89.             if(USART_RX_STA & 0x4000)               //接收到了0x0d
    & s6 x$ Z4 R" ^' v; ]! A
  90.             {
      ]9 d' {% J- Z1 |6 `
  91.                 if(Res != 0x0a) USART_RX_STA = 0;   //接收错误,重新开始
    $ S/ j+ g; D. ~2 V. _
  92.                 else USART_RX_STA |= 0x8000;        //接收完成了
    " B9 L, l$ E; ]7 C' g6 r' ~% P$ C
  93.             }
    ' k1 G: G, s( C/ u5 B+ e
  94.             else //还没收到0X0D9 I1 l4 N# Q1 l) f& g4 x" Y
  95.             {
    6 N- m8 z0 m/ S  f& S
  96.                 if(Res == 0x0d) USART_RX_STA |= 0x4000;1 D! e/ M( Y0 |2 A" c7 A& J
  97.                 else) ^# q; a  h" t: f6 p- o/ [0 B( M6 g
  98.                 {! u6 i% ?: P3 b. a
  99.                     USART_RX_BUF[USART_RX_STA & 0X3FFF] = Res;( ~' s1 u: m1 \+ R+ o+ q$ }1 H
  100.                     USART_RX_STA++;2 c0 `+ a- ?' G. ^3 W
  101.                     if(USART_RX_STA > (USART_REC_LEN - 1))USART_RX_STA = 0; //接收数据错误,重新开始接收+ C3 w- D5 d; W  B& S3 y
  102.                 }& {5 p/ G% D: X& C9 Z- x
  103.             }
    3 S& t0 p2 i' G! x9 R6 z: U
  104.         }4 N3 l- ^) _5 c9 k5 _+ P4 U
  105.         /*---- User Code Begin ----*/+ O/ k& D* L8 R

  106.   O; O' P9 r' J" Q. V
  107.         /*---- User Code End ----*/' b( R% d2 S' f# r
  108.     }
    9 {/ s& i4 ]. |, {
  109. }5 P' ~/ S8 J5 [
  110. #endif
复制代码
$ |9 o2 o& ?* [' W+ o( A
3XKR98{IF1ODKV}1PQNCG53.png
5 a& h, V2 b! G# w3 n0 Z0 D
! ]8 Z( ~1 w% Q# W QL}VQ#A`~~12`MZKX]38O.png , w; n4 [3 G0 x- J/ F: B( K

2 i9 E; V/ U* l; a' l _WQ@[ZKGE3$OF}}(C{RFQBP.png " ?/ B' e) J1 T3 ?7 m9 e
5 s. |7 c# Z4 Z( U8 P& G
QM1]1J[_0]IYJ{Q`MHFC@LW.png 3 K/ L/ `" F% ^9 c( c
0 e% C# X$ v; M
QN_DV9@TL@A{CTD)NTED2.png
( O- K4 ?9 x: R2 x
/ f/ ~: d$ z% F
- Q/ L* C8 y1 f5. 实现USART串口通信(以printf函数为例)
) [9 p. l: Z* ]" x# p' x: L: ^# G
6 j1 ?2 j5 @9 o9 A
  1. #include "stm32f10x.h"5 g) X: J; C( z
  2. #include "delay.h"
    / _' f; C" y& D) C8 \% `: Z
  3. #include "led.h"6 c: a8 P/ |$ r5 v4 f2 ]
  4. #include "tim.h"' G: }; ]! a, N
  5. #include "key.h"$ L5 ~; b& I% `, C
  6. #include "pwm.h"7 {6 N7 |! h; x4 ?" m3 F
  7. #include "usart.h"
    2 @& q3 K8 r9 v' v/ q

  8. 0 S: C, ^4 \( `$ U# n* j
  9. int main(void)5 K, q$ R/ K* W9 {
  10. {
    ' I5 e# ^# R+ o, H/ y4 A5 c5 [% ^
  11.     delay_init();
    $ ]5 J# S5 ?2 K3 W; b3 ^1 a
  12.     usart_init(115200);% M' H2 v4 v* V* H( x% Y9 D9 R- p
  13. ; s2 \5 z# }) _- L4 ~, D& X
  14.     printf("USART Init Complete.\r\n");
    ) v* r# {* u! T
  15.     while(1)' Z" x8 C- ?. a% k* V
  16.     {$ v) Q9 H$ m7 x0 Z) G
  17.         printf("Hello World !\r\n");
    , b/ p1 {. k' I& k
  18.         delay_ms(500);4 V2 K% t# q) `* W; n  c1 }
  19.     }: Y; \% i& O4 d. R) e
  20. }
复制代码
! E; K" e- c4 X( u0 X+ A; y( z
~F@@88S8U0SOG6K(CBHFF]8.png ) A9 e; S0 W, h; K3 T

( n5 H2 b. p% |3 g: L1 w+ d- q0 w5 ~! s3 u  J3 b1 i# S
测试结果:
/ F/ P6 V( `$ v- R4 l, P- G+ D  C+ o  t" b% a
%ZT}C0)X@J{4TBY8M27MW{F.png # y( s8 ^( ]4 w
4 c6 c  [8 q) h4 {$ A

0 q1 p2 R# {" ~! t% D/ C! c2 D
赞 收藏 评论0 发布时间:2022-4-5 20:21

举报

0个回答

所属标签

相似技术帖

官网相关资源

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