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

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

[复制链接]
STMCU小助手 发布时间:2022-5-9 18:00
前言
. L) r( L. }) @1 M* W本篇用库函数写个简单的串口收发,用的是 STM32F103RCT6 开发板(部分来自正点原子)。
$ v! ?8 W) t* \$ w; Z1 ySTM32F103RCT6 最多可提供 5 路串口,有分数波特率发生器、支持同步单线通信和半双工: g1 g2 F4 b' i4 W0 f
单线通讯、支持 LIN、支持调制解调器操作、智能卡协议和 IrDA SIR ENDEC 规范、具有 DMA2 Z/ ?5 q; [3 h( b6 i5 K; i
等。
1 M& e) W0 x0 s5 l2 G: o3 Y% E( v0 b0 s" g5 {
串口设置的一般步骤可以总结为如下几个步骤:4 ]/ _6 P, ]! x/ `6 V; {7 E# Y
- t0 N' y: i! U/ ]1 f# d# l; m
串口时钟使能,GPIO 时钟使能
! X7 g. I+ P3 x8 |串口复位
$ t# ]  s; g! r3 T% I6 s5 p& e+ X8 ^GPIO 端口模式设置
9 d* ?; e7 {  G5 Z- @串口参数初始化
: P0 O0 A. |& N2 u, k# F5 }开启中断并且初始化 NVIC(如果需要开启中断才需要这个步骤)
' \& l, ]. U0 b+ }: v$ ?( }使能串口
$ N' X$ R; R( W( i编写中断处理函数+ ?4 A/ r  P- O4 d' w5 N
一、串口配置步骤
9 X8 J: f6 j. l, @3 S函数和定义主要分布在 stm32f10x_usart.h 和 stm32f10x_usart.c 文件中。+ j1 n: [3 c+ C: x2 |8 R

0 w( f* w; v0 v' l7 r+ a1.串口时钟使能 串口是挂载在 APB2 下面的外设,所以使能函数为:' Z' s7 O! s. y
! {  w- w  v7 `( J1 q
  1. RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1);
复制代码

