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

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

[复制链接]
STMCU小助手 发布时间:2022-5-9 18:00
前言
! s* [' v( B9 L1 _* v, v  @本篇用库函数写个简单的串口收发,用的是 STM32F103RCT6 开发板(部分来自正点原子)。9 P+ ^9 S/ M* S  J9 b  X6 \5 O
STM32F103RCT6 最多可提供 5 路串口,有分数波特率发生器、支持同步单线通信和半双工& `3 K5 h) I% |
单线通讯、支持 LIN、支持调制解调器操作、智能卡协议和 IrDA SIR ENDEC 规范、具有 DMA
5 y5 p5 z# y5 c2 v& u1 T等。0 F) I1 [2 x  l1 {' Z

% N4 u1 t, \+ S0 Y5 ~( n/ U& j串口设置的一般步骤可以总结为如下几个步骤:* k7 Z  j/ d( O+ S3 B5 d  e* ]8 b1 @

7 K" ]& }, L' d串口时钟使能,GPIO 时钟使能* d/ M6 H7 z) N, u$ O
串口复位# N: s: x$ _$ j4 L5 g
GPIO 端口模式设置
9 |% I& E0 l) r( n串口参数初始化9 R0 n" {" @2 z% x* j
开启中断并且初始化 NVIC(如果需要开启中断才需要这个步骤)
$ o$ _" E" a' F. N* N0 I. Y使能串口+ M# W' t# }5 ?
编写中断处理函数
$ i  n0 ]  u# n5 j8 Z一、串口配置步骤
. O$ p! g$ x* Z# I函数和定义主要分布在 stm32f10x_usart.h 和 stm32f10x_usart.c 文件中。
  y' u5 |. @! _0 H$ Y0 |' }+ Y$ F- l
1.串口时钟使能 串口是挂载在 APB2 下面的外设,所以使能函数为:
0 Y8 Q6 W  X0 V- ?& `9 S+ N' H- X0 Q
* W( ]/ l) G/ O- L- j
  1. RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1);
复制代码

8 B) ~6 j* u0 i5 ^( ]/ H" \9 i2.串口复位 当外设出现异常的时候可以通过复位设置,实现该外设的复位,然后重新配置
" L1 T. b, ]2 A7 W: G3 c  E% t这个外设达到让其重新工作的目的。: }4 A% [3 Y/ E5 @
复位的是在函数 USART_DeInit()中完成:9 B; e1 ?: q: c, o* u4 n$ L& [) K# b

4 r& R7 ~. s, |0 _
  1. void USART_DeInit(USART_TypeDef* USARTx);//串口复位
复制代码

/ g. H1 F& A1 N2 e* s/ e+ l复位串口 1,方法为:
  1. USART_DeInit(USART1); //复位串口 1
复制代码

3 {6 m0 J3 t6 D& Z3 F0 b3.串口参数初始化 串口初始化是通过 USART_Init()函数实现的,
2 j# K& x+ Q# X$ D3 x) N6 I, d
2 {" c, D. E" ~$ b$ d
  1. void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);
复制代码

4 I2 j3 d1 n; y+ n8 O/ u第二个入口参数是USART_InitTypeDef 类型的结构体指针,这个结构体指针的成员变量用& ?6 @0 m$ }$ F) S$ k2 _
来设置串口的一些参数。2 b6 r5 O) Z. i8 M  b( k' ^
一般的实现格式为:
  1. USART_InitStructure.USART_BaudRate = bound; //波特率;7 @! p0 @" _" `' L; B1 j
  2. USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为 8 位数据格式- B' K* \7 O3 i, L
  3. USART_InitStructure.USART_StopBits = USART_StopBits_1; //一个停止位- @; y6 C7 B5 d. \6 {, E7 T
  4. USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶校验位
    ' f. E4 T0 n* Q: S
  5. USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件数据流控制
    7 ?6 b8 g9 j5 c& E0 x; ^  y7 h
  6. USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式; ~; V0 r* ]8 R) H0 n. A  r3 O
  7. USART_Init(USART1, &USART_InitStructure); //初始化串口
复制代码

