stm32F103C8T6标准库串口接收之中断方式2

目录

  • 1.阻塞模式接收数据的影响
  • [2.DEBUG 中断配置](#2.DEBUG 中断配置)
  • [3. 开启串口中断函数理解](#3. 开启串口中断函数理解)
  • [4. 配置中断回调函数](#4. 配置中断回调函数)
  • [5. 代码](#5. 代码)
    • [5.1 bsp_debug.h](#5.1 bsp_debug.h)
    • [5.2 bsp_debug.c](#5.2 bsp_debug.c)
    • [5.3 usart_com.h](#5.3 usart_com.h)
    • [5.4 usart_com.c](#5.4 usart_com.c)
  • 6.实验现象

1.阻塞模式接收数据的影响

根据上一节所学的,通过上位机给stm32C8T6发送数据,然后stm32C8T6接收数据后,重新发送回来,例如运行结果如下。

当我在上位机下面发送框给stm32C8T6发送数据123456789时候,stm32C8T6接收到数据后重新将数据123456789发送回来给上位机,上面框框是上位机接收到的数据。

但是这是在非阻塞模式下进行发送的数据,是正常的,我发送123456789后,单片机接收到,然后重新返回,9个字节数据,单片机每次只能接收一个字节数据,相当于它接收了9次,发送给上位机9次,数据正常,9个数据完全接收到了。

但是在另外一种情况下,在阻塞的情况下,当我在上位机向单片机发送123456789的时候,如果我已经发送过来数据了,但是单片机可能执行别的事情,比如延时3秒钟阻塞呀,这件事情的时候,就会出现数据接收不正确情况,这个是因为当我发送123456789的时候,可能在发送1的时候,1成功接收,但是发送2的时候,可能在阻塞里面了,会把那个2丢失,从而只能接收3,就是说当我吧发送的数据123456789的时候,中间可能有部分的数据会丢失,无法收到。

代码如下:

c 复制代码
/**
  ******************************************************************************
  * @file    main.c
  * @author  作者
  * @version v1.0
  * @date    2026.6.8
  * @brief   串口接收之中断方式标准库写法
  ******************************************************************************
  * @attention
  *
  * 版权声明
  *
  ******************************************************************************
  */
#include "main.h"
#include "led/bsp_gpio_led.h"
#include "systick/bsp_systick.h" 
#include "key/bsp_gpio_key.h"
#include "debug/bsp_debug.h"
#include "stm32f10x.h"
#include "usart/usart_com.h"
#include "delay/bsp_delay.h"

/**
  * @brief  主函数
  * @param  无
  * @note   无
  * @retval 无
  */

int main (void)
{   
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
    LED_GPIO_Config();
    KEY_Init(&key1_info);
    DEBUG_USART_Init();
    
    ProgramRunLed_TaskInit(500);
    Key_TaskInit(20);
    SysTick_Init();
    
    while(1) 
    {
        
        /* 程序正常指示灯 */
        ProgramRunLed_Task();
        
        /* 按键长短触发灯 */
        Key_Task();
        
        /* 数据回显 */
        if (USART_GetFlagStatus(DEBUG_USARTX, USART_FLAG_RXNE) == SET)
        {
            uint8_t data_temp = USART_ReceiveData(DEBUG_USARTX); //读取数据寄存器,读取后对应的寄存器会被复位 
            USART_SenByte(DEBUG_USARTX, data_temp);
            USART_ClearFlag(DEBUG_USARTX, USART_FLAG_RXNE);      //清除接收标志位
        }
        Rough_Delay_Ms(50);
    }
}

实验现象

当我在代码里面加一个短暂延时50ms,进行阻塞时候,进行在上位机发送数据,我对123456789重复多次发送,大部分时候出现的是单片机只接收到了1,并且吧1返回给上位机,个别的时候,接收到了12和17,这是因为我发送123456789的时候,由于有短暂的阻塞50ms,导致数据接收不正确,导致数据接收过程中丢失,就是在接收别的数据的时候,可能因为阻塞的时候,导致没有接收到。

所以串口接收的时候采取的是非阻塞方式下,接下来学习串口中断方式去接收数据。

2.DEBUG 中断配置

中断函数配置

c 复制代码
/**
  * @brief  配置 DEBUG 中断配置
  * @param  无
  * @retval 无
  */
void DEBUG_NVIC_Config()
{
    // 定义一个 NVIC 结构体
    NVIC_InitTypeDef nvic_initstauct = { 0 };
    
    /* 开启 AFIO 相关时钟 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); 
    
    /*配置中断源*/
    nvic_initstauct.NVIC_IRQChannel                   = DEBUG_IRQ;
    /*配置抢占优先级*/
    nvic_initstauct.NVIC_IRQChannelPreemptionPriority = 1;
    /*配置响应优先级*/
    nvic_initstauct.NVIC_IRQChannelSubPriority        = 0;
    /*开启中断*/
    nvic_initstauct.NVIC_IRQChannelCmd                = ENABLE;
    
    // 把配置写入硬件,生效
    NVIC_Init(&nvic_initstauct);
}

中断部分宏定义

c 复制代码
#define DEBUG_IRQ          USART1_IRQn                 /*外部中断向量号*/
#define DEBUG_IRQHANDLER   USART1_IRQHandler           /*中断处理函数*/

USART1_IRQn是在stm32f10x.h中

这个是中断号。

还有中断处理函数名字跟中断号前面一样,后面加了Handler, USART1_IRQnHandler。

3. 开启串口中断函数理解

c 复制代码
void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState)

这个函数是在stm32f10x_usart.h里面

有三个参数,

第一个参数选择的是哪一个串口,有串口1,串口2,串口3,那么我们用的是哪一个串口就选择哪一个串口

第二个参数选择的是哪一个中断源,有以下中断源选择

@arg USART_IT_CTS: CTS change interrupt (not available for UART4 and UART5)

@arg USART_IT_LBD: LIN Break detection interrupt

@arg USART_IT_TXE: Transmit Data Register empty interrupt

@arg USART_IT_TC: Transmission complete interrupt

@arg USART_IT_RXNE: Receive Data register not empty interrupt

@arg USART_IT_IDLE: Idle line detection interrupt

@arg USART_IT_PE: Parity Error interrupt

@arg USART_IT_ERR: Error interrupt(Frame error, noise error, overrun error)

而我们是用到的是接收数据的时候触发中断源,就选择 USART_IT_RXNE

第三个参数是开启或关闭串口中断,ENABLE or DISABLE.

ENABLE是开启,DISABLE是关闭

代码

c 复制代码
/**
  * @brief  配置 DEBUG 串口模式
  * @param  无
  * @retval 无
  */
  
void DEBUG_USART_MODEConfig(void)
{
    USART_InitTypeDef usart_InitStruct = { 0 };
    
    /* 开启 DEBUG 相关的GPIO外设/端口时钟 */
    DEBUG_APBXCLKCMD(DEBUG_USARTX_CLK_PORT, ENABLE); //开启 端口时钟
    
    /* 配置串口的工作参数 */
    
    //波特率配置:115200
    usart_InitStruct.USART_BaudRate            = DEBUG_BAUDRATE;
    //硬件流控开关配置:无
    usart_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    //配置工作模式:发送模式
    usart_InitStruct.USART_Mode                = USART_Mode_Tx | USART_Mode_Rx;
    //校验:无校验位
    usart_InitStruct.USART_Parity              = USART_Parity_No;
    //停止位:1个停止位
    usart_InitStruct.USART_StopBits            = USART_StopBits_1;
    //数据帧长度:8位
    usart_InitStruct.USART_WordLength          = USART_WordLength_8b;
    
    USART_Init(DEBUG_USARTX, &usart_InitStruct);
    
    /* 开启串口数据接收中断 */
    USART_ITConfig(DEBUG_USARTX, USART_IT_RXNE, ENABLE);
}

在配置串口模式代码里面末尾添加这行代码

c 复制代码
 /* 开启串口数据接收中断 */
USART_ITConfig(DEBUG_USARTX, USART_IT_RXNE, ENABLE);

开启串口1的接收数据中断源

4. 配置中断回调函数

c 复制代码
/**
  * @brief  DEBUG 串口中断 回调函数
  * @param  无
  * @retval 无
  */
void DEBUG_IRQHANDLER(void)
{
    /* 数据回显 */
    if (USART_GetFlagStatus(DEBUG_USARTX, USART_FLAG_RXNE) == SET)
    {
        uint8_t data_temp = USART_ReceiveData(DEBUG_USARTX); //读取数据寄存器,读取后对应的寄存器会被复位 
        USART_SenByte(DEBUG_USARTX, data_temp);
        USART_ClearFlag(DEBUG_USARTX, USART_FLAG_RXNE);      //清除接收标志位
    }
}

原本if里面那个函数是判断数据寄存器是否有数据,如果有就直接读取数据,但是现在是在中断函数里面操作,所以需要在中断寄存器里面判断数据寄存器是否有数据。

这个if是在SR寄存器里面操作的,而中断函数需要到中断寄存器操作

而检测数据寄存器是否有数据,在串口中断函数里面应该用这个

在stm32f10x_usart.c文件里面

这个函数操作的是CR1寄存器

在CR1中选择接收缓冲区非空中断使能RXNEIE

串口函数里面检测数据寄存器数据函数:

c 复制代码
ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT)

它有两个参数

参数1选择的是哪一个串口,有串口1,串口2,串口3...

参数2选择的是中断源

@param USART_IT: specifies the USART interrupt source to check.

This parameter can be one of the following values:

@arg USART_IT_CTS: CTS change interrupt (not available for UART4 and UART5)

@arg USART_IT_LBD: LIN Break detection interrupt

@arg USART_IT_TXE: Tansmit Data Register empty interrupt

@arg USART_IT_TC: Transmission complete interrupt

@arg USART_IT_RXNE: Receive Data register not empty interrupt

@arg USART_IT_IDLE: Idle line detection interrupt

@arg USART_IT_ORE_RX : OverRun Error interrupt if the RXNEIE bit is set

@arg USART_IT_ORE_ER : OverRun Error interrupt if the EIE bit is set

@arg USART_IT_NE: Noise Error interrupt

@arg USART_IT_FE: Framing Error interrupt

@arg USART_IT_PE: Parity Error interrupt

而我们第二个参数选择的是 USART_IT_RXNE

而清除标志位在中断函数也有一个函数

c 复制代码
void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT)

清除只能清除这四个中断源标志位

@arg USART_IT_CTS: CTS change interrupt (not available for UART4 and UART5)

@arg USART_IT_LBD: LIN Break detection interrupt

@arg USART_IT_TC: Transmission complete interrupt.

@arg USART_IT_RXNE: Receive Data register not empty interrupt.

原本我们的清除标志位函数是

c 复制代码
void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG)

它能清除四个标志位

This parameter can be any combination of the following values:

@arg USART_FLAG_CTS: CTS Change flag (not available for UART4 and UART5).

@arg USART_FLAG_LBD: LIN Break detection flag.

@arg USART_FLAG_TC: Transmission Complete flag.

@arg USART_FLAG_RXNE: Receive data register not empty flag.

这个清除是对寄存器SR操作清除

通过对比发现

不管是检测数据寄存器是否有数据函数还是清除标志位函数有两种:

第一种是普通的对直接对SR寄存器操作

c 复制代码
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG)
void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG)

第二种是在串口中断函数CR寄存器操作

c 复制代码
ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT)
void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT)