$ Q( j7 y* [* f% s7 @& H8 i2 f2.串口复位 当外设出现异常的时候可以通过复位设置,实现该外设的复位,然后重新配置0 p8 _% [5 L; V: C6 ~/ w
这个外设达到让其重新工作的目的。
" W# f8 f* N. t9 a6 @" P$ W8 Q+ {复位的是在函数 USART_DeInit()中完成:
  ~& `8 j7 n1 `5 b' e# `" J
/ \! I1 }. F$ d2 |
  1. void USART_DeInit(USART_TypeDef* USARTx);//串口复位
复制代码

" c) K9 S" ?+ C% O- r* o复位串口 1,方法为:
  1. USART_DeInit(USART1); //复位串口 1
复制代码

1 _6 R* w# T" g; S3.串口参数初始化 串口初始化是通过 USART_Init()函数实现的,) W- H4 H% D0 ^4 c

; U/ P3 V* w/ ~* H& G# _! L
  1. void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);
复制代码

0 q5 V$ ?/ A0 p: Q0 G/ x4 b第二个入口参数是USART_InitTypeDef 类型的结构体指针,这个结构体指针的成员变量用% L: X. {+ T. b" D/ U% ~6 L
来设置串口的一些参数。' g" m4 `4 o+ E* @5 m1 @$ ^/ X
一般的实现格式为:
  1. USART_InitStructure.USART_BaudRate = bound; //波特率;
    8 O& w( }1 U0 P$ j% \
  2. USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为 8 位数据格式
    ( Q4 G" X% D3 |/ \; t0 _* O
  3. USART_InitStructure.USART_StopBits = USART_StopBits_1; //一个停止位4 a. w% s" A8 N& P+ P) v
  4. USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶校验位' G' H9 A3 a* q4 o5 I, t
  5. USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件数据流控制9 M* j; ~6 o) w0 M5 E+ g% a& M
  6. USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式& m4 _; f! v, n3 f# x" @
  7. USART_Init(USART1, &USART_InitStructure); //初始化串口
复制代码

; Y( |' [  T5 D# S0 b. ]# v( v4.数据发送与接收 STM32 的发送与接收是通过数据寄存器 USART_DR 来实现的,这是) |, |( e: g: C8 }7 S
一个双寄存器,包含了 TDR 和 RDR。当向该寄存器写数据的时候,串口就会自动发送,当收
8 h' l* R* Z8 k! k: O; F到收据的时候,也是存在该寄存器内。
# k, V! {' A5 eSTM32 库函数操作 USART_DR 寄存器发送数据的函数是:- E  d& E  M5 \
, T/ n2 ]$ @. j; X, j2 W; M
  1. void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
复制代码

# w) o5 ?: l  L( g8 m/ aSTM32 库函数操作 USART_DR 寄存器读取串口接收到的数据的函数是:
  1. uint16_t USART_ReceiveData(USART_TypeDef* USARTx);
复制代码

8 S. p; Y( H2 K9 L6.串口使能 串口使能是通过函数 USART_Cmd()来实现的2 F8 P+ L9 Z  E& H, F0 s: t; Z
- `4 i7 A; r6 I" _- n& W+ w
  1. USART_Cmd(USART1, ENABLE); //使能串口
复制代码
! Z' e4 U. Z$ m1 e6 a! K+ ~
7.开启串口响应中断 使能串口中断的函数是:
  1. void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState)
复制代码
$ i' h1 g! n* N8 L( }  F" Z3 U
开启其中之一的中断的方法是:
! m( @* l  i2 L- f3 j: I  L; k" }$ X! I- ~! T9 X$ y4 E9 ~
  1. USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断,接收到数据中断
复制代码

  M% h7 X* \1 O1 Y发送数据结束的时候要产生中断:
3 {* g# H: e3 P4 m: h8 {
. B6 x# ]1 p3 B% |4 C+ @
  1. USART_ITConfig(USART1,USART_IT_TC,ENABLE);
复制代码
7 }3 W/ j: |. T) C; a/ H
8.获取相应中断状态 在中断处理函数中,要判断该中断是哪种中断,使用的函数是:
# o! n- Y) Z9 t: i; P. h  r& j8 |+ ~7 e( _- @
  1. ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT)
复制代码

' t4 ?+ @( f% @7 {* N2 j判断是否是串口发送完成中断:
* S1 K7 L# y. M9 d$ w
4 Z. N% \9 a, l& b# h2 S
  1. USART_GetITStatus(USART1, USART_IT_TC)
复制代码
" \- `! p9 y# l$ S
返回值是 SET,说明是串口发送完成中断发生。+ ]' O+ ]* n' J: c4 b
: H8 X( W$ W. ^7 |) }& [$ X8 y
二、实际编写! a# p  ?* n' L4 Y' O/ _
1.代码部分4 G+ Y1 I: K2 e- O8 A9 f1 y
——uart.c 文件
+ c. \* n8 Q+ ^# N2 }3 K
) e' a- j5 m( L& e# F①重定向fputc函数! a0 @5 h$ r& c* S& w7 {
使用串口1(USART1)输出Printf信息' v1 K2 F6 ~7 C% U  Z
4 K7 _4 r1 z  m( A  j. `
  1. #if 1  , [+ F8 j  k9 a9 u. p
  2. #pragma import(__use_no_semihosting)               
    & B" x0 e$ \: L2 e8 a8 I
  3. //标准库需要的支持函数                   : T3 W" }* G1 i& n7 p5 x1 \
  4. struct __FILE   / q" _! S$ n% E4 `
  5. {   
    7 t  t4 i/ r6 u$ u1 z7 w
  6.     int handle;   
      y5 j# I2 t5 k& ^
  7.     /* Whatever you require here. If the only file you are using is */   
    7 L# F1 R6 I+ l) x! ~
  8.     /* standard output using printf() for debugging, no file handling */   : i9 d! C% K3 `$ k5 l" _1 ?
  9.     /* is required. */   
    ) c4 }6 A: y5 A  H: y; M  G
  10. };   ) n5 U# p' {6 a* _' P  s8 q
  11. /* FILE is typedef’ d in stdio.h. */   
      q) H# h2 w+ L7 B
  12. FILE __stdout;         9 u/ H6 f& [+ P; G& S: e
  13. //定义_sys_exit()以避免使用半主机模式      : r$ V$ {: z# V; U) K7 n
  14. void _sys_exit(int x)   9 z% J) K% e1 A) z& B
  15. {   2 {7 E! K% M  o" F# T( C
  16.     x = x;   8 `: h, R9 i8 ]: H$ ~
  17. }   
    ' E5 f& {$ J0 `) t- [
  18. //重定向fputc函数  ; I& k! y5 R0 J: f
  19. //printf的输出,指向fputc,由fputc输出到串口  
    + j& a; N" {* i/ P
  20. //这里使用串口1(USART1)输出printf信息  
    - ~6 M- x3 d0 A$ f; a8 w
  21. int fputc(int ch, FILE *f)  
    ! M' V1 @8 f% r4 J
  22. {        ( S! q. B8 I; i# J
  23.     while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
    5 d, D& A7 Z3 p( F, }! ]  D
  24.     USART1->DR = (u8) ch; / J  ^0 O+ b# |! `
  25.     return ch;  " r7 u; r. M& Q9 J
  26. }  
    3 w0 M# d/ K; v4 E
  27. #endif
复制代码
5 o6 p8 T  O, B9 d8 _' x
②GPIO
, f% s  x# G/ B5 z& r9 E/ P8 \
  1. u8 USART_RX_BUF[USART_REC_LEN] __attribute__ ((at(0X20001000)));7 i3 d/ S- V* E3 G- T, C
  2. //接收缓冲,最大USART_REC_LEN个字节,起始地址为0X20001000." ]0 W2 Q3 N. \' T* K. h, [) D0 F- _
  3. u16 USART_RX_STA=0;       //接收状态标记         
    - p1 ^# T% o) k1 C
  4. u16 USART_RX_CNT=0;                        //接收的字节数         
复制代码
  1. void uart_init(u32 bound){
    * `7 t# C+ R  j7 S; y3 s
  2.   //GPIO端口设置(初始化)
      y8 i" u) p) N8 s0 E) H
  3.     GPIO_InitTypeDef GPIO_InitStructure;
    3 @1 Y- w: Z- ?0 q% W/ `  F8 V
  4.         USART_InitTypeDef USART_InitStructure;* G/ s& u% E, \5 B' P. X* o" R
  5.         NVIC_InitTypeDef NVIC_InitStructure;' X1 K! k' S, R0 Y, j+ M
  6.          
    5 T% P& J( ?8 \0 {% C
  7.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);        * H& K/ A5 B& `( G; A+ S% G3 P
  8.         //使能USART1,GPIOA时钟
    7 B) i3 H# U* D& a

  9. $ o1 N$ P0 V1 I
  10.         //USART1_TX   GPIOA.9; @( Q- J  ~5 q8 T- }
  11.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
    ( H# e4 I: J: }4 @; a+ |2 s* S$ O" j
  12.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;2 g) s* F5 _3 @6 V. J6 i8 I
  13.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        //复用推挽输出
    5 H0 Q% \7 |, K$ ?$ @
  14.   GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
    : R) _  A' w8 `2 A3 P0 I
  15. - }( e" l0 p% A9 x7 j0 e% m* }) x
  16.   //USART1_RX          GPIOA.10初始化
    ! G' V8 p1 I0 l! J; A. E
  17.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10' c8 R$ b, c" W) X, t
  18.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入! A! L0 Q% m  ~/ T
  19.   GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10  
    8 J& d- H" h9 @5 D2 w
  20. / x3 h! i' Z8 p: X0 l0 h) Q8 D: s
  21.   //Usart1 NVIC 配置
    $ g# f. C" b! ?3 W" K, i' r* A0 o
  22.     NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;; N& R" N' c2 h8 i
  23.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
    # q  X& `, H! S3 X
  24.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;                //子优先级3/ U/ t6 ?/ \0 u$ u
  25.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                        //IRQ通道使能2 j  {! G0 ?* |& y4 @
  26.         NVIC_Init(&NVIC_InitStructure);        //根据指定的参数初始化VIC寄存器' F& F, b/ G6 L, o

  27. + ]. |+ x4 @3 Z6 ?
  28.    //USART 初始化设置
    8 V* Q3 {% B; ?2 P# P% s' y
  29. 5 H6 x! d( V( }- I: R: C
  30.         USART_InitStructure.USART_BaudRate = bound;//串口波特率( V3 u7 M" T9 E# @. ^: a
  31.         USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式5 ~; I1 r- Y8 u. y! l
  32.         USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
    + q* j" A5 p4 g/ `& c
  33.         USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
    ' t1 N5 }8 E/ E! G
  34.         USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制8 H$ }. M" j$ O/ g  m  X
  35.         USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;        //收发模式
    ! L$ ~) Z+ b( d: p

  36. % s$ v; m- j! x* l% R' y! i
  37.   USART_Init(USART1, &USART_InitStructure); //初始化串口1
    * ]6 h# e* P. A1 z9 ^' ?; L
  38.   USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
    1 H  R0 o6 y% T
  39.   USART_Cmd(USART1, ENABLE);                    //使能串口1
    6 X/ ~  C3 A1 e8 L; @

  40. + A( _* r( ^$ d. x. @7 i- H0 \
  41. }
复制代码
  1. #if EN_USART1_RX   //如果使能了接收
    6 X7 J  d; z2 J8 D
  2. void USART1_IRQHandler(void)                        //串口1中断服务程序8 e7 B# s0 ?+ n+ Q" o
  3.         {
    - y) C$ j" l0 a/ a
  4.         u8 Res;  }1 q: ^: I3 u
  5. #if SYSTEM_SUPPORT_OS                 //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
    * G2 F2 ?) c' K" D
  6.         OSIntEnter();   
    ; \/ V* ^: T0 S  h0 l/ O
  7. #endif
    ; ]/ x2 ~4 X; P& C
  8.         if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)9 F/ D- ]  }4 R
  9.                 {
    4 i8 y/ b! V6 e: o8 q! K- H0 R
  10.                 Res =USART_ReceiveData(USART1);//(USART1->DR);        //读取接收到的数据  F" O: o' f9 @$ e
  11.                 if(USART_RX_CNT<USART_REC_LEN)
    ! f2 V) X6 [) z3 V1 M& B
  12.                 {4 `, _7 m% J1 g
  13.                         USART_RX_BUF[USART_RX_CNT]=Res;( C5 x2 [& H) @* q
  14.                         USART_RX_CNT++;                                                                                                      1 _" \) f0 z; L8 G! b3 ?9 Z! d, D
  15.                 }                  
      w# a1 L2 r& Y( D% P+ R
  16.      } 0 l7 [3 ?: p$ Z. _. N6 A
  17. #if SYSTEM_SUPPORT_OS         //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
    - q! ~$ T) Z; ?7 o' @
  18.         OSIntExit();                                                                                          
    0 b3 z" \; D0 H3 H. B. g
  19. #endif
    5 \7 `- m" k" t' M
  20. }
    . ~+ F4 @1 J( T$ @6 h2 P( M
  21. #endif        
复制代码

# R  B5 t; n6 [( J' L& G8 ?——uart.h 文件:  ^  T- c3 }2 v

- t) L3 {5 V" P9 E
  1. #define USART_REC_LEN                          41*1024         //定义最大接收字节数 41K
    ' g! ?' B$ U" @% Q0 N
  2. #define EN_USART1_RX                         1                //使能(1)/禁止(0)串口1接收9 `$ d* Q* T. ]* T( |) x. ]" G
  3.                   
    * L" U$ x4 Y, k) g5 O( l
  4. extern u8  USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
    ' C: L4 M+ `! ?, q0 b
  5. extern u16 USART_RX_STA;                         //接收状态标记        7 G: V: Z* k* ~( `. F. h- H2 i
  6. extern u16 USART_RX_CNT;                                //接收的字节数        
    9 W3 G5 Y+ h/ r5 K) d
  7. //如果想串口中断接收,请不要注释以下宏定义- \( ^) S* J* Q4 }- T6 C6 }
  8. ) O- n/ r& j: _8 d: ~, m
  9. void uart_init(u32 bound);# ?& `3 P% A3 P9 l& p, O/ @
  10. #endif
