刚开始学单片机的你,是不是会因用程序把LED点亮而感到高兴,会因用程序把数码管点亮而感到高兴。这是好事,这也是想继续学习下去的动力。; P8 ?; w8 b. j9 z
# e5 p8 O4 @! G2 Y( ^. E3 O" J% t$ M( B* D% V
但是数据相关的实验是学习单片机和STM32的一道坎,此时就需要用好本文要说的串口这个调试工具。" c' J: z" h8 e/ K- p6 [& H
! I# }* g' T% G, V" `
; E. f& R/ k1 e5 d9 Y- a串口通信介绍: ]. t& |& d9 _ j9 c
5 n9 U, m/ v* C5 l i6 n8 y1 P( r& t E; k1 ^9 B; @
关于串口通信的介绍,也可以点击阅读之前发的一篇文章: STM32串口通信基本原理1 c' ?- R' C' ?6 Y- Y9 z
. e7 ^1 r8 |1 ?6 |2 X+ a O: A% L2 a1 Y" T$ ~+ F; e
串口通信是指外设和计算机间,通过数据信号线 、地线、控制线等,按位进行传输数据的一种通讯方式......这种太过理论了,看似懂了,但又不懂。还是用我笔者自己的话来说吧。
; J/ q- R' [2 \
; _' |. t# w4 @' L2 Z$ ?8 c2 e0 n# Y! ~7 l
串口通信就是可以把程序在单片机或者STM32芯片中运行的结果发送到电脑的一种通信方式。) L4 M V j5 _) B3 |" @
7 K/ N8 j }: M/ [% J1 P' B) J$ x
" u; D2 @5 }! ]/ [2 [2 `' v" {; W# A' D- A* L0 J; z; K; B/ ^" P
% t6 K9 n' |1 n0 B: N) r+ Q
5 b( b% `9 q7 ^4 [" K
' r# Q5 G+ z: O3 L k. j/ k4 L T5 Q3 D- @6 x+ m
# f: H% K5 r* }/ n9 h/ a( }) s
如何使用串口通讯,你需要知道的几个重要的知识点:
6 r/ R* o7 h3 l6 S+ ?
# w; k- E% G* A# a; I0 m+ h4 C' A4 r7 I, ~9 H
- 波特率,数据传输的速度,如上图设置为9600,那么程序中也要设置为9600
- 硬件连接,接收、发送交叉连接,如上图TxD->RxD,RxD->TxD
- 停止位
- 奇偶校验
- 硬件数据流
' E! h/ w! b5 S 8 z I2 y4 \! S; G
0 u; Z! {% \; g0 T7 u3 t- c. Y1 h; ?, p- n1 l* x; y$ d
其中,后3项一般不需要改变。1 W2 u: {, H: L- s+ Y& c
% @1 e3 W% G/ e& }, w0 b/ K6 O% Z O
学会串口通信能做什么9 x; Z: T$ i# ]
' ~- x8 J. M( i; m9 v0 Y
4 ~4 r6 i9 N& A( d 学过C语言的人都知道,程序开发需要不断调试不断验证。很多的语言编程软件都有很完整的程序调试功能。使用起来很方便。而我们的开发虽然也是用C语言,但我们的程序最终运行的环境不是在我们的开平台而是在真正的硬件系统中运行。这时想要查看程序的运行过程或者结果就不像编程软件那么方便了。
) \* @* Z. p5 p! m+ |) _9 w" V8 N$ Z( R/ V1 q& }" U
7 r3 u: A9 H# x- B+ _ u6 _
想要解决这个问题,我们这时就可以借助串口通信来把我们需要知道的结果又或者是程序运行的关键步骤发送到电脑上,我们就知道程序在硬件系统中运行是否出现问题。51单片机可以用串口来调试,STM32可以用串口来调试,Linux开发板也是使用串口来调试。) ?( E. {* Q, p2 i' B' G/ i
6 G; R/ T4 r0 B& U( S, z! t3 X7 h
{2 G- z; _( l% G; K
当你学会串口通信时,你可以开始玩WIFI模块、GSM模块、蓝牙模块、GPS模块、以及各种使用串口通信的传感器等等。有能力你还可以编写上位机软件通过串口通信来控制设备。1 M" ^: G2 i) E
" s1 q# i/ t; ]% a0 F/ T( v
5 t# E0 E2 N5 @2 M1 v. m
串口通信需要什么$ w% K( k! \, u0 ^7 o1 A
4 E& x& Q% Z* L& q6 m: w K$ y5 M# o% Y
如果你只有STM32核心板,那么你还需要一个串口转USB模块和一个串口数据接收软件还有几根杜邦线就可以了。2 ?7 f8 r# |5 C* Y3 d( c2 G8 Y/ n! V- V
& u2 a; a" Z( e# X% x; P* B. }6 L/ |
如果你的是比较完整的一款开发板的话,一般都已经带有串口转USB模块,这样使用起来就更简单了。聪明的你是不是发现还缺少了点什么,对。没错因为还缺少了最重要的程序。想要使用串口通信当然还需要写串口通信的程序。6 P5 o% w4 ~6 |6 B
9 h/ s9 p& B, j% }' A6 t, B- l9 ^$ W% U; z5 o2 j, }
下文就教你如何去用,而不是写。) r+ i& ~+ r% v( U: ]8 R: i& v
, y) {5 ~% C8 r; o
b5 f/ t" r& ^: i串口实验
, J) E. n, q5 ^9 H8 ?2 L) e
) H O5 A6 l9 W/ J4 ~8 {
$ r/ Q0 B# ]- t- n( E# t; x) \ 关于串口的实验,之前录过一个基于HAL库来实现的视频,可以点击查看。" K5 l) k9 H) B4 F; o3 q9 n
( m* b0 [6 K1 c4 r. z+ h: Q+ R0 k8 p0 u& _& ^
STM32打印数据到串口助手# {( g. z) L$ W5 \+ B
, w. y, o' @# S! d) l
8 o3 Y# E$ s+ P. e
而下文中的实验基于标准库实现的,与HAL相比思路是一样的。
) Z2 m F+ R+ W0 C, E
8 A3 s' Q4 h7 R h
4 J% }# }' w% R, J4 ] 在做一个实验时,最好把这个实验分割成几个关键的步骤,这样做的好处就是可以清晰的知道自己需要做什么,以及做完了哪些。还有哪些还没做。
3 t h$ e! x, n, Y$ q# p7 X( G K' U
9 x2 y3 \5 O- y1 }6 n 下面把串口实验分成几个关键的步骤:
' ~( s: q; s) x: r$ p1)串口通信使用到的GPIO引脚配置
2 Y! {7 U& v% A' B5 x S6 N" F STM32F103系列的芯片一般都有三个串口以上,用来调试使用的串口一般都是使用USART1。其他的串口配置都是一样的。
9 X6 Y4 L' R3 `) j3 V( L z' }, O) N9 M- D4 T+ q0 h
! O+ p$ c/ R" Z: w/ j 下面这段就是串口配置的程序:
$ a/ Q7 f4 w7 {+ l9 B$ P/ r( E# k- <font face="微软雅黑" size="3">GPIO_InitTypeDef GPIO_InitStructure;
; }; z( j% f* m9 n - : L* H& J. n- U( G" q
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟7 Y. C' |& z' h" a+ a& b
$ W+ v( b+ ]6 O4 s- //USART1_TX GPIOA.9) V- Z% K/ f/ I' H$ ]/ A/ E
- 7 T4 L6 s& C/ L0 A
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
7 t- @% f4 b2 C) z4 c5 t
+ y4 w0 V& v+ I6 n! z6 O3 e# K5 b0 P- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
4 ~7 Y" @/ g& Q8 s# w. z1 }1 `
: N% c: }( |7 @- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出: N4 p) n( c, `3 Z4 p7 b
. q# f8 S" H8 O( Y- GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIOA.9
* H. |, C: b+ s" b/ f - 3 N! k" e: C5 j. W* M
- //USART1_RX GPIOA.10初始化9 L; S# r7 [- k. L( @
9 S' j5 l- H) Z/ |8 P- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PA10
) G' |; F7 ^7 A5 M; e - 1 \2 f6 t# @$ t; u# o# R4 c6 b6 T
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
2 j" m6 S$ V5 G, k( X" D0 H3 V - - y' s1 ^1 O* J* F& f5 m
- GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIOA.10 </font>
复制代码 2 t5 y& d5 Y7 J7 K; z& F! Q
- y0 w( Z6 i. \+ i# o; K0 w 串口使用的的GPIO口是PA9和PA10,所以只需配置这两个IO口的输入输出模式就可以了。
$ e7 Z" p4 C, d' E) ?/ c
( s. b' \3 c4 Z. H) N" @
, A4 S4 _9 t+ Q" \2)串口主要参数设置(直接看程序)
+ f ~; R- J3 F5 o0 k; d$ q" o: j! Y2 `
( t- r2 E8 m/ M- <font face="微软雅黑" size="3">USART_InitTypeDef USART_InitStructure;* G6 r# v& f9 O% K! b8 K0 ~# ?# c; y
- ' q: m5 d- V* J( o
- //USART 初始化设置 K; l9 ]3 @# c; h* o8 f
- + \) M# t/ j4 V6 L8 z- M, v
- USART_InitStructure.USART_BaudRate = bound;" k H% x' A/ i! _% t: H& Z5 a
- ( W8 \# `7 e. [! |5 n5 L
- //串口波特率+ g/ E% P8 j* D/ L, u# Z6 n
3 }9 T h" _9 I- USART_InitStructure.USART_WordLength = USART_WordLength_8b;
# j9 @# V; b& q4 k; s+ m - 1 w+ [: y0 k9 p" l9 {
- //数据格式,8位
7 G2 o1 U0 J- a, o: U6 E) H) q
# B% R5 k. ] k' B; m( s- USART_InitStructure.USART_StopBits = USART_StopBits_1;
# p; J: d o4 c3 w( }$ W4 } - " B5 @. x( z# d9 o( L
- //一个停止位 a/ u- v; n8 {4 d0 R
) E6 n4 E+ B! X- USART_InitStructure.USART_Parity = USART_Parity_No;
- n) g+ t$ B, ?! z
8 W1 P: `8 c, z8 J$ t9 C2 v- //无奇偶校验位# N9 z4 L b" p
- + D/ a- ~0 ~% ] E' o) P0 |
- USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;3 Y* ^; `$ c/ S, T# o+ d
7 M4 {$ S0 X) M) f5 r- @- //无硬件数据流控制
* d% ^" C6 ]4 M% K/ O# F
6 j7 v5 ]/ |* G. @: N- USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;" s/ Q- s% [1 q
& q% L5 O( [6 t; P( E- //收发模式
7 ?" G0 Z) s0 H/ o! b4 a5 w
5 @- n, E8 N7 Q3 d/ W1 P0 j- USART_Init(USART1, &USART_InitStructure);
# ?3 Z* ~! a6 e* U+ Q/ T - ! P; X, ?, y3 W
- //初始化串口1
4 D4 F; n5 B- z
# M1 _ O$ C) B7 C) t5 w9 p- USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);' q) V- c* [! ^" O' n' l* N% o
- * ~: R( `4 e; H2 X* }' U- z
- //开启串口接受中断</font>
复制代码 4 K+ e" t o* ]2 N$ a5 t6 T: _! u
# N- ^! L8 h+ |& f7 T- }( Q 串口参数配置无法就是配置串口的波特率、数据格式、停止位、奇偶校验、硬件流、收发模式。除了波特率需要改变其他的参数都不需要管。直接复制拿来用。1 d9 @/ n8 z: z, z1 T, b
, G# T9 t: h$ X' j& U
& B4 g/ Q4 x- M3)串口中断配置
% l5 m8 \9 q% ^# D8 } 串口如果使用中断接收,那么就需要配置串口的中断参数,配置项无法就是配置那个的中断源和中断的优先级。
/ v& A7 d( L+ |0 Z |$ c; b* M1 {+ [. o6 b8 S+ Z7 g
3 p" Z G# C. t4 y6 R
- <font face="微软雅黑" size="3">NVIC_InitTypeDef NVIC_InitStructure;
7 X$ x' X Y# j1 u9 W8 Q& g - ; c5 p6 U- ^* E. ~: d. n
- //Usart1 NVIC 配置
2 r {: O9 w; Z* `
8 X' [! ?1 c( G t4 F3 D( e7 q- NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;, k) a) z7 {) j# K
- ; |) i/ V- e1 Q9 a, ?( @
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ; //抢占优先级32 t9 k3 @( s- u _, j' L' Y
- 3 ^% w0 w' j4 k+ v
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
% L& ^2 j2 K B
: W: H3 b7 g4 @- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
0 R+ N2 F- ~2 e3 p- T6 p - ' y+ K& ^0 r% Q x
- NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器</font>
复制代码
/ |# ?( e, z" |
" O3 {0 b* q- m/ Y) c4)串口使能- b; ?4 A* f( E4 b; _) @( U- x1 X
就是你需要什么时候开始使用串口功能,就是一句原有的函数。( d: d" ~5 X" N8 v& z9 s
- <font face="微软雅黑" size="3">USART_Cmd(USART1, ENABLE); //使能串口1 </font>
复制代码 {- b* L' ^& V7 N
& f' o! b+ }7 X" N( x& y5)编写串口中断处理函数# b- p5 ^0 N n" F" S* M" y
使用库函数开发,所有的中断函数都是已经存在的,只是中断函数里面没有处理任何事情而已。中断函数如下:
$ I8 S5 \$ q! J1 K+ i" M$ v7 X
0 i5 y$ e" p9 B1 ~! L
& y( l: p: l5 D, P5 H
. @+ H/ v7 |" z; F
; Y, ^2 K+ U' k% B: V' k9 G9 l
7 W- X6 n( E4 x7 |0 Q: l) T& u 完整的串口中断函数:0 Q" T+ s7 V4 j
- <font face="微软雅黑" size="3">void USART1_IRQHandler(void)7 L. ^ T) {$ h0 L9 k
% K% f& b& c; {8 j: z- {
- w% ]* V2 C! R _2 {( U8 j& c - % n: ^4 L6 Q1 t0 P4 X
- int Res=0; //定义一个变量用来接收串口数据集1 j( q. o* Z) K r# t
/ }1 w n8 K( A0 ?$ I- if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)4 o# K4 H/ j+ u& a
, I0 s. j2 T6 @6 Z# g* T0 K3 y- {
- s( f: |/ M$ p: W - 5 h) W8 T T4 k& ?0 t
- Res =USART_ReceiveData(USART1); //读取接收到的数据
; ^ j5 n: g: d( H - , ]0 b0 ]% x$ ~9 w# B$ k
- USART_SendData(USART1,Res ); //把接收到的数据通过串口1发送出去
3 | `) `9 c: @
4 I$ Y) I0 }' K0 X+ M% |- }
1 H4 s: x# n3 A. h7 @; O - * [ g; A1 Y3 M2 Q2 `% }4 U
- }</font>
复制代码
# R, ^0 i1 R, k' \: w1 u# F7 s0 i6 Z, w& K1 r3 }) @9 Z
串口数据的接收和发送的函数都是库函数提供的,想用时只需找到它直接拿来用就可以了。
5 S% w! h' T1 N6 K/ [1 U* ]
& R! q( f' U$ _: K; a- w& K% S& [( }: S+ ?
6)实验现象) w0 Q0 {7 N' V: ~1 L
0 |( T/ {- _) X6 S" m& y! U: n
5 S8 K6 }. P7 G$ k7 R 把程序编译烧写到STM32然后用串口转USB模块连接到电脑,在串口调试工具设置好波特率,打开串口。正常的话,那发送什么到STM32单片机,串口工具上就会收到什么。
2 {; H2 ]0 L# x/ a: V1 q( p7 _2 z2 `( u2 F+ o2 G" n
& n% o/ ?3 d- u% [/ k. A总结2 J9 N1 M+ P7 x2 t# X
: h1 M3 a+ C$ _0 t s0 F3 w0 w& {/ g, y: \1 Y$ ~* G
以上就完成了一个最简单的串口实验。* K( y& \3 Z3 [9 ~7 d# h
0 ?6 p1 q9 C4 Y; W$ x. o; o6 ]! s
本文章主要是说明串口的重要性,用来调试程序很方便。1 E6 H2 R! }- `% ^
, ]9 _2 v+ z3 c, ]" O$ E
|