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

基于STM32F103入门4——串口通信

[复制链接]
STMCU小助手 发布时间:2022-8-22 17:40
最近能抽点时间学一下stm32了,串口通信用的挺多的,比如wifi模块,GSM模块,指纹模块等等…在这里用自己理解的写一下总结,如果有误的话请大家多多指点。
, y  L* O) @$ ^! K  k+ z4 R串口的基本概念% ?2 b- u( y/ g' {) k- e
串行和并行
0 m0 W& R* E" h# q# G串行

' v# X* H+ ^* I5 ?- c* M串行是一位一位的传输。
( ^! c9 I7 _- R- M1 p6 A, @. _9 h常用的有 USART、IIC、SPI等…$ ~0 o" |4 Y, z
串行也分为 同步通信 和 异步通信
7 s- M2 f. B! V/ o# U+ M同步:! h5 a2 c1 q# B5 d4 {# v6 y
就是一般有一根时钟线,有时钟就可以大家一起同步嘛。靠时钟来约定。一根数据线。一般一个时钟传输一个Bit位。同步的话 他们大部分都是有效数据来的。但是对于双方的时钟允许误差较小。' }) O  Q' ^7 y" d! i

9 Y- L) D" W0 w, v* Z$ \) J异步:1 S; t% ]2 u$ t/ {  e" p
异步就是我们平常玩串口用的最多的,它不像同步有个时钟,异步是没有时钟,那我们得为了数据不出错,所以通过 起始位、奇偶校验位、停止位这些来降低数据的错误。
/ k+ k# h+ a6 S  b- k: X所以异步的有效数据就没有同步的有效数据那么多。效率也没有同步的那么高。, _. s( z6 _9 n( P: U
% d* x+ M, q. [  u% W: @6 }
优点:传输距离远、抗干扰能力强、成本较低
% a4 |/ Q: }( Z( R2 e9 X缺点:传输速率慢1 K. N% P( S. B4 d; E2 c% H
- C8 T, ~9 `: _1 n% S
并行
& D6 }  D% `" U; m7 N  g并行是指多比特数据同时通过并行线进行传送,这样数据传送速度大大提高。9 D) ?* t5 j0 G: Y( L! R
简单的理解就是 比如我们用的LCD1602不是有一共10几个引脚么,然后8根是数据线,这就是属于并行,它们通常需要数据总线(八、十六或更多线路)。
1 x" r- @8 t2 ~7 ~
' O2 i: _# @' m/ a优点:线比较多嘛,所以我传输就快,这个容易理解。
' A& d# i2 f* s) t' k/ @4 c' X缺点:线这么多,那成本也会高嘛,别人一根线搞定了,你用了8根是吧。然后距离长了,那也容易受到干扰。
7 K2 Z+ B( w+ b% ^1 \- \+ _- h: L" t* K) ~; Q# K8 Q9 j" T
通信方式
& f3 V# w. L& t6 o4 w: ?$ T全双工

8 u) d4 [, n( F5 I) E- |就是双方都可以同时发送和接收,相当于我们的打电话。" i" K0 T/ A' ]5 a- G2 g  E

3 `' t, x; a8 X- n半双工
: j# b7 C9 b$ [# a9 X8 s2 S在同一时刻,只能一个发送、一个接收,相当于我们的对讲机。
9 h- ~0 L/ b, o" O# X+ r* f* ]2 C; N8 o) X6 L1 H$ J' S; W; f$ C
单工" q: P+ k" b( x4 l0 {9 `
这个就是一个只能发,一个只能收。相当于广播,他那边只能发,我们只能听。
0 X8 o! I8 ^- M/ x
* z" v1 c' L7 O5 b波特率

6 z; I! @" M0 D- C- ^" W3 E首先讲一下比特率; o8 \, \/ e3 I: n6 n. O
比特率:每秒钟传输的二进制位数,单位是(bit/s)* w0 w; W6 K: z6 V- F# z
跟波特率有点区别的,但是有时候也一样。
9 v8 I1 h/ f& I! J$ w6 K" J6 o0 e- _5 |) r+ x
波特率:表示每秒钟传输的码元个数。
4 w. Z; x1 ?: r1 N  X8 }# q& _* v码元:比如我们玩51的时候基本都是5V OV那么 5V相当于二进制1 0V就相当于二进制0。2 q) Q/ p# B" t$ q% R) w$ `7 ~
5V——1
5 ?2 D' T7 E5 U) a- `8 X- U0V——08 Q. a. @7 k# q$ Y0 A7 V" {

, k$ \; t( a* D7 L6 r: ^有时候多个,比如7 b7 B) j2 J2 T0 }1 y9 ^
0V——00
4 t2 K& C( N) f  T/ L2V——01
; m! ?+ s. s8 l5 |4V——10- A) L. v$ r/ C& Q6 o- s
6V——116 h, P7 X- ^% d4 C6 I$ v
这样就跟比特率不一样了。8 u2 M3 [( C7 y' s6 Y
6 X9 q: b; c; P; I
波特率计算5 U; @* R* O, N4 p
波特率 = Fck/(16*USARTDIV)
4 k2 A3 j$ t; K& e8 |Fck:串口的时钟  P% g6 W% c' J- V+ Q8 x( {  W
USARTDIV:无符号定点数
% \8 V; X. s$ v7 U" s/ S
" M0 B" f' f% Z8 u5 c比如我想设置115200波特率- s# U8 _7 @1 J* ~$ ]4 ]
时钟是72M. |0 X! y9 q1 b! W  l0 x4 W* x8 l
那USARTDIV = 39.0625
* t; L! w. m9 E& q, B# p, {
/ j/ O# L3 G% t& ^  P 8d4b8aa2c29a4ddcb6d77f8fab730a9d.png " I+ ]; h* e- y
) Z: h0 j' f4 u/ [. J3 b
串口的配置
1 ?/ ~. i8 ?3 y代码编写步骤
: f4 S/ O  O$ \) D+ N$ ^1 ?" [
我这里用USART1来举例。我这里是A9(TX)、A10(RX)(异步通信)
: w' E. r$ E. Z$ `1:打开对应 的时钟
. C. d* a9 n  _7 ~% k* j( H1.1:GPIO的时钟
7 k  {4 _7 n, N3 R1 s( Z! J1.2:串口的时钟
: U8 m9 P- p: z. ~3 f7 W, f  W4 \# A* n/ X) l7 o2 x
2.配置GPIO结构体
+ p6 ]0 f; Y( \7 [2.1:引脚2 R1 o1 U. l( S
2.2:模式(输入还是输出)0 o2 Q+ G2 ^5 N
2.3:速率(输出才用 输入不用)
% h- F0 N6 A5 L/ `2 J: v( Q2.4:对结构体成员初始化. s. ?+ G2 z- L3 Z1 n

! S6 b: @) D% i3配置串口结构体; B1 L& A" q- }: s! ^, a
3.1:波特率
$ U8 P( y5 q( w! n" B* q3.2:有效数据位4 j+ G6 }0 w. B
3.3:停止位
0 k2 B9 `5 e6 q& T& S! k) c6 u" S1 q3.4:奇偶校验位. M/ k3 \9 m, Y) C' v; I, U
3.5:硬件控制流' m0 C' k0 o+ e8 o
3.6:模式
+ l, \' y" e) R  C3.7:对结构体成员初始化' ~4 G& s& V& B8 j' v

# _1 W: D' _9 `/ G4配置NVIC中断优先级(misc.h)- p" a* O* h2 C& _
如果不需要中断可以不配置NVIC; a$ I$ W* Z+ ^/ Q9 A5 t5 R$ ?6 F/ A
4.1:选择哪个组 NVIC_PriorityGroupConfig) \) X' J# r3 \& U7 ^
4.2::哪个中断通道 (stm32f10x.h里 IRQn_Type结构体里找)) d6 V3 v! ?2 P0 `7 ~7 E
4.3:主优先级
: H& Q. s$ \7 t+ N# u7 K4.4:次优先级  x  a9 R$ c/ c# ]# H+ H+ {
4.5:通道使能开启
5 ~# D# H+ Q- o3 A4.6:对成员初始化( B, v) `3 T! m7 ~2 y6 R# o
4.7:串口中断配置 USART_ITConfig(采用什么方式中断)5 A; r% N3 Z5 b
8 B  }# I8 @0 ^* b/ U) [$ X
5串口使能
+ n6 A8 q5 y  [3 h( LUSART_Cmd();+ ^$ j$ I) t' V) ~

$ x" t9 e  U& P0 }7 z6:编写中断服务函数( t  R  o7 c) |. y: x( i+ ?0 G+ i
函数名字在启动文件里找。
+ X! L4 z6 @1 y$ b- s6 P& j9 C% I' R4 Z  {( @. A+ ~/ _
串口的重定向
/ j7 X: ]4 H+ L; a比如我们常用输出函数
6 I6 o2 u( }7 K8 q0 pprintf();
4 D- g  B: Q) o1 Mputchar();# C1 @4 ~4 }1 O
常用的输入函数' t  ?/ P3 ^) b: E
scanf();
' k* z& k- b# \9 @getchar();. K; A2 A+ l5 q. w  ~