8 k* F7 O/ q0 e1 v6 F# B5 d4 e3 D4.数据发送与接收 STM32 的发送与接收是通过数据寄存器 USART_DR 来实现的,这是: L, u! D% M+ Y! v, A
一个双寄存器,包含了 TDR 和 RDR。当向该寄存器写数据的时候,串口就会自动发送,当收
& T. f5 F4 J" h! s9 H; t/ m% ~2 `到收据的时候,也是存在该寄存器内。% C* L! g( J' J) w5 {0 ]. O
STM32 库函数操作 USART_DR 寄存器发送数据的函数是:3 m- f# M$ r, j! F" G# P# h
- v" N( V9 e, b8 Z) ~$ v
  1. void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
复制代码

- E8 z" O0 v: O. X5 dSTM32 库函数操作 USART_DR 寄存器读取串口接收到的数据的函数是:
  1. uint16_t USART_ReceiveData(USART_TypeDef* USARTx);
复制代码
) {* a( P6 T) o
6.串口使能 串口使能是通过函数 USART_Cmd()来实现的
2 J% Y" G; k# N# i6 r3 {$ Q# D6 j. X) I. i
  1. USART_Cmd(USART1, ENABLE); //使能串口
复制代码

- g6 X1 p7 K0 C8 d* N2 M* `+ s7.开启串口响应中断 使能串口中断的函数是:
  1. void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState)
复制代码
5 ^  g% }: z/ P/ @) q8 v
开启其中之一的中断的方法是:8 F, L3 S9 y6 y" q

  @; e; S- j5 t1 o- }0 R9 z# M
  1. USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断,接收到数据中断
复制代码

) c: b9 t! X+ E* k! ^5 {6 B  B- j% o: L发送数据结束的时候要产生中断:  \9 E2 G2 N1 G7 l
! t) H. v% _* _% O0 E
  1. USART_ITConfig(USART1,USART_IT_TC,ENABLE);
复制代码
0 f  C6 o& k% T, T0 ?$ o/ d
8.获取相应中断状态 在中断处理函数中,要判断该中断是哪种中断,使用的函数是:9 z8 n% P- V/ u4 @* z) g
0 V$ B( U3 z7 t  n% y6 h- s
  1. ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT)
复制代码
$ f" i. f2 ~5 ?0 o7 o
判断是否是串口发送完成中断:
6 G4 g/ X0 S4 Z3 e* ?7 B% \0 i& h3 [2 N" I; |
  1. USART_GetITStatus(USART1, USART_IT_TC)
复制代码
6 O" y3 D8 B! F/ O% y
返回值是 SET,说明是串口发送完成中断发生。( w3 G; ], S4 s( ?

, m/ ]& \3 b6 c* Y( ^  L  ~二、实际编写& j/ B, j, V" Z- s. g
1.代码部分8 G+ k( s% k* ?2 W' A
——uart.c 文件; S7 v9 O% m0 G# T% F# [
$ h3 r( P# d% @! h1 I/ S" e  [
①重定向fputc函数# V& K; ?, ]0 G9 b+ J
使用串口1(USART1)输出Printf信息
  b* F4 m1 j/ h$ E0 w
* K  s2 V) f# S, a2 w
  1. #if 1  2 F& s! ]7 a" ~* T( d+ L: F
  2. #pragma import(__use_no_semihosting)               
    - Q7 H5 I9 H8 z
  3. //标准库需要的支持函数                   0 i6 d+ A2 x9 B0 B# {7 O
  4. struct __FILE   
    . @" \" A8 D: _& L
  5. {   
    * U0 b# p7 g- Q/ k6 Z5 B, j
  6.     int handle;   
    9 @) x# x# B8 \
  7.     /* Whatever you require here. If the only file you are using is */   6 K* ^: h+ G2 V" s/ L  o% }
  8.     /* standard output using printf() for debugging, no file handling */   $ o5 B* K; f: w( I! ]( E1 p
  9.     /* is required. */   
    : m7 ?: Z! R) R1 X3 Q  [
  10. };   , w2 \1 A2 q; J( u% I
  11. /* FILE is typedef’ d in stdio.h. */   
    0 {. v2 [: {/ o5 U8 ~0 x
  12. FILE __stdout;         
    : d4 ]# a7 J) e& o; z
  13. //定义_sys_exit()以避免使用半主机模式      ) G& z7 k, _3 _" P2 ]0 [% L) P5 W
  14. void _sys_exit(int x)   7 o4 F; l. v7 A* z; T
  15. {   
    # [0 E+ }* v6 Y7 u
  16.     x = x;   / E# L9 |6 W" O1 L
  17. }   
    , C, L. m+ |  o" G" r$ c
  18. //重定向fputc函数  $ i! [  @3 t9 s! y! K
  19. //printf的输出,指向fputc,由fputc输出到串口  
    0 q( b4 s3 g' N( Q: |; C. ^
  20. //这里使用串口1(USART1)输出printf信息  + }8 s6 ~$ r; x- R, u
  21. int fputc(int ch, FILE *f)  
    9 P2 q0 D: P) F7 N* t. T0 |9 [1 S
  22. {        8 S0 m5 R% h& }9 R3 N
  23.     while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
    % Z3 ~2 Y9 H6 a; X, h- A" c
  24.     USART1->DR = (u8) ch;
    " m2 o' j: S; b5 T/ y+ Q
  25.     return ch;  % `( Q/ U! L- i$ `" r8 D$ e
  26. }  , F7 ^" R5 |2 C4 _9 x4 Q
  27. #endif
复制代码
1 t" [5 w$ m% X# y8 L- }
②GPIO
" h7 D0 K. E; W( A
  1. u8 USART_RX_BUF[USART_REC_LEN] __attribute__ ((at(0X20001000)));
    " w$ u) W* M* T3 s1 l3 j% j1 H  Y' D! g
  2. //接收缓冲,最大USART_REC_LEN个字节,起始地址为0X20001000.# n' O$ H. z* a& O) z$ v
  3. u16 USART_RX_STA=0;       //接收状态标记         # U, u* `9 k& F+ ], ^; ]
  4. u16 USART_RX_CNT=0;                        //接收的字节数         
