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

【经验分享】STM32库函数串口发送与接收实例(中断)

[复制链接]
STMCU小助手 发布时间:2022-5-9 18:00
前言
# K1 |2 E$ l" _9 ]' Y本篇用库函数写个简单的串口收发,用的是 STM32F103RCT6 开发板(部分来自正点原子)。
) y1 B/ N: ^2 F+ uSTM32F103RCT6 最多可提供 5 路串口,有分数波特率发生器、支持同步单线通信和半双工* v3 c( I" f" I( }2 J
单线通讯、支持 LIN、支持调制解调器操作、智能卡协议和 IrDA SIR ENDEC 规范、具有 DMA
: M- E$ \% a6 F- J2 |. r3 i  ?等。
3 n- l8 H0 X0 k' ~. w, I$ e8 @0 @- Y
串口设置的一般步骤可以总结为如下几个步骤:
) I9 _' q! L! q$ M3 G* d
4 Q7 G8 v! @" V7 T- ^串口时钟使能,GPIO 时钟使能
" B, A1 J2 ~, ~串口复位
( O0 r! Q2 S$ y$ k, y$ ?GPIO 端口模式设置
/ ?, ?0 q) B6 D" G* A) [串口参数初始化& r7 D8 E6 d( C: N: e: b) ^
开启中断并且初始化 NVIC(如果需要开启中断才需要这个步骤)
3 `" K- L$ s/ Q, f$ N* s使能串口
& f1 }4 R* ?- _' M& ~7 p7 m编写中断处理函数
3 q0 r8 W8 t5 `/ R% g$ K" [一、串口配置步骤( W8 W$ t0 L- g2 W% ^
函数和定义主要分布在 stm32f10x_usart.h 和 stm32f10x_usart.c 文件中。$ \3 }' e; w( Q

7 S$ x2 D5 \6 m0 ~1.串口时钟使能 串口是挂载在 APB2 下面的外设,所以使能函数为:
% K. M1 h- c9 j' X: P6 `$ Y+ S7 Q0 [3 }8 K+ t
  1. RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1);
复制代码

. ?) x" E" D5 Y: Q2.串口复位 当外设出现异常的时候可以通过复位设置,实现该外设的复位,然后重新配置2 G5 `# m  |7 ^; c* q, c( R7 b
这个外设达到让其重新工作的目的。$ i9 b% Z4 Q. Z/ ]7 K6 {
复位的是在函数 USART_DeInit()中完成:
, X/ g) G5 v3 Z9 c6 O2 |8 L6 w! [( H4 A0 H+ i4 g5 ~
  1. void USART_DeInit(USART_TypeDef* USARTx);//串口复位
复制代码

( y: A. E  h, L- ?& @+ `复位串口 1,方法为:
  1. USART_DeInit(USART1); //复位串口 1
复制代码
5 r/ a  d: l- b. X
3.串口参数初始化 串口初始化是通过 USART_Init()函数实现的,
/ G( W6 _6 K% I. i5 m5 c* f7 o) N+ h0 h9 i6 r1 ~( U
  1. void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);
复制代码