可以发现在中断函数里面操作的函数,函数名字中间带一个IT。

代码:

c 复制代码
/**
  * @brief  DEBUG 串口中断 回调函数
  * @param  无
  * @retval 无
  */
void DEBUG_IRQHANDLER(void)
{
    /* 数据回显 */
    if (USART_GetITStatus(DEBUG_USARTX, USART_IT_RXNE) == SET)
    {
        uint8_t data_temp = USART_ReceiveData(DEBUG_USARTX);        //读取数据寄存器,读取后对应的寄存器会被复位 
        USART_SenByte(DEBUG_USARTX, data_temp);
        USART_ClearITPendingBit(DEBUG_USARTX, USART_IT_RXNE);       //清除接收标志位
    }
}

5. 代码

5.1 bsp_debug.h

c 复制代码
#ifndef __BSP_DEBUG_H
#define __BSP_DEBUG_H

#include "stm32f10x.h"

#define DEBUG_USART_NUM 1

#if(DEBUG_USART_NUM == 1)

    #define DEBUG_TX_GPIO_PORT      GPIOA                       /* GPIO 端口 */
    #define DEBUG_TX_GPIO_CLK_PORT  RCC_APB2Periph_GPIOA        /* GPIO 端口时钟 */
    #define DEBUG_TX_GPIO_PIN       GPIO_Pin_9                  /* 对应PIN脚 */
    #define DEBUG_RX_GPIO_PORT      GPIOA                       /* GPIO 端口 */
    #define DEBUG_RX_GPIO_CLK_PORT  RCC_APB2Periph_GPIOA        /* GPIO 端口时钟 */
    #define DEBUG_RX_GPIO_PIN       GPIO_Pin_10                  /*对应PIN脚 */
    
    #define DEBUG_USARTX            USART1                      /* 串口号 */
    #define DEBUG_USARTX_CLK_PORT   RCC_APB2Periph_USART1       /* 串口外设时钟位 */
    #define DEBUG_APBXCLKCMD        RCC_APB2PeriphClockCmd      /* 串口外设时钟 */
    #define DEBUG_BAUDRATE          115200                      /* 波特率 */

    #define DEBUG_IRQ               USART1_IRQn                 /*外部中断向量号*/
    #define DEBUG_IRQHANDLER        USART1_IRQHandler           /*中断处理函数*/