% I( \1 Z7 l, M2 w- G4 ^9 m3 ~0 i输出
$ D4 f  `6 ]- D  T- t6 r% z. S/ }==记得包含头文件 stdio.h ==4 A9 J7 C& w# c  R
其次你添加下面的函数既可以用printf 和 putchar了。
  1. /*重定向C库函数printf到串口*/' m+ r5 I! W8 a2 J4 [
  2. int fputc(int ch, FILE *f)# L  U8 W: }8 F. P! a8 ^
  3. {
    , j: d1 i) ^6 I2 b8 d
  4.         USART_SendData(USART1, (uint8_t)ch);; //发送一字节到串口' |$ W- }$ f8 I  E0 u) ?/ ~
  5.         while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); //等待发送寄存器为空 证明发送完, A) X# I3 j1 L# s- W9 |
  6.         
    : ]3 k4 O) {: J/ V  Y- k4 h
  7.         return ch;
    , @; p8 v  K% s- O4 ?
  8. }
复制代码
3 J" G6 b% }$ g( N# m( a
输入$ Y/ B% M# J" h8 z( K6 N
==记得包含头文件 stdio.h ==& {1 ]* g# a  s
其次你添加下面的函数既可以用scanf 和 getchar了。
' v9 r1 f1 {* e7 L9 x7 d' h3 L1 A% P: ~3 O8 c
  1. /*重定向C库函数 scanf到串口*/
    7 Z, t2 X# R4 m
  2. int fgetc(FILE *f)
    3 Y& K; e5 A! j, `2 p# I- l/ ^! l
  3. {8 P" L. {% S& h: \9 J
  4.         while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET); //如果读数据寄存器非空" M- c) V6 ?8 X$ q/ R5 z0 m0 v; d6 Q
  5.         return (int)USART_ReceiveData(USART1);5 v/ ~6 s9 Z# K& e1 }' l* e  v
  6. }