5 E# z' _% g! m8 i6 |9 x% g9 f第二个入口参数是USART_InitTypeDef 类型的结构体指针,这个结构体指针的成员变量用/ V5 e' O& z/ U( w) t) i
来设置串口的一些参数。1 j8 }7 `% c' ]* z& {
一般的实现格式为:
  1. USART_InitStructure.USART_BaudRate = bound; //波特率;) \2 V' i9 y" l, Y9 l! v4 {! {
  2. USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为 8 位数据格式
    / K" R3 y* t4 S
  3. USART_InitStructure.USART_StopBits = USART_StopBits_1; //一个停止位
    1 }4 O$ l5 d+ C# y9 c! F
  4. USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶校验位# D& v' v  |1 Q: k, n5 G) R
  5. USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件数据流控制" u3 T7 B6 O! @9 {: P, |
  6. USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
    1 F- q9 S, P  g! j. V: h) ~
  7. USART_Init(USART1, &USART_InitStructure); //初始化串口
复制代码

8 |' n4 G7 V2 i0 \- w0 e4.数据发送与接收 STM32 的发送与接收是通过数据寄存器 USART_DR 来实现的,这是* |7 Q6 w# J" [, |0 ^+ C" K4 M( G# d
一个双寄存器,包含了 TDR 和 RDR。当向该寄存器写数据的时候,串口就会自动发送,当收
7 M7 R0 R) Y+ n1 r到收据的时候,也是存在该寄存器内。
/ a% j* a" R9 T# g5 l, ySTM32 库函数操作 USART_DR 寄存器发送数据的函数是:! c3 F9 T8 F$ L% R+ {1 n
- ~9 _1 j4 }! k8 o
  1. void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
复制代码
! }, o5 a' X" ]0 c5 [6 y
STM32 库函数操作 USART_DR 寄存器读取串口接收到的数据的函数是:
  1. uint16_t USART_ReceiveData(USART_TypeDef* USARTx);
复制代码
+ ~9 H! t% f- Q# h* E0 _
6.串口使能 串口使能是通过函数 USART_Cmd()来实现的% g) z4 Q) c$ Y9 q1 x

1 l/ {; P6 c5 t: r8 @9 \. h
  1. USART_Cmd(USART1, ENABLE); //使能串口
复制代码
  M# i; m1 C: `
7.开启串口响应中断 使能串口中断的函数是:
  1. void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState)
复制代码

7 U. g5 R/ ?6 J# w& M6 O3 A% w6 c开启其中之一的中断的方法是:  _: w' R& b2 I% F5 X

9 c0 J: a: D: N2 W
  1. USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断,接收到数据中断
复制代码

+ J7 ~% n8 d0 k0 E8 T发送数据结束的时候要产生中断:
9 H9 y; ?2 J8 L& ^) x7 v+ ?) D' i$ Z% e4 O; X
  1. USART_ITConfig(USART1,USART_IT_TC,ENABLE);