复制代码
  1. void uart_init(u32 bound){
    % p: ~1 r8 ~3 X$ B& a& z
  2.   //GPIO端口设置(初始化)
    8 Q/ H9 c2 f3 B' n) `4 s0 t
  3.     GPIO_InitTypeDef GPIO_InitStructure;
    " z$ s4 b+ X, u3 n# O
  4.         USART_InitTypeDef USART_InitStructure;& T, i. {* G5 Z  V; v- a
  5.         NVIC_InitTypeDef NVIC_InitStructure;/ q  ^4 l: s5 z5 K4 r) z, @" n
  6.          ) ?6 V9 Q. R2 S, ?& Z
  7.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);        + x( N/ |* r3 g* V
  8.         //使能USART1,GPIOA时钟
    4 K" b- ?4 V, G9 C
  9. # L. z: w. l# K/ [* g
  10.         //USART1_TX   GPIOA.9
    + X3 J% T* b, V- k( _
  11.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
    7 p; k7 r$ j8 I1 y2 _9 d
  12.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    % M; V$ W  o' P7 R1 l2 m
  13.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        //复用推挽输出& c: ?% x  d  T
  14.   GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.93 K4 [% F( z1 z3 \* \! t0 Q
  15. & U4 P% j+ j* F0 `
  16.   //USART1_RX          GPIOA.10初始化
    " G+ ]; r# @. Z% ]/ x  }- m
  17.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA101 w1 u" d3 Y  h
  18.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
    " t9 g0 C8 T, ?7 K* N
  19.   GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10  
    ! z# S2 _, y/ ~# w  \- C; C! v4 I

  20. - N; s3 Z0 X$ Q& ~
  21.   //Usart1 NVIC 配置: H/ K5 ^; `7 E9 O, d4 `5 r1 v0 [
  22.     NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;4 T6 @" I* f6 B+ K! s
  23.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3% q5 R$ S4 |6 X* ~; a. k4 w2 @' b
  24.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;                //子优先级33 z4 \8 m8 Q9 K
  25.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                        //IRQ通道使能; c. O6 D" d  `, F! M4 j2 N& Y
  26.         NVIC_Init(&NVIC_InitStructure);        //根据指定的参数初始化VIC寄存器
    . O2 z, Z  s% P+ w
  27. . y/ ^5 j% |! J: Z- t% b
  28.    //USART 初始化设置
    / M: `6 z4 m1 W9 z4 D7 R
  29. ; [% ^# [% n, z- b2 R- F- m/ y
  30.         USART_InitStructure.USART_BaudRate = bound;//串口波特率
    - x4 E+ \3 s& O2 g2 C1 N; X
  31.         USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
    / g' k# k+ U1 E! I3 v: N( S
  32.         USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
    3 n3 U+ E6 _* {4 H9 E7 F
  33.         USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位% o2 q5 U! Y, w; |4 k; ]8 Y$ W6 ~
  34.         USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制( y% f/ ~+ h5 o, w" x
  35.         USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;        //收发模式
    - y% v6 L7 E# p6 q# ^. l- j3 Y

  36. 9 J/ _; Q, o. m  V& [  P, x$ P
  37.   USART_Init(USART1, &USART_InitStructure); //初始化串口1
    $ c/ N: V+ j* k, F( J
  38.   USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
    * g0 H5 m% K# e+ z8 o. j& E. J
  39.   USART_Cmd(USART1, ENABLE);                    //使能串口1
    $ p% L1 U5 h3 y

  40. # Y# Y0 }5 M" w% u3 f3 c
  41. }
复制代码
  1. #if EN_USART1_RX   //如果使能了接收  H/ _$ z% T* X
  2. void USART1_IRQHandler(void)                        //串口1中断服务程序; G  @$ r1 u4 R- I
  3.         {( x5 e9 q& h1 O& g4 N3 @
  4.         u8 Res;
    7 i; k# X- p+ ~9 J7 n  j: X
  5. #if SYSTEM_SUPPORT_OS                 //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.7 W4 E3 [4 H0 f  g6 e/ U* Z1 g( C7 K
  6.         OSIntEnter();    ! E% J$ ~* ^- Z" E
  7. #endif
    ( V2 U7 v; o5 b' r
  8.         if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
    & [% I- k1 J0 j5 [3 A4 r* W
  9.                 {
    2 U' ?4 A- B# h. h& p5 K% Z+ q; s
  10.                 Res =USART_ReceiveData(USART1);//(USART1->DR);        //读取接收到的数据
    8 w$ a' R# k. ?! t( a
  11.                 if(USART_RX_CNT<USART_REC_LEN)" `" Q1 `2 P4 A( [5 D4 R$ S
  12.                 {
    1 j) F* y" ~$ H' @( f; e1 n+ j/ B
  13.                         USART_RX_BUF[USART_RX_CNT]=Res;' S4 \% O% N! P" u. o6 J3 B
  14.                         USART_RX_CNT++;                                                                                                      
    9 g& ^, L3 t/ G( ^8 c6 z( q
  15.                 }                  
    * O& E, v' q2 K6 s" k0 K
  16.      }
    7 |: T2 g$ ~4 U. J; i3 Y, S" `( X
  17. #if SYSTEM_SUPPORT_OS         //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.# |! f; w3 P4 a' M
  18.         OSIntExit();                                                                                           - e- f) p; n! W+ ?; X8 O
  19. #endif
    & E4 L& \. r# J. [
  20. }
    : ]9 w' x( k) B6 y# N
  21. #endif        
复制代码
* O3 Y# x5 M( g8 E& [/ A" O& U0 W
——uart.h 文件:; t' E8 u% {1 t# V+ m: S3 a
9 s2 m  @& n( O7 T4 O* j7 g; {  ?
  1. #define USART_REC_LEN                          41*1024         //定义最大接收字节数 41K6 ^* ~8 M5 A5 ^. P) \! V9 ^" E/ _% G
  2. #define EN_USART1_RX                         1                //使能(1)/禁止(0)串口1接收
    # w0 A3 x1 r8 I9 e
  3.                   - A% s! v2 E; w. F# H0 L
  4. extern u8  USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
    5 Q$ ?' Q$ L# R" y' q
  5. extern u16 USART_RX_STA;                         //接收状态标记        
    6 W: m+ D) D2 v5 }  q8 ~+ c
  6. extern u16 USART_RX_CNT;                                //接收的字节数        
    5 }8 T* U% }2 q. k/ t
  7. //如果想串口中断接收,请不要注释以下宏定义
    + ?. H8 `; o9 M5 W. d3 \

  8. . P6 |/ N$ C; P& }! g
  9. void uart_init(u32 bound);
    . ^* }- O# N! v0 H7 u! N! }4 B0 ?
  10. #endif
复制代码
9 g: X6 A: p' g3 i4 M9 P
——main.c 文件:
' h) c4 R/ n8 j. _/ c$ k1 h; h& u8 ~3 S
  1. int main(void)7 |& A2 e6 Y6 p; }3 T* Q4 f2 d
  2. {        & z: g* G) R. C- ]) |* }
  3.         u8 t;2 ~' Q( I4 K  J, d  S; n+ I6 u/ F
  4.         u8 len;        
    $ P) t7 S1 X. i0 X4 \# O
  5.         u16 times=0; 3 `5 A, S" q5 N: {# p% l6 r$ |! o
  6. 3 y, i% D$ s( [! E
  7.         delay_init();                     //延时函数初始化        
    ) [2 U; Y% s/ [, @& J; D" c
  8.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
    " L9 ~& w: V2 n3 i. e$ T" q
  9.         uart_init(115200);         //串口初始化为1152002 S! x! `- a; A7 v5 ]( }
  10. 1 s7 ?  y! c: f: W) w4 w
  11.         while(1)
    1 @9 f+ }$ K( }& g% W# @& b
  12.         {! g. _; v# ?$ N' E7 |# U
  13.                 if(USART_RX_STA&0x8000). Z& Q; t/ u6 |3 z
  14.                 {                                           $ k2 s9 ]$ w% f" X! A9 s1 w
  15.                         len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度+ s6 m& F3 K0 M, b; K' M9 B
  16.                         printf("\r\n您发送的消息为:\r\n");  r) ~" n2 P; f9 }& |
  17.                         for(t=0;t<len;t++)% H# q3 e. [2 V# P8 z# E
  18.                         {
    1 ^( q# Z8 R6 q, _
  19.                                 USART1->DR=USART_RX_BUF[t];( D! Q# h6 i/ A8 v3 g' X
  20.                                 while((USART1->SR&0X40)==0);//等待发送结束/ g. {3 A# y- G$ j6 P
  21.                         }
    % ]2 N9 d/ D7 }7 m/ \
  22.                         printf("\r\n\r\n");//插入换行- F2 J/ _' t0 ^0 T# D* x7 |
  23.                         USART_RX_STA=0;2 q' }. `* e8 T
  24.                 }else
    ! S$ p; E! p" `! X3 b
  25.                 {
    1 T: R% _3 ]5 M% x9 c8 v5 Y
  26.                         times++;
    : G) r/ U1 `0 S; O2 h' H2 y
  27.                         if(times%5000==0)! d9 ~# u% H2 N3 a. J
  28.                         {) p* Y' V, ^& T( O' w8 C
  29.                                 printf("\r\n串口发送与接收\r\n");
    ) n3 D5 ?, J+ N7 ]( Z
  30.                                 printf("\r\n123456\r\n\r\n");
    , x: _2 z( }6 N: g/ S: u
  31.                         }
    + a- J2 U6 h) d1 P8 j8 c5 h2 v
  32.                
    ( v0 U: ~! ^2 y
  33.                         delay_ms(10);   
    : i8 _* h6 M1 B! g
  34.                 }% o/ t, h  G$ i2 b# t
  35.         }         
    9 J2 L( N! x, Y7 n. K* K+ {
  36. }
    " R/ i" |" o* `9 x& h& `
复制代码

/ Z! U3 |, o7 q, Y
2 ]) p' ]0 K5 \5 v1 n* A) b
/ s: c, m# A" v9 J' R
; k$ O$ }3 Z) |, U: O
  y+ ?  q' B) x; Y! T
收藏 1 评论0 发布时间:2022-5-9 18:00

举报

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