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

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

[复制链接]
STMCU小助手 发布时间:2022-8-22 17:40
最近能抽点时间学一下stm32了,串口通信用的挺多的,比如wifi模块,GSM模块,指纹模块等等…在这里用自己理解的写一下总结,如果有误的话请大家多多指点。
1 C/ j! Z* J  R* t& W串口的基本概念
  ?" M0 ]( Y7 @& h串行和并行) T% N5 X# v+ V  a
串行

& @! v' ?( P2 c. Z/ f( f1 R% ?串行是一位一位的传输。
' D6 K2 X! Y: _" L常用的有 USART、IIC、SPI等…
+ U1 H* s* i% v. z串行也分为 同步通信 和 异步通信
, |1 l- R. q0 t8 E! n: o) F) I同步:
3 f1 z# ?' B9 {8 B3 N就是一般有一根时钟线,有时钟就可以大家一起同步嘛。靠时钟来约定。一根数据线。一般一个时钟传输一个Bit位。同步的话 他们大部分都是有效数据来的。但是对于双方的时钟允许误差较小。
( _* m3 d6 b6 ?; _9 u% J* s& ]4 e% H! k: x. @8 L
异步:" M3 F  V- V5 Z5 p* H
异步就是我们平常玩串口用的最多的,它不像同步有个时钟,异步是没有时钟,那我们得为了数据不出错,所以通过 起始位、奇偶校验位、停止位这些来降低数据的错误。4 y" I0 C+ ]" A: R3 k1 k( E! E
所以异步的有效数据就没有同步的有效数据那么多。效率也没有同步的那么高。
: t) R  ^7 }6 X$ n; B" B5 C
& @1 S" `, F' x* K2 e! p优点:传输距离远、抗干扰能力强、成本较低
3 ?' ^3 F" m# t缺点:传输速率慢: v2 I* T3 ?' {  g( ?

, R' k# Q0 x; l& J" k并行
; \( T  I5 l; m5 n) B并行是指多比特数据同时通过并行线进行传送,这样数据传送速度大大提高。
' [2 H( O; Z9 u- Y4 K1 y  ]  B简单的理解就是 比如我们用的LCD1602不是有一共10几个引脚么,然后8根是数据线,这就是属于并行,它们通常需要数据总线(八、十六或更多线路)。! X) P/ |; l- E% ~- n7 v
. Q' z! W- }9 ?" G' s2 P( M
优点:线比较多嘛,所以我传输就快,这个容易理解。
/ H4 D1 U" d; @缺点:线这么多,那成本也会高嘛,别人一根线搞定了,你用了8根是吧。然后距离长了,那也容易受到干扰。* x* \, B( t) P

) V' w3 H, h: h: _  C7 T3 H
通信方式5 R# {) f# s0 J' ~5 v; j  S# F
全双工
9 `* f  C$ D+ j! S' e; B& _
就是双方都可以同时发送和接收,相当于我们的打电话。6 |+ ]9 h$ V; w9 ]2 A

! o4 n" b" x9 h0 r半双工
$ x6 w! `+ s! a; M- r3 k8 v在同一时刻,只能一个发送、一个接收,相当于我们的对讲机。9 E+ {8 u- D$ p
7 t+ l4 H. x/ h# k! q3 h$ I- K/ w8 I
单工3 E" A1 U2 s+ V1 t2 c+ n6 t6 d0 W
这个就是一个只能发,一个只能收。相当于广播,他那边只能发,我们只能听。- @  Q. `" G, h* l4 }1 [# z
9 P8 K8 i1 ~  L. [7 `5 H0 z. U6 P
波特率
( H! d* k# h% u5 @% W+ }8 H" r
首先讲一下比特率/ [  j/ s6 S, _3 Z" P" R
比特率:每秒钟传输的二进制位数,单位是(bit/s)& C# S8 B3 e- m: i
跟波特率有点区别的,但是有时候也一样。; S4 ?! _9 B) E+ U2 c0 @

8 S& {6 c7 p& t7 R波特率:表示每秒钟传输的码元个数。  ^9 r* j7 A2 y5 M, {8 i
码元:比如我们玩51的时候基本都是5V OV那么 5V相当于二进制1 0V就相当于二进制0。
1 r0 c' ?* F  R3 {" N" Z5V——1
% Z+ [$ h* O$ t$ q0V——0# U7 E: j( d9 x

& D; F$ [3 R, [% l- H有时候多个,比如: R! t) I/ H, @: T
0V——00" p/ G/ V# f. N/ v
2V——01
  W+ [9 N- _& M! D+ f: n* @& G% M" @4V——10
9 M8 w3 i6 o( K) U: S$ ^! I9 n+ Y6V——11  S; a. R: I" F7 g& k% `* E9 b* X! n
这样就跟比特率不一样了。! D& E: F" q9 }) B/ S1 t" F

- N6 \0 W! M4 U2 G4 V, U3 z波特率计算
7 R7 a2 Y. p" n( b, E0 A, |2 `* o波特率 = Fck/(16*USARTDIV)4 }& M0 s- b# D& `$ I5 d- c
Fck:串口的时钟
+ L) Z6 L$ L- X* ^( ~+ jUSARTDIV:无符号定点数2 m$ I, j0 c# N
/ V$ {$ L/ s7 O$ s# s$ `+ S
比如我想设置115200波特率8 B: i9 q) H) q7 W" ]+ N
时钟是72M, M$ a, F& E$ c) z' Q
那USARTDIV = 39.06251 ~- Z' e; J4 J5 y; s
; U, h3 c  r! }& I; {8 ^7 S
8d4b8aa2c29a4ddcb6d77f8fab730a9d.png
7 h$ c3 |* I: T
' I' A6 D' B- P  I2 K0 B
串口的配置
7 k& |# v2 x( I, F4 Y1 w/ `3 _. t代码编写步骤
" X( m- u3 @( q, |) l  V# {3 v
我这里用USART1来举例。我这里是A9(TX)、A10(RX)(异步通信). ^6 a( M4 a+ J
1:打开对应 的时钟9 L; s& ^8 }  z) y3 s: o- M; I
1.1:GPIO的时钟
: G7 ^! w3 u! @* t1.2:串口的时钟+ d2 J4 M- r- Z- u- L- D

; y- {, @, \, j- ]2.配置GPIO结构体+ z( K  L* P2 r
2.1:引脚
, K! T7 [  k$ V/ f( B5 \8 g2.2:模式(输入还是输出)
! o* P) H/ g( d  r2.3:速率(输出才用 输入不用)
, ]6 V9 U, ^2 {! p) [# C* E9 W2.4:对结构体成员初始化& u2 W8 D# l0 g/ V% |* C. h
* H3 m! q; _0 d6 V( R5 l# L0 w: C
3配置串口结构体/ u% L1 s0 c/ f
3.1:波特率" A+ W* q) t+ \7 Y2 C
3.2:有效数据位
- A) C" M# o8 w% _6 o! J' j% N. K4 f3.3:停止位6 w" O( b: N( K* a
3.4:奇偶校验位
3 s8 Z: G. \6 B( `3.5:硬件控制流
1 N# G7 r, L% m8 Z- V3.6:模式
/ N5 W8 I1 I2 z( L! D. r8 L3.7:对结构体成员初始化& m+ }5 W. i8 r2 r
4 |, d& @( u: V
4配置NVIC中断优先级(misc.h)
- e% i: p3 ]) {' z/ E如果不需要中断可以不配置NVIC
. {* [" m2 X' ~: `% z4.1:选择哪个组 NVIC_PriorityGroupConfig
; i+ h0 [. t: I" f3 i, V4 K5 T4.2::哪个中断通道 (stm32f10x.h里 IRQn_Type结构体里找)$ {" X( p2 J8 l3 v! U. _
4.3:主优先级6 X5 R9 f0 s* O$ T4 |8 ^+ Q  u
4.4:次优先级
/ M  F6 a+ W6 D2 [4.5:通道使能开启/ H7 L! A7 Z3 P+ p, G6 F9 [& _
4.6:对成员初始化
* W1 u2 `3 `% i# F3 Y* X6 c4.7:串口中断配置 USART_ITConfig(采用什么方式中断)
* B9 Y8 B: ?. {; k' g# i, d
3 j/ b3 `0 \. h% H5串口使能/ l1 b, M9 w+ G* q% G/ H' n
USART_Cmd();
7 j3 t5 U1 L. Q: z# G" a7 @) j
: p: ]. _$ i. M! A6:编写中断服务函数
* K; R6 i/ }: i/ e函数名字在启动文件里找。
3 N8 k% |7 p0 e7 o/ b. \( w& C8 r8 g1 a" Y9 ~7 a
串口的重定向# |5 O! [7 O  ^0 x
比如我们常用输出函数0 }3 o6 B8 b  b+ v/ h
printf();
7 t3 L# `; g1 c3 bputchar();$ }9 ]; t$ X1 P2 Y
常用的输入函数
9 X8 ]* Y9 A, ?) e9 Q) h) fscanf();1 h# {" |0 [: j! y9 R
getchar();# v& Y; K. `+ f3 H% H  m
5 e" L# L3 y: h. J! G
输出( `7 p, e* I4 w0 i
==记得包含头文件 stdio.h ==/ W6 e) M- o; x$ g
其次你添加下面的函数既可以用printf 和 putchar了。
  1. /*重定向C库函数printf到串口*/" d3 F. \9 [8 ^  m
  2. int fputc(int ch, FILE *f)" U- z9 o+ z% B, b1 R% M
  3. {
    1 n. v8 ~7 T6 a# E
  4.         USART_SendData(USART1, (uint8_t)ch);; //发送一字节到串口& }: w! W3 j/ F; J1 D) P
  5.         while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); //等待发送寄存器为空 证明发送完8 `6 u0 O4 }  q! I0 I  K: r
  6.         - ^4 _% ]8 w* I8 g5 d
  7.         return ch;7 Y. i' ^' k9 T( S! l
  8. }
复制代码
9 G- `* ^& T" {6 s; p+ |9 b5 M7 e, f$ Z" A
输入7 b; n! F  K6 U% g' x% U5 Y& h
==记得包含头文件 stdio.h ==
# O. W3 Z( v. F* P$ m其次你添加下面的函数既可以用scanf 和 getchar了。+ T) Q# C4 W3 {  m/ S. {

' Y# l, Q) \) f2 P) K" o
  1. /*重定向C库函数 scanf到串口*/
    ; @! C9 ^/ V8 S
  2. int fgetc(FILE *f)
    ! g3 g) u( F2 m3 A- l9 T: E. v
  3. {% E. }4 Q& T7 \3 E: d& a& O
  4.         while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET); //如果读数据寄存器非空
    8 P4 h* B) j6 ^
  5.         return (int)USART_ReceiveData(USART1);# l& Z! E. D7 }7 W5 w* X
  6. }
复制代码

( Z3 {: ^, V) \6 f' b+ g串口的例程

# e. ?0 X' B( n" I# I我这里就实现一下 电脑端串口助手发送单字符到单片机,单片机接收到就立刻也发给电脑串口助手。
' d7 |+ T. {$ Z0 Q" t9 l比如 我在串口助手发送了 A
5 r6 o0 e% I, }8 e+ b$ J然后单片机接收到之后,让单片机发送receive data:A2 Z' h' b9 c6 q# J8 \+ [

: b2 g4 f' W; w. ^" ?& d4 t; jmain.c
5 ~* y9 d. S; o7 H$ o
  1. #include "stm32f10x.h"
    $ p* X  I9 j: O3 k3 ^6 p
  2. #include "usart.h"
    0 M6 V5 \0 L8 z6 j" {

  3. ) ~" \* s  N: F' B2 }! k5 T
  4. int main()
    ; N6 `) V) V: u3 {. ?" [# P
  5. {/ K; L) N& l2 v- R
  6.         usart1_init(115200); //串口1初始化函数
    0 I8 M9 N- T1 v2 o, F
  7.         while(1)1 p& R# H: C6 M! w! U. J4 a3 k
  8.         {' s/ Q+ t% @% u- T& g, p! w
  9.         }- ], K, T8 W* M5 O/ I0 q0 [
  10. }
    . t% s; f: |. D4 P
  11. ) w  N' W( x# b6 X8 g% g, @
  12. /*因为用的是中断接收所以少不了中断服务函数*/) p1 I1 j) F& ]! @
  13. /*串口1 中断服务函数*/; b! i  d+ c  A* i( e! W3 f" x
  14. void USART1_IRQHandler(void)4 P2 K" `9 q2 a- f
  15. {4 W8 P7 _+ W4 h$ b# T. b6 ?0 |
  16.         uint8_t data;
    " i( W: m* O4 @
  17.         if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //再次判断是否中断是否发生1 @, Q: w3 D6 ?3 t6 B( s% c6 u  T
  18.         {
    ! U( e' X; Q- v, G5 L0 T- N
  19.                 data = USART_ReceiveData(USART1);; u" d& R. ]& e% C; m7 D
  20.         }" q' U& y: o0 n& F& b. Z
  21.         usart_sendString(USART1,"receive data:");. E; H- a* D0 {+ G, g5 E  D
  22.         usart_sendByte(USART1,data);
    " W, w$ ?, l$ T- a7 O" a. b
  23.         usart_sendByte(USART1,'\n');
    ! ~" U' ]3 s2 j% F4 c: C
  24. }
复制代码
' H8 @' Y$ v& r& O! v
usart.c$ {( o1 {/ W6 ^6 S. s/ K: p
  1. /* 配置串口1 优先级 函数 */
    5 U3 V' D$ p% @7 n7 R
  2. static void NVIC_USART1_configuration(void)) r/ B/ |( o' r1 t
  3. {
      O7 k1 v4 D+ y7 n4 {4 T' g
  4.         NVIC_InitTypeDef NVIC_initStruction;% w3 L1 R2 |- y6 I; a9 k
  5.         
    2 y6 r4 j% y& g. s$ ]8 Q3 s
  6.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);                                //组7 @4 R% j/ ^: {4 x1 l& I
  7.         NVIC_initStruction.NVIC_IRQChannel = USART1_IRQn;                        //串口1中断/ Z" R3 m0 ^, y
  8.         NVIC_initStruction.NVIC_IRQChannelPreemptionPriority = 0;   //主优先级
    8 g' D+ Y* W6 C4 T8 H
  9.         NVIC_initStruction.NVIC_IRQChannelSubPriority = 0;                        //次优先级
    0 H/ F- H1 e3 M! j7 R6 k+ Y" I
  10.         NVIC_initStruction.NVIC_IRQChannelCmd = ENABLE;                                //使能
    % |# A0 M2 i5 {- o
  11.         NVIC_Init(&NVIC_initStruction);
    " B! k$ ?" ]' P" u* M. B
  12. }0 e8 {6 X! T8 {
  13. ! a8 {, p& T/ @& r$ h
  14. /* 配置串口1 函数*/; x- T9 j9 R" W! ^+ Z; Y& v# m
  15. void usart1_init(uint32_t baudRate)  o) Y7 {% k+ q2 q0 }
  16. {
    + Y7 q6 _& U+ B& ?
  17.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);        //打开GPIOA时钟
    / ?1 E; v+ A0 k# A9 ^. c: @
  18.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);        //打开串口1时钟
    4 V6 r# Q* J9 @/ ]9 b+ N4 v7 K
  19.         * H: S! u" n% o6 _4 X0 w
  20.         GPIO_InitTypeDef GPIO_initStruction;  X2 |& F% |/ @/ r" P$ w7 e3 G# U
  21.         USART_InitTypeDef USART_initStruction;
    ! l! D, k. W1 C+ G) F7 @# J
  22. + {1 L! q8 |+ k+ x1 h
  23.         /*配置GPIOA  TX */% D3 b5 z: b, Y8 v8 \8 z
  24.         GPIO_initStruction.GPIO_Pin = USART1_TX;                 // TX
    . w& G& }% K/ D) l
  25.         GPIO_initStruction.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
    : X4 R- @- D) @" ?; L! w# U+ e
  26.         GPIO_initStruction.GPIO_Speed = GPIO_Speed_50MHz;
    ; q' P# K$ h4 H0 j- u
  27.         GPIO_Init(GPIOA, &GPIO_initStruction);
    % G6 ?( G  D# x: n( W7 S8 I# s% b+ o, M
  28.         ; {* x  T2 ?* U# I
  29.         /*配置GPIOA RX */
    0 p5 t. e" B( L9 V( s
  30.         GPIO_initStruction.GPIO_Pin = USART1_RX;                 // RX6 X4 b6 U; u" J* \$ [
  31.         GPIO_initStruction.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入) b9 y" ^1 \; h7 L) t' U
  32.         GPIO_Init(GPIOA, &GPIO_initStruction);
    3 A% `- Y+ ?8 w; q. f2 S
  33.         % b' S/ S, X& r+ S( X7 B
  34.         /*配置USART1 TX和RX */
    % b$ M/ h% ?$ C0 x
  35.         USART_initStruction.USART_BaudRate = baudRate;        //波特率
      H( ^# W& `( H" k/ L. \
  36.         USART_initStruction.USART_WordLength = USART_WordLength_8b; //8位有效数据位) z$ }7 O( ^: I* I* `6 u- ]
  37.         USART_initStruction.USART_StopBits = USART_StopBits_1;        //1个停止位" L' o: C0 \* ]
  38.         USART_initStruction.USART_Parity = USART_Parity_No;                //无奇偶校验位+ f3 s. k5 L& \9 [# Q
  39.         USART_initStruction.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //不硬件控制流% [- I6 |5 S. {. v0 i
  40.         USART_initStruction.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; //发送 和 接收6 O& x$ \9 N: k! Q+ V" G; n& k& i  Z
  41.         USART_Init(USART1, &USART_initStruction);
    : H2 N( H: ], g' Z- ^
  42.         7 y9 |; ]6 P9 O' s* Z  I6 S2 B/ {: V
  43.         NVIC_USART1_configuration();        //串口1中断优先级配置
    5 y% r( h" y; }# ?, a  [
  44.         USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//使能接收中断
    8 I# }/ a1 b# r7 v/ i
  45.         USART_Cmd(USART1, ENABLE); //使能串口1
    1 U, l; Q4 r7 j2 R
  46. }+ r9 C3 u" p, _; c6 Z8 |# F
复制代码

8 `; j! j( `( ]$ k1 v效果呈现
7 J3 q6 ^+ o6 \2 b
  C7 Y: g8 d& ~. z0 A 2c8b827b72dd4d238ff4f828b95f436e.png
. K; d* ]  e* W$ _————————————————
; A4 }6 w$ n& }: ~7 J0 u转载:皮卡丘吉尔
/ B, Y, R# z$ a1 y
  }% h$ c- ]. }+ J& v; _
( M: x0 n4 j& J' L8 o2 N* ^' g5 x. V0 |+ j, L
收藏 评论0 发布时间:2022-8-22 17:40

举报

0个回答

所属标签

相似分享

官网相关资源

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