stm32F103C8T6标准库串口接收之多串口基础应用5

目录

  • 1.问题描述
  • 2.工程创建
  • 3.将源文件中同名,命名进行替换
  • 4.串口配置代码
    • [4.1 串口1配置代码](#4.1 串口1配置代码)
      • [4.1.1 bsp_debug.h](#4.1.1 bsp_debug.h)
      • [4.1.2 bsp_debug.c](#4.1.2 bsp_debug.c)
      • [4.1.3 app_debug.h](#4.1.3 app_debug.h)
      • [4.1.4 app_debug.c](#4.1.4 app_debug.c)
    • [4.2 串口3配置代码](#4.2 串口3配置代码)
      • [4.2.1 bsp_device.h](#4.2.1 bsp_device.h)
      • [4.2.2 bsp_device.c](#4.2.2 bsp_device.c)
      • [4.2.3 app_device.h](#4.2.3 app_device.h)
      • [4.2.4 app_device.c](#4.2.4 app_device.c)
  • [5. 视频演示](#5. 视频演示)

1.问题描述

A上位机发送命令给C8T6,C8T6吧这些命令进行解析处理,然后吧这个指令给这个设备,设备去正常运行。而从A到C8T6使用的是一个串口接口,从C8T6到B也是一个串口接口,所以需要借助于C8T6这个媒介,B设备运行状态也可以通过串口传回给C8T6,C8T6将处理好的信息给上位机去显示,这相当于拥有两个串口。

A给C8T6,C8T6给B

B给C8T6,C8T6给A

2.工程创建

在user文件中将debug文件复制一份,文件名为device(设备),源文件命名更改为bsp_device.h和bsp_device.c

同时在app文件也一样做法

将debug文件复制一份,名字命名为device,源文件命名更改为app_device.h和app_device.c

最后将源文件添加到工程中去。

3.将源文件中同名,命名进行替换

在这个文件中,将所有的DEBUG全部替换成DEVICE

1.CTRL+C复制USART,然后点击邮件图标

2.选择当前文件,勾选的地方全部去掉

3.Find what填原来的变量名

Replace with 填替换后的名字

最后选择当前文件

点击Replace

4.最后会自动定位到DEBUG命名上,一直点击Replace不断替换。

5.最终全部替换完成

4.串口配置代码

串口3的配置代码就是将串口1的bsp源文件和头文件,以及app源文件的头文件复制一份,只是吧原本串口1名字DEBUG更改为device,然后device在bsp头文件中打开串口3的定义

核心部分:

在上位机中如果连接的是串口1,上位机发送数据,然后在代码中,将上位机发送的数据用数据保存起来,然后在串口1执行任务函数中,调用发送数据的函数,函数的第一个参数更改为串口3,这样就可以将数据发送到串口3

同样的,串口3接收数据,在任务函数中,发送数据函数第一个参数填串口1

4.1 串口1配置代码

4.1.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

#define DEBUG_BUFFER_SIZE 1024

typedef struct 
{
    uint8_t buffer[DEBUG_BUFFER_SIZE];
    uint32_t len;
    uint32_t read_flag; 
}DEBUG_DataTypeDef;

extern DEBUG_DataTypeDef debug_receive;

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

4.1.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"

DEBUG_DataTypeDef debug_receive = { 0 };

/**
  * @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);
    /* 开启串口数据空闲中断 */
    USART_ITConfig(DEBUG_USARTX, USART_IT_IDLE, 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);
}

/*
1.因为数组下标从0开始的,定义buffer[DEBUG_BUFFER_SIZE]时,可取的末尾是buffer[DEBUG_BUFFER_SIZE - 1];

2.因为数组下标从0开始接收,当接收了len个,buffer[len-1]为最近一次保存位置,buffer[len]指向的是下一个准备接收空位,所以用len与DEBUG_BUFFER_SIZE-1比较

*/
/**
  * @brief  DEBUG 串口中断 回调函数
  * @param  无
  * @retval 无
  */
void DEBUG_IRQHANDLER(void)
{
    uint8_t data_temp = NULL;
    
    /* 数据回显 */
    if (USART_GetITStatus(DEBUG_USARTX, USART_IT_RXNE) == SET)
    {
        //读取数据寄存器,读取后对应的寄存器会被复位 
        data_temp = USART_ReceiveData(DEBUG_USARTX);        
        /*当存储数据的数组没有满 并且 是空闲状态可以接收*/
        if ((debug_receive.len < DEBUG_BUFFER_SIZE - 1) && (debug_receive.read_flag == 0))
        {
            debug_receive.buffer[debug_receive.len] = data_temp;
            debug_receive.len++;
        }
        /*满数据包*/
        if (debug_receive.len == DEBUG_BUFFER_SIZE - 1)
        {
            debug_receive.buffer[debug_receive.len] = '\0';
            debug_receive.read_flag = 1;
        }        
//        USART_SenByte(DEBUG_USARTX, data_temp);
        USART_ClearITPendingBit(DEBUG_USARTX, USART_IT_RXNE);       //清除接收标志位
    }
    
    /*
        串口检测到「一帧数据传输完毕,总线上持续一段时间没有新字节」,就触发空闲中断
        用来做数据结束
    */
    // 检测空闲中断 
    if (USART_GetITStatus(DEBUG_USARTX, USART_IT_IDLE) == SET)
    {
        /*
            根据手册实际描述(读取获取USART_ITIDLE、数据寄存器的数据,读取后对应的寄存器会被复位)
            用这样方式清除IDLE
        
            清除标志位过程
            1.获取中断状态USART_GetITStatus()
            2.读取数据寄存器数据USART_ReceiveData()
            最终将DEBUG_USARTX标志位清除
        */
        USART_ReceiveData(DEBUG_USARTX);//用来清除空闲中断标志位USART_IT_IDLE
        
        debug_receive.buffer[debug_receive.len] = '\0';
        debug_receive.read_flag = 1;
    }
}

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

4.1.3 app_debug.h

c 复制代码
#ifndef __APP_DEBUG_H
#define __APP_DEBUG_H

#include "stm32f10x.h"

void DEBUG_ReadBufferReset(void);
void DEBUG_TaskInit(void);
void DEBUG_Task(void);
//void DEBUG_Show_Message(void);
#endif /*__APP_DEBUG_H*/

4.1.4 app_debug.c

c 复制代码
/**
  ******************************************************************************
  * @file    App_debug.c
  * @author  作者
  * @version v1.0
  * @date    2026.9.22
  * @brief   DEBUG 串口 应用层功能接口
  ******************************************************************************
  * @attention
  *
  * 版权声明
  *
  ******************************************************************************
  */
#include "debug/bsp_debug.h"
#include "debug/app_debug.h"
#include "device/bsp_device.h"
#include "usart/usart_com.h"
#include <string.h>

/**
  * @brief  DEBUG串口 接收缓存区复位
  * @param  无
  * @retval 无
  */
void DEBUG_ReadBufferReset(void)
{
    memset(debug_receive.buffer, NULL, debug_receive.len);
    debug_receive.len = 0;
    debug_receive.read_flag = 0;
}

/**
  * @brief  DEBUG串口 任务初始化
  * @param  无
  * @retval 无
  */
void DEBUG_TaskInit(void)
{
    DEBUG_ReadBufferReset();
    //DEBUG_Show_Message();
}

///**
//  * @brief  打印指令输入提示信息
//  * @param  无
//  * @retval 无
//  */
//void DEBUG_Show_Message(void)
//{
//    printf("\r\n这是一个通过串口通信指令控制G/B实验\n");
//    printf("使用USART参数为:%d 8-N-1\n",DEBUG_BAUDRATE);
//    printf("开发板接到指令后控制G/B灯,指令对应如下(以\\n结束):\n");
//    printf("   指令   ------ 彩灯颜色\n");
//    printf("GREEN=ON  ------ 绿灯亮\n");
//    printf("GREEN=OFF ------ 绿灯灭\n");
//    printf("BLUE=ON   ------ 蓝灯亮\n");
//    printf("BLUE=OFF  ------ 蓝灯灭\n");
//}

/**
  * @brief  DEBUG串口 任务
  * @param  无
  * @retval 无
  */
void DEBUG_Task(void)
{
    if (debug_receive.read_flag)
    {
        USART_SenString(DEVICE_USARTX, "MCU已经接收DEBUG串口数据:");
        USART_SenArray(DEVICE_USARTX, debug_receive.buffer, debug_receive.len);
        
        DEBUG_ReadBufferReset();
    }
    
}

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

4.2 串口3配置代码

4.2.1 bsp_device.h

c 复制代码
#ifndef __BSP_DEVICE_H
#define __BSP_DEVICE_H

#include "stm32f10x.h"

#define DEVICE_USART_NUM 3

#if(DEVICE_USART_NUM == 1)

    #define DEVICE_TX_GPIO_PORT      GPIOA                       /* GPIO 端口 */
    #define DEVICE_TX_GPIO_CLK_PORT  RCC_APB2Periph_GPIOA        /* GPIO 端口时钟 */
    #define DEVICE_TX_GPIO_PIN       GPIO_Pin_9                  /* 对应PIN脚 */
    #define DEVICE_RX_GPIO_PORT      GPIOA                       /* GPIO 端口 */
    #define DEVICE_RX_GPIO_CLK_PORT  RCC_APB2Periph_GPIOA        /* GPIO 端口时钟 */
    #define DEVICE_RX_GPIO_PIN       GPIO_Pin_10                  /*对应PIN脚 */
    
    #define DEVICE_USARTX            USART1                      /* 串口号 */
    #define DEVICE_USARTX_CLK_PORT   RCC_APB2Periph_USART1       /* 串口外设时钟位 */
    #define DEVICE_APBXCLKCMD        RCC_APB2PeriphClockCmd      /* 串口外设时钟 */
    #define DEVICE_BAUDRATE          115200                      /* 波特率 */

    #define DEVICE_IRQ               USART1_IRQn                 /*外部中断向量号*/
    #define DEVICE_IRQHANDLER        USART1_IRQHandler           /*中断处理函数*/
#elif(DEVICE_USART_NUM == 2)

    #define DEVICE_TX_GPIO_PORT      GPIOA                       /* GPIO 端口 */
    #define DEVICE_TX_GPIO_CLK_PORT  RCC_APB2Periph_GPIOA        /* GPIO 端口时钟 */
    #define DEVICE_TX_GPIO_PIN       GPIO_Pin_2                 /* 对应PIN脚 */
    #define DEVICE_RX_GPIO_PORT      GPIOA                       /* GPIO 端口 */
    #define DEVICE_RX_GPIO_CLK_PORT  RCC_APB2Periph_GPIOA        /* GPIO 端口时钟 */
    #define DEVICE_RX_GPIO_PIN       GPIO_Pin_3                 /* 对应PIN脚 */
    
    #define DEVICE_USARTX            USART2                      /* 串口号 */
    #define DEVICE_USARTX_CLK_PORT   RCC_APB1Periph_USART2       /* 串口外设时钟位 */
    #define DEVICE_APBXCLKCMD        RCC_APB1PeriphClockCmd      /* 串口外设时钟 */
    #define DEVICE_BAUDRATE          115200                      /* 波特率 */

    #define DEVICE_IRQ               USART2_IRQn                 /*外部中断向量号*/
    #define DEVICE_IRQHANDLER        USART2_IRQHandler          /*中断处理函数*/
#elif(DEVICE_USART_NUM == 3)

    #define DEVICE_TX_GPIO_PORT      GPIOB                       /* GPIO 端口 */
    #define DEVICE_TX_GPIO_CLK_PORT  RCC_APB2Periph_GPIOB        /* GPIO 端口时钟 */
    #define DEVICE_TX_GPIO_PIN       GPIO_Pin_10                 /* 对应PIN脚 */
    #define DEVICE_RX_GPIO_PORT      GPIOB                       /* GPIO 端口 */
    #define DEVICE_RX_GPIO_CLK_PORT  RCC_APB2Periph_GPIOB        /* GPIO 端口时钟 */
    #define DEVICE_RX_GPIO_PIN       GPIO_Pin_11                 /* 对应PIN脚 */
    
    #define DEVICE_USARTX            USART3                      /* 串口号 */
    #define DEVICE_USARTX_CLK_PORT   RCC_APB1Periph_USART3       /* 串口外设时钟位 */
    #define DEVICE_APBXCLKCMD        RCC_APB1PeriphClockCmd      /* 串口外设时钟 */
    #define DEVICE_BAUDRATE          115200                      /* 波特率 */

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

#define DEVICE_BUFFER_SIZE 1024

typedef struct 
{
    uint8_t buffer[DEVICE_BUFFER_SIZE];
    uint32_t len;
    uint32_t read_flag; 
}DEVICE_DataTypeDef;

extern DEVICE_DataTypeDef device_receive;

void DEVICE_USART_PinConfig(void);
void DEVICE_USART_MODEConfig(void);
void DEVICE_USART_Init(void);
void DEVICE_NVIC_Config(void);
#endif /*__BSP_DEVICE_H*/

4.2.2 bsp_device.c

c 复制代码
/**
  ******************************************************************************
  * @file    bsp_device.c
  * @author  作者
  * @version v1.0
  * @date    2026.10.1
  * @brief   外部设备串口函数接口
  ******************************************************************************
  * @attention
  *
  * 版权声明
  *
  ******************************************************************************
  */
#include "device/bsp_device.h"
#include "usart/usart_com.h"

DEVICE_DataTypeDef device_receive = { 0 };

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

#if 1    
    /*对串口发送模式IO配置*/
    /* 开启 DEVICE 相关的GPIO外设/端口时钟 */
    RCC_APB2PeriphClockCmd(DEVICE_TX_GPIO_CLK_PORT, ENABLE); //开启GPIOA 端口时钟
    
    // 配置引脚:选择GPIOB的Pin10
    GPIO_InitStruct.GPIO_Pin = DEVICE_TX_GPIO_PIN;
    // 配置输出速度:50MHz
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    // 配置工作模式:推挽复用
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(DEVICE_TX_GPIO_PORT, &GPIO_InitStruct);
#endif
    
#if 1    
    /*对串口接收模式IO配置*/
    /* 开启 DEVICE 相关的GPIO外设/端口时钟 */
    RCC_APB2PeriphClockCmd(DEVICE_RX_GPIO_CLK_PORT, ENABLE); //开启GPIOA 端口时钟
    
    // 配置引脚:选择GPIOB的Pin11
    GPIO_InitStruct.GPIO_Pin = DEVICE_RX_GPIO_PIN;
    // 配置输出速度:50MHz
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    // 配置工作模式:上拉输入/浮空输入
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(DEVICE_RX_GPIO_PORT, &GPIO_InitStruct);
#endif

}

/**
  * @brief  配置 DEVICE 串口模式
  * @param  无
  * @retval 无
  */
  
void DEVICE_USART_MODEConfig(void)
{
    USART_InitTypeDef usart_InitStruct = { 0 };
    
    /* 开启 DEVICE 相关的GPIO外设/端口时钟 */
    DEVICE_APBXCLKCMD(DEVICE_USARTX_CLK_PORT, ENABLE); //开启 端口时钟
    
    /* 配置串口的工作参数 */
    
    //波特率配置:115200
    usart_InitStruct.USART_BaudRate            = DEVICE_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(DEVICE_USARTX, &usart_InitStruct);
    
    /* 开启串口数据接收中断 */
    USART_ITConfig(DEVICE_USARTX, USART_IT_RXNE, ENABLE);
    /* 开启串口数据空闲中断 */
    USART_ITConfig(DEVICE_USARTX, USART_IT_IDLE, ENABLE);
}

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

/**
  * @brief  DEVICE 串口初始化
  * @param  无
  * @retval 无
  */
void DEVICE_USART_Init(void)
{   
    /* 配置 DEVICE 中断配置 */
    DEVICE_NVIC_Config();
    
    /*配置 DEVICE 串口模式*/
    DEVICE_USART_MODEConfig();

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

/*
1.因为数组下标从0开始的,定义buffer[DEVICE_BUFFER_SIZE]时,可取的末尾是buffer[DEVICE_BUFFER_SIZE - 1];

2.因为数组下标从0开始接收,当接收了len个,buffer[len-1]为最近一次保存位置,buffer[len]指向的是下一个准备接收空位,所以用len与DEVICE_BUFFER_SIZE-1比较

*/
/**
  * @brief  DEVICE 串口中断 回调函数
  * @param  无
  * @retval 无
  */
void DEVICE_IRQHANDLER(void)
{
    uint8_t data_temp = NULL;
    
    /* 数据回显 */
    if (USART_GetITStatus(DEVICE_USARTX, USART_IT_RXNE) == SET)
    {
        //读取数据寄存器,读取后对应的寄存器会被复位 
        data_temp = USART_ReceiveData(DEVICE_USARTX);        
        /*当存储数据的数组没有满 并且 是空闲状态可以接收*/
        if ((device_receive.len < DEVICE_BUFFER_SIZE - 1) && (device_receive.read_flag == 0))
        {
            device_receive.buffer[device_receive.len] = data_temp;
            device_receive.len++;
        }
        /*满数据包*/
        if (device_receive.len == DEVICE_BUFFER_SIZE - 1)
        {
            device_receive.buffer[device_receive.len] = '\0';
            device_receive.read_flag = 1;
        }        
//        USART_SenByte(DEVICE_USARTX, data_temp);
        USART_ClearITPendingBit(DEVICE_USARTX, USART_IT_RXNE);       //清除接收标志位
    }
    
    /*
        串口检测到「一帧数据传输完毕,总线上持续一段时间没有新字节」,就触发空闲中断
        用来做数据结束
    */
    // 检测空闲中断 
    if (USART_GetITStatus(DEVICE_USARTX, USART_IT_IDLE) == SET)
    {
        /*
            根据手册实际描述(读取获取USART_ITIDLE、数据寄存器的数据,读取后对应的寄存器会被复位)
            用这样方式清除IDLE
        
            清除标志位过程
            1.获取中断状态USART_GetITStatus()
            2.读取数据寄存器数据USART_ReceiveData()
            最终将DEVICE_USARTX标志位清除
        */
        USART_ReceiveData(DEVICE_USARTX);//用来清除空闲中断标志位USART_IT_IDLE
        
        device_receive.buffer[device_receive.len] = '\0';
        device_receive.read_flag = 1;
    }
}

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

4.2.3 app_device.h

c 复制代码
#ifndef __APP_DEVICE_H
#define __APP_DEVICE_H

#include "stm32f10x.h"

void DEVICE_ReadBufferReset(void);
void DEVICE_TaskInit(void);
void DEVICE_Task(void);
//void DEVICE_Show_Message();
#endif /*__APP_DEVICE_H*/

4.2.4 app_device.c

c 复制代码
/**
  ******************************************************************************
  * @file    App_device.c
  * @author  作者
  * @version v1.0
  * @date    2026.9.22
  * @brief   外部设备串口 应用层功能接口
  ******************************************************************************
  * @attention
  *
  * 版权声明
  *
  ******************************************************************************
  */
#include "device/bsp_device.h"
#include "device/app_device.h"
#include "debug/bsp_debug.h"
#include "usart/usart_com.h"
#include <string.h>

/**
  * @brief  DEVICE串口 接收缓存区复位
  * @param  无
  * @retval 无
  */
void DEVICE_ReadBufferReset(void)
{
    memset(device_receive.buffer, NULL, device_receive.len);
    device_receive.len = 0;
    device_receive.read_flag = 0;
}

/**
  * @brief  DEVICE串口 任务初始化
  * @param  无
  * @retval 无
  */
void DEVICE_TaskInit(void)
{
    DEVICE_ReadBufferReset();
    //DEVICE_Show_Message();
}

///**
//  * @brief  打印指令输入提示信息
//  * @param  无
//  * @retval 无
//  */
//void DEVICE_Show_Message(void)
//{
//    printf("\r\n这是一个通过串口通信指令控制G/B实验\n");
//    printf("使用USART参数为:%d 8-N-1\n",DEVICE_BAUDRATE);
//    printf("开发板接到指令后控制G/B灯,指令对应如下(以\\n结束):\n");
//    printf("   指令   ------ 彩灯颜色\n");
//    printf("GREEN=ON  ------ 绿灯亮\n");
//    printf("GREEN=OFF ------ 绿灯灭\n");
//    printf("BLUE=ON   ------ 蓝灯亮\n");
//    printf("BLUE=OFF  ------ 蓝灯灭\n");
//}

/**
  * @brief  DEVICE串口 任务
  * @param  无
  * @retval 无
  */
void DEVICE_Task(void)
{
    if (device_receive.read_flag)
    {
        USART_SenString(DEBUG_USARTX, "MCU已经接收外部设备串口数据:");
        USART_SenArray(DEBUG_USARTX, device_receive.buffer, device_receive.len);
        
        
        
        DEVICE_ReadBufferReset();
    }
    
}

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

5. 视频演示

多串口基础应用

串口1

TX PA9

RX PA10

串口2

TX PB10

RX PB11

例如如果想要两个设备相互传输,A设备发送数据给B设备,B设备也可以发送数据给A设备

本次实验通过借助C8T6作为中间媒介

设备A发送数据给C8T6,C8T6通过PA10引脚接收数据,通过串口2的PB10发送数据给设备B

设备B发送数据给C8T6,C8T6通过PB11引I脚接收数据,通过串口1的PA9发送数据给设备A

相关推荐
木子单片机1 小时前
基于51单片机计步器—无线蓝牙APP上传
单片机·嵌入式硬件·51单片机·keil
智者知已应修善业2 小时前
【51单片机只有一个8*8点阵数据如何滚动起来一片595+一组IO+花样】2022-1-15
c++·经验分享·笔记·单片机·蓝桥杯·硬件架构
恒锐丰科技林技术员2 小时前
EG2123A 三相独立半桥驱动芯片解析与工程应用
经验分享·嵌入式硬件·硬件工程
硅基手札2 小时前
【Linux 内核专栏 13】快IO层
linux·服务器·嵌入式硬件
李日华大战鸡红2 小时前
滑膜观测器(学习记录)
stm32·单片机·学习·matlab·机器人
白搞电子2 小时前
ESP32-S31 项目如何制作 Windows 一键烧录包:完整镜像、esptool 与数据边界
windows·stm32·单片机
xiangw@GZ3 小时前
纽扣电池型号
嵌入式硬件
优信电子3 小时前
Raspberry Pi Pico 硬件开发 —— 第二课:MicroPython 从入门到项目实践(LED篇)
单片机·嵌入式硬件·树莓派·micropython·pico·入门教学
黑妹天下第一乖4 小时前
第 12 讲:阿加犀 AidLux 部署与量产——把端侧 AI 应用做成 7×24 产品
人工智能·嵌入式硬件·数码相机·接口隔离原则·iot