#elif(DEBUG_USART_NUM == 2)

    #define DEBUG_TX_GPIO_PORT      GPIOA                       /* GPIO 端口 */
    #define DEBUG_TX_GPIO_CLK_PORT  RCC_APB2Periph_GPIOA        /* GPIO 端口时钟 */
    #define DEBUG_TX_GPIO_PIN       GPIO_Pin_2                 /* 对应PIN脚 */
    #define DEBUG_RX_GPIO_PORT      GPIOA                       /* GPIO 端口 */
    #define DEBUG_RX_GPIO_CLK_PORT  RCC_APB2Periph_GPIOA        /* GPIO 端口时钟 */
    #define DEBUG_RX_GPIO_PIN       GPIO_Pin_3                 /* 对应PIN脚 */
    
    #define DEBUG_USARTX            USART2                      /* 串口号 */
    #define DEBUG_USARTX_CLK_PORT   RCC_APB1Periph_USART2       /* 串口外设时钟位 */
    #define DEBUG_APBXCLKCMD        RCC_APB1PeriphClockCmd      /* 串口外设时钟 */
    #define DEBUG_BAUDRATE          115200                      /* 波特率 */

    #define DEBUG_IRQ               USART2_IRQn                 /*外部中断向量号*/
    #define DEBUG_IRQHANDLER        USART2_IRQHandler          /*中断处理函数*/
