首先总结全文,通过查询方式运用USART1口收发数据的主要步骤如下:
) H G) T3 |. n3 n( J8 O# P* y( h+ J1.初始化GPIO口( n9 `2 A* l( j3 t% w5 D# m# b
2.初始化串口7 } z5 ], ~$ i0 m# h# s7 f
3.编写发送数据函数% R* `: Z ?& K* L5 U
4.编写主函数" B5 Y# u( c' V
下面介绍详细步骤:
' [ C: O- D a) W$ a- U/ x- P1 R" d, ?4 G+ v
1.初始化GPIO口
8 y/ e2 G5 T$ w$ l0 ?, S, L通过查阅STM32数据手册可知,stm32f103c8 ,USART1的输入、输出引脚,分别为GPIOA端口的 Pin_10,Pin_9引脚,所以先定义GPIO结构体并赋值:; f" ?- G! w/ W" l9 R
- void IO_Init()
# Q* S G- Y0 [6 B: X' _( [! ~3 H - {: W) e& i& q7 ^' `) n; y \6 f5 |* Q- G
- GPIO_InitTypeDef Uart_A;
! U7 G- s! G' ^ F! e2 ] - % p$ a* u# h; a! W) E! g
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
% a4 S! }4 M+ _# p2 O/ Y - Uart_A.GPIO_Pin = GPIO_Pin_9;5 k' F: l7 J- j- Y8 C
- Uart_A.GPIO_Speed = GPIO_Speed_50MHz;
9 o+ a! E6 O# s& q2 c - Uart_A.GPIO_Mode = GPIO_Mode_AF_PP; _" U# l% a9 c3 c
- GPIO_Init(GPIOA,&Uart_A);
" X2 f/ u% y" F: f- _ -
5 D X1 Y; n+ z: u* O7 i - Uart_A.GPIO_Pin = GPIO_Pin_10;* o6 t+ a" T8 h+ B* I+ U$ c# r8 D( Y
- Uart_A.GPIO_Speed = GPIO_Speed_50MHz;5 z! Z9 J% q _) ^
- Uart_A.GPIO_Mode = GPIO_Mode_IN_FLOATING; //stm32 data sheet page 110
2 c1 q. P0 W% P g - GPIO_Init(GPIOA,&Uart_A);
7 j, Q( D. `( W; x* M. E8 R: x - : }" o% C- h8 G' E- h! p4 J
- }
复制代码
# b! T/ F G% J$ N5 p! K# E }还和以前一样,先定义GPIO结构体变量,在使能GPIO外设时钟,紧接着分别对各个引脚的寄存器赋值并初始化。( s! K# l: L- e# W8 [# b
8 U7 V3 U0 m$ n( ~4 u/ O
这里需要注意引脚模式的选择:根据STM32参考手册,在全双工模式下,输出口的引脚(Pin_9)要配置为推挽复用输出,接收口的引脚(Pin_10)要配置为浮空输入或带上拉输入,刚开始学STM32不需要过深了解,只需要知道引脚要配置为相应模式即可。如想深究请查看STM32参考手册110页。7 p* ^ ?$ A! |. e
, d' V7 X+ j: K5 a
2,初始化串口
# X5 B: m8 x/ G) Y F要初始化串口可以利用库函数中的串口结构体 USART_InitTypeDef,这样对于初学者来说方便易懂。
; z F! ?0 f& }# M" {0 c7 Y( T/ A7 `* P k- }
库函数中的结构体 USART_InitTypeDef为:
" |/ Y! ]1 u! t" Z, M/ b+ L+ I1 H* F! C7 C6 h
- typedef struct* S' T! Q. L: Y
- {//波特率* O' d' t1 k- [. X; m
- uint32_t USART_BaudRate; /*!< This member configures the USART communication baud rate.& L0 S! l0 q$ u
- The baud rate is computed using the following formula:2 S: b2 a. q3 A' o8 y8 L9 v
- - IntegerDivider = ((PCLKx) / (16 * (USART_InitStruct->USART_BaudRate)))4 o& B5 N4 i: O1 Q, `' [
- - FractionalDivider = ((IntegerDivider - ((u32) IntegerDivider)) * 16) + 0.5 */
' e' M# c. z7 [ - //字长+ S x' N+ s& W0 L( Q8 t6 K
- uint16_t USART_WordLength; /*!< Specifies the number of data bits transmitted or received in a frame.
- Z0 ~* a8 T# a$ {% c8 e/ J - This parameter can be a value of @ref USART_Word_Length */
9 Y7 U9 f" P! B, {- y, B7 l5 } - //停止位
5 F) @3 v) F6 a% x c - uint16_t USART_StopBits; /*!< Specifies the number of stop bits transmitted.$ a j/ L+ p1 b) N4 `+ g( C( Z
- This parameter can be a value of @ref USART_Stop_Bits */
5 X: h5 c9 j4 A" D- l - //是否奇偶校验
( ?* U% z4 B3 [& y - uint16_t USART_Parity; /*!< Specifies the parity mode.& j( C# b6 y0 S) K/ g6 r
- This parameter can be a value of @ref USART_Parity
) y& T. C6 ^2 R- c' Y6 w& ^0 o0 n - @note When parity is enabled, the computed parity is inserted
- g* e4 n! e" W u0 K/ i) s" z# t8 u* c - at the MSB position of the transmitted data (9th bit when; Q) o- _( o8 h0 C! e7 n
- the word length is set to 9 data bits; 8th bit when the
8 b' M( I) }' } - word length is set to 8 data bits). */
8 m' j( @& f' Z: E- _ - //串口模式,收or发?
% A6 {2 I; N" s* x1 Z' @ - uint16_t USART_Mode; /*!< Specifies wether the Receive or Transmit mode is enabled or disabled." v# b; R- a/ G6 v, f6 Z
- This parameter can be a value of @ref USART_Mode */
% x1 L2 S8 l% S7 n! \6 t8 w - //是否使能硬件流,这个初学者暂时先放放,还用不到(博主现在是初学者)
& f1 D9 {$ H3 p# W+ N# e: Y" q - uint16_t USART_HardwareFlowControl; /*!< Specifies wether the hardware flow control mode is enabled8 E$ N1 O- N( H% c
- or disabled.4 O( O3 C3 @3 x$ g! F8 h2 B
- This parameter can be a value of @ref USART_Hardware_Flow_Control */
4 H2 W' f; k3 e; ]) w; ] - } USART_InitTypeDef;
复制代码
! f" q Q( g$ z! b0 a9 e* f知道了结构体,便可轻松理解下面的定义了。9 }, u" l [3 M( b9 N) K$ F. `
- {( b: q3 v" Z4 \2 u# z8 ~
+ E; v, i- a, t2 Y n5 X5 p6 u Z+ I" ?
使能串口时钟后,依次对结构体中的变量赋值(注:STM32的每个外设都有其单独的时钟,只有使能了其时钟,外设才能开始工作)详细代码如下:
6 Z0 G0 `( Q4 }" U, j8 p% p; R; {- RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);7 @2 I& F7 w+ Y7 d0 S( s$ {! L3 C
- Uart.USART_BaudRate = 115200;//波特率115200
8 ~" ~) \, b6 c# _ - Uart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件流失能7 E' ?# } `# I4 D8 L. h
- Uart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//设置为 输出和输入模式4 J% F, ?8 \( w, A5 @
- Uart.USART_Parity = USART_Parity_No;//不进行奇偶校验
# D3 ?3 m8 v1 o. ^- V) c8 r - Uart.USART_StopBits = USART_StopBits_1;//1个停止位7 ~- h% _6 s! r$ B
- Uart.USART_WordLength = USART_WordLength_8b;//单次数据长读为8- t# Q6 F5 j! M9 w
- USART_Init(USART1,&Uart);//初始化串口
复制代码
' m( u; {# r' e9 T2 `在初始化串口后,按照STM32参考手册还需要对usart使能见下图:; N0 p, n0 r/ A( g* r: d
+ i+ u& ^, ]/ |/ b' S
' i. P. }" \5 D* V/ T
" p9 K( C& o) N2 n5 |0 S! b: k
(注:博主当时在这里想到一个问题:STM32有多个串口,但是只有这一个串口使能位,也就是这么多串口公用一个使能位,那么,当使用多个串口工作,如果临时需要关闭一个串口,怎么办?答案见文章最下部分,答案1。)0 @) W9 O5 I; y: o# s
4 f1 t. g7 l ]8 M由上图可知,在初始化串口完毕后,还需要使能串口:
6 c, |' y. N. c# Q/ t
& C" o' n* i" {6 S- USART_Cmd(USART1,ENABLE);
复制代码
/ s# ?1 n- x/ X9 H4 t! o Q( v0 g `2 m/ }2 `* i
) N3 s1 z' \0 N$ u1 ~
然后根据参考手册:9 q9 F3 p' d0 M+ w% q, n8 }! e8 f
5 R. f* \# s( u, v
- E* A) ?) ~2 e" `- ~5 m9 C6 R8 Y: G: `" |; N
( @( }: ^8 l) O$ ?# K2 z- B
! C, f. _5 ]8 H& D3 @0 M, V9 b2 @: U+ Q4 \ X6 e' W* H" } e
此时还需要先清除状态寄存器USART_SR的发送完成(TC)位,要不然发送数据的第一个字节显示不出来。代码如下:- ?/ c- z, }- l9 @. U5 s% R/ `/ X
! W2 ?% k, C) m1 }
- SART_ClearFlag(USART1,USART_FLAG_TC);
复制代码
7 S* t' Z( w/ X/ }" o$ i到此,串口的初始化也就完成了。5 x1 R6 `. o; w! ?7 J7 I" ^
) L) V) }. s& m! f3,编写发送函数9 S$ }0 }% r5 ^) A2 _0 h# x
此处比较简单,先说代码:
2 S: h# R4 W( U0 G) C8 l' Y- void sendByte(uchar character)% B( \+ d6 D! g
- {& q% G% b5 k4 s. t
- USART1->DR = character;# ` x1 @ j; r$ X6 ?$ z
- while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);* H- C* _& |$ q
- }
复制代码 2 D8 b6 M2 a/ v# v
需要发送时,直接把数据赋值给USART1的数据寄存器(USART_DR),即可通过串口发出,接下来需要等待数据发送完毕,当数据发送完毕后,USART的状态寄存器的发送寄存器空(TXE)位会置1,(RESET在库函数的宏定义为 0),即,若数据未发送完成,那么循环会一直空转,直到数据全部转到移位寄存器。8 c" s! H- a5 I
$ p. z# O& V6 r2 A5 M( M
4.编写主函数# ]) _1 G! M4 S
本文是通过运用查询方法来实现串口的发送。通过串口向电脑发送一个字符,串口之后会自动向电脑发送已发送字符的后9个。
- V8 |' ?1 J* ]/ t/ l* }4 y+ m {" u/ Z
先粘贴代码在解释:
% k- R5 d( Z2 I4 `9 B w I1 k: j% |1 ]% I
- int main()- \5 j* ?( {5 p# a2 q
- {8 z+ `2 K% @; Z; S% h3 @
- int count= -1;! p- b: g: _, v) ?5 {' t+ p* K
- char temp= '0';0 v- b8 n4 \$ U" }. b. h# W
- IO_Init();
( ]# M# l6 u0 ?7 F/ g' r$ ` - Usart1_Init();% K9 z' P" E* P! m& C
- while(1){
3 c, j- h4 e: U' w5 Q. r, U, I7 N - if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE))//判断是否接受到数据5 J3 F$ w8 [0 }# ]2 y
- {5 w$ _6 Y% }1 W- m1 Z: c# Q3 L* R
- temp = USART1->DR;//若接收到数据,则将数据从数据寄存器取出
' D/ |2 W9 M* @2 |2 ]" A' r - count = 10;( @8 ~* k& o& m( [* r1 t9 X) q
- }
0 c' x! w2 w5 C8 r6 S) S - if(USART_GetFlagStatus(USART1,USART_FLAG_TC) && (count >=0))//判断能否发送数据
& H9 s& D; d L - {& a* n. m( h. o+ k! M6 v6 ^
- while(count >0){$ z* ~5 t7 D- w2 _
- sendByte(temp++);//若能发送数据,则向接收端发送数据/ u* g5 x) P k
- count--;//连着发送10个字符* z/ O) k* f, c4 b' n& Y8 |# V+ ^
- delay(1000);延时一秒3 ]/ [2 M: E7 \9 a
- }
& q0 c9 O4 ^) q: q - if(count<0){( n4 b( J* g5 m7 w% I/ d
- sendByte('\r');//博主本来想在电脑接收端输出回车换行,但是一直接收不了,还没弄明白。
7 F) N4 O: \- G" a - }
; p g4 _- B0 W; r0 @% ` - }6 Y5 m) L) @/ n2 {6 Z. b
- }% w7 q; A/ V! X5 E, m7 K5 x. i
- }
复制代码
( y+ F/ o% [: ], g% Q解释见代码中的注释。
- n, R/ O: I. v4 i* `% ~1 ^' x1 \
1 b! N- R$ L6 F6 f* n0 n答案1:当不需要使用多个串口中的一个时,直接将对应串口外设的时钟失能就可以了。" w1 U8 O! {3 Y1 @
$ K8 G5 b/ a/ v$ Y8 W
通过查询方式实现串口收发数据完结。2018年3月20日% }4 s# ^* }! X0 @
& S- h+ I" W. u3 _
下一篇,通过中断来使用串口。' v6 e: w C! O& d7 g t$ B4 ~
1 X. j5 x# @7 i( `! I3 J/ q
见STM32基础设计(3)---中断串口通信
- Z7 x9 k7 A8 P8 q) E0 J& V
% L) n6 l5 p: A* U& r本文的完整代码如下:
" `" \- q) Y& C' V# S- #include<stm32f10x.h>
) {4 h) ]4 U4 f. Q) }7 l - #define uint unsigned int v/ s, R. |7 [8 ~2 k' s( e
- #define uchar unsigned char
! n; S/ P4 z3 O$ F& X: D: a7 ` - void delay(uint n)3 N) _0 K6 w& Y1 \
- {+ x) C5 n* U+ z; q$ K- v
- int i,j;
/ B4 l( [* Z# O- M3 ^4 Y - for(i=0;i<n;i++)5 Q' N) K5 \5 I. S0 h! ]4 v+ r# w
- for(j=0;j<8500;j++);
4 P! T7 d) |: }3 Y - }& V2 p! y) k3 [; N
-
4 j3 O* F# z* s6 @5 Q0 M* z! x. z - void IO_Init()
K: l8 l) U) P+ ? - {2 U% \. m! W- }; q
- GPIO_InitTypeDef Uart_A;
1 j5 X+ `- d+ L1 s: y/ Q9 L -
8 ], o$ c7 z. ]0 \ - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); k# q. J6 R% O# a# k; y) H8 s
- Uart_A.GPIO_Pin = GPIO_Pin_9;
3 F0 W) E5 q) V* ~. [ - Uart_A.GPIO_Speed = GPIO_Speed_50MHz;
# ^; `0 I. d' C* ^9 | - Uart_A.GPIO_Mode = GPIO_Mode_AF_PP;
, q8 D& g' k8 x5 N! v - GPIO_Init(GPIOA,&Uart_A);
2 I. Q; Z( ~, N& G: Z5 W0 @ -
$ p9 |( {: C% Y. n; t$ E7 p6 @6 T% _ - Uart_A.GPIO_Pin = GPIO_Pin_10;
4 E; m) ^+ N" i* ^ - Uart_A.GPIO_Speed = GPIO_Speed_50MHz;
/ r' T! Q1 }4 I/ M) \$ J. M" [% ] - Uart_A.GPIO_Mode = GPIO_Mode_IN_FLOATING; //page 1108 n0 D4 C5 @0 N) ?9 |+ u/ r. G& y
- GPIO_Init(GPIOA,&Uart_A);
/ m2 R6 h3 a0 |& Q - / |! E Z( w3 Z% y
- }! c# j5 |- R8 e3 ?
- void Usart1_Init()0 s5 [; U" Q3 C5 {( p7 N
- {: p8 Q' Z8 c" W, e( w
- USART_InitTypeDef Uart;
}" J3 t" Y* `1 I - 2 j3 n1 b9 N0 k J, Q9 V
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);8 @( A8 }! t9 _/ S. @
- Uart.USART_BaudRate = 115200;4 \, j) L+ ^: m+ h( i# Q9 }, W
- Uart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;2 f! n$ \$ K, ~2 w6 @) Q
- Uart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
" Z0 F. h1 D+ w5 a2 o$ D# i - Uart.USART_Parity = USART_Parity_No;
6 o! J9 s! ^* P - Uart.USART_StopBits = USART_StopBits_1;# H) E* N% @7 [" J4 ^# d
- Uart.USART_WordLength = USART_WordLength_8b;
: ~# e" @- J( h& d - USART_Init(USART1,&Uart);% E1 P6 U6 s0 I/ ]* Y
-
; F) E- |- f( E6 l# T) T) t+ P. x - USART_Cmd(USART1,ENABLE);& L9 P" _) f/ w7 v, Z# z- \# T7 ^
- USART_ClearFlag(USART1,USART_FLAG_TC); //page 540& c) d2 I1 U' B5 B
- }
# Y" L0 C- D! T. U' q w8 j- W -
# x# Z4 b7 w# V' x( z8 X+ i. { - void sendByte(uchar character)
3 F! R2 e% s0 H5 K+ K0 V. Z/ k - {4 O/ {& k; ~# a# q* e
- USART1->DR = character;
U- ?) n8 c& O& t- i3 ? - while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
3 B1 F/ y# J& J9 ^( f2 D7 S - }
, w6 N( b1 H# J7 y5 A; X - 7 J) `9 B6 U: b) |! e9 A! i3 E
- int main(): S5 M$ p5 M. g) T7 D
- {9 x8 x5 G; k; V4 e1 {/ ^1 j* E% e% v
- int count= -1;
" t1 P. ]) G/ V/ ^ - char temp= '0';6 O0 M' K$ @/ C* k5 B& r
- IO_Init();* j- s+ N! i; B4 U; r
- Usart1_Init();
! y' n' m) u7 [; o# d0 Z1 V% T - while(1){
* ~ M k. S. k( |7 I2 b - if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE))
3 v* m$ h$ X2 w& E5 i& u0 ` - {
; V2 \6 {' v; Q - temp = USART1->DR;% `/ c/ I- H8 D L+ T
- count = 10;
# H2 P5 O1 }7 `+ t - } " s9 a5 F1 H8 Z$ E" o: ~
- if(USART_GetFlagStatus(USART1,USART_FLAG_TC) && (count >=0))
; f7 \8 h& ` h2 c w - {
9 ~5 n6 `- k) p! t; p: a- t7 O3 Y - while(count >0){
1 w9 q% i* x& T2 n- [ - sendByte(temp++);
* z0 M' h/ ]. ^( V - count--;6 b' ]/ G$ ~5 Y) R- Z& F* H! Q
- delay(1000);
! i) p' B+ }3 N! N5 R# ^ - }
6 ~3 c- J/ b8 y R- _* ~* q0 b - if(count<0){* s7 M/ |- ?8 r L$ u" T
- sendByte('\r');
7 G5 G$ @2 U5 Y! {+ b - }
) }! I2 x( K9 w - }
/ j, W0 c! [2 k+ }* @ - }
' w8 o h, U1 m# ]$ [ - }
复制代码
, c4 i5 r7 h/ r0 } ^) l————————————————
* G0 U# c$ ^0 p' t' {2 A; d' ~6 V版权声明:家安
. o. s1 B9 M4 A* V y' m5 R$ j" H' }$ E! t( [: N9 \0 R
3 h3 p' Q1 G7 D3 d; H; z5 t9 K6 w: v
|