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

STM32基础设计---查询串口通信

[复制链接]
STMCU小助手 发布时间:2023-1-5 21:11
首先总结全文,通过查询方式运用USART1口收发数据的主要步骤如下:
' j" C8 D* \( c4 S1.初始化GPIO口
/ k% @$ P4 y+ r. k( y) w: b5 r9 S2.初始化串口
. ?5 e/ ^! i9 X5 D' d* P# h# S$ e3.编写发送数据函数: o0 k* ^7 c: q+ R' l
4.编写主函数
5 B* c: ?2 A* f
下面介绍详细步骤:5 H& T! u; a5 x* k
( H3 `/ H: P7 I% p
1.初始化GPIO口% a2 M) |+ i7 i3 J  r1 z
通过查阅STM32数据手册可知,stm32f103c8 ,USART1的输入、输出引脚,分别为GPIOA端口的 Pin_10,Pin_9引脚,所以先定义GPIO结构体并赋值:% _$ Z3 O( M$ q5 d
  1. void IO_Init()
    9 M, M. {0 ?0 R1 |7 B$ r0 V
  2. {, V* x. _0 ~9 E! F5 }
  3.         GPIO_InitTypeDef Uart_A;
    ! W6 q. ^$ S0 m' I
  4.         ) c( g- t! d2 Q
  5.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);7 c7 e2 ?! l# n& Z) t) v: g+ o- W
  6.         Uart_A.GPIO_Pin = GPIO_Pin_9;
    ' q+ R. E6 j9 K6 s
  7.         Uart_A.GPIO_Speed = GPIO_Speed_50MHz;
    ; J! k1 \. y$ |! P
  8.         Uart_A.GPIO_Mode = GPIO_Mode_AF_PP;
    6 S3 _( V5 l) u. x! P) @0 x
  9.         GPIO_Init(GPIOA,&Uart_A);. ^7 t6 j9 l5 w
  10.         2 N8 Q  L$ y6 R% h& G2 `
  11.         Uart_A.GPIO_Pin = GPIO_Pin_10;
    4 x: e1 S5 M9 z$ Y4 ?1 S& `
  12.         Uart_A.GPIO_Speed = GPIO_Speed_50MHz;
    2 }: X% U) P% y/ R
  13.         Uart_A.GPIO_Mode = GPIO_Mode_IN_FLOATING; //stm32 data sheet page 1107 V* c8 N3 y9 s0 n$ X/ W# M
  14.         GPIO_Init(GPIOA,&Uart_A);
    # d3 u! I# e  \: g6 @  j  z+ R

  15. + y/ B. s/ K8 ?
  16. }
复制代码
' z! Y+ L2 s" A' k$ N
还和以前一样,先定义GPIO结构体变量,在使能GPIO外设时钟,紧接着分别对各个引脚的寄存器赋值并初始化。# }% x& W3 k/ V: B. }6 W8 B
! y% x$ z: P6 {* q( t, m% T
这里需要注意引脚模式的选择:根据STM32参考手册,在全双工模式下,输出口的引脚(Pin_9)要配置为推挽复用输出,接收口的引脚(Pin_10)要配置为浮空输入或带上拉输入,刚开始学STM32不需要过深了解,只需要知道引脚要配置为相应模式即可。如想深究请查看STM32参考手册110页。/ R1 x3 D) Y& ?4 X6 d3 k

" p. j1 Z3 p4 ^  `2,初始化串口
  X1 p( V, N3 A& m8 M要初始化串口可以利用库函数中的串口结构体 USART_InitTypeDef,这样对于初学者来说方便易懂。3 V3 `+ U# ~  l8 |- q, `: I

7 H1 m( {6 s( T  ~) [8 j( L. [+ H0 v: O库函数中的结构体 USART_InitTypeDef为:
7 C7 ~2 w2 n9 f1 c- g6 Q5 R+ g0 r5 s) `. L/ j
  1. typedef struct
    4 F% ^! x# ^7 {9 M- f8 Z2 N
  2. {//波特率# }. p6 B1 K) _/ O( B2 Q
  3.   uint32_t USART_BaudRate;            /*!< This member configures the USART communication baud rate.& X2 Z* \% Q% s, v
  4.                                            The baud rate is computed using the following formula:
    ( W( F! v& ~, ?6 b2 x
  5.                                             - IntegerDivider = ((PCLKx) / (16 * (USART_InitStruct->USART_BaudRate)))
    6 \; @# ]8 H+ f, t$ a  A0 F. G
  6.                                             - FractionalDivider = ((IntegerDivider - ((u32) IntegerDivider)) * 16) + 0.5 */
    , {1 A1 |  D9 |9 e
  7. //字长& l, Z' l0 c. {; h" Q/ M
  8.   uint16_t USART_WordLength;          /*!< Specifies the number of data bits transmitted or received in a frame.- r6 y3 ~* ]  e. ?+ o4 b
  9.                                            This parameter can be a value of @ref USART_Word_Length */
    - M$ I' l4 l) F* A0 ?
  10. //停止位3 o! o8 W  \0 \* ~. S/ W
  11.   uint16_t USART_StopBits;            /*!< Specifies the number of stop bits transmitted.4 K8 a/ {8 Z8 \& I3 ~" Q# m
  12.                                            This parameter can be a value of @ref USART_Stop_Bits */" V8 o! ?( l$ M- [
  13. //是否奇偶校验
    , O' V- |) n& L9 {9 M$ B" K9 e! x" ]( \
  14.   uint16_t USART_Parity;              /*!< Specifies the parity mode.3 I. P) j' u  I& b+ d( p
  15.                                            This parameter can be a value of @ref USART_Parity
    % K! b) ~, w+ F. F: S
  16.                                            @note When parity is enabled, the computed parity is inserted6 `& C. p- E7 c0 c+ d. i
  17.                                                  at the MSB position of the transmitted data (9th bit when8 U" I$ @( o% B8 N% L% E1 ^, ^9 ^
  18.                                                  the word length is set to 9 data bits; 8th bit when the
    : o$ T2 k0 \) m% m7 A
  19.                                                  word length is set to 8 data bits). */$ L  E$ r. e1 v# i; ]5 y) t' a( d
  20. //串口模式,收or发?3 X* h9 G9 S  |  q+ n* {" V  C
  21.   uint16_t USART_Mode;                /*!< Specifies wether the Receive or Transmit mode is enabled or disabled.
    9 ~; V- P* y$ }/ C6 O8 u8 C! o& i
  22.                                            This parameter can be a value of @ref USART_Mode */2 H  T  H4 b5 b9 {
  23. //是否使能硬件流,这个初学者暂时先放放,还用不到(博主现在是初学者)" V! e# s( s1 k1 Q
  24.   uint16_t USART_HardwareFlowControl; /*!< Specifies wether the hardware flow control mode is enabled
    1 |  f. {7 }  F) P; r5 x5 ], y4 X5 |
  25.                                            or disabled.+ t. S5 ^6 m, h6 i* ^4 k
  26.                                            This parameter can be a value of @ref USART_Hardware_Flow_Control */+ g% X1 p' r' c- n; X! }" F
  27. } USART_InitTypeDef;
复制代码
/ H& }# n, ]) f$ R& p
知道了结构体,便可轻松理解下面的定义了。& L& z) L. Z/ f2 O* Q
5 o8 N  ^& J" l
  1. USART_InitTypeDef Uart;
复制代码
5 w" r7 A6 t8 U0 _$ ?  b* M/ a
' N) C8 Q, ]5 k' O$ z, I! A0 \
使能串口时钟后,依次对结构体中的变量赋值(注:STM32的每个外设都有其单独的时钟,只有使能了其时钟,外设才能开始工作)详细代码如下:: R$ {( y2 J8 E# T5 b, \8 E( w
  1. RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);1 N) _+ `' ~7 p, X
  2. Uart.USART_BaudRate = 115200;//波特率115200
    + ?1 q0 [3 W( _
  3. Uart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件流失能
    $ b% d, }( o5 \; t" O
  4. Uart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//设置为 输出和输入模式
    & I3 J4 Z6 c: Y& k* q4 G# D
  5. Uart.USART_Parity = USART_Parity_No;//不进行奇偶校验" m6 R5 U* c, R2 O# l9 U
  6. Uart.USART_StopBits = USART_StopBits_1;//1个停止位
    8 u9 C0 ?2 a6 k$ i& }
  7. Uart.USART_WordLength = USART_WordLength_8b;//单次数据长读为8& j" U# y7 `2 a( O5 e: Q  B# e
  8. USART_Init(USART1,&Uart);//初始化串口
复制代码
, e+ }* t1 q& j  j9 T
在初始化串口后,按照STM32参考手册还需要对usart使能见下图:
- ?- B1 _) ^6 p. Y* y9 M8 W; g7 Z) z
9 P* O3 e$ t( r
20180319234442899.png 7 h" ^' n3 M$ S3 O0 L
8 N5 f5 p: Z. q, K9 J' ~6 N
(注:博主当时在这里想到一个问题:STM32有多个串口,但是只有这一个串口使能位,也就是这么多串口公用一个使能位,那么,当使用多个串口工作,如果临时需要关闭一个串口,怎么办?答案见文章最下部分,答案1。)7 U+ z+ v0 Q% {7 Z+ M5 D, o
' B, M, p" H- U# R" E* n
由上图可知,在初始化串口完毕后,还需要使能串口:( n9 R/ b( I9 K9 @* B
/ S4 q# h2 j0 E5 i  T
  1. USART_Cmd(USART1,ENABLE);
复制代码

2 u9 P) a3 R! z6 m& d8 o( ?0 F& ?: r& l" B0 W0 N: e

  {0 C% A5 k& a; J然后根据参考手册:. @7 `- A& E8 e9 M' S6 W6 X

( I. q9 p  a0 ^/ W+ H4 {
20180319234937352.png
8 }4 y+ q3 ^7 `
, P7 a5 ~1 K9 |+ ^/ X
2018031923501878.png
$ p2 z% o# G8 U1 |5 b. P6 _( a: L5 y. N8 R6 t* v
( t3 v$ C/ R$ [$ W5 ^% ~
此时还需要先清除状态寄存器USART_SR的发送完成(TC)位,要不然发送数据的第一个字节显示不出来。代码如下:5 ^4 @' S0 f3 T( ^
9 \  J  J, y" {, S/ s
  1. SART_ClearFlag(USART1,USART_FLAG_TC);
复制代码

( p6 {% e% O2 I6 e/ R; n% ~到此,串口的初始化也就完成了。
& m& I6 H: X% n( g% v+ M  d
) r  z* H+ |% d4 h9 @$ }' u3,编写发送函数
; k, h/ D$ P2 W. f此处比较简单,先说代码:
$ C3 p( l9 y, @. L
  1. void sendByte(uchar character)* u( b6 T- g5 Z- W, Y
  2. {1 L/ _; f8 y' _: O6 ]! [; p& \
  3.         USART1->DR = character;
    8 V# w' G8 T$ Y% a8 }2 h
  4.         while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
    ) Y& _* Z6 J+ u9 N6 j1 x
  5. }
复制代码
1 X/ k8 B" c6 c3 B
需要发送时,直接把数据赋值给USART1的数据寄存器(USART_DR),即可通过串口发出,接下来需要等待数据发送完毕,当数据发送完毕后,USART的状态寄存器的发送寄存器空(TXE)位会置1,(RESET在库函数的宏定义为 0),即,若数据未发送完成,那么循环会一直空转,直到数据全部转到移位寄存器。: N6 I# g8 Z3 j/ j
6 L) r  k2 [! \' c7 x- s0 @' i
4.编写主函数
2 L' p# y, y4 r! ~本文是通过运用查询方法来实现串口的发送。通过串口向电脑发送一个字符,串口之后会自动向电脑发送已发送字符的后9个。8 h8 X* E8 H2 T9 e' r* N

" h9 _% h' T" u7 g* J先粘贴代码在解释:( E( m" G) W5 l1 w1 o  s

; W/ O( r; V  `: |$ m3 s0 \
  1. int main()4 @' a( r; _) q# q0 J$ D
  2. {" r  `# u8 F! S0 l1 Y! G$ a+ M' c
  3.         int count= -1;
    / p* O* w4 v% }, A/ A# q2 e
  4.         char temp= '0';
    3 U- Z7 [2 P/ u" N/ ~5 o4 T4 \
  5.         IO_Init();
    / p( ~: g! m; k+ p
  6.         Usart1_Init();
    0 r: x7 j8 w0 K* [, ^2 s0 K
  7.         while(1){2 x+ L0 i! f4 Y$ K6 i& |
  8.                 if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE))//判断是否接受到数据9 Z, N8 n2 R, P$ p8 A' G
  9.                 {
    5 L' R. w+ X; B7 O1 r
  10.                         temp = USART1->DR;//若接收到数据,则将数据从数据寄存器取出( a; t( }' Z. g1 I" C9 F) v
  11.                         count = 10;
    , o$ X; ]: q0 N" W7 ?
  12.                 }        % M5 m6 O" ]3 [3 X
  13.                 if(USART_GetFlagStatus(USART1,USART_FLAG_TC) && (count >=0))//判断能否发送数据- v5 e+ f8 S8 M" k
  14.                 {$ ^  k& x+ X1 l
  15.                         while(count >0){
    . l6 E* Z5 K& |- t7 _: p& @
  16.                             sendByte(temp++);//若能发送数据,则向接收端发送数据
    ; T8 X0 X8 j' D: i) x
  17.                             count--;//连着发送10个字符- C  p! b3 l- d9 g/ o" ]! q  i7 z1 h. d
  18.                             delay(1000);延时一秒& D3 Z' z9 N4 o3 `
  19.                         }1 u& W( i9 U* C% b' k5 Q
  20.                         if(count<0){
    * Z8 F9 [7 c" Z; }* V: N. g0 s' }3 Y0 f
  21.                                 sendByte('\r');//博主本来想在电脑接收端输出回车换行,但是一直接收不了,还没弄明白。
    * J! z0 q7 h; i
  22.                         }
    8 B# B2 @' W! w4 }  s, A/ e
  23.                 }
    . j# K% ^6 Y  h
  24.         }
      V8 u1 Q3 T9 v7 d# {  n
  25. }
复制代码
5 v0 |  E2 m) P. @4 |: G
解释见代码中的注释。( W0 I% Z$ V4 O
* f1 y+ |. B& q/ i( Z2 M
答案1:当不需要使用多个串口中的一个时,直接将对应串口外设的时钟失能就可以了。: |$ c; B) ^6 c) e, ?5 E5 L

9 F- t5 M1 V5 D: W# x通过查询方式实现串口收发数据完结。2018年3月20日$ N( [6 |  X$ Y0 c* D1 |6 C% n
& O3 H( C; u+ _9 c7 Z
下一篇,通过中断来使用串口。
! e6 X4 `$ S- n2 |5 `! @2 W
! f2 s1 T* j3 U, C' M
见STM32基础设计(3)---中断串口通信
7 L# e8 m& e$ i  G% U3 v: `0 M
本文的完整代码如下:
. y% |8 i/ t% a) p. X; R" x
  1. #include<stm32f10x.h>
    4 `$ m' D6 d3 S
  2. #define uint unsigned int
    ! @% d! b# ^# Q( _7 M) ]
  3. #define uchar unsigned char' n* m$ A  w9 v3 `( R+ \
  4. void delay(uint n); h3 P. H9 _! I4 `1 x
  5. {: C, n+ q6 ]6 O3 W1 X: l: ]
  6.         int i,j;5 Q/ n- c0 s5 d/ j$ J  a
  7.         for(i=0;i<n;i++)
    . o1 B' f$ @0 p! Z- I
  8.         for(j=0;j<8500;j++);
    $ t+ u5 f0 e; L# k
  9. }
    2 `+ M+ A+ M! r9 m' T  {
  10. . e$ I  M  g: v8 y- k
  11. void IO_Init()) j6 n' g0 Z' [3 R
  12. {
    $ {/ _9 {: I6 q5 S6 H  N' H" d! t& a
  13.         GPIO_InitTypeDef Uart_A;' w5 W# c3 G/ F0 h
  14.        
    - K, H5 U% @5 D6 ?+ I$ ^4 w
  15.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);2 p$ G/ c0 _% W8 C) Q
  16.         Uart_A.GPIO_Pin = GPIO_Pin_9;
    1 N& X! R. V8 e4 X& K+ u
  17.         Uart_A.GPIO_Speed = GPIO_Speed_50MHz;; V# @+ j$ Y! H1 ~& x3 _
  18.         Uart_A.GPIO_Mode = GPIO_Mode_AF_PP;7 Z0 R1 Y9 F+ `, a4 O; h' f( m0 K
  19.         GPIO_Init(GPIOA,&Uart_A);5 J6 x( }* X' u! ?1 t- [
  20.         ' B2 w& q# V9 m; P8 J. s
  21.         Uart_A.GPIO_Pin = GPIO_Pin_10;
    - i! S; d  E' S- D# H8 v# X
  22.         Uart_A.GPIO_Speed = GPIO_Speed_50MHz;
    * O5 Y1 c  o4 K0 I
  23.         Uart_A.GPIO_Mode = GPIO_Mode_IN_FLOATING; //page 110
    7 x( z! {. f# e- w. F
  24.         GPIO_Init(GPIOA,&Uart_A);* l" s% ?1 q3 n: Z3 G

  25. * u) z- e5 n* ?+ e7 K9 F
  26. }
    8 A) g, a2 z4 ^& _) a
  27. void Usart1_Init(). A! @9 x% X( X; B7 m) O
  28. {) V, e) x0 R+ K2 V( b6 m, o( a
  29.         USART_InitTypeDef Uart;* r; O' n6 }& F$ Z' ^+ t
  30.         : t3 E9 e. ~" y( l
  31.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);# u" G+ i7 \- Y4 u3 ?. l
  32.         Uart.USART_BaudRate = 115200;) a0 E4 |, R$ l; r, n4 f3 \3 q. u
  33.         Uart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    : X2 D% J. q: }* o3 _
  34.         Uart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;& s' f3 K& U3 w; Q( W/ H  z
  35.         Uart.USART_Parity = USART_Parity_No;' k. {* w9 d; ~' u1 V
  36.         Uart.USART_StopBits = USART_StopBits_1;
    ( z8 V* d; H% U$ Z: R
  37.         Uart.USART_WordLength = USART_WordLength_8b;2 ?0 J1 U- U. G- H+ W! c
  38.         USART_Init(USART1,&Uart);  N. b$ s" O8 [: P
  39.        
    % L5 \8 b4 P9 z7 z/ n0 [
  40.         USART_Cmd(USART1,ENABLE);
    % U+ p: x" V2 R; v) G$ Y
  41.         USART_ClearFlag(USART1,USART_FLAG_TC); //page 540
    1 N! X4 y1 |- k' Q
  42. }/ s1 x* G+ c' V% E! W/ g/ E

  43. * Q& M+ _2 K) Z9 x6 Z# j
  44. void sendByte(uchar character)
    2 r: `' K- s$ b8 }8 ]: o
  45. {: |+ t. \& k# A& b% X  r) j5 d
  46.         USART1->DR = character;" j9 y5 c/ K4 f, i) J
  47.         while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);# G0 L6 a* P9 ~5 C4 B
  48. }8 i/ h# h( D) U/ s2 B- R
  49. : N9 b* ?; h. r5 O1 k
  50. int main()) C1 y4 {9 _, E- O
  51. {  r) `  R# J. X# s1 t0 R6 g4 T
  52.         int count= -1;- W* {& `& j8 Z" d
  53.         char temp= '0';
    7 q# o4 k5 L3 F' F" Q% M* C
  54.         IO_Init();
    & P% I, x9 J1 h  q" b
  55.         Usart1_Init();
    ) ^0 K. M5 n% g, ~6 l4 o
  56.         while(1){
    4 v' U: `: x0 }$ v0 [; u
  57.                 if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE))+ l9 ], y- l3 \8 {. R: s  |6 L
  58.                 {( v& k$ Z% ^' d' D% |
  59.                         temp = USART1->DR;
    4 e5 m. L5 ?9 ?% i% |
  60.                         count = 10;" m/ ^6 C3 W7 _: |1 b1 P
  61.                 }       
    & E6 J/ b7 ~1 t1 {
  62.                 if(USART_GetFlagStatus(USART1,USART_FLAG_TC) && (count >=0))% ~" Q/ ^4 L" A& o
  63.                 {8 P, u8 P: ]& I  F5 ?, A
  64.                         while(count >0){
    - Z3 S, o7 i+ n6 m
  65.                             sendByte(temp++);
    1 h  b" n0 Q# o" R' \! f
  66.                             count--;
    ; `( X2 p3 F- i
  67.                             delay(1000);
    & t6 _7 r) b% u& t7 t# }$ E! p
  68.                         }! a% |; W- R3 |) U( o( W
  69.                         if(count<0){) |9 j* ~6 c: n  ]& ?, j
  70.                             sendByte('\r');                                           ! j0 h+ s1 z+ t) ~; p0 F
  71.                         }/ t3 s" H; x) `! E( t' ?
  72.                 }
    . S& Q% H$ [  e7 k1 p
  73.         }
    6 y7 Y" B9 j' N: y
  74. }
复制代码
/ I! N6 u0 j) `( T+ s1 F: o0 Z
————————————————
9 S1 X6 e9 n1 W9 i, @* @版权声明:家安
" ]/ c/ o9 C, F; R+ ]# W; E# b: K" i
" O4 J+ @1 A. Q* m* c2 ]
收藏 评论0 发布时间:2023-1-5 21:11

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版