#elif(DEBUG_USART_NUM == 3)

    #define DEBUG_TX_GPIO_PORT      GPIOB                       /* GPIO 端口 */
    #define DEBUG_TX_GPIO_CLK_PORT  RCC_APB2Periph_GPIOB        /* GPIO 端口时钟 */
    #define DEBUG_TX_GPIO_PIN       GPIO_Pin_10                 /* 对应PIN脚 */
    #define DEBUG_RX_GPIO_PORT      GPIOB                       /* GPIO 端口 */
    #define DEBUG_RX_GPIO_CLK_PORT  RCC_APB2Periph_GPIOB        /* GPIO 端口时钟 */
    #define DEBUG_RX_GPIO_PIN       GPIO_Pin_11                 /* 对应PIN脚 */
    
    #define DEBUG_USARTX            USART3                      /* 串口号 */
    #define DEBUG_USARTX_CLK_PORT   RCC_APB1Periph_USART3       /* 串口外设时钟位 */
    #define DEBUG_APBXCLKCMD        RCC_APB1PeriphClockCmd      /* 串口外设时钟 */
    #define DEBUG_BAUDRATE          115200                      /* 波特率 */

    #define DEBUG_IRQ               USART3_IRQn                 /*外部中断向量号*/
    #define DEBUG_IRQHANDLER        USART3_IRQHandler          /*中断处理函数*/