复制代码

! _5 G' v) `, M5 Q, f串口的例程
7 G4 t( p  V( }# ?/ ~
我这里就实现一下 电脑端串口助手发送单字符到单片机,单片机接收到就立刻也发给电脑串口助手。
3 r, G3 s) W6 R. l" |比如 我在串口助手发送了 A$ D' |6 U3 Q3 U2 ]1 W7 r
然后单片机接收到之后,让单片机发送receive data:A- P" @- l8 y! p) m3 S4 C9 _% d+ [
3 }& n. x' ]0 u# t2 J2 y
main.c7 _0 |6 r9 `6 `2 r/ h, q
  1. #include "stm32f10x.h"
    ' s* P; L$ o' h4 l; d) c
  2. #include "usart.h"
    7 N; ?3 C" y& i9 i( X$ J

  3. 5 u8 F4 F1 ?' D, _9 h& T
  4. int main()3 E' q# [' I. g
  5. {
    7 w7 b+ u. A; t
  6.         usart1_init(115200); //串口1初始化函数6 y3 [" S4 E" p% U2 X2 M, w3 |) L, T
  7.         while(1)
    ! d! Q0 S% [% ~8 A( C3 D
  8.         {
    ' x9 S1 k3 }  L( c1 }
  9.         }
    $ M' F7 Q2 p* d/ F7 a  W, @% ?2 f
  10. }) k2 r$ _5 _1 `! o7 O' U
  11. . R) Z2 a& N# Z3 @# Q& C4 O
  12. /*因为用的是中断接收所以少不了中断服务函数*/
    6 G; J& _& A- }3 D( w
  13. /*串口1 中断服务函数*/
    ; K; Z" A& a$ t' D" ?! \
  14. void USART1_IRQHandler(void)
    % e; C3 w+ K- g) a$ k) e
  15. {
    6 _5 ~  j" F+ V0 |# c! k3 }
  16.         uint8_t data;
    , p" f! D) z) J1 S' }5 Z1 l, w
  17.         if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //再次判断是否中断是否发生
    ; X7 @" K/ l7 {' Z9 z$ S
  18.         {0 e! p) f/ G9 C( i( n8 `
  19.                 data = USART_ReceiveData(USART1);8 Z) F- J( d/ e2 K$ V. R
  20.         }3 m. h7 S( H. S7 z
  21.         usart_sendString(USART1,"receive data:");
    / p  H) U3 l/ S; h( C& C
  22.         usart_sendByte(USART1,data);
    ' i$ o8 M# T# L0 f) z! Q6 l5 I
  23.         usart_sendByte(USART1,'\n');
    0 V1 j/ \, V- m, q8 j
  24. }