复制代码

  X' v' V2 u( U( _& ?) Z6 [' U8.获取相应中断状态 在中断处理函数中,要判断该中断是哪种中断,使用的函数是:
' ?2 H# n. h& Y. F6 ?! M1 i
. @2 j/ x5 q* p( c3 g
  1. ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT)
复制代码

; E- r- n: M$ \% f# {判断是否是串口发送完成中断:/ h, N, u! {5 c1 c1 K
5 k8 i: o9 @% G& H3 L; K6 b, O
  1. USART_GetITStatus(USART1, USART_IT_TC)
复制代码
6 A/ ?6 B  m7 V. p/ a9 b. L7 i/ O
返回值是 SET,说明是串口发送完成中断发生。
2 M; _3 J) Q; m  G3 O, f# U7 M/ E$ h: M  R6 \
二、实际编写
0 e1 U5 I, d: c- O, Z" k1.代码部分
; S4 B% O9 }* L& L+ _8 C——uart.c 文件1 _! w  i( Z' O$ d8 _. b
, d1 E3 O& l2 s& j# D4 p+ c% ^" e
①重定向fputc函数# R' @& [- x0 r" `% l7 O  N7 b3 ?
使用串口1(USART1)输出Printf信息$ [7 r& R5 l% Y0 L  m) [

; b0 J( Z" F9 c$ z: ]  A; X8 P: t" ^8 T
  1. #if 1  5 u) c& o  |4 a# @
  2. #pragma import(__use_no_semihosting)               
    % u! g) ~3 d# P. P
  3. //标准库需要的支持函数                  
    % p0 s& E/ i* K6 b, o3 \
  4. struct __FILE   
    $ L/ h, L! @3 {: Q' @! [
  5. {   
    6 i$ j% f+ q5 d" y& U( n) F
  6.     int handle;   $ h1 D8 R% e6 w% \, Q
  7.     /* Whatever you require here. If the only file you are using is */   6 D  F; L$ S# ~& e" I% |5 B6 u# y$ b
  8.     /* standard output using printf() for debugging, no file handling */   # g) n9 F$ `: q2 m! H8 d  [1 N7 P' F
  9.     /* is required. */   ; \4 x1 P3 D6 Y6 d5 n; W# h" b
  10. };   
    7 J* U/ U4 C: q- {9 Z8 r+ J
  11. /* FILE is typedef’ d in stdio.h. */   
    4 W1 ], I# w0 p
  12. FILE __stdout;         
    : `4 d4 H% T- c5 q
  13. //定义_sys_exit()以避免使用半主机模式      
    ' S2 k' T* ?0 Q. n
  14. void _sys_exit(int x)   
    ) ?0 e2 P; n# M- h5 \/ [! ]4 m+ M
  15. {   7 f# o8 _3 m  J
  16.     x = x;   
    5 q  i% n4 u" ~
  17. }   8 M4 I$ p+ x. a) \
  18. //重定向fputc函数  
    . n# k' i. P8 Z- M. W' E; _
  19. //printf的输出,指向fputc,由fputc输出到串口  * H" O! ?: a8 e* i
  20. //这里使用串口1(USART1)输出printf信息  
    9 X& }& {% o3 s# U& [4 F: C
  21. int fputc(int ch, FILE *f)  
    ( O; {( N+ Y5 A" ^3 r- e
  22. {        
    ; j  t% {) Z2 u9 q" w* a) l
  23.     while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
    5 k4 ?* U' a0 c* o" r2 E
  24.     USART1->DR = (u8) ch;
    7 h) z! i6 g3 y, J+ R4 I# r  H+ c
  25.     return ch;  % }8 i6 R, c2 m' u# V9 i
  26. }  1 o$ x: B: P) F, m! A6 I' y$ m: {
  27. #endif
复制代码
1 H" v" _5 R  U5 ^$ ^
②GPIO* H3 L8 N) X6 E3 V& a3 q# Y- o
  1. u8 USART_RX_BUF[USART_REC_LEN] __attribute__ ((at(0X20001000)));
      u3 H- {1 I" M
  2. //接收缓冲,最大USART_REC_LEN个字节,起始地址为0X20001000.
    3 N! Z* Q: d; X9 E
  3. u16 USART_RX_STA=0;       //接收状态标记         
    " F- S  c4 R( f. s
  4. u16 USART_RX_CNT=0;                        //接收的字节数         
复制代码
  1. void uart_init(u32 bound){# L' U: X4 L) i$ ]4 D7 b* `
  2.   //GPIO端口设置(初始化)
    3 M. V, ]6 `& P. b) s
  3.     GPIO_InitTypeDef GPIO_InitStructure;
    8 n, I" e4 G: r8 }% \  S
  4.         USART_InitTypeDef USART_InitStructure;
    # W' i) S3 B& A( D
  5.         NVIC_InitTypeDef NVIC_InitStructure;
    ) o% k/ V/ b0 W! {. e: \
  6.          
    : S5 p- ?- X, ~( r3 R
  7.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);        
      d& a- {& ?: n% ?3 b
  8.         //使能USART1,GPIOA时钟
    / |! Q" d# k. h( _' w4 Q6 ?
  9. ( C/ C4 a1 \% \& Q7 `- p
  10.         //USART1_TX   GPIOA.9
    / t7 C# L% Y+ ^8 Y
  11.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
    5 ?8 u$ U# j( r: V2 |- M, x
  12.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      t+ Q. u1 X# M, K9 C/ r
  13.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        //复用推挽输出
    6 O2 X4 M6 t7 W  W% v
  14.   GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
    . m* Z: d& D( O& s, P: {

  15. % k! [. o$ U% P- p2 C1 k
  16.   //USART1_RX          GPIOA.10初始化
    4 S# X+ ?" K+ Q0 f2 Z8 h
  17.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10  G1 ^( ^0 N+ u: q3 @/ d& H
  18.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入, h; g1 _* u# O3 t2 x+ Y( Q, u4 Y0 S
  19.   GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10  
    , y" V3 C5 W6 g: I! f: u% K' }! K
  20. & N6 f4 o7 ~3 y) n" X* T
  21.   //Usart1 NVIC 配置
    ' Z/ v$ ?3 Q! ~$ H
  22.     NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    ) w6 q3 ?' `. s' G0 R, Q( `
  23.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级35 f1 w8 r$ p& v" n
  24.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;                //子优先级3
    ( y5 ^/ n7 z- R4 @+ j  }, }) j
  25.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                        //IRQ通道使能
    # u3 D+ C8 |- r5 V: O( [  R- d2 T
  26.         NVIC_Init(&NVIC_InitStructure);        //根据指定的参数初始化VIC寄存器2 g; \8 e- r! Q

  27. ) z0 V/ V9 B) C6 Z! _
  28.    //USART 初始化设置
    ( P  T( j1 a3 O* ~1 l: C
  29. . d/ ]/ }# X( m/ `0 h" C( E! j, N
  30.         USART_InitStructure.USART_BaudRate = bound;//串口波特率
    7 v. f8 v5 z% ]# L
  31.         USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
      d& N5 r0 H, ]
  32.         USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位/ {7 s  O. c' Q3 l6 d
  33.         USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位5 s2 l4 F7 B3 ]. Y# F
  34.         USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
    4 U; l3 ]- U( @/ O% b! U7 ^, h
  35.         USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;        //收发模式
      o" P9 h4 Z* B! E
  36. ) l  X* K( C: a5 O0 E0 {
  37.   USART_Init(USART1, &USART_InitStructure); //初始化串口1
    4 x0 W7 j- P8 s# v9 p5 ]9 u
  38.   USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断. J; T$ A) W5 _8 I1 O
  39.   USART_Cmd(USART1, ENABLE);                    //使能串口1
    1 |, U1 }. {6 U1 m5 s+ H3 P
  40. ) A5 ~% S2 R& w/ v9 P
  41. }
复制代码
  1. #if EN_USART1_RX   //如果使能了接收3 j  z! o+ D5 U4 X9 Y! Q( m7 P
  2. void USART1_IRQHandler(void)                        //串口1中断服务程序
    . c  m' v) _+ J$ f) U
  3.         {
      p. Y7 l" r6 s- G
  4.         u8 Res;1 ?, p  K3 o0 A# w% a4 X
  5. #if SYSTEM_SUPPORT_OS                 //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.9 l: q. P& |; m2 z- N( e
  6.         OSIntEnter();   
    ( f' y2 T" P% Z# s
  7. #endif8 x* I/ c" k# A: h' c
  8.         if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
    7 H; i1 `" F1 Z4 n5 j' h
  9.                 {. g" N: y% |4 d  x
  10.                 Res =USART_ReceiveData(USART1);//(USART1->DR);        //读取接收到的数据
    % R: ?9 w2 c/ [0 Y6 _
  11.                 if(USART_RX_CNT<USART_REC_LEN)* |9 v, Z8 b2 a. n$ i& `
  12.                 {
    % x: F6 |# q& c# C3 h, q0 n& d
  13.                         USART_RX_BUF[USART_RX_CNT]=Res;
    " ]- j  X# a+ Y' p
  14.                         USART_RX_CNT++;                                                                                                      
    " ~+ a% e: j- a
  15.                 }                  
    . c  B( h0 D8 _" U! f' X5 u
  16.      } : F0 V7 h8 v& P: X* q1 j
  17. #if SYSTEM_SUPPORT_OS         //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
    6 C' F8 T. X" v  O
  18.         OSIntExit();                                                                                           - R' @( ^! B7 U
  19. #endif' M, R5 Q" Z0 F9 r  \
  20. } 6 C0 n0 V% X% k1 Q* `4 \
  21. #endif        
复制代码

% c0 n. G8 c5 y) S4 f7 S! G——uart.h 文件:3 P9 y/ q3 a# b- e/ d3 ?
4 e% c8 F; |. ^. B- _5 t- c
  1. #define USART_REC_LEN                          41*1024         //定义最大接收字节数 41K1 ?; J/ q& a9 ?0 W2 o/ A
  2. #define EN_USART1_RX                         1                //使能(1)/禁止(0)串口1接收+ Q2 Y# a  p  m& h1 J; K4 s
  3.                   0 k8 U" S- Z; U
  4. extern u8  USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 3 u8 M. y, I3 x3 h  K; e$ \
  5. extern u16 USART_RX_STA;                         //接收状态标记        % I5 a* \) @, a! k/ V6 c+ G
  6. extern u16 USART_RX_CNT;                                //接收的字节数        
    + `+ k9 d' Q0 h' n2 Q0 r& v; b8 P
  7. //如果想串口中断接收,请不要注释以下宏定义2 x) k/ f9 t+ }. p# f7 x# v0 ?

  8. 4 ^! w- N; r! V- q3 ~
  9. void uart_init(u32 bound);; {0 D* M" ?, T
  10. #endif
复制代码

! A( ~8 K. r1 M# g/ m——main.c 文件:
2 ^! H2 |( v  i( D7 e) h2 B8 s9 O; w! c
  1. int main(void)
    0 f( g; y- C0 \7 X# W
  2. {        : D8 i: [* j6 U* ?
  3.         u8 t;( m  Y* V3 Y# y+ q
  4.         u8 len;        
    ) r) y- B" d# G/ i. J5 ^/ w) n
  5.         u16 times=0; ; E- @- O$ x: ~  [) K" G) N; E

  6. ; f$ L. V7 @8 O2 d+ Z$ C' y
  7.         delay_init();                     //延时函数初始化        0 R' F. V4 v: `; U* u, m0 h
  8.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组26 Y2 o3 u: u% O2 {
  9.         uart_init(115200);         //串口初始化为115200
    0 W* u7 P  z* O2 o9 g. q. K
  10.   r- l5 k0 q& P( D& p0 M  h4 v
  11.         while(1)
    ' [' P7 |7 k* x# r+ p2 Y5 ~
  12.         {) v% w  K/ c7 ^# R7 f( o" C
  13.                 if(USART_RX_STA&0x8000)
    ' N; l7 w# m2 B2 g- x" H
  14.                 {                                          
    # k  b8 ^9 m& z' L+ o* m! \4 L
  15.                         len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
    5 S. m6 x: ~- ~0 C! s
  16.                         printf("\r\n您发送的消息为:\r\n");8 p9 R+ C* ]2 k* r" p4 i
  17.                         for(t=0;t<len;t++)$ J5 o. v4 c: a; Q2 R) F
  18.                         {9 N: {- W5 m8 c0 M. c& h: B
  19.                                 USART1->DR=USART_RX_BUF[t];
    8 x" d' I  \# T
  20.                                 while((USART1->SR&0X40)==0);//等待发送结束0 Y' }% z: i! P1 x
  21.                         }
    ; B+ G% ~6 k3 ^. P9 }: Z. O
  22.                         printf("\r\n\r\n");//插入换行
    . ~. `/ P5 D( `% A6 e5 h& e* d
  23.                         USART_RX_STA=0;, i# u  g: s4 ?0 m9 x% h
  24.                 }else
    . m' K. b9 ~3 n# W8 Q0 o
  25.                 {
    . g  \  k4 ]& I2 M9 A/ a) O
  26.                         times++;8 f% w% Y7 E* I  N
  27.                         if(times%5000==0)
    ) Y9 `2 e. b" Z/ f/ C0 e
  28.                         {
    6 f- R8 W( I. W
  29.                                 printf("\r\n串口发送与接收\r\n");; ?5 W. O1 _" b$ b
  30.                                 printf("\r\n123456\r\n\r\n");
    - i2 r6 J0 S; x# ~. ^$ L
  31.                         }
    / _9 k; S3 H; Q  m
  32.                 % o! b8 n1 {- e3 f) d% Q
  33.                         delay_ms(10);   
    6 V8 L% {) ?2 K* @. X
  34.                 }( H! B# `$ H. B( ?& y+ u
  35.         }         
    . a! J% `: }- G( o' Y
  36. }
    3 Q) ~$ m3 z; s/ k; m, j6 k
复制代码

- ]+ `- z9 T" [4 V7 ~; u4 z3 K1 |# m4 k- _

- l2 V0 _7 Y) t. X
, O# d2 u# d3 q$ C8 C. S
+ Q6 j; _/ i* s2 }/ E+ P" U5 T% M
赞 收藏 1 评论0 发布时间:2022-5-9 18:00

举报

0个回答

所属标签

相似技术帖

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