#endif

void DEBUG_USART_PinConfig(void);
void DEBUG_USART_MODEConfig(void);
void DEBUG_USART_Init(void);
void DEBUG_NVIC_Config(void);
#endif /*__BSP_DEBUG_H*/

5.2 bsp_debug.c

c 复制代码
/**
  ******************************************************************************
  * @file    bsp_debug.c
  * @author  作者
  * @version v1.0
  * @date    2026.6.6
  * @brief   调试串口函数接口
  ******************************************************************************
  * @attention
  *
  * 版权声明
  *
  ******************************************************************************
  */
#include "debug/bsp_debug.h"
#include "usart/usart_com.h"

/**
  * @brief  初始化控制 DEBUG 串口 的IO
  * @param  无
  * @retval 无
  */
  
void DEBUG_USART_PinConfig(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = { 0 };

#if 1    
    /*对串口发送模式IO配置*/
    /* 开启 DEBUG 相关的GPIO外设/端口时钟 */
    RCC_APB2PeriphClockCmd(DEBUG_TX_GPIO_CLK_PORT, ENABLE); //开启GPIOA 端口时钟
    
    // 配置引脚:选择GPIOA的Pin9
    GPIO_InitStruct.GPIO_Pin = DEBUG_TX_GPIO_PIN;
    // 配置输出速度:50MHz
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    // 配置工作模式:推挽复用
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(DEBUG_TX_GPIO_PORT, &GPIO_InitStruct);
#endif
    
#if 1    
    /*对串口接收模式IO配置*/
    /* 开启 DEBUG 相关的GPIO外设/端口时钟 */
    RCC_APB2PeriphClockCmd(DEBUG_RX_GPIO_CLK_PORT, ENABLE); //开启GPIOA 端口时钟
    
    // 配置引脚:选择GPIOA的Pin10
    GPIO_InitStruct.GPIO_Pin = DEBUG_RX_GPIO_PIN;
    // 配置输出速度:50MHz
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    // 配置工作模式:上拉输入/浮空输入
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(DEBUG_RX_GPIO_PORT, &GPIO_InitStruct);
#endif
    
}

/**
  * @brief  配置 DEBUG 串口模式
  * @param  无
  * @retval 无
  */
  
void DEBUG_USART_MODEConfig(void)
{
    USART_InitTypeDef usart_InitStruct = { 0 };
    
    /* 开启 DEBUG 相关的GPIO外设/端口时钟 */
    DEBUG_APBXCLKCMD(DEBUG_USARTX_CLK_PORT, ENABLE); //开启 端口时钟
    
    /* 配置串口的工作参数 */
    
    //波特率配置:115200
    usart_InitStruct.USART_BaudRate            = DEBUG_BAUDRATE;
    //硬件流控开关配置:无
    usart_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    //配置工作模式:发送模式
    usart_InitStruct.USART_Mode                = USART_Mode_Tx | USART_Mode_Rx;
    //校验:无校验位
    usart_InitStruct.USART_Parity              = USART_Parity_No;
    //停止位:1个停止位
    usart_InitStruct.USART_StopBits            = USART_StopBits_1;
    //数据帧长度:8位
    usart_InitStruct.USART_WordLength          = USART_WordLength_8b;
    
    USART_Init(DEBUG_USARTX, &usart_InitStruct);
    
    /* 开启串口数据接收中断 */
    USART_ITConfig(DEBUG_USARTX, USART_IT_RXNE, ENABLE);
}