复制代码

6 G9 q' Q) D5 @  Musart.c
# I. p2 Q' r2 ^+ Y- o
  1. /* 配置串口1 优先级 函数 */
    ) u$ ?. p9 w0 A1 v6 r5 Z
  2. static void NVIC_USART1_configuration(void)1 k7 I# X: v$ C/ d3 q
  3. {' P% b# a/ B3 z
  4.         NVIC_InitTypeDef NVIC_initStruction;
    6 w) m1 b# q3 P3 S. U
  5.         
      _+ {5 @' j; y) E$ N
  6.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);                                //组. {! @3 I& R6 \
  7.         NVIC_initStruction.NVIC_IRQChannel = USART1_IRQn;                        //串口1中断
    ) r; S1 z6 j/ x& D3 R/ v
  8.         NVIC_initStruction.NVIC_IRQChannelPreemptionPriority = 0;   //主优先级: I! N: l# D5 q: B5 Y4 Q
  9.         NVIC_initStruction.NVIC_IRQChannelSubPriority = 0;                        //次优先级3 P/ r$ _& y0 ]+ u4 u3 N2 V
  10.         NVIC_initStruction.NVIC_IRQChannelCmd = ENABLE;                                //使能
    4 B. D6 o. G& E: s$ V9 V
  11.         NVIC_Init(&NVIC_initStruction);
    : ~+ d, B  s! D: }3 U  `0 J
  12. }4 Y+ Q9 a6 e* \) B2 r

  13. 2 y9 E- s4 r! l0 p: L
  14. /* 配置串口1 函数*/5 n' k& C5 E5 g% M  y
  15. void usart1_init(uint32_t baudRate)/ \5 M: t9 Z, k9 P' p
  16. {3 W; N6 ]8 E3 w! Q9 O" c
  17.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);        //打开GPIOA时钟+ d" U) O% E& i! A7 B3 K$ U, y
  18.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);        //打开串口1时钟
    ! a+ z$ O* Q" u+ [5 Y; ]0 e
  19.         4 t1 [! U! L. H1 ^
  20.         GPIO_InitTypeDef GPIO_initStruction;- x5 s$ ?% T6 t/ C
  21.         USART_InitTypeDef USART_initStruction;
    ' ?; \' s# [+ U2 h) s

  22. ( n  A, ^9 u) |3 d
  23.         /*配置GPIOA  TX */- ^( m: P, Q# N  |
  24.         GPIO_initStruction.GPIO_Pin = USART1_TX;                 // TX
    9 a& m; j8 p% A# s% h" p( f
  25.         GPIO_initStruction.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
    " [( ^" P# ^- l+ E) ?+ P6 m
  26.         GPIO_initStruction.GPIO_Speed = GPIO_Speed_50MHz;# }' ~1 t& g4 H+ k  x0 M
  27.         GPIO_Init(GPIOA, &GPIO_initStruction);) v) v& O" H  I+ P" `' g
  28.         
    & ?$ J* ^0 l. n. t
  29.         /*配置GPIOA RX */
    % u1 A8 d3 ]1 G8 Y7 j! b
  30.         GPIO_initStruction.GPIO_Pin = USART1_RX;                 // RX
    : `5 n" G8 A( T, t) z  N1 C! i) j
  31.         GPIO_initStruction.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入+ S! c+ Q( ?) [3 W" i
  32.         GPIO_Init(GPIOA, &GPIO_initStruction);, ]+ _: B6 H3 B6 {4 ~
  33.         
    7 X3 a6 R1 J: ]& A* ]
  34.         /*配置USART1 TX和RX */
    ( L; K& z; x" `$ S, L5 U$ B, O
  35.         USART_initStruction.USART_BaudRate = baudRate;        //波特率% u: W0 U9 o6 u7 i
  36.         USART_initStruction.USART_WordLength = USART_WordLength_8b; //8位有效数据位/ I- P4 K+ @& |0 o
  37.         USART_initStruction.USART_StopBits = USART_StopBits_1;        //1个停止位# k% a, B5 ~5 k& _0 x7 G8 w( K
  38.         USART_initStruction.USART_Parity = USART_Parity_No;                //无奇偶校验位/ u3 v) p$ I  a; I9 W" x: L
  39.         USART_initStruction.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //不硬件控制流. I9 W. k. t( ?. i7 t6 C
  40.         USART_initStruction.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; //发送 和 接收. b. J, _' Z0 R4 ~0 C
  41.         USART_Init(USART1, &USART_initStruction);
      e- O$ A7 b) I5 c' `" E
  42.         ! ^. J' u; _& D; t9 _; A7 o
  43.         NVIC_USART1_configuration();        //串口1中断优先级配置/ ?7 V  g; I- c/ p5 C: Q
  44.         USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//使能接收中断" f' f. v. K# p  ~, }4 r: q0 T- _
  45.         USART_Cmd(USART1, ENABLE); //使能串口14 U" w$ E) R' ?# \( g
  46. }1 |5 u6 |; k- P) s" D* [
复制代码
) C! v+ H: {3 I5 ^: n
效果呈现+ j7 B3 @) D5 c1 C- [5 v/ x

( o) c* |1 P2 Q) K; o& A* M 2c8b827b72dd4d238ff4f828b95f436e.png
. g0 d$ Y" n0 y9 k0 a( q4 h) V/ ^————————————————
* E5 c5 N  x! M/ B$ j$ |转载:皮卡丘吉尔- i, C: e9 _2 M; ?5 I
& \: ?8 y5 K6 M' E# H4 t1 Q

! I  D1 o7 {! e1 M3 q3 s; X1 j* [
2 M4 |9 B; F3 V) M7 Q6 s. Q
赞 收藏 评论0 发布时间:2022-8-22 17:40

举报

0个回答

所属标签

相似技术帖

官网相关资源

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