复制代码

3 K- M$ Z3 m  x4 l. u——main.c 文件:
: r" J' R/ A( L& K! ]: P# F) m- G# a
  1. int main(void), w+ R/ Z, \: g. W) M  }0 I$ ~' @
  2. {        
    % q+ C6 S: M8 F2 _# p
  3.         u8 t;
    $ ^( ?! p' i3 w; [5 G: F, E
  4.         u8 len;        
    9 E5 T1 W: l8 e- o; l
  5.         u16 times=0;
    $ N% K2 B% c& W

  6. ' N( m* o2 ~2 B& l1 j* B
  7.         delay_init();                     //延时函数初始化        
    ! n; g, ?' d- V
  8.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组27 _" B, U* [! h% W
  9.         uart_init(115200);         //串口初始化为115200
    & Q/ w4 X) F# V. _* _5 Q3 b

  10. 6 a9 U% M) \, }6 e. m' K
  11.         while(1)4 o, p4 N3 D# a
  12.         {
    $ [9 W+ ^6 R9 N# \+ l
  13.                 if(USART_RX_STA&0x8000)
    ; c1 n- G, Z: x! D: ?
  14.                 {                                          
    5 }: A, @$ z0 z4 z6 g8 \0 k4 H
  15.                         len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
    ; V1 g+ J4 V) d) g* H
  16.                         printf("\r\n您发送的消息为:\r\n");
    - ]! [8 K/ q& [0 ^
  17.                         for(t=0;t<len;t++)0 m' @  T* m1 y, u5 ]
  18.                         {6 [! R. I& f' i  r3 e
  19.                                 USART1->DR=USART_RX_BUF[t];2 A6 J8 g* r$ H! }
  20.                                 while((USART1->SR&0X40)==0);//等待发送结束3 Z7 M* c; i- G, Y
  21.                         }
    % n. _2 N/ t$ w1 ~
  22.                         printf("\r\n\r\n");//插入换行! B% r2 h$ s% v1 M$ E5 H
  23.                         USART_RX_STA=0;0 ~$ w! s& I8 B% L) s9 r( `
  24.                 }else0 F3 b2 c5 ]- Q% D1 A& B( ]
  25.                 {
    & [" j$ L* u, D8 y
  26.                         times++;3 N# x* D/ F0 l% W6 ^6 ~
  27.                         if(times%5000==0)
    & C! g5 A; ~  ~
  28.                         {
    % C$ j! j: |7 r7 Y$ D% L  ?
  29.                                 printf("\r\n串口发送与接收\r\n");0 }& [) @/ @/ `) ]/ l2 R
  30.                                 printf("\r\n123456\r\n\r\n");7 s% ~. e) W/ \5 a& [  ~* Q
  31.                         }9 f6 R' I3 K) K6 Z
  32.                
    0 t3 h$ q, F" w, Z
  33.                         delay_ms(10);   6 O) [6 p% m% `4 R# ?/ }
  34.                 }
    ; }3 _. E" \' F! e9 ~+ _
  35.         }         
    * T5 U; {" i7 V; ]( K1 P
  36. }% E9 u; v/ K$ ?% n) A
复制代码
1 {7 `) B/ k' O) R2 D$ @) M

. \! o" Q' @5 T2 y/ f1 H
. F. v1 c* y( I+ M9 d, m8 W" r; |, Q4 `: j2 l/ b& s& T! H) x
  ]$ H9 h- D/ K9 S$ K6 z% i: ]
收藏 1 评论0 发布时间:2022-5-9 18:00

举报

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