/**
  * @brief  配置 DEBUG 中断配置
  * @param  无
  * @retval 无
  */
void DEBUG_NVIC_Config()
{
    // 定义一个 NVIC 结构体
    NVIC_InitTypeDef nvic_initstauct = { 0 };
    
    /* 开启 AFIO 相关时钟 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); 
    
    /*配置中断源*/
    nvic_initstauct.NVIC_IRQChannel                   = DEBUG_IRQ;
    /*配置抢占优先级*/
    nvic_initstauct.NVIC_IRQChannelPreemptionPriority = 1;
    /*配置响应优先级*/
    nvic_initstauct.NVIC_IRQChannelSubPriority        = 0;
    /*开启中断*/
    nvic_initstauct.NVIC_IRQChannelCmd                = ENABLE;
    
    // 把配置写入硬件,生效
    NVIC_Init(&nvic_initstauct);
}

/**
  * @brief  DEBUG 串口初始化
  * @param  无
  * @retval 无
  */
void DEBUG_USART_Init(void)
{   
    /* 配置 DEBUG 中断配置 */
    DEBUG_NVIC_Config();
    
    /*配置 DEBUG 串口模式*/
    DEBUG_USART_MODEConfig();

    /* 串口 GPIO 配置 */
    DEBUG_USART_PinConfig();
    
    /* 串口使能 */
    USART_Cmd(DEBUG_USARTX, ENABLE);
}

/**
  * @brief  DEBUG 串口中断 回调函数
  * @param  无
  * @retval 无
  */
void DEBUG_IRQHANDLER(void)
{
    /* 数据回显 */
    if (USART_GetITStatus(DEBUG_USARTX, USART_IT_RXNE) == SET)
    {
        uint8_t data_temp = USART_ReceiveData(DEBUG_USARTX);        //读取数据寄存器,读取后对应的寄存器会被复位 
        USART_SenByte(DEBUG_USARTX, data_temp);
        USART_ClearITPendingBit(DEBUG_USARTX, USART_IT_RXNE);       //清除接收标志位
    }
}

/***************************************END OF FILE *********************************************************/

5.3 usart_com.h

c 复制代码
#ifndef __USART_COM_H
#define __USART_COM_H

#include "stm32f10x.h"
#include "stdio.h"

void USART_SenByte(USART_TypeDef* pUSARTx, uint8_t ch);
void USART_SenArray(USART_TypeDef* pUSARTx, uint8_t* array, uint32_t num);
void USART_SenString(USART_TypeDef* pUSARTx, char* str);

#endif /*__USART_COM_H*/

5.4 usart_com.c

c 复制代码
/**
  ******************************************************************************
  * @file    usart_com.c
  * @author  作者
  * @version v1.0
  * @date    2026.6.7
  * @brief   重定向c库printf函数到usart端口
  ******************************************************************************
  * @attention
  *
  * 版权声明
  *
  ******************************************************************************
  */
#include "usart/usart_com.h"
#include "debug/bsp_debug.h"

/**
  * @brief  发送一字节函数
  * @param  pUSARTx:USARTx(X=1,2,3)/UARTx(x=4,5)
  * @param  ch:要发送的数据
  * @note   
  * @retval 无
  */
  
void USART_SenByte(USART_TypeDef* pUSARTx, uint8_t ch)
{
    /* 等待发送完成 */
    while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TC) == RESET);
    
    /*发送一字节数据到pUSARTx*/
    USART_SendData(pUSARTx, ch);
    
    /* 等待发送数据寄存器为空 */
    while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
} 

/**
  * @brief  发送8位的数组函数
  * @param  pUSARTx:USARTx(X=1,2,3)/UARTx(x=4,5)
  * @param  arrary:要发送的数组
  * @param  num: 数组大小
  * @note   
  * @retval 无
  */
  
void USART_SenArray(USART_TypeDef* pUSARTx, uint8_t* array, uint32_t num)
{
    /* 等待发送完成 */
    while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TC) == RESET);
    
    for(uint32_t i = 0; i < num; i++)
    {
        /*发送一字节数据到pUSARTx*/
        USART_SendData(pUSARTx, array[i]);
        
        /* 等待发送数据寄存器为空 */
        while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
    }  
} 

/**
  * @brief  发送字符串函数
  * @param  pUSARTx:USARTx(X=1,2,3)/UARTx(x=4,5)
  * @param  str:要发送的字符串
  * @note   
  * @retval 无
  */
  
void USART_SenString(USART_TypeDef* pUSARTx, char* str)
{
    uint32_t k = 0;
    /* 等待发送完成 */
    while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TC) == RESET);
    
    do
    {
        /*发送一字节数据到pUSARTx*/
        USART_SendData(pUSARTx, *(str + k));        
        k++;
        
        /* 等待发送数据寄存器为空 */
        while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
    
    }while(*(str + k) != '\0');
     
} 

/**
  * @brief  将一个字符写入到文件中,重定向C库函数printf到串口,重定向后可使用printf函数
  * @param  ch:要写入的字符
  * @param  f:指向FILE结构的指针
  * @note  无 
  * @retval 成功,返回该字符
  */
  
int fputc(int ch, FILE* f)
{
   /* 等待发送完成 */
    while(USART_GetFlagStatus(DEBUG_USARTX, USART_FLAG_TC) == RESET);
    
    /*发送一字节数据到pUSARTx*/
    USART_SendData(DEBUG_USARTX, ch);
    
    /* 等待发送数据寄存器为空 */
    while(USART_GetFlagStatus(DEBUG_USARTX, USART_FLAG_TXE) == RESET);
    
    return ch;
}
/***************************************END OF FILE *********************************************************/

6.实验现象

去个人主页找到视频名字是:串口发送与接收

相关推荐
充哥单片机设计1 小时前
【STM32开源项目】智能小区充电桩
stm32·单片机·嵌入式硬件·毕业设计·小区充电桩·智能小区充电桩
嵌入式-老费1 小时前
esp32开发与应用(如何解决SoC冷启动的问题)
单片机·嵌入式硬件
充哥单片机设计3 小时前
【STM32开源项目】智能语音台灯
stm32·单片机·嵌入式硬件·毕业设计·单片机设计·智能语音台灯
EatFan3 小时前
全栈自造 Status Deck(四):硬件终于到了,从点亮屏幕到跑通第一个 Demo
单片机·物联网·esp32
sunoo-2294 小时前
【嵌入式裸机开发Day04】i.MX6ULL 蜂鸣器驱动详解:从引脚地址查找到代码实现全流程
arm开发·单片机·嵌入式硬件·学习·串口·裸机
Brilliantwxx5 小时前
【STM32】 SPI阻塞式通信与HAL源码 (源码分析)
stm32·单片机·嵌入式硬件
Doraemomo5 小时前
IMX6ULL裸机开发——PWM
arm开发·嵌入式硬件·imx6ull
老当益壮梁奶奶6 小时前
ARM汇编学习笔记(五):从按键轮询到 GIC 中断控制器(ARM Cortex-A7 )
arm开发·笔记·单片机·嵌入式硬件
WWJA王文举6 小时前
Bootloader、App 和升级分区之间是什么关系?
stm32·freertos·嵌入式开发·在线升级