超子物联网HAL库笔记:串口篇

news/2024/11/8 7:39:07 标签: 单片机, 嵌入式硬件

超子物联网 HAL库学习 汇总入口:

超子物联网HAL库笔记:[汇总]

写作不易,如果您觉得写的不错,欢迎给博主来一波点赞、收藏~让博主更有动力吧!

这篇文章介绍了HAL库串口大多的使用方法,并配有详细的思路和注释

一、介绍

HAL库在 异步通信UART 串口部分提供了三种方式:

  • 轮询阻塞
  • 非阻塞中断 或者 DMA
  • 所以在使用串口时,也要添加DMA.c到库

以STM32C8T6为例,有三个串口资源:

  • USART1
    • TX:PA9 可重映射为 PB 6
    • RX:PA10 可重映射为 PB 7
  • USART2
    • TX:PA2
    • RX:PA3
  • USART3
    • TX:PB10
    • RX:PB11

二、HAL库:阻塞轮询方式 实现USART1 串口 异步收发

1. 引脚定义

  • USART1
    • TX:PA9
    • RX:PA10

2. 补充:为什么在while循环接收时,没必要对HAL_ERROR、HAL_BUSY进行处理

HAL_ERROR:

  • 用于判断buff为空指针或者数据长度为0的情况
if ((pData == NULL) || (Size == 0U))
{
return  HAL_ERROR;
}

HAL_BUSY:

  • 用于判断Busy状态
 if (huart->RxState == HAL_UART_STATE_READY //判断busy)
 {
	   …………
 
	   huart->RxState = HAL_UART_STATE_BUSY_RX;  //变为busy
    
	   …………
	   return HAL_OK;
 }
 else
 {
	   return HAL_BUSY;
 }

所以我们只需要判断他的另外两种状态,HAL_OK(在规定时间内接收到n个数据)、和HAL_TIMEOUT(未在规定时间接收到n个数据,导致超时退出接收)

3. 注意事项:

  • HAL库的串口初始化, 硬件部分的时钟以及GPIO口的配置,需要我们自己来配置

    HAL_UART_Init(&Uart1); 函数被调用时。 会调用一个weak弱声明的void HAL_UART_MspInit(UART_HandleTypeDef *huart) 函数。 这个函数就是留给我们强声明 配置硬件用的。我们需要在里边打开 串口1 和 GPIO的 时钟。

  • 需要注意的是USART1与定时器的引脚有冲突。 如果发生冲突 可以重映射 串口到别的引脚。

  • RxXferSiZe是用来记录接收总量的

  • RxXferCount是用来记录剩余需要接收数量的

    /* Check the remain data to be received */
    while (huart->RxXferCount > 0U)
    {
      huart->RxXferCount--;
    

    注意,这里的RxXferCount 进到while中就先减1 了。这个知识点后面会用到

4. 串口1初始化部分:

#include "stm32f1xx_hal.h"
#include "Uart.h"

//串口1 配置结构体
UART_HandleTypeDef Uart1;

void Uart1_Init(uint32_t Bandrate)
{
    Uart1.Instance = USART1;//选择串口1
    Uart1.Init.BaudRate = Bandrate;//波特率
    Uart1.Init.WordLength = UART_WORDLENGTH_8B;//数据长度
    Uart1.Init.StopBits = UART_STOPBITS_1;//停止位
    Uart1.Init.Parity = UART_PARITY_NONE;//奇偶校验
    Uart1.Init.Mode = UART_MODE_TX_RX;//收发模式
    Uart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;//流控
    
    HAL_UART_Init(&Uart1);
}

5. 串口1配置硬件部分

//定义 强声明 的IO口和时钟打开的 回调函数
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
    //判断传入的结构体中第一个成员  来判断是串口1 、 2、 3
    if(huart->Instance == USART1)
    {
        __HAL_RCC_GPIOA_CLK_ENABLE();//打开串口1 对应的GPIOA(PA9 PA10)时钟
        __HAL_RCC_USART1_CLK_ENABLE();//打开串口1 的时钟
    
        GPIO_InitTypeDef GPIO_InitStructure;
        //TX初始化 PA9
        GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;//输出
        GPIO_InitStructure.Pin = GPIO_PIN_9;
        GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_MEDIUM;//速度中等为10M
        HAL_GPIO_Init(GPIOA,&GPIO_InitStructure);
        
        //RX初始化 PA10
        GPIO_InitStructure.Mode = GPIO_MODE_AF_INPUT;//输入
        GPIO_InitStructure.Pin = GPIO_PIN_10;
        GPIO_InitStructure.Pull = GPIO_NOPULL;//浮空输入
        HAL_GPIO_Init(GPIOA,&GPIO_InitStructure);
    }
}

6. 主函数部分

  • 主函数中。需要使用接收串口的函数:HAL_UART_Receive(&Uart1,Buff,Rx_Size,200)

    他的参数分别为:串口配置结构体地址、接收缓冲区(我们自己定义的数组)、预计接收的字节个数(我们自己定义)、超时时间(单位为ms)

    这里的 Rx_Size 为 200

    因此我们需要在UART.h 头文件中添加结构体对外声明extern UART_HandleTypeDef Uart1;

  • 接收串口的函数会有 四个返回值:

    • HAL_OK、 代表此次在200ms内接受到了 200 字节。 (也就是与预计相等)
    • HAL_ERROR 、代表传参错误、 比如超时时间为0、或者数据缓冲区地址为空
    • HAL_TIMEOUT 、代表未能在规定时间内接收到 200 个字节
      • 往往分为两种情况: 1、接收了但没接收完、2、一点没接收
    • HAL_BUSY、代表已经在接受了。你别来烦我

下面可以看代码来分析

#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "Uart.h"
/*函 数 名:设置PA 9 PA10 实现串口接收*/

//接收缓冲区
uint8_t Buff[256];

//接收数量
#define Rx_Size 200

int main (void)
{
    HAL_Init();//初始化HAL库
    
    RccClock_Init();//配置时钟树72M

    LED_Init();
    
    Uart1_Init(921600);//初始化串口1
    
    while(1)
    {
       switch ( HAL_UART_Receive(&Uart1,Buff,Rx_Size,200) )
       {
           case HAL_OK ://如果刚好填满接收缓冲区,就会进入此分支(比如发送200个1)
           {
                HAL_UART_Transmit(&Uart1,Buff,Rx_Size,200);
                break;
           }
           case HAL_TIMEOUT ://在没有接收到数据时会进入 此 超时退出分支
           {
               
                if( Uart1.RxXferCount != (Rx_Size - 1) )    //如果接收但没接收 满 预期的字节量(200)、会进入下面的分支:
                {
                    HAL_UART_Transmit(&Uart1,Buff,(Rx_Size - 1 - Uart1.RxXferCount),200);//发送接收到的部分
                    HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_15);//点亮LED灯
                }
                else
                {
                    ;//如果什么都不发送,每次轮询都会进入这个 if 分支
                }
                break;
           }
           case HAL_ERROR : break;
           case HAL_BUSY : break;

       }
    }

}

三、HAL库:阻塞轮询方式 实现串口2、3 和串口1重映射

1. 引脚定义

  • USART1
    • TX:PA9 可重映射为 PB 6
    • RX:PA10 可重映射为 PB 7
  • USART2
    • TX:PA2
    • RX:PA3
  • USART3
    • TX:PB10
    • RX:PB11

2. 关键代码:

  • 如果需要重映射,则还需要打开AFIO的时钟和 使用重映射 API:

        __HAL_RCC_AFIO_CLK_ENABLE();
        __HAL_AFIO_REMAP_USART1_ENABLE();
    
    

3. 串口1、2、3、初始化部分:

与之前的无异,只是添加拷贝了三次

#include "stm32f1xx_hal.h"
#include "uart.h"

//创建串口总控结构体
UART_HandleTypeDef  uart1;
UART_HandleTypeDef  uart2;
UART_HandleTypeDef  uart3;

/* 初始化串口 */
void U1_Init(uint32_t bandrate){
    uart1.Instance = USART1;                    //使用那个串口
    uart1.Init.BaudRate = bandrate;             //波特率
    uart1.Init.WordLength = UART_WORDLENGTH_8B; //数据位长度
    uart1.Init.StopBits = UART_STOPBITS_1;      //停止位
    uart1.Init.Parity = UART_PARITY_NONE;       //校验模式
    uart1.Init.Mode = UART_MODE_TX_RX;          //传输模式
    uart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; //流控
    HAL_UART_Init(&uart1);
}

void U2_Init(uint32_t bandrate){
    uart2.Instance = USART2;                    //使用那个串口
    uart2.Init.BaudRate = bandrate;             //波特率
    uart2.Init.WordLength = UART_WORDLENGTH_8B; //数据位长度
    uart2.Init.StopBits = UART_STOPBITS_1;      //停止位
    uart2.Init.Parity = UART_PARITY_NONE;       //校验模式
    uart2.Init.Mode = UART_MODE_TX_RX;          //传输模式
    uart2.Init.HwFlowCtl = UART_HWCONTROL_NONE; //流控
    HAL_UART_Init(&uart2);
}

void U3_Init(uint32_t bandrate){
    uart3.Instance = USART3;                    //使用那个串口
    uart3.Init.BaudRate = bandrate;             //波特率
    uart3.Init.WordLength = UART_WORDLENGTH_8B; //数据位长度
    uart3.Init.StopBits = UART_STOPBITS_1;      //停止位
    uart3.Init.Parity = UART_PARITY_NONE;       //校验模式
    uart3.Init.Mode = UART_MODE_TX_RX;          //传输模式
    uart3.Init.HwFlowCtl = UART_HWCONTROL_NONE; //流控
    HAL_UART_Init(&uart3);
}

/* UART硬件初始化回调 */
void HAL_UART_MspInit(UART_HandleTypeDef *huart){
    
    GPIO_InitTypeDef GPIO_InitType;
    
    if(huart->Instance == USART1){          //判断那个串口在进行初始化
        #if(0)
        __HAL_RCC_USART1_CLK_ENABLE();
        __HAL_RCC_GPIOA_CLK_ENABLE();
        
        GPIO_InitType.Pin = GPIO_PIN_9;
        GPIO_InitType.Mode = GPIO_MODE_AF_PP;
        GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
        HAL_GPIO_Init(GPIOA,&GPIO_InitType);
        
        GPIO_InitType.Pin = GPIO_PIN_10;
        GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
        GPIO_InitType.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(GPIOA,&GPIO_InitType);
        #else
        /* 重映射串口1 */
        __HAL_RCC_USART1_CLK_ENABLE();
        __HAL_RCC_GPIOB_CLK_ENABLE();
        
        __HAL_RCC_AFIO_CLK_ENABLE();
        __HAL_AFIO_REMAP_USART1_ENABLE();
        
        GPIO_InitType.Pin = GPIO_PIN_6;
        GPIO_InitType.Mode = GPIO_MODE_AF_PP;
        GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
        HAL_GPIO_Init(GPIOB,&GPIO_InitType);
        
        GPIO_InitType.Pin = GPIO_PIN_7;
        GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
        GPIO_InitType.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(GPIOB,&GPIO_InitType);
        #endif
    }else if(huart->Instance == USART2){
        __HAL_RCC_GPIOA_CLK_ENABLE();
        __HAL_RCC_USART2_CLK_ENABLE();
        
        GPIO_InitType.Pin = GPIO_PIN_2;
        GPIO_InitType.Mode = GPIO_MODE_AF_PP;
        GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
        HAL_GPIO_Init(GPIOA,&GPIO_InitType);
        
        GPIO_InitType.Pin = GPIO_PIN_3;
        GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
        GPIO_InitType.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(GPIOA,&GPIO_InitType);
    }else if(huart->Instance == USART3){
        __HAL_RCC_GPIOB_CLK_ENABLE();
        __HAL_RCC_USART3_CLK_ENABLE();
        
        GPIO_InitType.Pin = GPIO_PIN_10;
        GPIO_InitType.Mode = GPIO_MODE_AF_PP;
        GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
        HAL_GPIO_Init(GPIOB,&GPIO_InitType);
        
        GPIO_InitType.Pin = GPIO_PIN_11;
        GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
        GPIO_InitType.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(GPIOB,&GPIO_InitType);
    }
}

4. 主函数部分

  • 与之前的一样,想使用什么修改下”UartX“参数就行,
#include "stm32f1xx_hal.h"

#include "rcc.h"
#include "led.h"
#include "key.h"

#include "Uart.h"
/*函 数 名:HAL库:轮询方式 实现USART1、2、3串口 异步收发
            对USART1 进行重映射。PA9 PA10到TX_PB6 、 RX_PB7
 */
 
//接收缓冲区
uint8_t Buff[256];

//接收数量
#define Rx_Size 200

int main (void)
{
    HAL_Init();//初始化HAL库
    
    RccClock_Init();//配置时钟树72M

    LED_Init();
    
    Uart1_Init(921600);//初始化串口1
    Uart2_Init(921600);//初始化串口2
    Uart3_Init(921600);//初始化串口3
    while(1)
    {
       switch ( HAL_UART_Receive(&Uart1,Buff,Rx_Size,200) )
       {
           case HAL_OK ://如果刚好填满接收缓冲区,就会进入此分支(比如发送200个1)
           {
                HAL_UART_Transmit(&Uart1,Buff,Rx_Size,200);
                break;
           }
           case HAL_TIMEOUT ://在没有接收到数据时会进入 此 超时退出分支
           {
               
                if( Uart1.RxXferCount != (Rx_Size - 1) )    //如果接收但没接收 满 预期的字节量(200)、会进入下面的分支:
                {
                    HAL_UART_Transmit(&Uart1,Buff,(Rx_Size - 1 - Uart1.RxXferCount),200);//发送接收到的部分
                    HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_15);//点亮LED灯
                }
                else
                {
                    ;//如果什么都不发送,每次轮询都会进入这个 if 分支
                }
                break;
           }
           case HAL_ERROR : break;
           case HAL_BUSY : break;

       }
    }

}

四、HAL库:中断方式 实现串口1 定长数组异步收发

我们就使用上一小节所讲的多指针定位+循环收发缓冲区方案设计,来实现这次的中断接收~

1. 注意事项

  1. HAL库为 串口中断提供了很多回调函数。 比如 错误回调、半完成回调、Rx、Tx完成回调。你需要用什么回调,就声明什么回调~

    • 这里只用了接收完成回调函数:void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)

      其中“RxCpltCallback” 可以分解为以下部分:

      • “Rx” 通常代表 “Receive”,即接收。
      • “Cplt” 通常代表 “Complete”,即完成。
      • “Callback” 即回调,指的是当某个特定事件发生时被调用的函数。
  2. 我们在回调函数中。 我们将接收缓冲区的数据memcpy到 发送缓冲区。 并置 接收完成标志位。 在主函数中,只需要循环检测 标志位 后 并发送发送缓冲区中的数据就可以完成接收并发送数据了。 中断接收在接收到数据之后 需要在回调函数中要重新打开。 因为中断接收一次会自动关闭

  3. 在使用UART 的IT 接收时。要配置NVIC :USART 线的 优先级和 使能USART线

        //打开了串口1的总中断
        HAL_NVIC_SetPriority(USART1_IRQn,3,0);
        HAL_NVIC_EnableIRQ(USART1_IRQn);
    
  4. 这里的定长,是因为中断只有接收到20个字节之后,才会进入回调函数

2. 初始化UART1部分

  • 主要关注中断 完成接收回调函数部分。 主要完成了数据cpy 和置位接收状态以及 重新启动接收数据。
  • 以及关注定义的接收、发送缓冲区和Rx_Date接收状态标志位
/* 初始化串口 */
void U1_Init(uint32_t bandrate){
    uart1.Instance = USART1;                    //使用那个串口
    uart1.Init.BaudRate = bandrate;             //波特率
    uart1.Init.WordLength = UART_WORDLENGTH_8B; //数据位长度
    uart1.Init.StopBits = UART_STOPBITS_1;      //停止位
    uart1.Init.Parity = UART_PARITY_NONE;       //校验模式
    uart1.Init.Mode = UART_MODE_TX_RX;          //传输模式
    uart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; //流控
    HAL_UART_Init(&uart1);
    HAL_UART_Receive_IT(&uart1,rxBuff,20);  //接收20个,以中断方式
}

void U2_Init(uint32_t bandrate){
    uart2.Instance = USART2;                    //使用那个串口
    uart2.Init.BaudRate = bandrate;             //波特率
    uart2.Init.WordLength = UART_WORDLENGTH_8B; //数据位长度
    uart2.Init.StopBits = UART_STOPBITS_1;      //停止位
    uart2.Init.Parity = UART_PARITY_NONE;       //校验模式
    uart2.Init.Mode = UART_MODE_TX_RX;          //传输模式
    uart2.Init.HwFlowCtl = UART_HWCONTROL_NONE; //流控
    HAL_UART_Init(&uart2);
}

void U3_Init(uint32_t bandrate){
    uart3.Instance = USART3;                    //使用那个串口
    uart3.Init.BaudRate = bandrate;             //波特率
    uart3.Init.WordLength = UART_WORDLENGTH_8B; //数据位长度
    uart3.Init.StopBits = UART_STOPBITS_1;      //停止位
    uart3.Init.Parity = UART_PARITY_NONE;       //校验模式
    uart3.Init.Mode = UART_MODE_TX_RX;          //传输模式
    uart3.Init.HwFlowCtl = UART_HWCONTROL_NONE; //流控
    HAL_UART_Init(&uart3);
}

3. UART硬件初始化回调

/* UART硬件初始化回调 */
void HAL_UART_MspInit(UART_HandleTypeDef *huart){
    
    GPIO_InitTypeDef GPIO_InitType;
    
    if(huart->Instance == USART1){          //判断那个串口在进行初始化
        __HAL_RCC_USART1_CLK_ENABLE();
        __HAL_RCC_GPIOA_CLK_ENABLE();
        
        GPIO_InitType.Pin = GPIO_PIN_9;
        GPIO_InitType.Mode = GPIO_MODE_AF_PP;
        GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
        HAL_GPIO_Init(GPIOA,&GPIO_InitType);
        
        GPIO_InitType.Pin = GPIO_PIN_10;
        GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
        GPIO_InitType.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(GPIOA,&GPIO_InitType);
        //打开了串口1的总中断
        HAL_NVIC_SetPriority(USART1_IRQn,3,0);
        HAL_NVIC_EnableIRQ(USART1_IRQn);
        
    }else if(huart->Instance == USART2){
        __HAL_RCC_GPIOA_CLK_ENABLE();
        __HAL_RCC_USART2_CLK_ENABLE();
        
        GPIO_InitType.Pin = GPIO_PIN_2;
        GPIO_InitType.Mode = GPIO_MODE_AF_PP;
        GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
        HAL_GPIO_Init(GPIOA,&GPIO_InitType);
        
        GPIO_InitType.Pin = GPIO_PIN_3;
        GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
        GPIO_InitType.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(GPIOA,&GPIO_InitType);
    }else if(huart->Instance == USART3){
        __HAL_RCC_GPIOB_CLK_ENABLE();
        __HAL_RCC_USART3_CLK_ENABLE();
        
        GPIO_InitType.Pin = GPIO_PIN_10;
        GPIO_InitType.Mode = GPIO_MODE_AF_PP;
        GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
        HAL_GPIO_Init(GPIOB,&GPIO_InitType);
        
        GPIO_InitType.Pin = GPIO_PIN_11;
        GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
        GPIO_InitType.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(GPIOB,&GPIO_InitType);
    }
}

3. 回调函数部分

/* 强声明的接收完成回调函数 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1){
        memcpy(txBuff, rxBuff, 20);             // 拷贝到txBuff
        rxState = 1;                            // 表示接收完成
        HAL_UART_Receive_IT(&uart1,rxBuff,20);  // 准备接收下一次
            
    }else if(huart->Instance == USART2){
        
    }else if(huart->Instance == USART3){
        
    }
}

/* 强声明的错误回调函数 */
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1){
                
        }else if(huart->Instance == USART2){
            
        }else if(huart->Instance == USART3){
            
        }
}

/* 强声明的发送完成回调函数 */
void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1){
            
    }else if(huart->Instance == USART2){
        
    }else if(huart->Instance == USART3){
        
    }
}

4. 函数测试部分

  • 主要完成了轮询检测状态并返回接收到的 拷贝到 发送缓冲区 的 数据
#include "stm32f1xx_hal.h"

#include "rcc.h"
#include "led.h"
#include "key.h"

#include "Uart.h"
/*函 数 名:HAL库:中断方式。实现UART串口数据收发。 定长  20字节 */
 

int main (void)
{
    HAL_Init();//初始化HAL库
    
    RccClock_Init();//配置时钟树72M

    LED_Init();
    
    Uart1_Init(921600);//初始化串口1
    
    while(1)
    {
       if(Rx_Date == 1) //如果接收标志位置1 
       {
           Rx_Date = 0;
           HAL_UART_Transmit_IT(&Uart1,Tx_Buff,20);//发送 发送缓冲区的20个字节
       }
        
    }
}

五、多指针定位+循环收发缓冲区方案设计(“六”为实践此方案)

1. 介绍

轮询阻塞的方式效率不高,一般会使用中断或者DMA方式收发数据

这时就需要定义一个缓冲区,这里暂定为2048字节。

  • 缓冲区为一个、一维数组,循环使用,要注意缓冲区不要出现回卷覆盖,接收的数据要及时处理。

2. 大致思路

标记2048缓冲区每次数据的起始和结束位置

  • 创建一个标记结构体,成员为指针pS(Start)和pE(Een)。他们用来在2048的缓冲区中,指向每次接收的数据的开头和起始位置。
  • 使用我们刚才创建的‘标记结构体’,创建一个有10个成员的数组SN
  • 创建一个IN和OUT指针,初始化时指向SN数组的起始位置(0号成员)
  • 创建一个END指针,指向SN数组的结束位置(9号成员)

巧妙地判断接收到数据,并循环利用标记

  • 当第一次接收到数据之后,使用0号成员的pS、pE指针定位数组的起始和结束位置, 同时IN++,指向数组SN的1号成员
    • 此时,可以在while循环中判断,当OUT指针与IN指针不指向同一个位置了,那么就代表已经缓冲区收到数据了。在处理完数据之后,使得OUT++,指向第1号成员~
  • 当第pS跳到END指向的位置时,应使得PS下次跳的位置为数组SN的起始位置:数据回滚,防止越界

防止2048缓冲区空余位置不够

  • 约定每次接收数据的MAX值,防止空余位置不够。
  • 所以在每次接收之后,都需要判断空余位置,若小于MAX值,则直接回卷,防止越界

利用空闲中断,完成对数据的处理

  • 定义了单次接收的最大值MAX,若MAX=256,那么别人一次发送的值最多为255字节,因为当一次次发送256时,会同时触发完成中断和空闲中断,这是不允许的。
  • 我们只利用空闲中断对数据进行处理哦~

六、HAL库:空闲中断方式实现串口1+不定长数据接收+循环收发缓冲区+收发数据

1. 不定长接收数据的实现思路及相关函数

在使用简单串口时,无法知道对方给我发送的确切的数据量。我就没法确切的定义我们需要接收多少个字节的字节。只能接收到固定长度的字节后统一处理。

要实现不定长接收数据,我们通常是利用空闲中断。

当一次连续的接收完成后,会出现空闲帧,然后进入空闲中断中。

我们就可以利用空闲中断,来判断当前为一次数据的接收结束。

然后可以利用RxferCount,来获取本次接受了多少个字节。

在空闲中断回调中,我们可以对数据进行处理或判断

注意:

  1. 定义了单次接收的最大值MAX,若MAX=256,那么别人一次发送的值最多为255字节,因为当一次次发送256时,会同时触发完成中断和空闲中断,这是不允许的。

  2. 一定要想明白,位置控制数组rxLocation 和 rxInPtr和 rxOutPtr的关系,可以看图理解

  • 我们只利用空闲中断对数据进行处理哦~

相关函数

  • 空闲中断打开函数:__HAL_UART_ENABLE_IT(&uart1.uart,UART_IT_IDLE);

  • 在每次进入中断后,判断是否为空闲中断: if(__HAL_UART_GET_FLAG(&uart1.uart, UART_FLAG_IDLE))

  • 清除空闲标志位 __HAL_UART_CLEAR_FLAG(&uart1.uart, UART_FLAG_IDLE);

  • 终止当前的接收(会把RxferCount清零) HAL_UART_AbortReceive_IT(&uart1.uart);

  • 终止接收回调函数

    void HAL_UART_AbortReceiveCpltCallback(UART_HandleTypeDef *huart)

  • 发送完成回调函数

    HAL_UART_TxCpltCallback

2. 程序设计

STM32C8T6单片机一共有20K的RAM

2.1 设计介绍:

  • 定义缓冲区宏

    /* 缓冲区宏定义 */
    #define U1_RX_SIZE 2048
    #define U1_TX_SIZE 2048
    #define U1_RX_MAX  256          //这里需要注意,我们是利用空闲中断对数据进行处理,不能单次发送256字节,否则进入完成中断
    
  • 定义接收、发送缓冲区、单次最大接收量(2K 2048字节大小)

    /* 缓冲区 */
    uint8_t U1_Rx_Buff[U1_RX_SIZE];
    uint8_t U1_Tx_Buff[U1_TX_SIZE];
    
  • 定义结构体,成员为 :Start End 指针

    /* Location Ctrl Block */
    /* (接收/发送)位置控制块 */
    typedef struct{
        uint8_t* start;
        uint8_t* end;
    }LCB;
    
    
  • 定义结构体串口控制块,其中包含了所有的指针和总控结构体

    /* Uart Ctrl Block */
    /* 串口控制块 */
    typedef struct{
        uint32_t    rxCount;            //记录接收缓冲区中当前已有的数据量
        uint32_t    txCount;            //记录发送缓冲区中当前已有的数据量
        
        LCB         rxLocation[10];     //记录接收缓冲区每次接收的位置
        LCB         txLocation[10];     //记录发送缓冲区每次接收的位置
        
        LCB*        rxInPtr;            //指向下次接收缓冲区存放位置
        LCB*        rxOutPtr;           //指向下次接收缓冲区读取位置
        LCB*        rxEndPtr;           //指向接收缓冲区结束位置
        
        LCB*        txInPtr;            //指向下次发送缓冲区存放位置
        LCB*        txOutPtr;           //指向下次发送缓冲区读取位置
        LCB*        txEndPtr;           //指向发送缓冲区结束位置
        
        UART_HandleTypeDef  uart;       //串口总控结构体
        
        uint8_t     TxState;            //发送忙碌标志位
    }UCB;
    
  • 其他

    /* 初始化 */
    void U1_Init(uint32_t bandrate);
    
    /* 初始化UCB控制块指针 */
    void U1_PtrInit(void);
    
    /* 转移RxBuff数据到TxBuff */
    void U1_DataRxToTx(uint8_t* data, uint32_t data_len);
    
    /* 总控结构体 */
    extern UCB  uart1;
    
    /* 缓冲区 */
    extern uint8_t U1_Rx_Buff[U1_RX_SIZE];
    extern uint8_t U1_Tx_Buff[U1_TX_SIZE];
    
    /* 状态位 */
    extern uint8_t rxState;
    
    

2.2 文件架构:

  • Uart.h :定义了 宏、结构体、函数与变量声明
  • Uart.c :主要针对串口 1 进行配置:空闲中断打开和处理、包括初始化参数、设置缓冲区指针….
  • stm32fxx_It.c : 主要是 void USART1_IRQHandler(void) 的中断函数:该函数是串口 1 的中断服务函数。首先调用 HAL 库的中断处理函数,后续 检测到串口 1 进入空闲状态时,清除空闲中断标志位,计算接收字节数量并累加,然后终止接收,触发终止接收回调函数。终止接收回调函数在Uart.c中
  • main.c :在主循环中,通过判断接收和发送缓冲区的指针状态,实现数据的接收和发送,并在指针到达末尾时进行回卷操作。当接收缓冲区有数据时,将其拷贝到发送缓冲区并移动输出指针;当发送缓冲区有数据且处于空闲状态时,发送数据并移动输出指针。

uart.h

#ifndef __UART_H
#define __UART_H

#include "stm32f1xx_hal.h"
#include "stdint.h"

#include "string.h"

/* 缓冲区宏定义 */
#define U1_RX_SIZE 2048
#define U1_TX_SIZE 2048
#define U1_RX_MAX  256          //这里需要注意,我们是利用空闲中断对数据进行处理,不能单次发送256字节,否则进入完成中断

/* Location Ctrl Block */
/* (接收/发送)位置控制块 */
typedef struct{
    uint8_t* start;
    uint8_t* end;
}LCB;

/* Uart Ctrl Block */
/* 串口控制块 */
typedef struct{
    uint32_t    rxCount;            //记录接收缓冲区中当前已有的数据量
    uint32_t    txCount;            //记录发送缓冲区中当前已有的数据量
    
    LCB         rxLocation[10];     //记录接收缓冲区每次接收的位置
    LCB         txLocation[10];     //记录发送缓冲区每次接收的位置
    
    LCB*        rxInPtr;            //指向下次接收缓冲区存放位置
    LCB*        rxOutPtr;           //指向下次接收缓冲区读取位置
    LCB*        rxEndPtr;           //指向接收缓冲区结束位置
    
    LCB*        txInPtr;            //指向下次发送缓冲区存放位置
    LCB*        txOutPtr;           //指向下次发送缓冲区读取位置
    LCB*        txEndPtr;           //指向发送缓冲区结束位置
    
    UART_HandleTypeDef  uart;       //串口总控结构体
    
    uint8_t     TxState;            //发送忙碌标志位
}UCB;

/* 初始化 */
void U1_Init(uint32_t bandrate);

/* 初始化UCB控制块指针 */
void U1_PtrInit(void);

/* 转移RxBuff数据到TxBuff */
void U1_DataRxToTx(uint8_t* data, uint32_t data_len);

/* 总控结构体 */
extern UCB  uart1;

/* 缓冲区 */
extern uint8_t U1_Rx_Buff[U1_RX_SIZE];
extern uint8_t U1_Tx_Buff[U1_TX_SIZE];

/* 状态位 */
extern uint8_t rxState;

#endif

uart.c

#include "uart.h"

/* 创建串口总控结构体 */
UCB uart1;

/* 缓冲区 */
uint8_t U1_Rx_Buff[U1_RX_SIZE];
uint8_t U1_Tx_Buff[U1_TX_SIZE];

/* 初始化串口 */
void U1_Init(uint32_t bandrate){
    uart1.uart.Instance = USART1;                    //使用那个串口
    uart1.uart.Init.BaudRate = bandrate;             //波特率
    uart1.uart.Init.WordLength = UART_WORDLENGTH_8B; //数据位长度
    uart1.uart.Init.StopBits = UART_STOPBITS_1;      //停止位
    uart1.uart.Init.Parity = UART_PARITY_NONE;       //校验模式
    uart1.uart.Init.Mode = UART_MODE_TX_RX;          //传输模式
    uart1.uart.Init.HwFlowCtl = UART_HWCONTROL_NONE; //流控
    HAL_UART_Init(&uart1.uart);
    
    /* 初始化UCB控制块指针 */
    U1_PtrInit();
    
    /* 打开空闲中断 */
    __HAL_UART_ENABLE_IT(&uart1.uart,UART_IT_IDLE);
    
    /* 开始接收数据 */
    HAL_UART_Receive_IT(&uart1.uart, uart1.rxInPtr->start, U1_RX_MAX);  //接收位置为当前LCB位置控制块的In指针所指向的缓冲区的位置
}

/* 初始化U1_UCB控制块指针 */
void U1_PtrInit(void){
    uart1.rxCount  = 0;
    uart1.rxInPtr  = &uart1.rxLocation[0];
    uart1.rxOutPtr = &uart1.rxLocation[0];
    uart1.rxEndPtr = &uart1.rxLocation[9];
    uart1.rxInPtr->start = &U1_Rx_Buff[0];      //让当前接收位置控制块的start,指向下一次接收到的数据将要存放的位置
    
    uart1.txCount  = 0;
    uart1.txInPtr  = &uart1.txLocation[0];
    uart1.txOutPtr = &uart1.txLocation[0];
    uart1.txEndPtr = &uart1.txLocation[9];
    uart1.txInPtr->start = &U1_Tx_Buff[0];      //让当前发送位置控制块的start,指向下一次需要发送的数据的存放位置
}

/* 转移U1_Rx_Buff数据到 U1_Tx_Buff */
void U1_DataRxToTx(uint8_t* data, uint32_t data_len){
    /* 判断剩余空间是否足够,要不要回卷 */
    if((U1_TX_SIZE - uart1.txCount) > data_len){    
        /* 如果够 */
        uart1.txInPtr->start = &U1_Tx_Buff[uart1.txCount];
    }
    else{/* 如果剩余空间不够 */
        uart1.txCount = 0;
        uart1.txInPtr->start = &U1_Tx_Buff[0];
    }
    /* 复制data到U1_Tx_Buff缓冲区 */
    memcpy(uart1.txInPtr->start, data, data_len);
    /* 累加txCount */
    uart1.txCount += data_len;
    /* 标记这次的发送数据的结束位置 */
    uart1.txInPtr->end = &U1_Tx_Buff[uart1.txCount - 1];
    /* 移动txIn */
    uart1.txInPtr++;
    /* 判断txIn指针是否需要回卷 */
    if(uart1.txInPtr == uart1.txEndPtr){
        uart1.txInPtr = &uart1.txLocation[0];
    }
}

/* UART硬件初始化回调 */
void HAL_UART_MspInit(UART_HandleTypeDef *huart){
    
    GPIO_InitTypeDef GPIO_InitType;
    
    if(huart->Instance == USART1){          //判断那个串口在进行初始化
        __HAL_RCC_USART1_CLK_ENABLE();
        __HAL_RCC_GPIOA_CLK_ENABLE();
        
        GPIO_InitType.Pin = GPIO_PIN_9;
        GPIO_InitType.Mode = GPIO_MODE_AF_PP;
        GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
        HAL_GPIO_Init(GPIOA,&GPIO_InitType);
        
        GPIO_InitType.Pin = GPIO_PIN_10;
        GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
        GPIO_InitType.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(GPIOA,&GPIO_InitType);
        //打开了串口1的总中断
        HAL_NVIC_SetPriority(USART1_IRQn,3,0);
        HAL_NVIC_EnableIRQ(USART1_IRQn);
        
    }else if(huart->Instance == USART2){
        __HAL_RCC_GPIOA_CLK_ENABLE();
        __HAL_RCC_USART2_CLK_ENABLE();
        
        GPIO_InitType.Pin = GPIO_PIN_2;
        GPIO_InitType.Mode = GPIO_MODE_AF_PP;
        GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
        HAL_GPIO_Init(GPIOA,&GPIO_InitType);
        
        GPIO_InitType.Pin = GPIO_PIN_3;
        GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
        GPIO_InitType.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(GPIOA,&GPIO_InitType);
    }else if(huart->Instance == USART3){
        __HAL_RCC_GPIOB_CLK_ENABLE();
        __HAL_RCC_USART3_CLK_ENABLE();
        
        GPIO_InitType.Pin = GPIO_PIN_10;
        GPIO_InitType.Mode = GPIO_MODE_AF_PP;
        GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
        HAL_GPIO_Init(GPIOB,&GPIO_InitType);
        
        GPIO_InitType.Pin = GPIO_PIN_11;
        GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
        GPIO_InitType.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(GPIOB,&GPIO_InitType);
    }
}

/* 强声明的接收完成回调函数 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1){
            
    }else if(huart->Instance == USART2){
        
    }else if(huart->Instance == USART3){
        
    }
}

/* 强声明的错误回调函数 */
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1){
                
        }else if(huart->Instance == USART2){
            
        }else if(huart->Instance == USART3){
            
        }
}

/* 强声明的发送完成回调函数 */
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1){
        /* 发送完成,标志位清零 */
        uart1.TxState = 0;
    }else if(huart->Instance == USART2){
        
    }else if(huart->Instance == USART3){
        
    }
}

/* 强声明的接收终止回调函数 */
void HAL_UART_AbortReceiveCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1){
        /* 标记结束位置 */
        uart1.rxInPtr->end = &U1_Rx_Buff[uart1.rxCount - 1];
        
        /* 挪动rxIn指针 */
        uart1.rxInPtr++;
        /* 判断rxIn指针是否需要回卷 */
        if(uart1.rxInPtr == uart1.rxEndPtr){
            uart1.rxInPtr = &uart1.rxLocation[0];
        }
        
        /* 判断接收缓冲区是否需要回卷 */
        if((U1_RX_SIZE - uart1.rxCount) < U1_RX_MAX){
            uart1.rxCount = 0;
            uart1.rxInPtr->start = &U1_Rx_Buff[0];
        }else{
            /* 剩余位置够 */
            uart1.rxInPtr->start = &U1_Rx_Buff[uart1.rxCount];
        }
        /* 重新开启中断接收 */
        HAL_UART_Receive_IT(&uart1.uart, uart1.rxInPtr->start, U1_RX_MAX);
    }else if(huart->Instance == USART2){

    }else if(huart->Instance == USART3){
 
    }

}

stm32fxx_It.c

/*-------------------------------------------------*/
/*                                                 */
/*          实现各种中断服务函数的源文件           */
/*                                                 */
/*-------------------------------------------------*/

#include "stm32f1xx_hal.h"   
#include "stm32f1xx_it.h"

#include "uart.h"

void EXTI15_10_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);
}
void EXTI0_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}

/*-------------------------------------------------*/
/*函数名:不可屏蔽中断处理函数                     */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void NMI_Handler(void)
{

}

/*-------------------------------------------------*/
/*函数名:硬件出错后进入的中断处理函数             */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void HardFault_Handler(void)
{

}
/*-------------------------------------------------*/
/*函数名:软中断,SWI 指令调用的处理函数           */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void SVC_Handler(void)
{
    
}
/*-------------------------------------------------*/
/*函数名:可挂起的系统服务处理函数                 */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void PendSV_Handler(void)
{
    
}
/*-------------------------------------------------*/
/*函数名:SysTic系统嘀嗒定时器处理函数             */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void SysTick_Handler(void)
{  
    HAL_IncTick();
}

/*-------------------------------------------------*/
/*函数名:串口1中断处理函数             */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void USART1_IRQHandler(void)
{  
    HAL_UART_IRQHandler(&uart1.uart);
    
    /* 在每次进入中断后,判断是否为空闲中断 */
    if(__HAL_UART_GET_FLAG(&uart1.uart, UART_FLAG_IDLE)){
        /* 清除空闲标志位 */
        //__HAL_UART_CLEAR_FLAG(&uart1.uart, UART_FLAG_IDLE);
        __HAL_UART_CLEAR_IDLEFLAG(&uart1.uart);
        /* 获取这次传输了多少字节 */
        uart1.rxCount += (U1_RX_MAX - uart1.uart.RxXferCount);
        
        /* 终止当前的接收(会把RxferCount清零) */
        HAL_UART_AbortReceive_IT(&uart1.uart);
        
    }
}

main.c

#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "sw.h"
#include "uart.h"

int main(void){

    HAL_Init();
    RccClock_Init();
    U1_Init(921600);
    
    while(1){
        /* 判断接收缓冲区是否有数据 */
        if(uart1.rxInPtr != uart1.rxOutPtr){
            /* 转移这次接收的一段数据到发送缓冲区 */
            U1_DataRxToTx(uart1.rxOutPtr->start, (uart1.rxOutPtr->end - uart1.rxOutPtr->start + 1));
            /* 移动rxOutPtr到下一次cpy的地址 */
            uart1.rxOutPtr++;
            /* 判断rxOutPtr是否需要回卷 */
            if(uart1.rxOutPtr == uart1.rxEndPtr){
                uart1.rxOutPtr = &uart1.rxLocation[0];
            }
        }
        
        /* 判断发送缓冲区是否有数据 */
        if((uart1.txInPtr != uart1.txOutPtr) && (uart1.TxState == 0) ){
            uart1.TxState = 1;
            
            /* 发送数据 */
            HAL_UART_Transmit_IT(&uart1.uart, uart1. txOutPtr->start, (uart1.txOutPtr->end - uart1.txOutPtr->start + 1));
            /* 移动txOutPtr到下一次cpy的地址 */
            uart1.txOutPtr++;
            /* 判断txOutPtr是否需要回卷 */
            if(uart1.txOutPtr == uart1.txEndPtr){
                uart1.txOutPtr = &uart1.txLocation[0];
            }
        }
        
    }
}

七、HAL库:空闲中断方式实现串口123+不定长数据接收+循环收发缓冲区+收发数据

在第七小节拓展而来:实现串口1 2 3 同时收发数据,可以用来控制多个设备用

uart.h

#ifndef __UART_H
#define __UART_H

#include "stm32f1xx_hal.h"
#include "stdint.h"

#include "string.h"

/* 缓冲区宏定义 */
#define U1_RX_SIZE 2048         //接收缓冲区长度
#define U1_TX_SIZE 2048         //发送缓冲区长度
#define U1_RX_MAX  256          //最大单次发送量(实际值 - 1 = 255字节)

#define U2_RX_SIZE 2048
#define U2_TX_SIZE 2048
#define U2_RX_MAX  256 

#define U3_RX_SIZE 2048
#define U3_TX_SIZE 2048
#define U3_RX_MAX  256 

/* Location Ctrl Block */
/* (接收/发送)位置控制块 */
typedef struct{
    uint8_t* start;
    uint8_t* end;
}LCB;

/* Uart Ctrl Block */
/* 串口控制块 */
typedef struct{
    uint32_t    rxCount;            //记录接收缓冲区中当前已有的数据量
    uint32_t    txCount;            //记录发送缓冲区中当前已有的数据量
    
    LCB         rxLocation[10];     //记录接收缓冲区每次接收的位置
    LCB         txLocation[10];     //记录发送缓冲区每次接收的位置
    
    LCB*        rxInPtr;            //指向下次接收缓冲区存放位置
    LCB*        rxOutPtr;           //指向下次接收缓冲区读取位置
    LCB*        rxEndPtr;           //指向接收缓冲区结束位置
    
    LCB*        txInPtr;            //指向下次发送缓冲区存放位置
    LCB*        txOutPtr;           //指向下次发送缓冲区读取位置
    LCB*        txEndPtr;           //指向发送缓冲区结束位置
    
    UART_HandleTypeDef  uart;       //串口总控结构体
    
    uint8_t     TxState;            //发送忙碌标志位
}UCB;

/* 初始化 */
void U1_Init(uint32_t bandrate);
void U2_Init(uint32_t bandrate);
void U3_Init(uint32_t bandrate);

/* 初始化UCB控制块指针 */
void U1_PtrInit(void);
void U2_PtrInit(void);
void U3_PtrInit(void);

/* 转移RxBuff数据到TxBuff */
void U1_DataRxToTx(uint8_t* data, uint32_t data_len);
void U2_DataRxToTx(uint8_t* data, uint32_t data_len);
void U3_DataRxToTx(uint8_t* data, uint32_t data_len);

/* 总控结构体 */
extern UCB  uart1;
extern UCB  uart2;
extern UCB  uart3;

/* 缓冲区 */
extern uint8_t U1_Rx_Buff[U1_RX_SIZE];
extern uint8_t U1_Tx_Buff[U1_TX_SIZE];

extern uint8_t U2_Rx_Buff[U2_RX_SIZE];
extern uint8_t U2_Tx_Buff[U2_TX_SIZE];

extern uint8_t U3_Rx_Buff[U3_RX_SIZE];
extern uint8_t U3_Tx_Buff[U3_TX_SIZE];

#endif

uart.c

#include "uart.h"

/* 创建串口总控结构体 */
UCB uart1;
UCB uart2;
UCB uart3;

/* 缓冲区 */
uint8_t U1_Rx_Buff[U1_RX_SIZE];
uint8_t U1_Tx_Buff[U1_TX_SIZE];

uint8_t U2_Rx_Buff[U2_RX_SIZE];
uint8_t U2_Tx_Buff[U2_TX_SIZE];

uint8_t U3_Rx_Buff[U3_RX_SIZE];
uint8_t U3_Tx_Buff[U3_TX_SIZE];

/* 初始化串口 */
void U1_Init(uint32_t bandrate){
    uart1.uart.Instance = USART1;                    //使用那个串口
    uart1.uart.Init.BaudRate = bandrate;             //波特率
    uart1.uart.Init.WordLength = UART_WORDLENGTH_8B; //数据位长度
    uart1.uart.Init.StopBits = UART_STOPBITS_1;      //停止位
    uart1.uart.Init.Parity = UART_PARITY_NONE;       //校验模式
    uart1.uart.Init.Mode = UART_MODE_TX_RX;          //传输模式
    uart1.uart.Init.HwFlowCtl = UART_HWCONTROL_NONE; //流控
    HAL_UART_Init(&uart1.uart);
    
    /* 初始化UCB控制块指针 */
    U1_PtrInit();
    
}

/* 初始化串口 */
void U2_Init(uint32_t bandrate){
    uart2.uart.Instance = USART2;                    //使用那个串口
    uart2.uart.Init.BaudRate = bandrate;             //波特率
    uart2.uart.Init.WordLength = UART_WORDLENGTH_8B; //数据位长度
    uart2.uart.Init.StopBits = UART_STOPBITS_1;      //停止位
    uart2.uart.Init.Parity = UART_PARITY_NONE;       //校验模式
    uart2.uart.Init.Mode = UART_MODE_TX_RX;          //传输模式
    uart2.uart.Init.HwFlowCtl = UART_HWCONTROL_NONE; //流控
    HAL_UART_Init(&uart2.uart);
    
    /* 初始化UCB控制块指针 */
    U2_PtrInit();
    
}

/* 初始化串口 */
void U3_Init(uint32_t bandrate){
    uart3.uart.Instance = USART3;                    //使用那个串口
    uart3.uart.Init.BaudRate = bandrate;             //波特率
    uart3.uart.Init.WordLength = UART_WORDLENGTH_8B; //数据位长度
    uart3.uart.Init.StopBits = UART_STOPBITS_1;      //停止位
    uart3.uart.Init.Parity = UART_PARITY_NONE;       //校验模式
    uart3.uart.Init.Mode = UART_MODE_TX_RX;          //传输模式
    uart3.uart.Init.HwFlowCtl = UART_HWCONTROL_NONE; //流控
    HAL_UART_Init(&uart3.uart);
    
    /* 初始化UCB控制块指针 */
    U3_PtrInit();
    
}

/* 初始化U1_UCB控制块指针 */
void U1_PtrInit(void){
    uart1.rxCount  = 0;
    uart1.rxInPtr  = &uart1.rxLocation[0];
    uart1.rxOutPtr = &uart1.rxLocation[0];
    uart1.rxEndPtr = &uart1.rxLocation[9];
    uart1.rxInPtr->start = &U1_Rx_Buff[0];
    
    uart1.txCount  = 0;
    uart1.txInPtr  = &uart1.txLocation[0];
    uart1.txOutPtr = &uart1.txLocation[0];
    uart1.txEndPtr = &uart1.txLocation[9];
    uart1.txInPtr->start = &U1_Tx_Buff[0];
    
    __HAL_UART_ENABLE_IT(&uart1.uart,UART_IT_IDLE);
    HAL_UART_Receive_IT(&uart1.uart, uart1.rxInPtr->start, U1_RX_MAX);
}

void U2_PtrInit(void){
    uart2.rxCount  = 0;
    uart2.rxInPtr  = &uart2.rxLocation[0];
    uart2.rxOutPtr = &uart2.rxLocation[0];
    uart2.rxEndPtr = &uart2.rxLocation[9];
    uart2.rxInPtr->start = &U2_Rx_Buff[0];
    
    uart2.txCount  = 0;
    uart2.txInPtr  = &uart2.txLocation[0];
    uart2.txOutPtr = &uart2.txLocation[0];
    uart2.txEndPtr = &uart2.txLocation[9];
    uart2.txInPtr->start = &U2_Tx_Buff[0];
    
    __HAL_UART_ENABLE_IT(&uart2.uart,UART_IT_IDLE);
    HAL_UART_Receive_IT(&uart2.uart, uart2.rxInPtr->start, U2_RX_MAX);
}

void U3_PtrInit(void){
    uart3.rxCount  = 0;
    uart3.rxInPtr  = &uart3.rxLocation[0];
    uart3.rxOutPtr = &uart3.rxLocation[0];
    uart3.rxEndPtr = &uart3.rxLocation[9];
    uart3.rxInPtr->start = &U3_Rx_Buff[0];
    
    uart3.txCount  = 0;
    uart3.txInPtr  = &uart3.txLocation[0];
    uart3.txOutPtr = &uart3.txLocation[0];
    uart3.txEndPtr = &uart3.txLocation[9];
    uart3.txInPtr->start = &U3_Tx_Buff[0];
    
    __HAL_UART_ENABLE_IT(&uart3.uart,UART_IT_IDLE);
    HAL_UART_Receive_IT(&uart3.uart, uart3.rxInPtr->start, U3_RX_MAX);
}

/* 转移Rx_Buff数据到 Tx_Buff */
void U1_DataRxToTx(uint8_t* data, uint32_t data_len){
    if((U1_TX_SIZE - uart1.txCount) > data_len){
        uart1.txInPtr->start = &U1_Tx_Buff[uart1.txCount];
    }
    else{
        uart1.txCount = 0;
        uart1.txInPtr->start = &U1_Tx_Buff[0];
    }
    memcpy(uart1.txInPtr->start, data, data_len);
    uart1.txCount += data_len;
    uart1.txInPtr->end = &U1_Tx_Buff[uart1.txCount - 1];
    uart1.txInPtr++;
    if(uart1.txInPtr == uart1.txEndPtr){
        uart1.txInPtr = &uart1.txLocation[0];
    }
}

void U2_DataRxToTx(uint8_t* data, uint32_t data_len){
    if((U2_TX_SIZE - uart2.txCount) > data_len){
        uart2.txInPtr->start = &U2_Tx_Buff[uart2.txCount];
    }
    else{
        uart2.txCount = 0;
        uart2.txInPtr->start = &U2_Tx_Buff[0];
    }
    memcpy(uart2.txInPtr->start, data, data_len);
    uart2.txCount += data_len;
    uart2.txInPtr->end = &U2_Tx_Buff[uart2.txCount - 1];
    uart2.txInPtr++;
    if(uart2.txInPtr == uart2.txEndPtr){
        uart2.txInPtr = &uart2.txLocation[0];
    }
}

void U3_DataRxToTx(uint8_t* data, uint32_t data_len){
    if((U3_TX_SIZE - uart3.txCount) > data_len){
        uart3.txInPtr->start = &U3_Tx_Buff[uart3.txCount];
    }
    else{
        uart3.txCount = 0;
        uart3.txInPtr->start = &U3_Tx_Buff[0];
    }
    memcpy(uart3.txInPtr->start, data, data_len);
    uart3.txCount += data_len;
    uart3.txInPtr->end = &U3_Tx_Buff[uart3.txCount - 1];
    uart3.txInPtr++;
    if(uart3.txInPtr == uart3.txEndPtr){
        uart3.txInPtr = &uart3.txLocation[0];
    }
}

/* UART硬件初始化回调 */
void HAL_UART_MspInit(UART_HandleTypeDef *huart){
    
    GPIO_InitTypeDef GPIO_InitType;
    
    if(huart->Instance == USART1){
        __HAL_RCC_USART1_CLK_ENABLE();
        __HAL_RCC_GPIOA_CLK_ENABLE();
        
        GPIO_InitType.Pin = GPIO_PIN_9;
        GPIO_InitType.Mode = GPIO_MODE_AF_PP;
        GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
        HAL_GPIO_Init(GPIOA,&GPIO_InitType);
        
        GPIO_InitType.Pin = GPIO_PIN_10;
        GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
        GPIO_InitType.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(GPIOA,&GPIO_InitType);

        HAL_NVIC_SetPriority(USART1_IRQn,3,0);
        HAL_NVIC_EnableIRQ(USART1_IRQn);
        
    }else if(huart->Instance == USART2){
        __HAL_RCC_GPIOA_CLK_ENABLE();
        __HAL_RCC_USART2_CLK_ENABLE();
        
        GPIO_InitType.Pin = GPIO_PIN_2;
        GPIO_InitType.Mode = GPIO_MODE_AF_PP;
        GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
        HAL_GPIO_Init(GPIOA,&GPIO_InitType);
        
        GPIO_InitType.Pin = GPIO_PIN_3;
        GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
        GPIO_InitType.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(GPIOA,&GPIO_InitType);
        
        HAL_NVIC_SetPriority(USART2_IRQn,3,0);
        HAL_NVIC_EnableIRQ(USART2_IRQn);
    }else if(huart->Instance == USART3){
        __HAL_RCC_GPIOB_CLK_ENABLE();
        __HAL_RCC_USART3_CLK_ENABLE();
        
        GPIO_InitType.Pin = GPIO_PIN_10;
        GPIO_InitType.Mode = GPIO_MODE_AF_PP;
        GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
        HAL_GPIO_Init(GPIOB,&GPIO_InitType);
        
        GPIO_InitType.Pin = GPIO_PIN_11;
        GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
        GPIO_InitType.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(GPIOB,&GPIO_InitType);
        
        HAL_NVIC_SetPriority(USART3_IRQn,3,0);
        HAL_NVIC_EnableIRQ(USART3_IRQn);
    }
}

/* 强声明的接收完成回调函数 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1){
            
    }else if(huart->Instance == USART2){
        
    }else if(huart->Instance == USART3){
        
    }
}

/* 强声明的错误回调函数 */
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1){
                
        }else if(huart->Instance == USART2){
            
        }else if(huart->Instance == USART3){
            
        }
}

/* 强声明的发送完成回调函数 */
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1){
        /* 发送完成,标志位清零 */
        uart1.TxState = 0;
    }else if(huart->Instance == USART2){
        uart2.TxState = 0;
    }else if(huart->Instance == USART3){
        uart3.TxState = 0;
    }
}

/* 强声明的接收终止回调函数 */
void HAL_UART_AbortReceiveCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1){
        uart1.rxInPtr->end = &U1_Rx_Buff[uart1.rxCount - 1];
        uart1.rxInPtr++;
        if(uart1.rxInPtr == uart1.rxEndPtr){
            uart1.rxInPtr = &uart1.rxLocation[0];
        }
        if((U1_RX_SIZE - uart1.rxCount) < U1_RX_MAX){
            uart1.rxCount = 0;
            uart1.rxInPtr->start = &U1_Rx_Buff[0];
        }else{
            uart1.rxInPtr->start = &U1_Rx_Buff[uart1.rxCount];
        }
        HAL_UART_Receive_IT(&uart1.uart, uart1.rxInPtr->start, U1_RX_MAX);
    }else if(huart->Instance == USART2){
        uart2.rxInPtr->end = &U2_Rx_Buff[uart2.rxCount - 1];
        uart2.rxInPtr++;
        if(uart2.rxInPtr == uart2.rxEndPtr){
            uart2.rxInPtr = &uart2.rxLocation[0];
        }
        if((U2_RX_SIZE - uart2.rxCount) < U2_RX_MAX){
            uart2.rxCount = 0;
            uart2.rxInPtr->start = &U2_Rx_Buff[0];
        }else{
            uart2.rxInPtr->start = &U2_Rx_Buff[uart2.rxCount];
        }
        HAL_UART_Receive_IT(&uart2.uart, uart2.rxInPtr->start, U2_RX_MAX);
    }else if(huart->Instance == USART3){
        uart3.rxInPtr->end = &U3_Rx_Buff[uart3.rxCount - 1];
        uart3.rxInPtr++;
        if(uart3.rxInPtr == uart3.rxEndPtr){
            uart3.rxInPtr = &uart3.rxLocation[0];
        }
        if((U3_RX_SIZE - uart3.rxCount) < U3_RX_MAX){
            uart3.rxCount = 0;
            uart3.rxInPtr->start = &U3_Rx_Buff[0];
        }else{
            uart3.rxInPtr->start = &U3_Rx_Buff[uart3.rxCount];
        }
        HAL_UART_Receive_IT(&uart3.uart, uart3.rxInPtr->start, U3_RX_MAX);
    }

}

stm32fxx_It.c

/*-------------------------------------------------*/
/*                                                 */
/*          实现各种中断服务函数的源文件           */
/*                                                 */
/*-------------------------------------------------*/

#include "stm32f1xx_hal.h"   
#include "stm32f1xx_it.h"

#include "uart.h"

void EXTI15_10_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);
}
void EXTI0_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}

/*-------------------------------------------------*/
/*函数名:不可屏蔽中断处理函数                     */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void NMI_Handler(void)
{

}

/*-------------------------------------------------*/
/*函数名:硬件出错后进入的中断处理函数             */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void HardFault_Handler(void)
{

}
/*-------------------------------------------------*/
/*函数名:软中断,SWI 指令调用的处理函数           */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void SVC_Handler(void)
{
    
}
/*-------------------------------------------------*/
/*函数名:可挂起的系统服务处理函数                 */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void PendSV_Handler(void)
{
    
}
/*-------------------------------------------------*/
/*函数名:SysTic系统嘀嗒定时器处理函数             */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void SysTick_Handler(void)
{  
    HAL_IncTick();
}

/*-------------------------------------------------*/
/*函数名:串口1中断处理函数                        */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void USART1_IRQHandler(void)
{  
    HAL_UART_IRQHandler(&uart1.uart);
    
    /* 在每次进入中断后,判断是否为空闲中断 */
    if(__HAL_UART_GET_FLAG(&uart1.uart, UART_FLAG_IDLE)){
        /* 清除空闲标志位 */
        //__HAL_UART_CLEAR_FLAG(&uart1.uart, UART_FLAG_IDLE);
        __HAL_UART_CLEAR_IDLEFLAG(&uart1.uart);
        /* 获取这次传输了多少字节 */
        uart1.rxCount += (U1_RX_MAX - uart1.uart.RxXferCount);
        
        /* 终止当前的接收(会把RxferCount清零) */
        HAL_UART_AbortReceive_IT(&uart1.uart);
        
    }
}

/*-------------------------------------------------*/
/*函数名:串口2中断处理函数                        */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void USART2_IRQHandler(void)
{  
    HAL_UART_IRQHandler(&uart2.uart);
    

    if(__HAL_UART_GET_FLAG(&uart2.uart, UART_FLAG_IDLE)){
        __HAL_UART_CLEAR_IDLEFLAG(&uart2.uart);
        
        uart2.rxCount += (U2_RX_MAX - uart2.uart.RxXferCount);
        
        HAL_UART_AbortReceive_IT(&uart2.uart);
    }
}

/*-------------------------------------------------*/
/*函数名:串口3中断处理函数                        */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void USART3_IRQHandler(void)
{  
    HAL_UART_IRQHandler(&uart3.uart);
    
    if(__HAL_UART_GET_FLAG(&uart3.uart, UART_FLAG_IDLE)){
        __HAL_UART_CLEAR_IDLEFLAG(&uart3.uart);
        
        uart3.rxCount += (U3_RX_MAX - uart3.uart.RxXferCount);
  
        HAL_UART_AbortReceive_IT(&uart3.uart);
        
    }
}

main.c

#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "sw.h"
#include "uart.h"

int main(void){

    HAL_Init();
    RccClock_Init();
    U1_Init(921600);
    U2_Init(921600);
    U3_Init(921600);
    
    while(1){
        
        /* ------------------UART1------------------ */
        /* 判断接收缓冲区是否有数据 */
        if(uart1.rxInPtr != uart1.rxOutPtr){
            U1_DataRxToTx(uart1.rxOutPtr->start, (uart1.rxOutPtr->end - uart1.rxOutPtr->start + 1));

            
            uart1.rxOutPtr++;
            if(uart1.rxOutPtr == uart1.rxEndPtr){
                uart1.rxOutPtr = &uart1.rxLocation[0];
            }
        }
        
        /* 判断发送缓冲区是否有数据 */
        if((uart1.txInPtr != uart1.txOutPtr) && (uart1.TxState == 0) ){
            uart1.TxState = 1;
            HAL_UART_Transmit_IT(&uart1.uart, uart1. txOutPtr->start, (uart1.txOutPtr->end - uart1.txOutPtr->start + 1));
            
            
            uart1.txOutPtr++;
            if(uart1.txOutPtr == uart1.txEndPtr){
                uart1.txOutPtr = &uart1.txLocation[0];
            }
        }
        
        /* ------------------UART2------------------ */
        if(uart2.rxInPtr != uart2.rxOutPtr){
            U2_DataRxToTx(uart2.rxOutPtr->start, (uart2.rxOutPtr->end - uart2.rxOutPtr->start + 1));

            
            uart2.rxOutPtr++;
            if(uart2.rxOutPtr == uart2.rxEndPtr){
                uart2.rxOutPtr = &uart2.rxLocation[0];
            }
        }
        
        /* 判断发送缓冲区是否有数据 */
        if((uart2.txInPtr != uart2.txOutPtr) && (uart2.TxState == 0) ){
            uart2.TxState = 1;
            HAL_UART_Transmit_IT(&uart2.uart, uart2. txOutPtr->start, (uart2.txOutPtr->end - uart2.txOutPtr->start + 1));
            
            
            uart2.txOutPtr++;
            if(uart2.txOutPtr == uart2.txEndPtr){
                uart2.txOutPtr = &uart2.txLocation[0];
            }
        }
        /* ------------------UART3------------------ */
        if(uart3.rxInPtr != uart3.rxOutPtr){
            U3_DataRxToTx(uart3.rxOutPtr->start, (uart3.rxOutPtr->end - uart3.rxOutPtr->start + 1));

            
            uart3.rxOutPtr++;
            if(uart3.rxOutPtr == uart3.rxEndPtr){
                uart3.rxOutPtr = &uart3.rxLocation[0];
            }
        }
        
        /* 判断发送缓冲区是否有数据 */
        if((uart3.txInPtr != uart3.txOutPtr) && (uart3.TxState == 0) ){
            uart3.TxState = 1;
            HAL_UART_Transmit_IT(&uart3.uart, uart3. txOutPtr->start, (uart3.txOutPtr->end - uart3.txOutPtr->start + 1));
            
            
            uart3.txOutPtr++;
            if(uart3.txOutPtr == uart3.txEndPtr){
                uart3.txOutPtr = &uart3.txLocation[0];
            }
        }
    }
}

七、HAL库:DMA不定长接收 + 空闲中断 + 循环收发缓冲区 串口123收发数据

1. 介绍

DMA(Direct Memory Access)是一种直接内存访问技术,

可以在不经过CPU的情况下实现外设与内存之间的数据传输,提高数据传输效率

2. DMA实现的相关函数

#define __HAL_LINKDMA(**HANDLE**, **PPP_DMA_FIELD**, **DMA_HANDLE**) \\ do{ \\ (**HANDLE**)->**PPP_DMA_FIELD** = &(**DMA_HANDLE**); \\ (**DMA_HANDLE**).Parent = (**HANDLE**); \\ } while(0U)

  • 三个参数:第一个是外设句柄,第二个是外设句柄内的一个DMA句柄指针,最后一个参数是DMA句柄。
  • 每个外设的句柄结构体中都一个该外设关于DMA相关的设置例如串口为
    • DMA_HandleTypeDef *hdmatx; UART TX 的DMA句柄参数
    • DMA_HandleTypeDef *hdmarx; UART RX 的DMA句柄参数
    • 函数的第二个参数用于指定外设中的 DMA 请求标识符。 不同外设有不同含义: 如在定时器中可对应更新、捕获 / 比较等事件的 DMA 请求标识符,用于触发相关 DMA 传输实现自动更新参数等; 在 SPI 中是发送或接收 DMA 请求标识符,能实现高速自动收发数据; 在 ADC 中则通常是转换完成 DMA 请求标识符,可将转换结果自动存储到内存缓冲区。 总之,该参数起到将特定外设事件与 DMA 传输关联起来的作用,以提高数据传输处理效率。

调用这个API,会把用到DMA的外设总控结构体和DMA响应通道的总控结构体 进行双向的父子链接, 也就是 你能找到我 我也能找到你。

DMA 1 - 7 有各自的中断入口点, 有各自的 中断处理函数。

通过这个Link 就建立起来的 DMA和外设的双向的链接了。

然后HAL库会自动配置好 在 发生特定事件时,对内存进行搬运的代码。

__HAL_DMA_GET_COUNTER(__HANDLE__);

  • **HANDLE**用到DMA的外设

获取DMA剩余 未传输的数据量

3. 注意事项:

  1. DMA有不同的通道,也就需要有不同的DMA总控结构体, 例如 串口3的Tx在通道2 , Rx在通道3…

    所以在选用DMA通道的时候, 一定要选对!千万不要Link错了

  2. 使用串口的DMA接收和发送之后, 是不会通过中断来接收的(RXNE)

  3. 使用串口的DMA发送之后, 会进入发送完成回调函数, 和 中断等一样。

    (DMA发送完毕之后会置TCIE 发送完成中断为 1)

  4. 注意循环和正常模式。

4. 程序设计

3.1 大致流程

  1. 打开DMA时钟
  2. 配置 DMA_HandleTypeDef 类型的 DMA通道
    • 实例、初始化的方向、存储区是否递增、目标地址是否自增、两方字长、工作模式等
  3. 通过__HAL_LINKDMA 链接 外设与通道,并配置第二个参数。在发生发送、或接收事件时,开始搬运数据。
  4. 打开对应通道的中断(虽然暂时不用)
  5. 可以利用__HAL_DMA_GET_COUNTER函数来获得当前DMA的未搬运的量

uart.h

#ifndef __UART_H
#define __UART_H

#include "stm32f1xx_hal.h"
#include "stdint.h"

#include "string.h"

/* 缓冲区宏定义 */
#define U1_RX_SIZE 2048         //接收缓冲区长度
#define U1_TX_SIZE 2048         //发送缓冲区长度
#define U1_RX_MAX  256          //最大单次发送量(实际值 - 1 = 255字节)

#define U2_RX_SIZE 2048
#define U2_TX_SIZE 2048
#define U2_RX_MAX  256 

#define U3_RX_SIZE 2048
#define U3_TX_SIZE 2048
#define U3_RX_MAX  256 

/* Location Ctrl Block */
/* (接收/发送)位置控制块 */
typedef struct{
    uint8_t* start;
    uint8_t* end;
}LCB;

/* Uart Ctrl Block */
/* 串口控制块 */
typedef struct{
    uint32_t    rxCount;            //记录接收缓冲区中当前已有的数据量
    uint32_t    txCount;            //记录发送缓冲区中当前已有的数据量
    
    LCB         rxLocation[10];     //记录接收缓冲区每次接收的位置
    LCB         txLocation[10];     //记录发送缓冲区每次接收的位置
    
    LCB*        rxInPtr;            //指向下次接收缓冲区存放位置
    LCB*        rxOutPtr;           //指向下次接收缓冲区读取位置
    LCB*        rxEndPtr;           //指向接收缓冲区结束位置
    
    LCB*        txInPtr;            //指向下次发送缓冲区存放位置
    LCB*        txOutPtr;           //指向下次发送缓冲区读取位置
    LCB*        txEndPtr;           //指向发送缓冲区结束位置
    
    UART_HandleTypeDef  uart;       //串口总控结构体
    DMA_HandleTypeDef   dmaRx;      //DMA Rx通道 总控结构体
    DMA_HandleTypeDef   dmaTx;      //DMA Tx通道 总控结构体
    
    uint8_t     TxState;            //发送忙碌标志位
}UCB;

/* 初始化 */
void U1_Init(uint32_t bandrate);
void U2_Init(uint32_t bandrate);
void U3_Init(uint32_t bandrate);

/* 初始化UCB控制块指针 */
void U1_PtrInit(void);
void U2_PtrInit(void);
void U3_PtrInit(void);

/* 转移RxBuff数据到TxBuff */
void U1_DataRxToTx(uint8_t* data, uint32_t data_len);
void U2_DataRxToTx(uint8_t* data, uint32_t data_len);
void U3_DataRxToTx(uint8_t* data, uint32_t data_len);

/* 总控结构体 */
extern UCB  uart1;
extern UCB  uart2;
extern UCB  uart3;

/* 缓冲区 */
extern uint8_t U1_Rx_Buff[U1_RX_SIZE];
extern uint8_t U1_Tx_Buff[U1_TX_SIZE];

extern uint8_t U2_Rx_Buff[U2_RX_SIZE];
extern uint8_t U2_Tx_Buff[U2_TX_SIZE];

extern uint8_t U3_Rx_Buff[U3_RX_SIZE];
extern uint8_t U3_Tx_Buff[U3_TX_SIZE];

#endif

uart.c

#include "uart.h"

/* 创建串口总控结构体 */
UCB uart1;
UCB uart2;
UCB uart3;

/* 缓冲区 */
uint8_t U1_Rx_Buff[U1_RX_SIZE];
uint8_t U1_Tx_Buff[U1_TX_SIZE];

uint8_t U2_Rx_Buff[U2_RX_SIZE];
uint8_t U2_Tx_Buff[U2_TX_SIZE];

uint8_t U3_Rx_Buff[U3_RX_SIZE];
uint8_t U3_Tx_Buff[U3_TX_SIZE];

/* 初始化串口 */
void U1_Init(uint32_t bandrate){
    uart1.uart.Instance = USART1;                    //使用那个串口
    uart1.uart.Init.BaudRate = bandrate;             //波特率
    uart1.uart.Init.WordLength = UART_WORDLENGTH_8B; //数据位长度
    uart1.uart.Init.StopBits = UART_STOPBITS_1;      //停止位
    uart1.uart.Init.Parity = UART_PARITY_NONE;       //校验模式
    uart1.uart.Init.Mode = UART_MODE_TX_RX;          //传输模式
    uart1.uart.Init.HwFlowCtl = UART_HWCONTROL_NONE; //流控
    HAL_UART_Init(&uart1.uart);
    
    /* 初始化UCB控制块指针 */
    U1_PtrInit();
    
}

/* 初始化串口 */
void U2_Init(uint32_t bandrate){
    uart2.uart.Instance = USART2;                    //使用那个串口
    uart2.uart.Init.BaudRate = bandrate;             //波特率
    uart2.uart.Init.WordLength = UART_WORDLENGTH_8B; //数据位长度
    uart2.uart.Init.StopBits = UART_STOPBITS_1;      //停止位
    uart2.uart.Init.Parity = UART_PARITY_NONE;       //校验模式
    uart2.uart.Init.Mode = UART_MODE_TX_RX;          //传输模式
    uart2.uart.Init.HwFlowCtl = UART_HWCONTROL_NONE; //流控
    HAL_UART_Init(&uart2.uart);
    
    /* 初始化UCB控制块指针 */
    U2_PtrInit();
    
}

/* 初始化串口 */
void U3_Init(uint32_t bandrate){
    uart3.uart.Instance = USART3;                    //使用那个串口
    uart3.uart.Init.BaudRate = bandrate;             //波特率
    uart3.uart.Init.WordLength = UART_WORDLENGTH_8B; //数据位长度
    uart3.uart.Init.StopBits = UART_STOPBITS_1;      //停止位
    uart3.uart.Init.Parity = UART_PARITY_NONE;       //校验模式
    uart3.uart.Init.Mode = UART_MODE_TX_RX;          //传输模式
    uart3.uart.Init.HwFlowCtl = UART_HWCONTROL_NONE; //流控
    HAL_UART_Init(&uart3.uart);
    
    /* 初始化UCB控制块指针 */
    U3_PtrInit();
    
}

/* 初始化U1_UCB控制块指针 */
void U1_PtrInit(void){
    uart1.rxCount  = 0;
    uart1.rxInPtr  = &uart1.rxLocation[0];
    uart1.rxOutPtr = &uart1.rxLocation[0];
    uart1.rxEndPtr = &uart1.rxLocation[9];
    uart1.rxInPtr->start = &U1_Rx_Buff[0];
    
    uart1.txCount  = 0;
    uart1.txInPtr  = &uart1.txLocation[0];
    uart1.txOutPtr = &uart1.txLocation[0];
    uart1.txEndPtr = &uart1.txLocation[9];
    uart1.txInPtr->start = &U1_Tx_Buff[0];
    
    __HAL_UART_ENABLE_IT(&uart1.uart,UART_IT_IDLE);
    HAL_UART_Receive_DMA(&uart1.uart, uart1.rxInPtr->start, U1_RX_MAX); //DMA方式接收
}

void U2_PtrInit(void){
    uart2.rxCount  = 0;
    uart2.rxInPtr  = &uart2.rxLocation[0];
    uart2.rxOutPtr = &uart2.rxLocation[0];
    uart2.rxEndPtr = &uart2.rxLocation[9];
    uart2.rxInPtr->start = &U2_Rx_Buff[0];
    
    uart2.txCount  = 0;
    uart2.txInPtr  = &uart2.txLocation[0];
    uart2.txOutPtr = &uart2.txLocation[0];
    uart2.txEndPtr = &uart2.txLocation[9];
    uart2.txInPtr->start = &U2_Tx_Buff[0];
    
    __HAL_UART_ENABLE_IT(&uart2.uart,UART_IT_IDLE);
    HAL_UART_Receive_DMA(&uart2.uart, uart2.rxInPtr->start, U2_RX_MAX);
}

void U3_PtrInit(void){
    uart3.rxCount  = 0;
    uart3.rxInPtr  = &uart3.rxLocation[0];
    uart3.rxOutPtr = &uart3.rxLocation[0];
    uart3.rxEndPtr = &uart3.rxLocation[9];
    uart3.rxInPtr->start = &U3_Rx_Buff[0];
    
    uart3.txCount  = 0;
    uart3.txInPtr  = &uart3.txLocation[0];
    uart3.txOutPtr = &uart3.txLocation[0];
    uart3.txEndPtr = &uart3.txLocation[9];
    uart3.txInPtr->start = &U3_Tx_Buff[0];
    
    __HAL_UART_ENABLE_IT(&uart3.uart,UART_IT_IDLE);
    HAL_UART_Receive_DMA(&uart3.uart, uart3.rxInPtr->start, U3_RX_MAX);
}

/* 转移Rx_Buff数据到 Tx_Buff */
void U1_DataRxToTx(uint8_t* data, uint32_t data_len){
    if((U1_TX_SIZE - uart1.txCount) > data_len){
        uart1.txInPtr->start = &U1_Tx_Buff[uart1.txCount];
    }
    else{
        uart1.txCount = 0;
        uart1.txInPtr->start = &U1_Tx_Buff[0];
    }
    memcpy(uart1.txInPtr->start, data, data_len);
    uart1.txCount += data_len;
    uart1.txInPtr->end = &U1_Tx_Buff[uart1.txCount - 1];
    uart1.txInPtr++;
    if(uart1.txInPtr == uart1.txEndPtr){
        uart1.txInPtr = &uart1.txLocation[0];
    }
}

void U2_DataRxToTx(uint8_t* data, uint32_t data_len){
    if((U2_TX_SIZE - uart2.txCount) > data_len){
        uart2.txInPtr->start = &U2_Tx_Buff[uart2.txCount];
    }
    else{
        uart2.txCount = 0;
        uart2.txInPtr->start = &U2_Tx_Buff[0];
    }
    memcpy(uart2.txInPtr->start, data, data_len);
    uart2.txCount += data_len;
    uart2.txInPtr->end = &U2_Tx_Buff[uart2.txCount - 1];
    uart2.txInPtr++;
    if(uart2.txInPtr == uart2.txEndPtr){
        uart2.txInPtr = &uart2.txLocation[0];
    }
}

void U3_DataRxToTx(uint8_t* data, uint32_t data_len){
    if((U3_TX_SIZE - uart3.txCount) > data_len){
        uart3.txInPtr->start = &U3_Tx_Buff[uart3.txCount];
    }
    else{
        uart3.txCount = 0;
        uart3.txInPtr->start = &U3_Tx_Buff[0];
    }
    memcpy(uart3.txInPtr->start, data, data_len);
    uart3.txCount += data_len;
    uart3.txInPtr->end = &U3_Tx_Buff[uart3.txCount - 1];
    uart3.txInPtr++;
    if(uart3.txInPtr == uart3.txEndPtr){
        uart3.txInPtr = &uart3.txLocation[0];
    }
}

/* UART硬件初始化回调 */
void HAL_UART_MspInit(UART_HandleTypeDef *huart){
    
    GPIO_InitTypeDef GPIO_InitType;
    
    if(huart->Instance == USART1){
        __HAL_RCC_USART1_CLK_ENABLE();
        __HAL_RCC_GPIOA_CLK_ENABLE();
        __HAL_RCC_DMA1_CLK_ENABLE();    //打开DMA时钟
        
        GPIO_InitType.Pin = GPIO_PIN_9;
        GPIO_InitType.Mode = GPIO_MODE_AF_PP;
        GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
        HAL_GPIO_Init(GPIOA,&GPIO_InitType);
        
        GPIO_InitType.Pin = GPIO_PIN_10;
        GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
        GPIO_InitType.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(GPIOA,&GPIO_InitType);

        HAL_NVIC_SetPriority(USART1_IRQn,3,0);
        HAL_NVIC_EnableIRQ(USART1_IRQn);
        
        /* DMA配置 */
        //    发送配置
        uart1.dmaTx.Instance = DMA1_Channel4;                       //DMA通道:4
        uart1.dmaTx.Init.Direction = DMA_MEMORY_TO_PERIPH;          //方向:存储区到外设
        uart1.dmaTx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;    //存储区数据宽度
        uart1.dmaTx.Init.MemInc = DMA_MINC_ENABLE;                  //存储区是否递增?
        uart1.dmaTx.Init.Mode = DMA_NORMAL;                         //工作模式(正常或循环)
        uart1.dmaTx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; //外设数据宽度
        uart1.dmaTx.Init.PeriphInc = DMA_PINC_DISABLE;              //目标地址是否递增?
        uart1.dmaTx.Init.Priority = DMA_PRIORITY_MEDIUM;            //优先级
        //链接
        __HAL_LINKDMA(huart, hdmatx, uart1.dmaTx);
        //初始化
        HAL_DMA_Init(&uart1.dmaTx);
        //打开DMA通道中断
        HAL_NVIC_SetPriority(DMA1_Channel4_IRQn,3,0);
        HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);
        
        //    接收配置
        uart1.dmaRx.Instance = DMA1_Channel5;                      //DMA通道:5
        uart1.dmaRx.Init.Direction = DMA_PERIPH_TO_MEMORY;         //方向:外设区到存储
        uart1.dmaRx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;   
        uart1.dmaRx.Init.MemInc = DMA_MINC_ENABLE;                 
        uart1.dmaRx.Init.Mode = DMA_NORMAL;                        
        uart1.dmaRx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        uart1.dmaRx.Init.PeriphInc = DMA_PINC_DISABLE;             
        uart1.dmaRx.Init.Priority = DMA_PRIORITY_MEDIUM;           
        //链接
        __HAL_LINKDMA(huart, hdmarx, uart1.dmaRx);
        //初始化
        HAL_DMA_Init(&uart1.dmaRx);
        //打开DMA中断
        HAL_NVIC_SetPriority(DMA1_Channel5_IRQn,3,0);
        HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
    }else if(huart->Instance == USART2){
        __HAL_RCC_GPIOA_CLK_ENABLE();
        __HAL_RCC_USART2_CLK_ENABLE();
        __HAL_RCC_DMA1_CLK_ENABLE();
        
        GPIO_InitType.Pin = GPIO_PIN_2;
        GPIO_InitType.Mode = GPIO_MODE_AF_PP;
        GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
        HAL_GPIO_Init(GPIOA,&GPIO_InitType);
        
        GPIO_InitType.Pin = GPIO_PIN_3;
        GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
        GPIO_InitType.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(GPIOA,&GPIO_InitType);
        
        HAL_NVIC_SetPriority(USART2_IRQn,3,0);
        HAL_NVIC_EnableIRQ(USART2_IRQn);
        
        /* DMA配置 */
        uart2.dmaTx.Instance = DMA1_Channel7;                      
        uart2.dmaTx.Init.Direction = DMA_MEMORY_TO_PERIPH;         
        uart2.dmaTx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;   
        uart2.dmaTx.Init.MemInc = DMA_MINC_ENABLE;                 
        uart2.dmaTx.Init.Mode = DMA_NORMAL;                        
        uart2.dmaTx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        uart2.dmaTx.Init.PeriphInc = DMA_PINC_DISABLE;             
        uart2.dmaTx.Init.Priority = DMA_PRIORITY_MEDIUM;           
        __HAL_LINKDMA(huart, hdmatx, uart2.dmaTx);
        HAL_DMA_Init(&uart2.dmaTx);
        HAL_NVIC_SetPriority(DMA1_Channel7_IRQn,3,0);
        HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);
        uart2.dmaRx.Instance = DMA1_Channel6;
        uart2.dmaRx.Init.Direction = DMA_PERIPH_TO_MEMORY;
        uart2.dmaRx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;   
        uart2.dmaRx.Init.MemInc = DMA_MINC_ENABLE;                 
        uart2.dmaRx.Init.Mode = DMA_NORMAL;                        
        uart2.dmaRx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        uart2.dmaRx.Init.PeriphInc = DMA_PINC_DISABLE;             
        uart2.dmaRx.Init.Priority = DMA_PRIORITY_MEDIUM;
        __HAL_LINKDMA(huart, hdmarx, uart2.dmaRx);
        HAL_DMA_Init(&uart2.dmaRx);
        HAL_NVIC_SetPriority(DMA1_Channel6_IRQn,3,0);
        HAL_NVIC_EnableIRQ(DMA1_Channel6_IRQn);
    }else if(huart->Instance == USART3){
        __HAL_RCC_GPIOB_CLK_ENABLE();
        __HAL_RCC_USART3_CLK_ENABLE();
        __HAL_RCC_DMA1_CLK_ENABLE();
        
        GPIO_InitType.Pin = GPIO_PIN_10;
        GPIO_InitType.Mode = GPIO_MODE_AF_PP;
        GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
        HAL_GPIO_Init(GPIOB,&GPIO_InitType);
        
        GPIO_InitType.Pin = GPIO_PIN_11;
        GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
        GPIO_InitType.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(GPIOB,&GPIO_InitType);
        
        HAL_NVIC_SetPriority(USART3_IRQn,3,0);
        HAL_NVIC_EnableIRQ(USART3_IRQn);
        
        /* DMA配置 */
        uart3.dmaTx.Instance = DMA1_Channel2;                      
        uart3.dmaTx.Init.Direction = DMA_MEMORY_TO_PERIPH;         
        uart3.dmaTx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;   
        uart3.dmaTx.Init.MemInc = DMA_MINC_ENABLE;                 
        uart3.dmaTx.Init.Mode = DMA_NORMAL;                        
        uart3.dmaTx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        uart3.dmaTx.Init.PeriphInc = DMA_PINC_DISABLE;             
        uart3.dmaTx.Init.Priority = DMA_PRIORITY_MEDIUM;           
        __HAL_LINKDMA(huart, hdmatx, uart3.dmaTx);
        HAL_DMA_Init(&uart3.dmaTx);
        HAL_NVIC_SetPriority(DMA1_Channel2_IRQn,3,0);
        HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
        uart3.dmaRx.Instance = DMA1_Channel3;
        uart3.dmaRx.Init.Direction = DMA_PERIPH_TO_MEMORY;
        uart3.dmaRx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;   
        uart3.dmaRx.Init.MemInc = DMA_MINC_ENABLE;                 
        uart3.dmaRx.Init.Mode = DMA_NORMAL;                        
        uart3.dmaRx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        uart3.dmaRx.Init.PeriphInc = DMA_PINC_DISABLE;             
        uart3.dmaRx.Init.Priority = DMA_PRIORITY_MEDIUM;
        __HAL_LINKDMA(huart, hdmarx, uart3.dmaRx);
        HAL_DMA_Init(&uart3.dmaRx);
        HAL_NVIC_SetPriority(DMA1_Channel3_IRQn,3,0);
        HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
    }
}

/* 强声明的接收完成回调函数 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1){
            
    }else if(huart->Instance == USART2){
        
    }else if(huart->Instance == USART3){
        
    }
}

/* 强声明的错误回调函数 */
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1){
                
        }else if(huart->Instance == USART2){
            
        }else if(huart->Instance == USART3){
            
        }
}

/* 强声明的发送完成回调函数 */
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1){
        /* 发送完成,标志位清零 */
        uart1.TxState = 0;
    }else if(huart->Instance == USART2){
        uart2.TxState = 0;
    }else if(huart->Instance == USART3){
        uart3.TxState = 0;
    }
}

/* 强声明的接收终止回调函数 */
void HAL_UART_AbortReceiveCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1){
        uart1.rxInPtr->end = &U1_Rx_Buff[uart1.rxCount - 1];
        uart1.rxInPtr++;
        if(uart1.rxInPtr == uart1.rxEndPtr){
            uart1.rxInPtr = &uart1.rxLocation[0];
        }
        if((U1_RX_SIZE - uart1.rxCount) < U1_RX_MAX){
            uart1.rxCount = 0;
            uart1.rxInPtr->start = &U1_Rx_Buff[0];
        }else{
            uart1.rxInPtr->start = &U1_Rx_Buff[uart1.rxCount];
        }
        HAL_UART_Receive_DMA(&uart1.uart, uart1.rxInPtr->start, U1_RX_MAX);
    }else if(huart->Instance == USART2){
        uart2.rxInPtr->end = &U2_Rx_Buff[uart2.rxCount - 1];
        uart2.rxInPtr++;
        if(uart2.rxInPtr == uart2.rxEndPtr){
            uart2.rxInPtr = &uart2.rxLocation[0];
        }
        if((U2_RX_SIZE - uart2.rxCount) < U2_RX_MAX){
            uart2.rxCount = 0;
            uart2.rxInPtr->start = &U2_Rx_Buff[0];
        }else{
            uart2.rxInPtr->start = &U2_Rx_Buff[uart2.rxCount];
        }
        HAL_UART_Receive_DMA(&uart2.uart, uart2.rxInPtr->start, U2_RX_MAX);
    }else if(huart->Instance == USART3){
        uart3.rxInPtr->end = &U3_Rx_Buff[uart3.rxCount - 1];
        uart3.rxInPtr++;
        if(uart3.rxInPtr == uart3.rxEndPtr){
            uart3.rxInPtr = &uart3.rxLocation[0];
        }
        if((U3_RX_SIZE - uart3.rxCount) < U3_RX_MAX){
            uart3.rxCount = 0;
            uart3.rxInPtr->start = &U3_Rx_Buff[0];
        }else{
            uart3.rxInPtr->start = &U3_Rx_Buff[uart3.rxCount];
        }
        HAL_UART_Receive_DMA(&uart3.uart, uart3.rxInPtr->start, U3_RX_MAX);
    }

}

stm32fxx_It.c

/*-------------------------------------------------*/
/*                                                 */
/*          实现各种中断服务函数的源文件           */
/*                                                 */
/*-------------------------------------------------*/

#include "stm32f1xx_hal.h"   
#include "stm32f1xx_it.h"

#include "uart.h"

void EXTI15_10_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);
}
void EXTI0_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}

/*-------------------------------------------------*/
/*函数名:不可屏蔽中断处理函数                     */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void NMI_Handler(void)
{

}

/*-------------------------------------------------*/
/*函数名:硬件出错后进入的中断处理函数             */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void HardFault_Handler(void)
{

}
/*-------------------------------------------------*/
/*函数名:软中断,SWI 指令调用的处理函数           */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void SVC_Handler(void)
{
    
}
/*-------------------------------------------------*/
/*函数名:可挂起的系统服务处理函数                 */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void PendSV_Handler(void)
{
    
}
/*-------------------------------------------------*/
/*函数名:SysTic系统嘀嗒定时器处理函数             */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void SysTick_Handler(void)
{  
    HAL_IncTick();
}

/*-------------------------------------------------*/
/*函数名:串口1中断处理函数                        */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void USART1_IRQHandler(void)
{  
    HAL_UART_IRQHandler(&uart1.uart);
    
    /* 在每次进入中断后,判断是否为空闲中断 */
    if(__HAL_UART_GET_FLAG(&uart1.uart, UART_FLAG_IDLE)){
        /* 清除空闲标志位 */
        //__HAL_UART_CLEAR_FLAG(&uart1.uart, UART_FLAG_IDLE);
        __HAL_UART_CLEAR_IDLEFLAG(&uart1.uart);
        /* 获取这次传输了多少字节 */
        //uart1.rxCount += (U1_RX_MAX - uart1.uart.RxXferCount);
        uart1.rxCount += (U1_RX_MAX - (__HAL_DMA_GET_COUNTER(&uart1.dmaRx)));   //利用DMA的api 获取剩余未发送数据量
        /* 终止当前的接收(会把RxferCount清零) */
        HAL_UART_AbortReceive_IT(&uart1.uart);
        
    }
}

/*-------------------------------------------------*/
/*函数名:串口2中断处理函数                        */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void USART2_IRQHandler(void)
{  
    HAL_UART_IRQHandler(&uart2.uart);
    

    if(__HAL_UART_GET_FLAG(&uart2.uart, UART_FLAG_IDLE)){
        __HAL_UART_CLEAR_IDLEFLAG(&uart2.uart);
        
        uart2.rxCount += (U2_RX_MAX - (__HAL_DMA_GET_COUNTER(&uart2.dmaRx)));
        
        HAL_UART_AbortReceive_IT(&uart2.uart);
    }
}

/*-------------------------------------------------*/
/*函数名:串口3中断处理函数                        */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void USART3_IRQHandler(void)
{  
    HAL_UART_IRQHandler(&uart3.uart);
    
    if(__HAL_UART_GET_FLAG(&uart3.uart, UART_FLAG_IDLE)){
        __HAL_UART_CLEAR_IDLEFLAG(&uart3.uart);
        
        uart3.rxCount += (U3_RX_MAX - (__HAL_DMA_GET_COUNTER(&uart3.dmaRx)));
  
        HAL_UART_AbortReceive_IT(&uart3.uart);
        
    }
}

/*-------------------------------------------------*/
/*函数名:DMA通道4中断处理函数                     */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void DMA1_Channel4_IRQHandler(void) //Uart1 Tx通道
{  
    HAL_DMA_IRQHandler(&uart1.dmaTx);
}

/*-------------------------------------------------*/
/*函数名:DMA通道5中断处理函数                     */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void DMA1_Channel5_IRQHandler(void) //Uart1 Rx通道
{  
    HAL_DMA_IRQHandler(&uart1.dmaRx);
}

/*-------------------------------------------------*/
/*函数名:DMA通道7中断处理函数                     */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void DMA1_Channel7_IRQHandler(void) //Uart2 Tx通道
{  
    HAL_DMA_IRQHandler(&uart2.dmaTx);
}

/*-------------------------------------------------*/
/*函数名:DMA通道6中断处理函数                     */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void DMA1_Channel6_IRQHandler(void) //Uart2 Rx通道
{  
    HAL_DMA_IRQHandler(&uart2.dmaRx);
}

/*-------------------------------------------------*/
/*函数名:DMA通道2中断处理函数                     */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void DMA1_Channel2_IRQHandler(void) //Uart3 Tx通道
{  
    HAL_DMA_IRQHandler(&uart3.dmaTx);
}

/*-------------------------------------------------*/
/*函数名:DMA通道3中断处理函数                     */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void DMA1_Channel3_IRQHandler(void) //Uart3 Rx通道
{  
    HAL_DMA_IRQHandler(&uart3.dmaRx);
}

main.c

#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "sw.h"
#include "uart.h"

int main(void){

    HAL_Init();
    RccClock_Init();
    U1_Init(921600);
    U2_Init(921600);
    U3_Init(921600);
    
    while(1){
        
        /* ------------------UART1------------------ */
        /* 判断接收缓冲区是否有数据 */
        if(uart1.rxInPtr != uart1.rxOutPtr){
            U1_DataRxToTx(uart1.rxOutPtr->start, (uart1.rxOutPtr->end - uart1.rxOutPtr->start + 1));

            
            uart1.rxOutPtr++;
            if(uart1.rxOutPtr == uart1.rxEndPtr){
                uart1.rxOutPtr = &uart1.rxLocation[0];
            }
        }
        
        /* 判断发送缓冲区是否有数据 */
        if((uart1.txInPtr != uart1.txOutPtr) && (uart1.TxState == 0) ){
            uart1.TxState = 1;
            HAL_UART_Transmit_DMA(&uart1.uart, uart1. txOutPtr->start, (uart1.txOutPtr->end - uart1.txOutPtr->start + 1));
            
            
            uart1.txOutPtr++;
            if(uart1.txOutPtr == uart1.txEndPtr){
                uart1.txOutPtr = &uart1.txLocation[0];
            }
        }
        
        /* ------------------UART2------------------ */
        if(uart2.rxInPtr != uart2.rxOutPtr){
            U2_DataRxToTx(uart2.rxOutPtr->start, (uart2.rxOutPtr->end - uart2.rxOutPtr->start + 1));

            
            uart2.rxOutPtr++;
            if(uart2.rxOutPtr == uart2.rxEndPtr){
                uart2.rxOutPtr = &uart2.rxLocation[0];
            }
        }
        
        /* 判断发送缓冲区是否有数据 */
        if((uart2.txInPtr != uart2.txOutPtr) && (uart2.TxState == 0) ){
            uart2.TxState = 1;
            HAL_UART_Transmit_DMA(&uart2.uart, uart2. txOutPtr->start, (uart2.txOutPtr->end - uart2.txOutPtr->start + 1));
            
            
            uart2.txOutPtr++;
            if(uart2.txOutPtr == uart2.txEndPtr){
                uart2.txOutPtr = &uart2.txLocation[0];
            }
        }
        /* ------------------UART3------------------ */
        if(uart3.rxInPtr != uart3.rxOutPtr){
            U3_DataRxToTx(uart3.rxOutPtr->start, (uart3.rxOutPtr->end - uart3.rxOutPtr->start + 1));

            
            uart3.rxOutPtr++;
            if(uart3.rxOutPtr == uart3.rxEndPtr){
                uart3.rxOutPtr = &uart3.rxLocation[0];
            }
        }
        
        /* 判断发送缓冲区是否有数据 */
        if((uart3.txInPtr != uart3.txOutPtr) && (uart3.TxState == 0) ){
            uart3.TxState = 1;
            HAL_UART_Transmit_DMA(&uart3.uart, uart3. txOutPtr->start, (uart3.txOutPtr->end - uart3.txOutPtr->start + 1));
            
            
            uart3.txOutPtr++;
            if(uart3.txOutPtr == uart3.txEndPtr){
                uart3.txOutPtr = &uart3.txLocation[0];
            }
        }
    }
}

八、HAL库:双机通信,DMA方式收发 控制对方LED灯

在上面的基础上进行修改

1. 大概思路

在本机 按键按下时,进入中断。在中断回调中使用UART1 发送数据LED_ON或LED_OFF

在UART1接收到数据时,进行判断,使用strcmp函数

if(memcmp("LED_ON", uart1.rxOutPtr->start, 6) == 0 ) //比较
{
    LED_ON();
}else if(memcmp("LED_OFF", uart1.rxOutPtr->start, 7) == 0 ){

    LED_OFF();
}

插线的话,两个设备 TX对RX RX对TX, GND对GND就Ok了

九、HAL库:单线半双工,双机通信,DMA方式收发 控制对方LED灯

在上面的基础上进行修改

1. 单线半双工简介

两个单片机之间通过串口,单线半双工通信。

**半双工:**同一时间只能发送或者接收,此时仅使用TX引脚

注意:此时TX引脚需要配置为OD模式,外接上拉电阻

2. 大概思路

在本机 按键按下时,进入中断。在中断回调中使用UART1 发送数据LED_ON或LED_OFF

在UART1接收到数据时,进行判断,使用strcmp函数

if(memcmp("LED_ON", uart1.rxOutPtr->start, 6) == 0 ) //比较
{
    LED_ON();
}else if(memcmp("LED_OFF", uart1.rxOutPtr->start, 7) == 0 ){

    LED_OFF();
}

插线的话,两个设备 TX对RX RX对TX, GND对GND就Ok了

3. 注意

  • 在初始化时,要使用HAL_HalfDuplex_Init 来初始化
  • 单线半双工用的是串口的Tx引脚, 注意Tx引脚要初始化为AF_OD 模式,并且接上拉电阻
  • 一般在初始化的时候,默认为单线半双工的接收状态,只有在使用发送的时候,才使用HAL_HalfDuplex_EnableTransmitter(&uart1.uart);来使能单线半双工的发射模式。并且在发送完成之后,(一般使用发送完成回调)把发射模式重置为默认的接收模式。HAL_HalfDuplex_EnableReceiver(&uart1.uart);

十、HAL库:多主机通信 地址检测唤醒 定时器超时 DMA不定长接收

1. 设备唤醒介绍

1.1 唤醒方式:

  • 三个及以上单片机之间通过串口,相互通信收发数据时。
  • 此时我们需要涉及到主机和从机之分,从机的唤醒有分为:地址 or 空闲唤醒

1.2 地址唤醒:

  • 每个从机会具备一个硬件的从机地址, 地址会记录在USART_CR2寄存器的ADD,占用了4个二进制位。范围0x00~0x0F
  • 但是主机在发送时,需要区分地址 还是数据:如果最高位为1,表示地址,为0表示数据。 所以主机发送的数据,首个字节是从机的地址,范围应该是0x80~0x8F, 8表示最高位7为1。 所以在发送数据时,最高位为 0 数据的有效位为 bit0~bit6 7位数据

1.3 多处理器通信:

与I2C类似,主机Tx为PP模式

  • 主机的tx,接到各个从设备的Rx引脚。 从机的tx输出逻辑 地与(线与)在一起,
  • 注意:
    • 从机的Tx不能为PP模式,否则两个从机输出1 、0会形成短路。
    • 从机的Tx‘应该为OD模式,外接上拉电阻。
    • 并且上拉电阻尽量选择外部上拉电阻,否则选择内部上拉,在波特率比较高的时候,电压上拉速度慢,导致检测为0等情况。
  • USART_CR1寄存器的RWU位
    • RWU可以被硬件自动控制或在某个条件先由软件写入
    • RWU高电平表示从机为静默模式,不会接收数据
    • RWU低电平表示从机为正常模式,会接收数据
    • 从机通过判断地址,切换到正常模式
    • 未匹配的地址可以把正常模式的从机**返回为静默模式,**也可以手动返回为静默模式,
    • 在初始化从机之后 需要手动把RWU变为高电平:静默模式

2. 特别注意:

  1. **DMA在搬运UART的的数据时,会顺便把RXNE的标志位硬件清除。**所以在开启DMA接收时,RXNE在软件上检测不到标志位为1

  2. 多处理器有空闲总线唤醒机制,只要用了多处理器的模式,那么空闲中断就不会产生了

    就不能使用空闲中断来进行数据的不定长接收,可以换一种方式:使用定时器的超时判断,来进行数据的不定长接收。

2.1 使用定时器的超时判断,来进行数据的不定长接收思路详解

假设波特率为9600 ,那么一秒钟最快能发送960个字节,也就是1ms多点。也就是在一个连续的数据流中,每个字节的传输间隔为1ms。

现在开一个定时器,定时时间为大于1ms的值,比如 15 ms。

在每次接收一个字节之后,都清空定时器的计数值。 当定时器超时时,就代表当前一次的数据已经传输完毕。

优点:利用空闲中断时,如果数据发生波动,那么会把一个数据分成两次数据。 而定时器不会,定时器时通过时间判断。 初始化定时器 用于超时计时TIM4_TimerInit(300,7200); 30ms超时时间

需要 打开接收中断 __HAL_UART_ENABLE_IT(&uart2.uart,UART_IT_RXNE);

判断接收标志位 if(__HAL_UART_GET_FLAG(&uart1.uart, UART_FLAG_RXNE)){

文件部分

  • 需要修改hal_uart.c(虽然不建议,但是只能这样了)

  • 关闭了RXNE中断和发生空闲中断,让每次接收字节后都进入自己的函数中stm32f1xx_hal_uart.c

    void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
    {
      uint32_t isrflags   = READ_REG(huart->Instance->SR);
      uint32_t cr1its     = READ_REG(huart->Instance->CR1);
      uint32_t cr3its     = READ_REG(huart->Instance->CR3);
      uint32_t errorflags = 0x00U;
      uint32_t dmarequest = 0x00U;
    
      /* If no error occurs */
      errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));
        //删除  RXNE中断
      //if (errorflags == RESET)
      //{
      //  /* UART in mode Receiver -------------------------------------------------*/
      //  if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
      //  {
      //    UART_Receive_IT(huart);
      //    return;
      //  }
      //}
    
      /* If some errors occur */
      if ((errorflags != RESET) && (((cr3its & USART_CR3_EIE) != RESET) || ((cr1its & (USART_CR1_RXNEIE | USART_CR1_PEIE)) != RESET)))
      {
        /* UART parity error interrupt occurred ----------------------------------*/
        if (((isrflags & USART_SR_PE) != RESET) && ((cr1its & USART_CR1_PEIE) != RESET))
        {
          huart->ErrorCode |= HAL_UART_ERROR_PE;
        }
    
        /* UART noise error interrupt occurred -----------------------------------*/
        if (((isrflags & USART_SR_NE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
        {
          huart->ErrorCode |= HAL_UART_ERROR_NE;
        }
    
        /* UART frame error interrupt occurred -----------------------------------*/
        if (((isrflags & USART_SR_FE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
        {
          huart->ErrorCode |= HAL_UART_ERROR_FE;
        }
    
        /* UART Over-Run interrupt occurred --------------------------------------*/
        if (((isrflags & USART_SR_ORE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
        {
          huart->ErrorCode |= HAL_UART_ERROR_ORE;
        }
    
        /* Call UART Error Call back function if need be --------------------------*/
        if (huart->ErrorCode != HAL_UART_ERROR_NONE)
        {
          /* UART in mode Receiver -----------------------------------------------*/
          if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
          {
            UART_Receive_IT(huart);
          }
    
          /* If Overrun error occurs, or if any error occurs in DMA mode reception,
             consider error as blocking */
          dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR);
          if (((huart->ErrorCode & HAL_UART_ERROR_ORE) != RESET) || dmarequest)
          {
            /* Blocking error : transfer is aborted
               Set the UART state ready to be able to start again the process,
               Disable Rx Interrupts, and disable Rx DMA request, if ongoing */
            UART_EndRxTransfer(huart);
    
            /* Disable the UART DMA Rx request if enabled */
            if (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR))
            {
              CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
    
              /* Abort the UART DMA Rx channel */
              if (huart->hdmarx != NULL)
              {
                /* Set the UART DMA Abort callback :
                   will lead to call HAL_UART_ErrorCallback() at end of DMA abort procedure */
                huart->hdmarx->XferAbortCallback = UART_DMAAbortOnError;
                if (HAL_DMA_Abort_IT(huart->hdmarx) != HAL_OK)
                {
                  /* Call Directly XferAbortCallback function in case of error */
                  huart->hdmarx->XferAbortCallback(huart->hdmarx);
                }
              }
              else
              {
                /* Call user error callback */
    #if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
                /*Call registered error callback*/
                huart->ErrorCallback(huart);
    #else
                /*Call legacy weak error callback*/
                HAL_UART_ErrorCallback(huart);
    #endif /* USE_HAL_UART_REGISTER_CALLBACKS */
              }
            }
            else
            {
              /* Call user error callback */
    #if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
              /*Call registered error callback*/
              huart->ErrorCallback(huart);
    #else
              /*Call legacy weak error callback*/
              HAL_UART_ErrorCallback(huart);
    #endif /* USE_HAL_UART_REGISTER_CALLBACKS */
            }
          }
          else
          {
            /* Non Blocking error : transfer could go on.
               Error is notified to user through user error callback */
    #if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
            /*Call registered error callback*/
            huart->ErrorCallback(huart);
    #else
            /*Call legacy weak error callback*/
            HAL_UART_ErrorCallback(huart);
    #endif /* USE_HAL_UART_REGISTER_CALLBACKS */
    
            huart->ErrorCode = HAL_UART_ERROR_NONE;
          }
        }
        return;
      } /* End if some error occurs */
    
      /* UART in mode Transmitter ------------------------------------------------*/
      //删除  发送缓冲区空的中断
    //  if (((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
    //  {
    //    UART_Transmit_IT(huart);
    //    return;
    //  }
    
      /* UART in mode Transmitter end --------------------------------------------*/
      if (((isrflags & USART_SR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET))
      {
        UART_EndTransmit_IT(huart);
        return;
      }
      /* 写自己的中断回调,现在只能进入我们这个了。 */
      #include "uart.h"
      #include "timer.h"
      else
      {
        if(uart2.RxState == 0){ /* 首字节 */
            __HAL_TIM_ENABLE(&htim4);  //打开tim4的计数
            uart2.RxStat = 1;   //标记接收
        }else{/* 后续字节 */
            __HAL_TIM_SET_COUNTER(&htim4, 0)//清除tim4的计数
        
        }
      
      }
    }
    

2. 要测试功能

主机SW8(PC14)发送:S1_LED(让从机1 LED4翻转状态 UART1

主机SW11(PA0)发送:S2_LED(让从机2 LED4翻转状态)

从机1+从机2 SW8(PC14):LED ON(让主机LED4点亮) UART2

从机1+从机2 SW11(PA0):LED OFF(让主机LED4熄灭) UART3

一般情况下,从机不会主动发送数据,因为这里并没有硬件仲裁机制。 一般都是主机问,从机答

3. 相关函数

  • 可以使用转义字符,在字符串中插入16进制数 用于指定从机地址((uint8_t*)"\\x81S1_LED", 7); \为转义字符 x0x81 为插入的16进制数, 字节为1字节
  • 从机初始化函数:HAL_MultiProcessor_Init(&uart2.uart, 0x01, UART_WAKEUPMETHOD_ADDRESSMARK);
    • 第一个参数,串口总控结构体
    • 第二个参数,设备地址:0x00~0x0F
    • 第三个参数,唤醒方法:地址唤醒或者空闲唤醒

4. 主机程序

uart.c

#include "stm32f1xx_hal.h"
#include "uart.h"

UCB  uart1;
UCB  uart2;
UCB  uart3;

uint8_t U1_RxBuff[U1_RX_SIZE];
uint8_t U1_TxBuff[U1_TX_SIZE];

uint8_t U2_RxBuff[U2_RX_SIZE];
uint8_t U2_TxBuff[U2_TX_SIZE];

uint8_t U3_RxBuff[U3_RX_SIZE];
uint8_t U3_TxBuff[U3_TX_SIZE];

void U1_Init(uint32_t bandrate){
    uart1.uart.Instance = USART1;
    uart1.uart.Init.BaudRate = bandrate;
    uart1.uart.Init.WordLength = UART_WORDLENGTH_8B;
    uart1.uart.Init.StopBits = UART_STOPBITS_1;
    uart1.uart.Init.Parity = UART_PARITY_NONE;
    uart1.uart.Init.Mode = UART_MODE_TX_RX;
    uart1.uart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    HAL_UART_Init(&uart1.uart);
    U1_PtrInit();
}
void U1_PtrInit(void){
    uart1.RxInPtr = &uart1.RxLocation[0];
    uart1.RxOutPtr = &uart1.RxLocation[0];
    uart1.RxEndPtr = &uart1.RxLocation[9];
    uart1.RxCounter = 0;
    uart1.RxInPtr->start = U1_RxBuff;
    
    uart1.TxInPtr = &uart1.TxLocation[0];
    uart1.TxOutPtr = &uart1.TxLocation[0];
    uart1.TxEndPtr = &uart1.TxLocation[9];
    uart1.TxCounter = 0;
    uart1.TxInPtr->start = U1_TxBuff;	
    
    __HAL_UART_ENABLE_IT(&uart1.uart, UART_IT_IDLE);
    HAL_UART_Receive_DMA(&uart1.uart,uart1.RxInPtr->start,U1_RX_MAX);
}
void U1_Txdata(uint8_t *data, uint32_t data_len){
    if((U1_TX_SIZE - uart1.TxCounter )>=data_len){
        uart1.TxInPtr->start = &U1_TxBuff[uart1.TxCounter];
    }else{
        uart1.TxCounter = 0;
        uart1.TxInPtr->start = U1_TxBuff;
    }
    memcpy(uart1.TxInPtr->start,data,data_len);
    uart1.TxCounter += data_len;
    uart1.TxInPtr->end = &U1_TxBuff[uart1.TxCounter - 1];
    uart1.TxInPtr++;
    if(uart1.TxInPtr == uart1.TxEndPtr){
        uart1.TxInPtr = &uart1.TxLocation[0];
    }
}
void U2_Init(uint32_t bandrate){
    uart2.uart.Instance = USART2;
    uart2.uart.Init.BaudRate = bandrate;
    uart2.uart.Init.WordLength = UART_WORDLENGTH_8B;
    uart2.uart.Init.StopBits = UART_STOPBITS_1;
    uart2.uart.Init.Parity = UART_PARITY_NONE;
    uart2.uart.Init.Mode = UART_MODE_TX_RX;
    uart2.uart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    HAL_HalfDuplex_Init(&uart2.uart);
    HAL_HalfDuplex_EnableReceiver(&uart2.uart);
    U2_PtrInit();
}
void U2_PtrInit(void){
    uart2.RxInPtr = &uart2.RxLocation[0];
    uart2.RxOutPtr = &uart2.RxLocation[0];
    uart2.RxEndPtr = &uart2.RxLocation[9];
    uart2.RxCounter = 0;
    uart2.RxInPtr->start = U2_RxBuff;
    
    uart2.TxInPtr = &uart2.TxLocation[0];
    uart2.TxOutPtr = &uart2.TxLocation[0];
    uart2.TxEndPtr = &uart2.TxLocation[9];
    uart2.TxCounter = 0;
    uart2.TxInPtr->start = U2_TxBuff;	
    
    __HAL_UART_ENABLE_IT(&uart2.uart, UART_IT_IDLE);
    HAL_UART_Receive_DMA(&uart2.uart,uart2.RxInPtr->start,U2_RX_MAX);
}
void U2_Txdata(uint8_t *data, uint32_t data_len){
    if((U2_TX_SIZE - uart2.TxCounter )>=data_len){
        uart2.TxInPtr->start = &U2_TxBuff[uart2.TxCounter];
    }else{
        uart2.TxCounter = 0;
        uart2.TxInPtr->start = U2_TxBuff;
    }
    memcpy(uart2.TxInPtr->start,data,data_len);
    uart2.TxCounter += data_len;
    uart2.TxInPtr->end = &U2_TxBuff[uart2.TxCounter - 1];
    uart2.TxInPtr++;
    if(uart2.TxInPtr == uart2.TxEndPtr){
        uart2.TxInPtr = &uart2.TxLocation[0];
    }
}
void U3_Init(uint32_t bandrate){
    uart3.uart.Instance = USART3;
    uart3.uart.Init.BaudRate = bandrate;
    uart3.uart.Init.WordLength = UART_WORDLENGTH_8B;
    uart3.uart.Init.StopBits = UART_STOPBITS_1;
    uart3.uart.Init.Parity = UART_PARITY_NONE;
    uart3.uart.Init.Mode = UART_MODE_TX_RX;
    uart3.uart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    HAL_HalfDuplex_Init(&uart3.uart);
    HAL_HalfDuplex_EnableReceiver(&uart3.uart);
    U3_PtrInit();
}
void U3_PtrInit(void){
    uart3.RxInPtr = &uart3.RxLocation[0];
    uart3.RxOutPtr = &uart3.RxLocation[0];
    uart3.RxEndPtr = &uart3.RxLocation[9];
    uart3.RxCounter = 0;
    uart3.RxInPtr->start = U3_RxBuff;
    
    uart3.TxInPtr = &uart3.TxLocation[0];
    uart3.TxOutPtr = &uart3.TxLocation[0];
    uart3.TxEndPtr = &uart3.TxLocation[9];
    uart3.TxCounter = 0;
    uart3.TxInPtr->start = U3_TxBuff;	
    
    __HAL_UART_ENABLE_IT(&uart3.uart, UART_IT_IDLE);
    HAL_UART_Receive_DMA(&uart3.uart,uart3.RxInPtr->start,U3_RX_MAX);
}
void U3_Txdata(uint8_t *data, uint32_t data_len){
    if((U3_TX_SIZE - uart3.TxCounter )>=data_len){
        uart3.TxInPtr->start = &U3_TxBuff[uart3.TxCounter];
    }else{
        uart3.TxCounter = 0;
        uart3.TxInPtr->start = U3_TxBuff;
    }
    memcpy(uart3.TxInPtr->start,data,data_len);
    uart3.TxCounter += data_len;
    uart3.TxInPtr->end = &U3_TxBuff[uart3.TxCounter - 1];
    uart3.TxInPtr++;
    if(uart3.TxInPtr == uart3.TxEndPtr){
        uart3.TxInPtr = &uart3.TxLocation[0];
    }
}
void HAL_UART_MspInit(UART_HandleTypeDef *huart){
    
    GPIO_InitTypeDef GPIO_InitType;
    
    if(huart->Instance == USART1){
        
        __HAL_RCC_GPIOA_CLK_ENABLE();
        __HAL_RCC_USART1_CLK_ENABLE();
        __HAL_RCC_DMA1_CLK_ENABLE();
            
        GPIO_InitType.Pin = GPIO_PIN_9;
        GPIO_InitType.Mode = GPIO_MODE_AF_PP;
        GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
        HAL_GPIO_Init(GPIOA,&GPIO_InitType);
        
        GPIO_InitType.Pin = GPIO_PIN_10;
        GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
        GPIO_InitType.Pull = GPIO_PULLUP;
        HAL_GPIO_Init(GPIOA,&GPIO_InitType);
        
        HAL_NVIC_SetPriority(USART1_IRQn,3,0);
        HAL_NVIC_EnableIRQ(USART1_IRQn);

        uart1.dmatx.Instance = DMA1_Channel4;
        uart1.dmatx.Init.Direction = DMA_MEMORY_TO_PERIPH;
        uart1.dmatx.Init.PeriphInc = DMA_PINC_DISABLE;
        uart1.dmatx.Init.MemInc = DMA_MINC_ENABLE;
        uart1.dmatx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        uart1.dmatx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        uart1.dmatx.Init.Mode = DMA_NORMAL;
        uart1.dmatx.Init.Priority = DMA_PRIORITY_MEDIUM;
        __HAL_LINKDMA(huart, hdmatx, uart1.dmatx);
        HAL_DMA_Init(&uart1.dmatx);
        
        HAL_NVIC_SetPriority(DMA1_Channel4_IRQn,3,0);
        HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);
        
        uart1.dmarx.Instance = DMA1_Channel5;
        uart1.dmarx.Init.Direction = DMA_PERIPH_TO_MEMORY;
        uart1.dmarx.Init.PeriphInc = DMA_PINC_DISABLE;
        uart1.dmarx.Init.MemInc = DMA_MINC_ENABLE;
        uart1.dmarx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        uart1.dmarx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        uart1.dmarx.Init.Mode = DMA_NORMAL;
        uart1.dmarx.Init.Priority = DMA_PRIORITY_MEDIUM;
        __HAL_LINKDMA(huart, hdmarx, uart1.dmarx);
        HAL_DMA_Init(&uart1.dmarx);
        
        HAL_NVIC_SetPriority(DMA1_Channel5_IRQn,3,0);
        HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
                
    }else if(huart->Instance == USART2){
        __HAL_RCC_GPIOA_CLK_ENABLE();
        __HAL_RCC_USART2_CLK_ENABLE();
        __HAL_RCC_DMA1_CLK_ENABLE();
        
        GPIO_InitType.Pin = GPIO_PIN_2;
        GPIO_InitType.Mode = GPIO_MODE_AF_OD;
        GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
        HAL_GPIO_Init(GPIOA,&GPIO_InitType);
        
        HAL_NVIC_SetPriority(USART2_IRQn,3,0);
        HAL_NVIC_EnableIRQ(USART2_IRQn);
        
        uart2.dmatx.Instance = DMA1_Channel7;
        uart2.dmatx.Init.Direction = DMA_MEMORY_TO_PERIPH;
        uart2.dmatx.Init.PeriphInc = DMA_PINC_DISABLE;
        uart2.dmatx.Init.MemInc = DMA_MINC_ENABLE;
        uart2.dmatx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        uart2.dmatx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        uart2.dmatx.Init.Mode = DMA_NORMAL;
        uart2.dmatx.Init.Priority = DMA_PRIORITY_MEDIUM;
        __HAL_LINKDMA(huart, hdmatx, uart2.dmatx);
        HAL_DMA_Init(&uart2.dmatx);
        
        HAL_NVIC_SetPriority(DMA1_Channel7_IRQn,3,0);
        HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);
        
        uart2.dmarx.Instance = DMA1_Channel6;
        uart2.dmarx.Init.Direction = DMA_PERIPH_TO_MEMORY;
        uart2.dmarx.Init.PeriphInc = DMA_PINC_DISABLE;
        uart2.dmarx.Init.MemInc = DMA_MINC_ENABLE;
        uart2.dmarx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        uart2.dmarx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        uart2.dmarx.Init.Mode = DMA_NORMAL;
        uart2.dmarx.Init.Priority = DMA_PRIORITY_MEDIUM;
        __HAL_LINKDMA(huart, hdmarx, uart2.dmarx);
        HAL_DMA_Init(&uart2.dmarx);
        
        HAL_NVIC_SetPriority(DMA1_Channel6_IRQn,3,0);
        HAL_NVIC_EnableIRQ(DMA1_Channel6_IRQn);
        
    }else if(huart->Instance == USART3){
        __HAL_RCC_GPIOB_CLK_ENABLE();
        __HAL_RCC_USART3_CLK_ENABLE();
        __HAL_RCC_DMA1_CLK_ENABLE();
        
        GPIO_InitType.Pin = GPIO_PIN_10;
        GPIO_InitType.Mode = GPIO_MODE_AF_OD;
        GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
        HAL_GPIO_Init(GPIOB,&GPIO_InitType);
        
        HAL_NVIC_SetPriority(USART3_IRQn,3,0);
        HAL_NVIC_EnableIRQ(USART3_IRQn);
        
        uart3.dmatx.Instance = DMA1_Channel2;
        uart3.dmatx.Init.Direction = DMA_MEMORY_TO_PERIPH;
        uart3.dmatx.Init.PeriphInc = DMA_PINC_DISABLE;
        uart3.dmatx.Init.MemInc = DMA_MINC_ENABLE;
        uart3.dmatx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        uart3.dmatx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        uart3.dmatx.Init.Mode = DMA_NORMAL;
        uart3.dmatx.Init.Priority = DMA_PRIORITY_MEDIUM;
        __HAL_LINKDMA(huart, hdmatx, uart3.dmatx);
        HAL_DMA_Init(&uart3.dmatx);
        
        HAL_NVIC_SetPriority(DMA1_Channel2_IRQn,3,0);
        HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
        
        uart3.dmarx.Instance = DMA1_Channel3;
        uart3.dmarx.Init.Direction = DMA_PERIPH_TO_MEMORY;
        uart3.dmarx.Init.PeriphInc = DMA_PINC_DISABLE;
        uart3.dmarx.Init.MemInc = DMA_MINC_ENABLE;
        uart3.dmarx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        uart3.dmarx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        uart3.dmarx.Init.Mode = DMA_NORMAL;
        uart3.dmarx.Init.Priority = DMA_PRIORITY_MEDIUM;
        __HAL_LINKDMA(huart, hdmarx, uart3.dmarx);
        HAL_DMA_Init(&uart3.dmarx);
        
        HAL_NVIC_SetPriority(DMA1_Channel3_IRQn,3,0);
        HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
    }
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1){

    }
}
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1){

    }
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{	
    if(huart->Instance == USART1){
        uart1.TxState = 0;
    }else if(huart->Instance == USART2){
        uart2.TxState = 0;
    }else if(huart->Instance == USART3){
        uart3.TxState = 0;
    }
}
void HAL_UART_AbortReceiveCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1){
        uart1.RxInPtr->end = &U1_RxBuff[uart1.RxCounter - 1];
        uart1.RxInPtr++;
        if(uart1.RxInPtr == uart1.RxEndPtr){
            uart1.RxInPtr = &uart1.RxLocation[0];
        }
        if((U1_RX_SIZE - uart1.RxCounter)<U1_RX_MAX){
            uart1.RxCounter = 0;
            uart1.RxInPtr->start = U1_RxBuff;
        }else{
            uart1.RxInPtr->start = &U1_RxBuff[uart1.RxCounter];
        }
        HAL_UART_Receive_DMA(&uart1.uart,uart1.RxInPtr->start,U1_RX_MAX);
    }else if(huart->Instance == USART2){
        uart2.RxInPtr->end = &U2_RxBuff[uart2.RxCounter - 1];
        uart2.RxInPtr++;
        if(uart2.RxInPtr == uart2.RxEndPtr){
            uart2.RxInPtr = &uart2.RxLocation[0];
        }
        if((U2_RX_SIZE - uart2.RxCounter)<U2_RX_MAX){
            uart2.RxCounter = 0;
            uart2.RxInPtr->start = U2_RxBuff;
        }else{
            uart2.RxInPtr->start = &U2_RxBuff[uart2.RxCounter];
        }
        HAL_UART_Receive_DMA(&uart2.uart,uart2.RxInPtr->start,U2_RX_MAX);
    }else if(huart->Instance == USART3){
        uart3.RxInPtr->end = &U3_RxBuff[uart3.RxCounter - 1];
        uart3.RxInPtr++;
        if(uart3.RxInPtr == uart3.RxEndPtr){
            uart3.RxInPtr = &uart3.RxLocation[0];
        }
        if((U3_RX_SIZE - uart3.RxCounter)<U3_RX_MAX){
            uart3.RxCounter = 0;
            uart3.RxInPtr->start = U3_RxBuff;
        }else{
            uart3.RxInPtr->start = &U3_RxBuff[uart3.RxCounter];
        }
        HAL_UART_Receive_DMA(&uart3.uart,uart3.RxInPtr->start,U3_RX_MAX);
    }
}

uart.h

#ifndef __UART_H
#define __UART_H

#include "string.h"
#include "stdint.h"
#include "stm32f1xx_hal_uart.h"
#include "stm32f1xx_hal_dma.h"

#define U1_TX_SIZE 2048
#define U1_RX_SIZE 2048
#define U1_RX_MAX  256

#define U2_TX_SIZE 2048
#define U2_RX_SIZE 2048
#define U2_RX_MAX  256

#define U3_TX_SIZE 2048
#define U3_RX_SIZE 2048
#define U3_RX_MAX  256

typedef struct{
	uint8_t  *start;
	uint8_t  *end;
}LCB;

typedef struct{
	uint32_t  RxCounter;
	uint32_t  TxCounter;
	uint32_t  TxState;
	LCB       RxLocation[10];
	LCB       TxLocation[10];
	LCB      *RxInPtr;
	LCB      *RxOutPtr;
	LCB      *RxEndPtr;
	LCB      *TxInPtr;
	LCB      *TxOutPtr;
	LCB      *TxEndPtr;
	UART_HandleTypeDef uart;
	DMA_HandleTypeDef dmatx;
	DMA_HandleTypeDef dmarx;
	
}UCB;

void U1_Init(uint32_t bandrate);
void U2_Init(uint32_t bandrate);
void U3_Init(uint32_t bandrate);
void U1_PtrInit(void);
void U2_PtrInit(void);
void U3_PtrInit(void);
void U1_Txdata(uint8_t *data, uint32_t data_len);
void U2_Txdata(uint8_t *data, uint32_t data_len);
void U3_Txdata(uint8_t *data, uint32_t data_len);

extern UCB  uart1;
extern UCB  uart2;
extern UCB  uart3;

#endif

sw.c

#include "stm32f1xx_hal.h"
#include "sw.h"
#include "uart.h"

uint8_t sw1_sta,sw2_sta;    //0:没有按下  1:按下了

void SW_Init(void){
    GPIO_InitTypeDef GPIO_InitType;
    
    __HAL_RCC_GPIOC_CLK_ENABLE();
    GPIO_InitType.Pin = GPIO_PIN_14;
    GPIO_InitType.Mode = GPIO_MODE_INPUT;
    GPIO_InitType.Pull = GPIO_PULLDOWN;
    HAL_GPIO_Init(GPIOC,&GPIO_InitType);
    
    __HAL_RCC_GPIOA_CLK_ENABLE();
    GPIO_InitType.Pin = GPIO_PIN_0;
    GPIO_InitType.Mode = GPIO_MODE_INPUT;
    GPIO_InitType.Pull = GPIO_PULLDOWN;
    HAL_GPIO_Init(GPIOA,&GPIO_InitType);
}

void SW_InitEvent(void){
    GPIO_InitTypeDef GPIO_InitType;
    //SW1
    __HAL_RCC_GPIOA_CLK_ENABLE();
    GPIO_InitType.Pin = GPIO_PIN_2;
    GPIO_InitType.Mode = GPIO_MODE_EVT_RISING_FALLING;
    GPIO_InitType.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(GPIOA,&GPIO_InitType);
}

void SW_InitEventOut(void){
    GPIO_InitTypeDef GPIO_InitType;
    //PA3
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_AFIO_CLK_ENABLE();
    GPIO_InitType.Pin = GPIO_PIN_3;
    GPIO_InitType.Mode = GPIO_MODE_AF_PP;
    GPIO_InitType.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA,&GPIO_InitType);
    HAL_GPIOEx_ConfigEventout(AFIO_EVENTOUT_PORT_A,AFIO_EVENTOUT_PIN_3);
    HAL_GPIOEx_EnableEventout();
}

//mode 0:按下执行  1:抬起执行
void SW_Init_IT(uint8_t mode){
    GPIO_InitTypeDef GPIO_InitType;
    
    __HAL_RCC_GPIOC_CLK_ENABLE();
    GPIO_InitType.Pin = GPIO_PIN_14;
    if(mode == 0)
        GPIO_InitType.Mode = GPIO_MODE_IT_RISING;
    else
        GPIO_InitType.Mode = GPIO_MODE_IT_FALLING;
    GPIO_InitType.Pull = GPIO_PULLDOWN;
    HAL_GPIO_Init(GPIOC,&GPIO_InitType);
    HAL_NVIC_SetPriority(EXTI15_10_IRQn,4,0);
    HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
    
    __HAL_RCC_GPIOA_CLK_ENABLE();
    GPIO_InitType.Pin = GPIO_PIN_0;
    if(mode == 0)
        GPIO_InitType.Mode = GPIO_MODE_IT_RISING;
    else
        GPIO_InitType.Mode = GPIO_MODE_IT_FALLING;
    GPIO_InitType.Pull = GPIO_PULLDOWN;
    HAL_GPIO_Init(GPIOA,&GPIO_InitType);
    HAL_NVIC_SetPriority(EXTI0_IRQn,3,0);
    HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}

void SW_Init_IT2(void){
    GPIO_InitTypeDef GPIO_InitType;
    
    __HAL_RCC_GPIOC_CLK_ENABLE();
    GPIO_InitType.Pin = GPIO_PIN_14;
    GPIO_InitType.Mode = GPIO_MODE_IT_RISING_FALLING;
    GPIO_InitType.Pull = GPIO_PULLDOWN;
    HAL_GPIO_Init(GPIOC,&GPIO_InitType);
    HAL_NVIC_SetPriority(EXTI15_10_IRQn,4,0);
    HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
    
    __HAL_RCC_GPIOA_CLK_ENABLE();
    GPIO_InitType.Pin = GPIO_PIN_0;
    GPIO_InitType.Mode = GPIO_MODE_IT_RISING_FALLING;
    GPIO_InitType.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(GPIOA,&GPIO_InitType);
    HAL_NVIC_SetPriority(EXTI0_IRQn,3,0);
    HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}

//返回值  0:无按键触发  8:SW8触发
//mode 0:按下执行  1:抬起执行
uint8_t SW_Scan(uint8_t mode){
    
    uint32_t i;
    /*-------------SW8------------------*/
    if((SW1_IN == 1)&&(sw1_sta == 0)){
        for(i=0;i<0x7FFF;i++){
            if(SW1_IN == 0){
                return 0;
            }
        }
        sw1_sta = 1;
        if(mode == 0){
            return 8;
        }
    }else if((SW1_IN == 0)&&(sw1_sta == 1)){
        for(i=0;i<0x7FFF;i++){
            if(SW1_IN == 1){
                return 0;
            }
        }
        sw1_sta = 0;
        if(mode == 1){
            return 8;
        }
    }
    /*-------------SW11------------------*/
    if((SW2_IN == 0)&&(sw2_sta == 0)){
        for(i=0;i<0x7FFF;i++){
            if(SW2_IN == 1){
                return 0;
            }
        }
        sw2_sta = 1;
        if(mode == 0){
            return 11;
        }
    }else if((SW2_IN == 1)&&(sw2_sta == 1)){
        for(i=0;i<0x7FFF;i++){
            if(SW2_IN == 0){
                return 0;
            }
        }
        sw2_sta = 0;
        if(mode == 1){
            return 11;
        }
    }
    
    return 0;
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    uint32_t i;
    
    //SW8:PC13  SW11:PA0(抢占优先级高)
    switch(GPIO_Pin){
        case GPIO_PIN_14:	if(SW1_IN == 1){
                                for(i=0;i<0x7FFF;i++){
                                    if(SW1_IN == 0){
                                        return;
                                    }
                                }
                                U1_Txdata((uint8_t *)"\\x81S1_LED",7);
                                //U2_Txdata((uint8_t *)"LED_ON",6);
                                //U3_Txdata((uint8_t *)"LED_ON",6);
                            }else if(SW1_IN == 0){
                                for(i=0;i<0x7FFF;i++){
                                    if(SW1_IN == 1){
                                        return;
                                    }
                                }
                                HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_0);
                            } 
                            break;
                            
        case GPIO_PIN_0:    if(SW2_IN == 1){
                                for(i=0;i<0x7FFF;i++){
                                    if(SW2_IN == 0){
                                        return;
                                    }
                                }
                                U1_Txdata((uint8_t *)"\\x82S2_LED",7);
                                //U2_Txdata((uint8_t *)"LED_OFF",7);
                                //U3_Txdata((uint8_t *)"LED_OFF",7);
                            }else if(SW2_IN == 1){
                                for(i=0;i<0x7FFF;i++){
                                    if(SW2_IN == 0){
                                        return;
                                    }
                                }
                                HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_0);
                            }
                            break;
    }
}

sw.h

#ifndef __SW_H
#define __SW_H

#include "stdint.h"

#define  SW1_IN   HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_14)
#define  SW2_IN  HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)

void SW_Init(void);
uint8_t SW_Scan(uint8_t mode);
void SW_Init_IT(uint8_t mode);
void SW_Init_IT2(void);
void SW_InitEvent(void);
void SW_InitEventOut(void);

#endif

led.c

#include "stm32f1xx_hal.h"
#include "led.h"

void LED_Init(void){
    GPIO_InitTypeDef GPIO_InitType;
    
    __HAL_RCC_GPIOC_CLK_ENABLE();
    GPIO_InitType.Pin = GPIO_PIN_13;
    GPIO_InitType.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitType.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOC,&GPIO_InitType);
    HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);
}

void LED_ON(void){
    HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);
}

void LED_OFF(void){
    HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);
}

void LED_Toggle(void){
    HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);
}

led.h

#ifndef __LED_H
#define __LED_H

void LED_Init(void);

void LED_ON(void);

void LED_OFF(void);

void LED_Toggle(void);
#endif

stm32f1xx_it.c


/*-------------------------------------------------*/
/*                                                 */
/*          实现各种中断服务函数的源文件           */
/*                                                 */
/*-------------------------------------------------*/

#include "stm32f1xx_hal.h"   
#include "stm32f1xx_it.h"
#include "uart.h"

void EXTI15_10_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_14);
}
void EXTI0_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
void USART1_IRQHandler(void)
{
    HAL_UART_IRQHandler(&uart1.uart);
    
    if(__HAL_UART_GET_FLAG(&uart1.uart, UART_FLAG_IDLE)){
        __HAL_UART_CLEAR_IDLEFLAG(&uart1.uart);
        uart1.RxCounter += (U1_RX_MAX - __HAL_DMA_GET_COUNTER(&uart1.dmarx));
        HAL_UART_AbortReceive_IT(&uart1.uart);
    }
}
void USART2_IRQHandler(void)
{
    HAL_UART_IRQHandler(&uart2.uart);
    
    if(__HAL_UART_GET_FLAG(&uart2.uart, UART_FLAG_IDLE)){
        __HAL_UART_CLEAR_IDLEFLAG(&uart2.uart);
        uart2.RxCounter += (U2_RX_MAX - __HAL_DMA_GET_COUNTER(&uart2.dmarx));
        HAL_UART_AbortReceive_IT(&uart2.uart);
    }
}
void USART3_IRQHandler(void)
{
    HAL_UART_IRQHandler(&uart3.uart);
    
    if(__HAL_UART_GET_FLAG(&uart3.uart, UART_FLAG_IDLE)){
        __HAL_UART_CLEAR_IDLEFLAG(&uart3.uart);
        uart3.RxCounter += (U3_RX_MAX - __HAL_DMA_GET_COUNTER(&uart3.dmarx));
        HAL_UART_AbortReceive_IT(&uart3.uart);
    }
}
void DMA1_Channel4_IRQHandler(void)
{
    HAL_DMA_IRQHandler(&uart1.dmatx);
}
void DMA1_Channel5_IRQHandler(void)
{
    HAL_DMA_IRQHandler(&uart1.dmarx);
}
void DMA1_Channel7_IRQHandler(void)
{
    HAL_DMA_IRQHandler(&uart2.dmatx);
}
void DMA1_Channel6_IRQHandler(void)
{
    HAL_DMA_IRQHandler(&uart2.dmarx);
}
void DMA1_Channel2_IRQHandler(void)
{
    HAL_DMA_IRQHandler(&uart3.dmatx);
}
void DMA1_Channel3_IRQHandler(void)
{
    HAL_DMA_IRQHandler(&uart3.dmarx);
}
/*-------------------------------------------------*/
/*函数名:不可屏蔽中断处理函数                     */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void NMI_Handler(void)
{

}

/*-------------------------------------------------*/
/*函数名:硬件出错后进入的中断处理函数             */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void HardFault_Handler(void)
{

}
/*-------------------------------------------------*/
/*函数名:软中断,SWI 指令调用的处理函数           */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void SVC_Handler(void)
{
    
}
/*-------------------------------------------------*/
/*函数名:可挂起的系统服务处理函数                 */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void PendSV_Handler(void)
{
    
}
/*-------------------------------------------------*/
/*函数名:SysTic系统嘀嗒定时器处理函数             */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void SysTick_Handler(void)
{  
    HAL_IncTick();	
}

main.c

#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "sw.h"
#include "uart.h"

int main(void){

    HAL_Init();
    RccClock_Init();
    SW_Init_IT(0);
    LED_Init();
    U1_Init(921600);
    U2_Init(921600);
    U3_Init(921600);
    
    
    while(1){
        //串口1收发
        if(uart1.RxOutPtr != uart1.RxInPtr){
            
            if(((uart1.RxOutPtr->end - uart1.RxOutPtr->start + 1)==6)&&(memcmp(uart1.RxOutPtr->start,"LED_ON",6) == 0)){
                LED_ON();
            }else if(((uart1.RxOutPtr->end - uart1.RxOutPtr->start + 1)==7)&&(memcmp(uart1.RxOutPtr->start,"LED_OFF",7) == 0)){
                LED_OFF();
            }
            
            uart1.RxOutPtr++;
            if(uart1.RxOutPtr == uart1.RxEndPtr){
                uart1.RxOutPtr = &uart1.RxLocation[0];
            }
        }
        if((uart1.TxOutPtr != uart1.TxInPtr)&&(uart1.TxState==0)){
            uart1.TxState = 1;
            HAL_UART_Transmit_DMA(&uart1.uart,uart1.TxOutPtr->start,uart1.TxOutPtr->end - uart1.TxOutPtr->start + 1);
            uart1.TxOutPtr++;
            if(uart1.TxOutPtr == uart1.TxEndPtr){
                uart1.TxOutPtr = &uart1.TxLocation[0];
            }
        }
        //串口2收发
        if(uart2.RxOutPtr != uart2.RxInPtr){
                    
            if(((uart2.RxOutPtr->end - uart2.RxOutPtr->start + 1)==6)&&(memcmp(uart2.RxOutPtr->start,"LED_ON",6) == 0)){
                HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
            }else if(((uart2.RxOutPtr->end - uart2.RxOutPtr->start + 1)==7)&&(memcmp(uart2.RxOutPtr->start,"LED_OFF",7) == 0)){
                HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);
            }
            
            uart2.RxOutPtr++;
            if(uart2.RxOutPtr == uart2.RxEndPtr){
                uart2.RxOutPtr = &uart2.RxLocation[0];
            }
        }
        if((uart2.TxOutPtr != uart2.TxInPtr)&&(uart2.TxState==0)){
            uart2.TxState = 1;
            HAL_HalfDuplex_EnableTransmitter(&uart2.uart);
            HAL_UART_Transmit_DMA(&uart2.uart,uart2.TxOutPtr->start,uart2.TxOutPtr->end - uart2.TxOutPtr->start + 1);
            uart2.TxOutPtr++;
            if(uart2.TxOutPtr == uart2.TxEndPtr){
                uart2.TxOutPtr = &uart2.TxLocation[0];
            }
        }
        //串口3收发
        if(uart3.RxOutPtr != uart3.RxInPtr){
            
            if(((uart3.RxOutPtr->end - uart3.RxOutPtr->start + 1)==6)&&(memcmp(uart3.RxOutPtr->start,"LED_ON",6) == 0)){
                HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
            }else if(((uart3.RxOutPtr->end - uart3.RxOutPtr->start + 1)==7)&&(memcmp(uart3.RxOutPtr->start,"LED_OFF",7) == 0)){
                HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);
            }
            
            uart3.RxOutPtr++;
            if(uart3.RxOutPtr == uart3.RxEndPtr){
                uart3.RxOutPtr = &uart3.RxLocation[0];
            }
        }
        if((uart3.TxOutPtr != uart3.TxInPtr)&&(uart3.TxState==0)){
            uart3.TxState = 1;
            HAL_HalfDuplex_EnableTransmitter(&uart3.uart);
            HAL_UART_Transmit_DMA(&uart3.uart,uart3.TxOutPtr->start,uart3.TxOutPtr->end - uart3.TxOutPtr->start + 1);
            uart3.TxOutPtr++;
            if(uart3.TxOutPtr == uart3.TxEndPtr){
                uart3.TxOutPtr = &uart3.TxLocation[0];
            }
        }
    }
        
}

5. 从机1程序

uart.c

#include "stm32f1xx_hal.h"
#include "uart.h"

UCB  uart1;
UCB  uart2;
UCB  uart3;

uint8_t U1_RxBuff[U1_RX_SIZE];
uint8_t U1_TxBuff[U1_TX_SIZE];

uint8_t U2_RxBuff[U2_RX_SIZE];
uint8_t U2_TxBuff[U2_TX_SIZE];

uint8_t U3_RxBuff[U3_RX_SIZE];
uint8_t U3_TxBuff[U3_TX_SIZE];

void U1_Init(uint32_t bandrate){
    uart1.uart.Instance = USART1;
    uart1.uart.Init.BaudRate = bandrate;
    uart1.uart.Init.WordLength = UART_WORDLENGTH_8B;
    uart1.uart.Init.StopBits = UART_STOPBITS_1;
    uart1.uart.Init.Parity = UART_PARITY_NONE;
    uart1.uart.Init.Mode = UART_MODE_TX_RX;
    uart1.uart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    HAL_UART_Init(&uart1.uart);
    U1_PtrInit();
}
void U1_PtrInit(void){
    uart1.RxInPtr = &uart1.RxLocation[0];
    uart1.RxOutPtr = &uart1.RxLocation[0];
    uart1.RxEndPtr = &uart1.RxLocation[9];
    uart1.RxCounter = 0;
    uart1.RxInPtr->start = U1_RxBuff;
    
    uart1.TxInPtr = &uart1.TxLocation[0];
    uart1.TxOutPtr = &uart1.TxLocation[0];
    uart1.TxEndPtr = &uart1.TxLocation[9];
    uart1.TxCounter = 0;
    uart1.TxInPtr->start = U1_TxBuff;
    
    __HAL_UART_ENABLE_IT(&uart1.uart, UART_IT_IDLE);
    HAL_UART_Receive_DMA(&uart1.uart,uart1.RxInPtr->start,U1_RX_MAX);
}
void U1_Txdata(uint8_t *data, uint32_t data_len){
    if((U1_TX_SIZE - uart1.TxCounter )>=data_len){
        uart1.TxInPtr->start = &U1_TxBuff[uart1.TxCounter];
    }else{
        uart1.TxCounter = 0;
        uart1.TxInPtr->start = U1_TxBuff;
    }
    memcpy(uart1.TxInPtr->start,data,data_len);
    uart1.TxCounter += data_len;
    uart1.TxInPtr->end = &U1_TxBuff[uart1.TxCounter - 1];
    uart1.TxInPtr++;
    if(uart1.TxInPtr == uart1.TxEndPtr){
        uart1.TxInPtr = &uart1.TxLocation[0];
    }
}
void U2_Init(uint32_t bandrate){
    uart2.uart.Instance = USART2;
    uart2.uart.Init.BaudRate = bandrate;
    uart2.uart.Init.WordLength = UART_WORDLENGTH_8B;
    uart2.uart.Init.StopBits = UART_STOPBITS_1;
    uart2.uart.Init.Parity = UART_PARITY_NONE;
    uart2.uart.Init.Mode = UART_MODE_TX_RX;
    uart2.uart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    HAL_MultiProcessor_Init(&uart2.uart, 0x01, UART_WAKEUPMETHOD_ADDRESSMARK);   //多设备初始化
    HAL_MultiProcessor_EnterMuteMode(&uart2.uart);  //手动进入静默模式
    TIM4_TimerInit(300, 7200);  //定时器超时时间30ms
    U2_PtrInit();
}
void U2_PtrInit(void){
    uart2.RxInPtr = &uart2.RxLocation[0];
    uart2.RxOutPtr = &uart2.RxLocation[0];
    uart2.RxEndPtr = &uart2.RxLocation[9];
    uart2.RxCounter = 0;
    uart2.RxInPtr->start = U2_RxBuff;
    
    uart2.TxInPtr = &uart2.TxLocation[0];
    uart2.TxOutPtr = &uart2.TxLocation[0];
    uart2.TxEndPtr = &uart2.TxLocation[9];
    uart2.TxCounter = 0;
    uart2.TxInPtr->start = U2_TxBuff;	
    
    uart2.RxState = 0;  //初始化接受状态为0
    
    __HAL_UART_ENABLE_IT(&uart2.uart, UART_IT_RXNE);    //打开接收中断
    
    HAL_UART_Receive_DMA(&uart2.uart,uart2.RxInPtr->start,U2_RX_MAX);
}
void U2_Txdata(uint8_t *data, uint32_t data_len){
    if((U2_TX_SIZE - uart2.TxCounter )>=data_len){
        uart2.TxInPtr->start = &U2_TxBuff[uart2.TxCounter];
    }else{
        uart2.TxCounter = 0;
        uart2.TxInPtr->start = U2_TxBuff;
    }
    memcpy(uart2.TxInPtr->start,data,data_len);
    uart2.TxCounter += data_len;
    uart2.TxInPtr->end = &U2_TxBuff[uart2.TxCounter - 1];
    uart2.TxInPtr++;
    if(uart2.TxInPtr == uart2.TxEndPtr){
        uart2.TxInPtr = &uart2.TxLocation[0];
    }
}
void U3_Init(uint32_t bandrate){
    uart3.uart.Instance = USART3;
    uart3.uart.Init.BaudRate = bandrate;
    uart3.uart.Init.WordLength = UART_WORDLENGTH_8B;
    uart3.uart.Init.StopBits = UART_STOPBITS_1;
    uart3.uart.Init.Parity = UART_PARITY_NONE;
    uart3.uart.Init.Mode = UART_MODE_TX_RX;
    uart3.uart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    HAL_HalfDuplex_Init(&uart3.uart);
    HAL_HalfDuplex_EnableReceiver(&uart3.uart);
    U3_PtrInit();
}
void U3_PtrInit(void){
    uart3.RxInPtr = &uart3.RxLocation[0];
    uart3.RxOutPtr = &uart3.RxLocation[0];
    uart3.RxEndPtr = &uart3.RxLocation[9];
    uart3.RxCounter = 0;
    uart3.RxInPtr->start = U3_RxBuff;
    
    uart3.TxInPtr = &uart3.TxLocation[0];
    uart3.TxOutPtr = &uart3.TxLocation[0];
    uart3.TxEndPtr = &uart3.TxLocation[9];
    uart3.TxCounter = 0;
    uart3.TxInPtr->start = U3_TxBuff;	
    
    __HAL_UART_ENABLE_IT(&uart3.uart, UART_IT_IDLE);
    HAL_UART_Receive_DMA(&uart3.uart,uart3.RxInPtr->start,U3_RX_MAX);
}
void U3_Txdata(uint8_t *data, uint32_t data_len){
    if((U3_TX_SIZE - uart3.TxCounter )>=data_len){
        uart3.TxInPtr->start = &U3_TxBuff[uart3.TxCounter];
    }else{
        uart3.TxCounter = 0;
        uart3.TxInPtr->start = U3_TxBuff;
    }
    memcpy(uart3.TxInPtr->start,data,data_len);
    uart3.TxCounter += data_len;
    uart3.TxInPtr->end = &U3_TxBuff[uart3.TxCounter - 1];
    uart3.TxInPtr++;
    if(uart3.TxInPtr == uart3.TxEndPtr){
        uart3.TxInPtr = &uart3.TxLocation[0];
    }
}
void HAL_UART_MspInit(UART_HandleTypeDef *huart){
    
    GPIO_InitTypeDef GPIO_InitType;
    
    if(huart->Instance == USART1){
        
        __HAL_RCC_GPIOA_CLK_ENABLE();
        __HAL_RCC_USART1_CLK_ENABLE();
        __HAL_RCC_DMA1_CLK_ENABLE();
            
        GPIO_InitType.Pin = GPIO_PIN_9;
        GPIO_InitType.Mode = GPIO_MODE_AF_PP;
        GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
        HAL_GPIO_Init(GPIOA,&GPIO_InitType);
        
        GPIO_InitType.Pin = GPIO_PIN_10;
        GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
        GPIO_InitType.Pull = GPIO_PULLUP;
        HAL_GPIO_Init(GPIOA,&GPIO_InitType);
        
        HAL_NVIC_SetPriority(USART1_IRQn,3,0);
        HAL_NVIC_EnableIRQ(USART1_IRQn);

        uart1.dmatx.Instance = DMA1_Channel4;
        uart1.dmatx.Init.Direction = DMA_MEMORY_TO_PERIPH;
        uart1.dmatx.Init.PeriphInc = DMA_PINC_DISABLE;
        uart1.dmatx.Init.MemInc = DMA_MINC_ENABLE;
        uart1.dmatx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        uart1.dmatx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        uart1.dmatx.Init.Mode = DMA_NORMAL;
        uart1.dmatx.Init.Priority = DMA_PRIORITY_MEDIUM;
        __HAL_LINKDMA(huart, hdmatx, uart1.dmatx);
        HAL_DMA_Init(&uart1.dmatx);
        
        HAL_NVIC_SetPriority(DMA1_Channel4_IRQn,3,0);
        HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);
        
        uart1.dmarx.Instance = DMA1_Channel5;
        uart1.dmarx.Init.Direction = DMA_PERIPH_TO_MEMORY;
        uart1.dmarx.Init.PeriphInc = DMA_PINC_DISABLE;
        uart1.dmarx.Init.MemInc = DMA_MINC_ENABLE;
        uart1.dmarx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        uart1.dmarx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        uart1.dmarx.Init.Mode = DMA_NORMAL;
        uart1.dmarx.Init.Priority = DMA_PRIORITY_MEDIUM;
        __HAL_LINKDMA(huart, hdmarx, uart1.dmarx);
        HAL_DMA_Init(&uart1.dmarx);
        
        HAL_NVIC_SetPriority(DMA1_Channel5_IRQn,3,0);
        HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
                
    }else if(huart->Instance == USART2){
        __HAL_RCC_GPIOA_CLK_ENABLE();
        __HAL_RCC_USART2_CLK_ENABLE();
        __HAL_RCC_DMA1_CLK_ENABLE();
        
        GPIO_InitType.Pin = GPIO_PIN_2;
        GPIO_InitType.Mode = GPIO_MODE_AF_OD;   //OD模式
        GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
        HAL_GPIO_Init(GPIOA,&GPIO_InitType);
        
        GPIO_InitType.Pin = GPIO_PIN_3;
        GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
        GPIO_InitType.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(GPIOA,&GPIO_InitType);
        
        HAL_NVIC_SetPriority(USART2_IRQn,3,0);
        HAL_NVIC_EnableIRQ(USART2_IRQn);
        
        uart2.dmatx.Instance = DMA1_Channel7;
        uart2.dmatx.Init.Direction = DMA_MEMORY_TO_PERIPH;
        uart2.dmatx.Init.PeriphInc = DMA_PINC_DISABLE;
        uart2.dmatx.Init.MemInc = DMA_MINC_ENABLE;
        uart2.dmatx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        uart2.dmatx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        uart2.dmatx.Init.Mode = DMA_NORMAL;
        uart2.dmatx.Init.Priority = DMA_PRIORITY_MEDIUM;
        __HAL_LINKDMA(huart, hdmatx, uart2.dmatx);
        HAL_DMA_Init(&uart2.dmatx);
        
        HAL_NVIC_SetPriority(DMA1_Channel7_IRQn,3,0);
        HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);
        
        uart2.dmarx.Instance = DMA1_Channel6;
        uart2.dmarx.Init.Direction = DMA_PERIPH_TO_MEMORY;
        uart2.dmarx.Init.PeriphInc = DMA_PINC_DISABLE;
        uart2.dmarx.Init.MemInc = DMA_MINC_ENABLE;
        uart2.dmarx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        uart2.dmarx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        uart2.dmarx.Init.Mode = DMA_NORMAL;
        uart2.dmarx.Init.Priority = DMA_PRIORITY_MEDIUM;
        __HAL_LINKDMA(huart, hdmarx, uart2.dmarx);
        HAL_DMA_Init(&uart2.dmarx);
        
        HAL_NVIC_SetPriority(DMA1_Channel6_IRQn,3,0);
        HAL_NVIC_EnableIRQ(DMA1_Channel6_IRQn);
        
    }else if(huart->Instance == USART3){
        __HAL_RCC_GPIOB_CLK_ENABLE();
        __HAL_RCC_USART3_CLK_ENABLE();
        __HAL_RCC_DMA1_CLK_ENABLE();
        
        GPIO_InitType.Pin = GPIO_PIN_10;
        GPIO_InitType.Mode = GPIO_MODE_AF_OD;
        GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
        HAL_GPIO_Init(GPIOB,&GPIO_InitType);
        
        HAL_NVIC_SetPriority(USART3_IRQn,3,0);
        HAL_NVIC_EnableIRQ(USART3_IRQn);
        
        uart3.dmatx.Instance = DMA1_Channel2;
        uart3.dmatx.Init.Direction = DMA_MEMORY_TO_PERIPH;
        uart3.dmatx.Init.PeriphInc = DMA_PINC_DISABLE;
        uart3.dmatx.Init.MemInc = DMA_MINC_ENABLE;
        uart3.dmatx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        uart3.dmatx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        uart3.dmatx.Init.Mode = DMA_NORMAL;
        uart3.dmatx.Init.Priority = DMA_PRIORITY_MEDIUM;
        __HAL_LINKDMA(huart, hdmatx, uart3.dmatx);
        HAL_DMA_Init(&uart3.dmatx);
        
        HAL_NVIC_SetPriority(DMA1_Channel2_IRQn,3,0);
        HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
        
        uart3.dmarx.Instance = DMA1_Channel3;
        uart3.dmarx.Init.Direction = DMA_PERIPH_TO_MEMORY;
        uart3.dmarx.Init.PeriphInc = DMA_PINC_DISABLE;
        uart3.dmarx.Init.MemInc = DMA_MINC_ENABLE;
        uart3.dmarx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        uart3.dmarx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        uart3.dmarx.Init.Mode = DMA_NORMAL;
        uart3.dmarx.Init.Priority = DMA_PRIORITY_MEDIUM;
        __HAL_LINKDMA(huart, hdmarx, uart3.dmarx);
        HAL_DMA_Init(&uart3.dmarx);
        
        HAL_NVIC_SetPriority(DMA1_Channel3_IRQn,3,0);
        HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
    }
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1){

    }
}
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1){

    }
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{	
    if(huart->Instance == USART1){
        uart1.TxState = 0;
    }else if(huart->Instance == USART2){
        uart2.TxState = 0;
    }else if(huart->Instance == USART3){
        uart3.TxState = 0;
    }
}

/* 接收终止回调 */
void HAL_UART_AbortReceiveCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1){
        uart1.RxInPtr->end = &U1_RxBuff[uart1.RxCounter - 1];
        uart1.RxInPtr++;
        if(uart1.RxInPtr == uart1.RxEndPtr){
            uart1.RxInPtr = &uart1.RxLocation[0];
        }
        if((U1_RX_SIZE - uart1.RxCounter)<U1_RX_MAX){
            uart1.RxCounter = 0;
            uart1.RxInPtr->start = U1_RxBuff;
        }else{
            uart1.RxInPtr->start = &U1_RxBuff[uart1.RxCounter];
        }
        HAL_UART_Receive_DMA(&uart1.uart,uart1.RxInPtr->start,U1_RX_MAX);
    }else if(huart->Instance == USART2){
        uart2.RxInPtr->end = &U2_RxBuff[uart2.RxCounter - 1];
        uart2.RxInPtr++;
        if(uart2.RxInPtr == uart2.RxEndPtr){
            uart2.RxInPtr = &uart2.RxLocation[0];
        }
        if((U2_RX_SIZE - uart2.RxCounter)<U2_RX_MAX){
            uart2.RxCounter = 0;
            uart2.RxInPtr->start = U2_RxBuff;
        }else{
            uart2.RxInPtr->start = &U2_RxBuff[uart2.RxCounter];
        }
        HAL_MultiProcessor_EnterMuteMode(&uart2.uart);  //手动进入静默模式
        __HAL_UART_ENABLE_IT(&uart2.uart, UART_IT_RXNE);    //打开接收中断
        HAL_UART_Receive_DMA(&uart2.uart,uart2.RxInPtr->start,U2_RX_MAX);
    }else if(huart->Instance == USART3){
        uart3.RxInPtr->end = &U3_RxBuff[uart3.RxCounter - 1];
        uart3.RxInPtr++;
        if(uart3.RxInPtr == uart3.RxEndPtr){
            uart3.RxInPtr = &uart3.RxLocation[0];
        }
        if((U3_RX_SIZE - uart3.RxCounter)<U3_RX_MAX){
            uart3.RxCounter = 0;
            uart3.RxInPtr->start = U3_RxBuff;
        }else{
            uart3.RxInPtr->start = &U3_RxBuff[uart3.RxCounter];
        }
        HAL_UART_Receive_DMA(&uart3.uart,uart3.RxInPtr->start,U3_RX_MAX);
    }
}

uart.h

/*-----------------------------------------------------*/
/*                     程序结构                        */
/*-----------------------------------------------------*/
/*USER   :包含程序的 main 函数,是整个程序的入        */
/*HW     :包含开发板各种功能外设的驱动程序            */
/*LIB    :官方提供的 HAL 库文件                       */
/*CMSIS  :CM3 内核相关的启动文件系统文件              */
/*-----------------------------------------------------*/
/*                                                     */
/*                实现定时器功能的头文件               */
/*                                                     */
/*-----------------------------------------------------*/

#ifndef _TIMER_H
#define _TIMER_H

#include "stdint.h"  
#include "stm32f1xx_hal_tim.h"

extern TIM_HandleTypeDef htim4;                   //外部变量声明

void TIM4_TimerInit(uint16_t, uint16_t);          //函数声明

#endif

sw.c

#include "stm32f1xx_hal.h"
#include "sw.h"
#include "uart.h"

uint8_t sw1_sta,sw2_sta;    //0:没有按下  1:按下了

void SW_Init(void){
    GPIO_InitTypeDef GPIO_InitType;
    
    __HAL_RCC_GPIOC_CLK_ENABLE();
    GPIO_InitType.Pin = GPIO_PIN_14;
    GPIO_InitType.Mode = GPIO_MODE_INPUT;
    GPIO_InitType.Pull = GPIO_PULLDOWN;
    HAL_GPIO_Init(GPIOC,&GPIO_InitType);
    
    __HAL_RCC_GPIOA_CLK_ENABLE();
    GPIO_InitType.Pin = GPIO_PIN_0;
    GPIO_InitType.Mode = GPIO_MODE_INPUT;
    GPIO_InitType.Pull = GPIO_PULLDOWN;
    HAL_GPIO_Init(GPIOA,&GPIO_InitType);
}

void SW_InitEvent(void){
    GPIO_InitTypeDef GPIO_InitType;
    //SW1
    __HAL_RCC_GPIOA_CLK_ENABLE();
    GPIO_InitType.Pin = GPIO_PIN_2;
    GPIO_InitType.Mode = GPIO_MODE_EVT_RISING_FALLING;
    GPIO_InitType.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(GPIOA,&GPIO_InitType);
}

void SW_InitEventOut(void){
    GPIO_InitTypeDef GPIO_InitType;
    //PA3
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_AFIO_CLK_ENABLE();
    GPIO_InitType.Pin = GPIO_PIN_3;
    GPIO_InitType.Mode = GPIO_MODE_AF_PP;
    GPIO_InitType.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA,&GPIO_InitType);
    HAL_GPIOEx_ConfigEventout(AFIO_EVENTOUT_PORT_A,AFIO_EVENTOUT_PIN_3);
    HAL_GPIOEx_EnableEventout();
}

//mode 0:按下执行  1:抬起执行
void SW_Init_IT(uint8_t mode){
    GPIO_InitTypeDef GPIO_InitType;
    
    __HAL_RCC_GPIOC_CLK_ENABLE();
    GPIO_InitType.Pin = GPIO_PIN_14;
    if(mode == 0)
        GPIO_InitType.Mode = GPIO_MODE_IT_RISING;
    else
        GPIO_InitType.Mode = GPIO_MODE_IT_FALLING;
    GPIO_InitType.Pull = GPIO_PULLDOWN;
    HAL_GPIO_Init(GPIOC,&GPIO_InitType);
    HAL_NVIC_SetPriority(EXTI15_10_IRQn,4,0);
    HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
    
    __HAL_RCC_GPIOA_CLK_ENABLE();
    GPIO_InitType.Pin = GPIO_PIN_0;
    if(mode == 0)
        GPIO_InitType.Mode = GPIO_MODE_IT_RISING;
    else
        GPIO_InitType.Mode = GPIO_MODE_IT_FALLING;
    GPIO_InitType.Pull = GPIO_PULLDOWN;
    HAL_GPIO_Init(GPIOA,&GPIO_InitType);
    HAL_NVIC_SetPriority(EXTI0_IRQn,3,0);
    HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}

void SW_Init_IT2(void){
    GPIO_InitTypeDef GPIO_InitType;
    
    __HAL_RCC_GPIOC_CLK_ENABLE();
    GPIO_InitType.Pin = GPIO_PIN_14;
    GPIO_InitType.Mode = GPIO_MODE_IT_RISING_FALLING;
    GPIO_InitType.Pull = GPIO_PULLDOWN;
    HAL_GPIO_Init(GPIOC,&GPIO_InitType);
    HAL_NVIC_SetPriority(EXTI15_10_IRQn,4,0);
    HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
    
    __HAL_RCC_GPIOA_CLK_ENABLE();
    GPIO_InitType.Pin = GPIO_PIN_0;
    GPIO_InitType.Mode = GPIO_MODE_IT_RISING_FALLING;
    GPIO_InitType.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(GPIOA,&GPIO_InitType);
    HAL_NVIC_SetPriority(EXTI0_IRQn,3,0);
    HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}

//返回值  0:无按键触发  8:SW8触发
//mode 0:按下执行  1:抬起执行
uint8_t SW_Scan(uint8_t mode){
    
    uint32_t i;
    /*-------------SW8------------------*/
    if((SW1_IN == 1)&&(sw1_sta == 0)){
        for(i=0;i<0x7FFF;i++){
            if(SW1_IN == 0){
                return 0;
            }
        }
        sw1_sta = 1;
        if(mode == 0){
            return 8;
        }
    }else if((SW1_IN == 0)&&(sw1_sta == 1)){
        for(i=0;i<0x7FFF;i++){
            if(SW1_IN == 1){
                return 0;
            }
        }
        sw1_sta = 0;
        if(mode == 1){
            return 8;
        }
    }
    /*-------------SW11------------------*/
    if((SW2_IN == 0)&&(sw2_sta == 0)){
        for(i=0;i<0x7FFF;i++){
            if(SW2_IN == 1){
                return 0;
            }
        }
        sw2_sta = 1;
        if(mode == 0){
            return 11;
        }
    }else if((SW2_IN == 1)&&(sw2_sta == 1)){
        for(i=0;i<0x7FFF;i++){
            if(SW2_IN == 0){
                return 0;
            }
        }
        sw2_sta = 0;
        if(mode == 1){
            return 11;
        }
    }
    
    return 0;
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    uint32_t i;
    
    //SW8:PC13  SW11:PA0(抢占优先级高)
    switch(GPIO_Pin){
        case GPIO_PIN_14:	if(SW1_IN == 1){
                                for(i=0;i<0x7FFF;i++){
                                    if(SW1_IN == 0){
                                        return;
                                    }
                                }
                                //U1_Txdata((uint8_t *)"\\x81S1_LED",7);
                                U2_Txdata((uint8_t *)"LED_ON",6);
                                //U3_Txdata((uint8_t *)"LED_ON",6);
                            }else if(SW1_IN == 0){
                                for(i=0;i<0x7FFF;i++){
                                    if(SW1_IN == 1){
                                        return;
                                    }
                                }
                                HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_0);
                            } 
                            break;
                            
        case GPIO_PIN_0:    if(SW2_IN == 1){
                                for(i=0;i<0x7FFF;i++){
                                    if(SW2_IN == 0){
                                        return;
                                    }
                                }
                                //U1_Txdata((uint8_t *)"\\x82S2_LED",7);
                                U2_Txdata((uint8_t *)"LED_OFF",7);
                                //U3_Txdata((uint8_t *)"LED_OFF",7);
                            }else if(SW2_IN == 1){
                                for(i=0;i<0x7FFF;i++){
                                    if(SW2_IN == 0){
                                        return;
                                    }
                                }
                                HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_0);
                            }
                            break;
    }
}

sw.h

#ifndef __SW_H
#define __SW_H

#include "stdint.h"

#define  SW1_IN   HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_14)
#define  SW2_IN  HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)

void SW_Init(void);
uint8_t SW_Scan(uint8_t mode);
void SW_Init_IT(uint8_t mode);
void SW_Init_IT2(void);
void SW_InitEvent(void);
void SW_InitEventOut(void);

#endif

led.c

#include "stm32f1xx_hal.h"
#include "led.h"

void LED_Init(void){
    GPIO_InitTypeDef GPIO_InitType;
    
    __HAL_RCC_GPIOC_CLK_ENABLE();
    GPIO_InitType.Pin = GPIO_PIN_13;
    GPIO_InitType.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitType.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOC,&GPIO_InitType);
    HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);
}

void LED_ON(void){
    HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);
}

void LED_OFF(void){
    HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);
}

void LED_Toggle(void){
    HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);
}

led.h

#ifndef __LED_H
#define __LED_H

void LED_Init(void);

void LED_ON(void);

void LED_OFF(void);

void LED_Toggle(void);
#endif

stm32f1xx_it.c

/*-------------------------------------------------*/
/*                                                 */
/*          实现各种中断服务函数的源文件           */
/*                                                 */
/*-------------------------------------------------*/

#include "stm32f1xx_hal.h"   
#include "stm32f1xx_it.h"
#include "uart.h"
#include "timer.h"
void EXTI15_10_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_14);
}
void EXTI0_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
void USART1_IRQHandler(void)
{
    HAL_UART_IRQHandler(&uart1.uart);
    
    if(__HAL_UART_GET_FLAG(&uart1.uart, UART_FLAG_IDLE)){
        __HAL_UART_CLEAR_IDLEFLAG(&uart1.uart);
        uart1.RxCounter += (U1_RX_MAX - __HAL_DMA_GET_COUNTER(&uart1.dmarx));
        HAL_UART_AbortReceive_IT(&uart1.uart);
    }
}
int aaa;
void USART2_IRQHandler(void)
{
    HAL_UART_IRQHandler(&uart2.uart);
    
    //if(__HAL_UART_GET_FLAG(&uart2.uart, UART_FLAG_IDLE)){
    //    __HAL_UART_CLEAR_IDLEFLAG(&uart2.uart);
    //    uart2.RxCounter += (U2_RX_MAX - __HAL_DMA_GET_COUNTER(&uart2.dmarx));
    //    HAL_UART_AbortReceive_IT(&uart2.uart);
    //}
    aaa++;
}
void USART3_IRQHandler(void)
{
    HAL_UART_IRQHandler(&uart3.uart);
    
    if(__HAL_UART_GET_FLAG(&uart3.uart, UART_FLAG_IDLE)){
        __HAL_UART_CLEAR_IDLEFLAG(&uart3.uart);
        uart3.RxCounter += (U3_RX_MAX - __HAL_DMA_GET_COUNTER(&uart3.dmarx));
        HAL_UART_AbortReceive_IT(&uart3.uart);
    }
}
void DMA1_Channel4_IRQHandler(void)
{
    HAL_DMA_IRQHandler(&uart1.dmatx);
}
void DMA1_Channel5_IRQHandler(void)
{
    HAL_DMA_IRQHandler(&uart1.dmarx);
}
void DMA1_Channel7_IRQHandler(void)
{
    HAL_DMA_IRQHandler(&uart2.dmatx);
}
void DMA1_Channel6_IRQHandler(void)
{
    HAL_DMA_IRQHandler(&uart2.dmarx);
}
void DMA1_Channel2_IRQHandler(void)
{
    HAL_DMA_IRQHandler(&uart3.dmatx);
}
void DMA1_Channel3_IRQHandler(void)
{
    HAL_DMA_IRQHandler(&uart3.dmarx);
}

//定时器中断处理函数
void TIM4_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&htim4);
}
/*-------------------------------------------------*/
/*函数名:不可屏蔽中断处理函数                     */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void NMI_Handler(void)
{

}

/*-------------------------------------------------*/
/*函数名:硬件出错后进入的中断处理函数             */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void HardFault_Handler(void)
{

}
/*-------------------------------------------------*/
/*函数名:软中断,SWI 指令调用的处理函数           */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void SVC_Handler(void)
{
    
}
/*-------------------------------------------------*/
/*函数名:可挂起的系统服务处理函数                 */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void PendSV_Handler(void)
{
    
}
/*-------------------------------------------------*/
/*函数名:SysTic系统嘀嗒定时器处理函数             */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void SysTick_Handler(void)
{  
    HAL_IncTick();	
}

timer.c

/*-----------------------------------------------------*/
/*                     程序结构                        */
/*-----------------------------------------------------*/
/*USER   :包含程序的 main 函数,是整个程序的入        */
/*HW     :包含开发板各种功能外设的驱动程序            */
/*LIB    :官方提供的 HAL 库文件                       */
/*CMSIS  :CM3 内核相关的启动文件系统文件              */
/*-----------------------------------------------------*/
/*                                                     */
/*                实现定时器功能的源文件               */
/*                                                     */
/*-----------------------------------------------------*/

#include "stm32f1xx_hal.h"  
#include "timer.h"            
#include "uart.h"  

TIM_HandleTypeDef htim4;    //定时器4总控制结构体

/*-------------------------------------------------*/
/*函数名:定时器4 定时初始化                       */
/*参  数:arr:自动重装值                          */
/*参  数:psc:时钟预分频数                        */
/*返回值:无                                       */
/*-------------------------------------------------*/
void TIM4_TimerInit(uint16_t arr, uint16_t psc)
{
    htim4.Instance = TIM4;                                         //设置使用哪个定时器
    htim4.Init.Prescaler = psc - 1;                                //设置预分频器的值
    htim4.Init.Period = arr - 1;                                   //设置自动重载值
    htim4.Init.CounterMode = TIM_COUNTERMODE_UP;                   //设置计数模式
    htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; //自动重载预装载 禁止
    HAL_TIM_Base_Init(&htim4);                                     //配置,如果失败进入if

    __HAL_TIM_CLEAR_IT(&htim4, TIM_IT_UPDATE);                     //清除定时器4的中断标志
    __HAL_TIM_ENABLE_IT(&htim4, TIM_IT_UPDATE);                    //打开更新中断
}
/*-------------------------------------------------*/
/*函数名:定时器底层驱动,开启时钟,设置中断优先级 */
/*参  数:htim:定时器句柄                         */
/*返回值:无                                       */
/*说  明:此函数会被HAL_TIM_Base_Init()函数调用    */
/*-------------------------------------------------*/
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
    if(htim->Instance==TIM4){	                   //判断是哪个定时器	
        __HAL_RCC_TIM4_CLK_ENABLE();               //使能定时器时钟
        HAL_NVIC_SetPriority(TIM4_IRQn,4,0);       //设置中断优先级,中断分组在HAL_Init()函数中,被设置为4
        HAL_NVIC_EnableIRQ(TIM4_IRQn);             //开启定时器中断   
    }
}
/*---------------------------------------------------*/
/*函数名:定时器中断回调函数                         */
/*参  数:htim:定时器句柄                           */
/*返回值:无                                         */
/*说  明:此函数会被HAL_TIM_IRQHandler()中断函数调用 */
/*---------------------------------------------------*/
//超时回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim->Instance==TIM4){	          //判断是哪个定时器
        __HAL_TIM_DISABLE(htim);          //关闭定时器4的计数
        __HAL_TIM_SET_COUNTER(htim,0);    //清零定时器4计数器
        uart2.RxState = 0;  //恢复首字节接收标志位
        uart2.RxCounter += (U2_RX_MAX - __HAL_DMA_GET_COUNTER(&uart2.dmarx));   //记录剩余未发送
        HAL_UART_AbortReceive_IT(&uart2.uart);  //终止接收
    }
}

stm32f1xx_hal_uart.c

void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
  uint32_t isrflags   = READ_REG(huart->Instance->SR);
  uint32_t cr1its     = READ_REG(huart->Instance->CR1);
  uint32_t cr3its     = READ_REG(huart->Instance->CR3);
  uint32_t errorflags = 0x00U;
  uint32_t dmarequest = 0x00U;

  /* If no error occurs */
  errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));
    //删除  RXNE中断
  //if (errorflags == RESET)
  //{
  //  /* UART in mode Receiver -------------------------------------------------*/
  //  if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
  //  {
  //    UART_Receive_IT(huart);
  //    return;
  //  }
  //}

  /* If some errors occur */
  if ((errorflags != RESET) && (((cr3its & USART_CR3_EIE) != RESET) || ((cr1its & (USART_CR1_RXNEIE | USART_CR1_PEIE)) != RESET)))
  {
    /* UART parity error interrupt occurred ----------------------------------*/
    if (((isrflags & USART_SR_PE) != RESET) && ((cr1its & USART_CR1_PEIE) != RESET))
    {
      huart->ErrorCode |= HAL_UART_ERROR_PE;
    }

    /* UART noise error interrupt occurred -----------------------------------*/
    if (((isrflags & USART_SR_NE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
    {
      huart->ErrorCode |= HAL_UART_ERROR_NE;
    }

    /* UART frame error interrupt occurred -----------------------------------*/
    if (((isrflags & USART_SR_FE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
    {
      huart->ErrorCode |= HAL_UART_ERROR_FE;
    }

    /* UART Over-Run interrupt occurred --------------------------------------*/
    if (((isrflags & USART_SR_ORE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
    {
      huart->ErrorCode |= HAL_UART_ERROR_ORE;
    }

    /* Call UART Error Call back function if need be --------------------------*/
    if (huart->ErrorCode != HAL_UART_ERROR_NONE)
    {
      /* UART in mode Receiver -----------------------------------------------*/
      if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
      {
        UART_Receive_IT(huart);
      }

      /* If Overrun error occurs, or if any error occurs in DMA mode reception,
         consider error as blocking */
      dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR);
      if (((huart->ErrorCode & HAL_UART_ERROR_ORE) != RESET) || dmarequest)
      {
        /* Blocking error : transfer is aborted
           Set the UART state ready to be able to start again the process,
           Disable Rx Interrupts, and disable Rx DMA request, if ongoing */
        UART_EndRxTransfer(huart);

        /* Disable the UART DMA Rx request if enabled */
        if (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR))
        {
          CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);

          /* Abort the UART DMA Rx channel */
          if (huart->hdmarx != NULL)
          {
            /* Set the UART DMA Abort callback :
               will lead to call HAL_UART_ErrorCallback() at end of DMA abort procedure */
            huart->hdmarx->XferAbortCallback = UART_DMAAbortOnError;
            if (HAL_DMA_Abort_IT(huart->hdmarx) != HAL_OK)
            {
              /* Call Directly XferAbortCallback function in case of error */
              huart->hdmarx->XferAbortCallback(huart->hdmarx);
            }
          }
          else
          {
            /* Call user error callback */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
            /*Call registered error callback*/
            huart->ErrorCallback(huart);
#else
            /*Call legacy weak error callback*/
            HAL_UART_ErrorCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
          }
        }
        else
        {
          /* Call user error callback */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
          /*Call registered error callback*/
          huart->ErrorCallback(huart);
#else
          /*Call legacy weak error callback*/
          HAL_UART_ErrorCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
        }
      }
      else
      {
        /* Non Blocking error : transfer could go on.
           Error is notified to user through user error callback */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
        /*Call registered error callback*/
        huart->ErrorCallback(huart);
#else
        /*Call legacy weak error callback*/
        HAL_UART_ErrorCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */

        huart->ErrorCode = HAL_UART_ERROR_NONE;
      }
    }
    return;
  } /* End if some error occurs */

  /* UART in mode Transmitter ------------------------------------------------*/
  //删除  发送缓冲区空的中断
//  if (((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
//  {
//    UART_Transmit_IT(huart);
//    return;
//  }

  /* UART in mode Transmitter end --------------------------------------------*/
  if (((isrflags & USART_SR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET))
  {
    UART_EndTransmit_IT(huart);
    return;
  }
  /* 写自己的中断回调,现在只能进入我们这个了。 */
  #include "uart.h"
  #include "timer.h"
  else
  {
    if(uart2.RxState == 0){ /* 首字节 */
        __HAL_TIM_ENABLE(&htim4);  //打开tim4的计数
        uart2.RxStat = 1;   //标记接收
    }else{/* 后续字节 */
        __HAL_TIM_SET_COUNTER(&htim4, 0)//清除tim4的计数
    
    }
  
  }
}

main.c

#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "sw.h"
#include "uart.h"

int main(void){

    HAL_Init();
    RccClock_Init();
    SW_Init_IT(0);
    LED_Init();
    U1_Init(9600);
    U2_Init(9600);
    U3_Init(9600);
    
    while(1){
        //串口1收发
        if(uart1.RxOutPtr != uart1.RxInPtr){
            
            if(((uart1.RxOutPtr->end - uart1.RxOutPtr->start + 1)==6)&&(memcmp(uart1.RxOutPtr->start,"LED_ON",6) == 0)){
                LED_ON();
            }else if(((uart1.RxOutPtr->end - uart1.RxOutPtr->start + 1)==7)&&(memcmp(uart1.RxOutPtr->start,"LED_OFF",7) == 0)){
                LED_OFF();
            }
            
            uart1.RxOutPtr++;
            if(uart1.RxOutPtr == uart1.RxEndPtr){
                uart1.RxOutPtr = &uart1.RxLocation[0];
            }
        }
        if((uart1.TxOutPtr != uart1.TxInPtr)&&(uart1.TxState==0)){
            uart1.TxState = 1;
            HAL_UART_Transmit_DMA(&uart1.uart,uart1.TxOutPtr->start,uart1.TxOutPtr->end - uart1.TxOutPtr->start + 1);
            uart1.TxOutPtr++;
            if(uart1.TxOutPtr == uart1.TxEndPtr){
                uart1.TxOutPtr = &uart1.TxLocation[0];
            }
        }
        //串口2收发
        if(uart2.RxOutPtr != uart2.RxInPtr){
                    
            if(((uart2.RxOutPtr->end - uart2.RxOutPtr->start + 1)==7)&&(memcmp(uart2.RxOutPtr->start,"\\x81S1_LED",7) == 0)){
                LED_Toggle();
            }
            
            uart2.RxOutPtr++;
            if(uart2.RxOutPtr == uart2.RxEndPtr){
                uart2.RxOutPtr = &uart2.RxLocation[0];
            }
        }
        if((uart2.TxOutPtr != uart2.TxInPtr)&&(uart2.TxState==0)){
            uart2.TxState = 1;
            HAL_UART_Transmit_DMA(&uart2.uart,uart2.TxOutPtr->start,uart2.TxOutPtr->end - uart2.TxOutPtr->start + 1);
            uart2.TxOutPtr++;
            if(uart2.TxOutPtr == uart2.TxEndPtr){
                uart2.TxOutPtr = &uart2.TxLocation[0];
            }
        }
        //串口3收发
        if(uart3.RxOutPtr != uart3.RxInPtr){
            
            if(((uart3.RxOutPtr->end - uart3.RxOutPtr->start + 1)==6)&&(memcmp(uart3.RxOutPtr->start,"LED_ON",6) == 0)){
                HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
            }else if(((uart3.RxOutPtr->end - uart3.RxOutPtr->start + 1)==7)&&(memcmp(uart3.RxOutPtr->start,"LED_OFF",7) == 0)){
                HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);
            }
            
            uart3.RxOutPtr++;
            if(uart3.RxOutPtr == uart3.RxEndPtr){
                uart3.RxOutPtr = &uart3.RxLocation[0];
            }
        }
        if((uart3.TxOutPtr != uart3.TxInPtr)&&(uart3.TxState==0)){
            uart3.TxState = 1;
            HAL_HalfDuplex_EnableTransmitter(&uart3.uart);
            HAL_UART_Transmit_DMA(&uart3.uart,uart3.TxOutPtr->start,uart3.TxOutPtr->end - uart3.TxOutPtr->start + 1);
            uart3.TxOutPtr++;
            if(uart3.TxOutPtr == uart3.TxEndPtr){
                uart3.TxOutPtr = &uart3.TxLocation[0];
            }
        }
    }
        
}

6. 从机2程序

uart.c

#include "stm32f1xx_hal.h"
#include "uart.h"

UCB  uart1;
UCB  uart2;
UCB  uart3;

uint8_t U1_RxBuff[U1_RX_SIZE];
uint8_t U1_TxBuff[U1_TX_SIZE];

uint8_t U2_RxBuff[U2_RX_SIZE];
uint8_t U2_TxBuff[U2_TX_SIZE];

uint8_t U3_RxBuff[U3_RX_SIZE];
uint8_t U3_TxBuff[U3_TX_SIZE];

void U1_Init(uint32_t bandrate){
    uart1.uart.Instance = USART1;
    uart1.uart.Init.BaudRate = bandrate;
    uart1.uart.Init.WordLength = UART_WORDLENGTH_8B;
    uart1.uart.Init.StopBits = UART_STOPBITS_1;
    uart1.uart.Init.Parity = UART_PARITY_NONE;
    uart1.uart.Init.Mode = UART_MODE_TX_RX;
    uart1.uart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    HAL_UART_Init(&uart1.uart);
    U1_PtrInit();
}
void U1_PtrInit(void){
    uart1.RxInPtr = &uart1.RxLocation[0];
    uart1.RxOutPtr = &uart1.RxLocation[0];
    uart1.RxEndPtr = &uart1.RxLocation[9];
    uart1.RxCounter = 0;
    uart1.RxInPtr->start = U1_RxBuff;
    
    uart1.TxInPtr = &uart1.TxLocation[0];
    uart1.TxOutPtr = &uart1.TxLocation[0];
    uart1.TxEndPtr = &uart1.TxLocation[9];
    uart1.TxCounter = 0;
    uart1.TxInPtr->start = U1_TxBuff;
    
    __HAL_UART_ENABLE_IT(&uart1.uart, UART_IT_IDLE);
    HAL_UART_Receive_DMA(&uart1.uart,uart1.RxInPtr->start,U1_RX_MAX);
}
void U1_Txdata(uint8_t *data, uint32_t data_len){
    if((U1_TX_SIZE - uart1.TxCounter )>=data_len){
        uart1.TxInPtr->start = &U1_TxBuff[uart1.TxCounter];
    }else{
        uart1.TxCounter = 0;
        uart1.TxInPtr->start = U1_TxBuff;
    }
    memcpy(uart1.TxInPtr->start,data,data_len);
    uart1.TxCounter += data_len;
    uart1.TxInPtr->end = &U1_TxBuff[uart1.TxCounter - 1];
    uart1.TxInPtr++;
    if(uart1.TxInPtr == uart1.TxEndPtr){
        uart1.TxInPtr = &uart1.TxLocation[0];
    }
}
void U2_Init(uint32_t bandrate){
    uart2.uart.Instance = USART2;
    uart2.uart.Init.BaudRate = bandrate;
    uart2.uart.Init.WordLength = UART_WORDLENGTH_8B;
    uart2.uart.Init.StopBits = UART_STOPBITS_1;
    uart2.uart.Init.Parity = UART_PARITY_NONE;
    uart2.uart.Init.Mode = UART_MODE_TX_RX;
    uart2.uart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    HAL_MultiProcessor_Init(&uart2.uart, 0x01, UART_WAKEUPMETHOD_ADDRESSMARK);   //多设备初始化
    HAL_MultiProcessor_EnterMuteMode(&uart2.uart);  //手动进入静默模式
    TIM4_TimerInit(300, 7200);  //定时器超时时间30ms
    U2_PtrInit();
}
void U2_PtrInit(void){
    uart2.RxInPtr = &uart2.RxLocation[0];
    uart2.RxOutPtr = &uart2.RxLocation[0];
    uart2.RxEndPtr = &uart2.RxLocation[9];
    uart2.RxCounter = 0;
    uart2.RxInPtr->start = U2_RxBuff;
    
    uart2.TxInPtr = &uart2.TxLocation[0];
    uart2.TxOutPtr = &uart2.TxLocation[0];
    uart2.TxEndPtr = &uart2.TxLocation[9];
    uart2.TxCounter = 0;
    uart2.TxInPtr->start = U2_TxBuff;	
    
    uart2.RxState = 0;  //初始化接受状态为0
    
    __HAL_UART_ENABLE_IT(&uart2.uart, UART_IT_RXNE);    //打开接收中断
    
    HAL_UART_Receive_DMA(&uart2.uart,uart2.RxInPtr->start,U2_RX_MAX);
}
void U2_Txdata(uint8_t *data, uint32_t data_len){
    if((U2_TX_SIZE - uart2.TxCounter )>=data_len){
        uart2.TxInPtr->start = &U2_TxBuff[uart2.TxCounter];
    }else{
        uart2.TxCounter = 0;
        uart2.TxInPtr->start = U2_TxBuff;
    }
    memcpy(uart2.TxInPtr->start,data,data_len);
    uart2.TxCounter += data_len;
    uart2.TxInPtr->end = &U2_TxBuff[uart2.TxCounter - 1];
    uart2.TxInPtr++;
    if(uart2.TxInPtr == uart2.TxEndPtr){
        uart2.TxInPtr = &uart2.TxLocation[0];
    }
}
void U3_Init(uint32_t bandrate){
    uart3.uart.Instance = USART3;
    uart3.uart.Init.BaudRate = bandrate;
    uart3.uart.Init.WordLength = UART_WORDLENGTH_8B;
    uart3.uart.Init.StopBits = UART_STOPBITS_1;
    uart3.uart.Init.Parity = UART_PARITY_NONE;
    uart3.uart.Init.Mode = UART_MODE_TX_RX;
    uart3.uart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    HAL_MultiProcessor_Init(&uart3.uart, 0x02, UART_WAKEUPMETHOD_ADDRESSMARK);   //多设备初始化
    HAL_MultiProcessor_EnterMuteMode(&uart3.uart);  //手动进入静默模式
    TIM4_TimerInit(300, 7200);  //定时器超时时间30ms
    U3_PtrInit();
}
void U3_PtrInit(void){
    uart3.RxInPtr = &uart3.RxLocation[0];
    uart3.RxOutPtr = &uart3.RxLocation[0];
    uart3.RxEndPtr = &uart3.RxLocation[9];
    uart3.RxCounter = 0;
    uart3.RxInPtr->start = U3_RxBuff;
    
    uart3.TxInPtr = &uart3.TxLocation[0];
    uart3.TxOutPtr = &uart3.TxLocation[0];
    uart3.TxEndPtr = &uart3.TxLocation[9];
    uart3.TxCounter = 0;
    uart3.TxInPtr->start = U3_TxBuff;
    
    uart3.RxState = 0;  //初始化接受状态为0
    __HAL_UART_ENABLE_IT(&uart3.uart, UART_IT_RXNE);    //打开接收中断
    
    HAL_UART_Receive_DMA(&uart3.uart,uart3.RxInPtr->start,U3_RX_MAX);
}
void U3_Txdata(uint8_t *data, uint32_t data_len){
    if((U3_TX_SIZE - uart3.TxCounter )>=data_len){
        uart3.TxInPtr->start = &U3_TxBuff[uart3.TxCounter];
    }else{
        uart3.TxCounter = 0;
        uart3.TxInPtr->start = U3_TxBuff;
    }
    memcpy(uart3.TxInPtr->start,data,data_len);
    uart3.TxCounter += data_len;
    uart3.TxInPtr->end = &U3_TxBuff[uart3.TxCounter - 1];
    uart3.TxInPtr++;
    if(uart3.TxInPtr == uart3.TxEndPtr){
        uart3.TxInPtr = &uart3.TxLocation[0];
    }
}
void HAL_UART_MspInit(UART_HandleTypeDef *huart){
    
    GPIO_InitTypeDef GPIO_InitType;
    
    if(huart->Instance == USART1){
        
        __HAL_RCC_GPIOA_CLK_ENABLE();
        __HAL_RCC_USART1_CLK_ENABLE();
        __HAL_RCC_DMA1_CLK_ENABLE();
            
        GPIO_InitType.Pin = GPIO_PIN_9;
        GPIO_InitType.Mode = GPIO_MODE_AF_PP;
        GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
        HAL_GPIO_Init(GPIOA,&GPIO_InitType);
        
        GPIO_InitType.Pin = GPIO_PIN_10;
        GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
        GPIO_InitType.Pull = GPIO_PULLUP;
        HAL_GPIO_Init(GPIOA,&GPIO_InitType);
        
        HAL_NVIC_SetPriority(USART1_IRQn,3,0);
        HAL_NVIC_EnableIRQ(USART1_IRQn);

        uart1.dmatx.Instance = DMA1_Channel4;
        uart1.dmatx.Init.Direction = DMA_MEMORY_TO_PERIPH;
        uart1.dmatx.Init.PeriphInc = DMA_PINC_DISABLE;
        uart1.dmatx.Init.MemInc = DMA_MINC_ENABLE;
        uart1.dmatx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        uart1.dmatx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        uart1.dmatx.Init.Mode = DMA_NORMAL;
        uart1.dmatx.Init.Priority = DMA_PRIORITY_MEDIUM;
        __HAL_LINKDMA(huart, hdmatx, uart1.dmatx);
        HAL_DMA_Init(&uart1.dmatx);
        
        HAL_NVIC_SetPriority(DMA1_Channel4_IRQn,3,0);
        HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);
        
        uart1.dmarx.Instance = DMA1_Channel5;
        uart1.dmarx.Init.Direction = DMA_PERIPH_TO_MEMORY;
        uart1.dmarx.Init.PeriphInc = DMA_PINC_DISABLE;
        uart1.dmarx.Init.MemInc = DMA_MINC_ENABLE;
        uart1.dmarx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        uart1.dmarx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        uart1.dmarx.Init.Mode = DMA_NORMAL;
        uart1.dmarx.Init.Priority = DMA_PRIORITY_MEDIUM;
        __HAL_LINKDMA(huart, hdmarx, uart1.dmarx);
        HAL_DMA_Init(&uart1.dmarx);
        
        HAL_NVIC_SetPriority(DMA1_Channel5_IRQn,3,0);
        HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
                
    }else if(huart->Instance == USART2){
        __HAL_RCC_GPIOA_CLK_ENABLE();
        __HAL_RCC_USART2_CLK_ENABLE();
        __HAL_RCC_DMA1_CLK_ENABLE();
        
        GPIO_InitType.Pin = GPIO_PIN_2;
        GPIO_InitType.Mode = GPIO_MODE_AF_OD;   //OD模式
        GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
        HAL_GPIO_Init(GPIOA,&GPIO_InitType);
        
        GPIO_InitType.Pin = GPIO_PIN_3;
        GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
        GPIO_InitType.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(GPIOA,&GPIO_InitType);
        
        HAL_NVIC_SetPriority(USART2_IRQn,3,0);
        HAL_NVIC_EnableIRQ(USART2_IRQn);
        
        uart2.dmatx.Instance = DMA1_Channel7;
        uart2.dmatx.Init.Direction = DMA_MEMORY_TO_PERIPH;
        uart2.dmatx.Init.PeriphInc = DMA_PINC_DISABLE;
        uart2.dmatx.Init.MemInc = DMA_MINC_ENABLE;
        uart2.dmatx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        uart2.dmatx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        uart2.dmatx.Init.Mode = DMA_NORMAL;
        uart2.dmatx.Init.Priority = DMA_PRIORITY_MEDIUM;
        __HAL_LINKDMA(huart, hdmatx, uart2.dmatx);
        HAL_DMA_Init(&uart2.dmatx);
        
        HAL_NVIC_SetPriority(DMA1_Channel7_IRQn,3,0);
        HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);
        
        uart2.dmarx.Instance = DMA1_Channel6;
        uart2.dmarx.Init.Direction = DMA_PERIPH_TO_MEMORY;
        uart2.dmarx.Init.PeriphInc = DMA_PINC_DISABLE;
        uart2.dmarx.Init.MemInc = DMA_MINC_ENABLE;
        uart2.dmarx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        uart2.dmarx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        uart2.dmarx.Init.Mode = DMA_NORMAL;
        uart2.dmarx.Init.Priority = DMA_PRIORITY_MEDIUM;
        __HAL_LINKDMA(huart, hdmarx, uart2.dmarx);
        HAL_DMA_Init(&uart2.dmarx);
        
        HAL_NVIC_SetPriority(DMA1_Channel6_IRQn,3,0);
        HAL_NVIC_EnableIRQ(DMA1_Channel6_IRQn);
        
    }else if(huart->Instance == USART3){
        __HAL_RCC_GPIOB_CLK_ENABLE();
        __HAL_RCC_USART3_CLK_ENABLE();
        __HAL_RCC_DMA1_CLK_ENABLE();
        
        GPIO_InitType.Pin = GPIO_PIN_10;    
        GPIO_InitType.Mode = GPIO_MODE_AF_OD;    //OD模式
        GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
        HAL_GPIO_Init(GPIOB,&GPIO_InitType);
        
        GPIO_InitType.Pin = GPIO_PIN_11;
        GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
        GPIO_InitType.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(GPIOB,&GPIO_InitType);
        
        HAL_NVIC_SetPriority(USART3_IRQn,3,0);
        HAL_NVIC_EnableIRQ(USART3_IRQn);
        
        uart3.dmatx.Instance = DMA1_Channel2;
        uart3.dmatx.Init.Direction = DMA_MEMORY_TO_PERIPH;
        uart3.dmatx.Init.PeriphInc = DMA_PINC_DISABLE;
        uart3.dmatx.Init.MemInc = DMA_MINC_ENABLE;
        uart3.dmatx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        uart3.dmatx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        uart3.dmatx.Init.Mode = DMA_NORMAL;
        uart3.dmatx.Init.Priority = DMA_PRIORITY_MEDIUM;
        __HAL_LINKDMA(huart, hdmatx, uart3.dmatx);
        HAL_DMA_Init(&uart3.dmatx);
        
        HAL_NVIC_SetPriority(DMA1_Channel2_IRQn,3,0);
        HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
        
        uart3.dmarx.Instance = DMA1_Channel3;
        uart3.dmarx.Init.Direction = DMA_PERIPH_TO_MEMORY;
        uart3.dmarx.Init.PeriphInc = DMA_PINC_DISABLE;
        uart3.dmarx.Init.MemInc = DMA_MINC_ENABLE;
        uart3.dmarx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        uart3.dmarx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        uart3.dmarx.Init.Mode = DMA_NORMAL;
        uart3.dmarx.Init.Priority = DMA_PRIORITY_MEDIUM;
        __HAL_LINKDMA(huart, hdmarx, uart3.dmarx);
        HAL_DMA_Init(&uart3.dmarx);
        
        HAL_NVIC_SetPriority(DMA1_Channel3_IRQn,3,0);
        HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
    }
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1){

    }
}
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1){

    }
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{	
    if(huart->Instance == USART1){
        uart1.TxState = 0;
    }else if(huart->Instance == USART2){
        uart2.TxState = 0;
    }else if(huart->Instance == USART3){
        uart3.TxState = 0;
    }
}

/* 接收终止回调 */
void HAL_UART_AbortReceiveCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1){
        uart1.RxInPtr->end = &U1_RxBuff[uart1.RxCounter - 1];
        uart1.RxInPtr++;
        if(uart1.RxInPtr == uart1.RxEndPtr){
            uart1.RxInPtr = &uart1.RxLocation[0];
        }
        if((U1_RX_SIZE - uart1.RxCounter)<U1_RX_MAX){
            uart1.RxCounter = 0;
            uart1.RxInPtr->start = U1_RxBuff;
        }else{
            uart1.RxInPtr->start = &U1_RxBuff[uart1.RxCounter];
        }
        HAL_UART_Receive_DMA(&uart1.uart,uart1.RxInPtr->start,U1_RX_MAX);
    }else if(huart->Instance == USART2){
        uart2.RxInPtr->end = &U2_RxBuff[uart2.RxCounter - 1];
        uart2.RxInPtr++;
        if(uart2.RxInPtr == uart2.RxEndPtr){
            uart2.RxInPtr = &uart2.RxLocation[0];
        }
        if((U2_RX_SIZE - uart2.RxCounter)<U2_RX_MAX){
            uart2.RxCounter = 0;
            uart2.RxInPtr->start = U2_RxBuff;
        }else{
            uart2.RxInPtr->start = &U2_RxBuff[uart2.RxCounter];
        }
        HAL_MultiProcessor_EnterMuteMode(&uart2.uart);  //手动进入静默模式
        __HAL_UART_ENABLE_IT(&uart2.uart, UART_IT_RXNE);    //打开接收中断
        HAL_UART_Receive_DMA(&uart2.uart,uart2.RxInPtr->start,U2_RX_MAX);
    }else if(huart->Instance == USART3){
        uart3.RxInPtr->end = &U3_RxBuff[uart3.RxCounter - 1];
        uart3.RxInPtr++;
        if(uart3.RxInPtr == uart3.RxEndPtr){
            uart3.RxInPtr = &uart3.RxLocation[0];
        }
        if((U3_RX_SIZE - uart3.RxCounter)<U3_RX_MAX){
            uart3.RxCounter = 0;
            uart3.RxInPtr->start = U3_RxBuff;
        }else{
            uart3.RxInPtr->start = &U3_RxBuff[uart3.RxCounter];
        }
        HAL_MultiProcessor_EnterMuteMode(&uart3.uart);  //手动进入静默模式
        __HAL_UART_ENABLE_IT(&uart3.uart, UART_IT_RXNE);    //打开接收中断
        HAL_UART_Receive_DMA(&uart3.uart,uart3.RxInPtr->start,U3_RX_MAX);
    }
}

uart.h

/*-----------------------------------------------------*/
/*                     程序结构                        */
/*-----------------------------------------------------*/
/*USER   :包含程序的 main 函数,是整个程序的入        */
/*HW     :包含开发板各种功能外设的驱动程序            */
/*LIB    :官方提供的 HAL 库文件                       */
/*CMSIS  :CM3 内核相关的启动文件系统文件              */
/*-----------------------------------------------------*/
/*                                                     */
/*                实现定时器功能的头文件               */
/*                                                     */
/*-----------------------------------------------------*/

#ifndef _TIMER_H
#define _TIMER_H

#include "stdint.h"  
#include "stm32f1xx_hal_tim.h"

extern TIM_HandleTypeDef htim4;                   //外部变量声明

void TIM4_TimerInit(uint16_t, uint16_t);          //函数声明

#endif

sw.c

#include "stm32f1xx_hal.h"
#include "sw.h"
#include "uart.h"

uint8_t sw1_sta,sw2_sta;    //0:没有按下  1:按下了

void SW_Init(void){
    GPIO_InitTypeDef GPIO_InitType;
    
    __HAL_RCC_GPIOC_CLK_ENABLE();
    GPIO_InitType.Pin = GPIO_PIN_14;
    GPIO_InitType.Mode = GPIO_MODE_INPUT;
    GPIO_InitType.Pull = GPIO_PULLDOWN;
    HAL_GPIO_Init(GPIOC,&GPIO_InitType);
    
    __HAL_RCC_GPIOA_CLK_ENABLE();
    GPIO_InitType.Pin = GPIO_PIN_0;
    GPIO_InitType.Mode = GPIO_MODE_INPUT;
    GPIO_InitType.Pull = GPIO_PULLDOWN;
    HAL_GPIO_Init(GPIOA,&GPIO_InitType);
}

void SW_InitEvent(void){
    GPIO_InitTypeDef GPIO_InitType;
    //SW1
    __HAL_RCC_GPIOA_CLK_ENABLE();
    GPIO_InitType.Pin = GPIO_PIN_2;
    GPIO_InitType.Mode = GPIO_MODE_EVT_RISING_FALLING;
    GPIO_InitType.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(GPIOA,&GPIO_InitType);
}

void SW_InitEventOut(void){
    GPIO_InitTypeDef GPIO_InitType;
    //PA3
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_AFIO_CLK_ENABLE();
    GPIO_InitType.Pin = GPIO_PIN_3;
    GPIO_InitType.Mode = GPIO_MODE_AF_PP;
    GPIO_InitType.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA,&GPIO_InitType);
    HAL_GPIOEx_ConfigEventout(AFIO_EVENTOUT_PORT_A,AFIO_EVENTOUT_PIN_3);
    HAL_GPIOEx_EnableEventout();
}

//mode 0:按下执行  1:抬起执行
void SW_Init_IT(uint8_t mode){
    GPIO_InitTypeDef GPIO_InitType;
    
    __HAL_RCC_GPIOC_CLK_ENABLE();
    GPIO_InitType.Pin = GPIO_PIN_14;
    if(mode == 0)
        GPIO_InitType.Mode = GPIO_MODE_IT_RISING;
    else
        GPIO_InitType.Mode = GPIO_MODE_IT_FALLING;
    GPIO_InitType.Pull = GPIO_PULLDOWN;
    HAL_GPIO_Init(GPIOC,&GPIO_InitType);
    HAL_NVIC_SetPriority(EXTI15_10_IRQn,4,0);
    HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
    
    __HAL_RCC_GPIOA_CLK_ENABLE();
    GPIO_InitType.Pin = GPIO_PIN_0;
    if(mode == 0)
        GPIO_InitType.Mode = GPIO_MODE_IT_RISING;
    else
        GPIO_InitType.Mode = GPIO_MODE_IT_FALLING;
    GPIO_InitType.Pull = GPIO_PULLDOWN;
    HAL_GPIO_Init(GPIOA,&GPIO_InitType);
    HAL_NVIC_SetPriority(EXTI0_IRQn,3,0);
    HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}

void SW_Init_IT2(void){
    GPIO_InitTypeDef GPIO_InitType;
    
    __HAL_RCC_GPIOC_CLK_ENABLE();
    GPIO_InitType.Pin = GPIO_PIN_14;
    GPIO_InitType.Mode = GPIO_MODE_IT_RISING_FALLING;
    GPIO_InitType.Pull = GPIO_PULLDOWN;
    HAL_GPIO_Init(GPIOC,&GPIO_InitType);
    HAL_NVIC_SetPriority(EXTI15_10_IRQn,4,0);
    HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
    
    __HAL_RCC_GPIOA_CLK_ENABLE();
    GPIO_InitType.Pin = GPIO_PIN_0;
    GPIO_InitType.Mode = GPIO_MODE_IT_RISING_FALLING;
    GPIO_InitType.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(GPIOA,&GPIO_InitType);
    HAL_NVIC_SetPriority(EXTI0_IRQn,3,0);
    HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}

//返回值  0:无按键触发  8:SW8触发
//mode 0:按下执行  1:抬起执行
uint8_t SW_Scan(uint8_t mode){
    
    uint32_t i;
    /*-------------SW8------------------*/
    if((SW1_IN == 1)&&(sw1_sta == 0)){
        for(i=0;i<0x7FFF;i++){
            if(SW1_IN == 0){
                return 0;
            }
        }
        sw1_sta = 1;
        if(mode == 0){
            return 8;
        }
    }else if((SW1_IN == 0)&&(sw1_sta == 1)){
        for(i=0;i<0x7FFF;i++){
            if(SW1_IN == 1){
                return 0;
            }
        }
        sw1_sta = 0;
        if(mode == 1){
            return 8;
        }
    }
    /*-------------SW11------------------*/
    if((SW2_IN == 0)&&(sw2_sta == 0)){
        for(i=0;i<0x7FFF;i++){
            if(SW2_IN == 1){
                return 0;
            }
        }
        sw2_sta = 1;
        if(mode == 0){
            return 11;
        }
    }else if((SW2_IN == 1)&&(sw2_sta == 1)){
        for(i=0;i<0x7FFF;i++){
            if(SW2_IN == 0){
                return 0;
            }
        }
        sw2_sta = 0;
        if(mode == 1){
            return 11;
        }
    }
    
    return 0;
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    uint32_t i;
    
    //SW8:PC13  SW11:PA0(抢占优先级高)
    switch(GPIO_Pin){
        case GPIO_PIN_14:	if(SW1_IN == 1){
                                for(i=0;i<0x7FFF;i++){
                                    if(SW1_IN == 0){
                                        return;
                                    }
                                }
                                //U1_Txdata((uint8_t *)"\\x81S1_LED",7);
                                //U2_Txdata((uint8_t *)"LED_ON",6);
                                U3_Txdata((uint8_t *)"LED_ON",6);
                            }else if(SW1_IN == 0){
                                for(i=0;i<0x7FFF;i++){
                                    if(SW1_IN == 1){
                                        return;
                                    }
                                }
                                HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_0);
                            } 
                            break;
                            
        case GPIO_PIN_0:    if(SW2_IN == 1){
                                for(i=0;i<0x7FFF;i++){
                                    if(SW2_IN == 0){
                                        return;
                                    }
                                }
                                //U1_Txdata((uint8_t *)"\\x82S2_LED",7);
                                //U2_Txdata((uint8_t *)"LED_OFF",7);
                                U3_Txdata((uint8_t *)"LED_OFF",7);
                            }else if(SW2_IN == 1){
                                for(i=0;i<0x7FFF;i++){
                                    if(SW2_IN == 0){
                                        return;
                                    }
                                }
                                HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_0);
                            }
                            break;
    }
}

sw.h

#ifndef __SW_H
#define __SW_H

#include "stdint.h"

#define  SW1_IN   HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_14)
#define  SW2_IN  HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)

void SW_Init(void);
uint8_t SW_Scan(uint8_t mode);
void SW_Init_IT(uint8_t mode);
void SW_Init_IT2(void);
void SW_InitEvent(void);
void SW_InitEventOut(void);

#endif

led.c

#include "stm32f1xx_hal.h"
#include "led.h"

void LED_Init(void){
    GPIO_InitTypeDef GPIO_InitType;
    
    __HAL_RCC_GPIOC_CLK_ENABLE();
    GPIO_InitType.Pin = GPIO_PIN_13;
    GPIO_InitType.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitType.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOC,&GPIO_InitType);
    HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);
}

void LED_ON(void){
    HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);
}

void LED_OFF(void){
    HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);
}

void LED_Toggle(void){
    HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);
}

led.h

#ifndef __LED_H
#define __LED_H

void LED_Init(void);

void LED_ON(void);

void LED_OFF(void);

void LED_Toggle(void);
#endif

stm32f1xx_it.c

/*-------------------------------------------------*/
/*            超子说物联网STM32系列开发板          */
/*-------------------------------------------------*/
/*                                                 */
/*          实现各种中断服务函数的源文件           */
/*                                                 */
/*-------------------------------------------------*/

#include "stm32f1xx_hal.h"   
#include "stm32f1xx_it.h"
#include "uart.h"
#include "timer.h"
void EXTI15_10_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_14);
}
void EXTI0_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
void USART1_IRQHandler(void)
{
    HAL_UART_IRQHandler(&uart1.uart);
    
    if(__HAL_UART_GET_FLAG(&uart1.uart, UART_FLAG_IDLE)){
        __HAL_UART_CLEAR_IDLEFLAG(&uart1.uart);
        uart1.RxCounter += (U1_RX_MAX - __HAL_DMA_GET_COUNTER(&uart1.dmarx));
        HAL_UART_AbortReceive_IT(&uart1.uart);
    }
}

void USART2_IRQHandler(void)
{
    HAL_UART_IRQHandler(&uart2.uart);
    
    //if(__HAL_UART_GET_FLAG(&uart2.uart, UART_FLAG_IDLE)){
    //    __HAL_UART_CLEAR_IDLEFLAG(&uart2.uart);
    //    uart2.RxCounter += (U2_RX_MAX - __HAL_DMA_GET_COUNTER(&uart2.dmarx));
    //    HAL_UART_AbortReceive_IT(&uart2.uart);
    //}
}
void USART3_IRQHandler(void)
{
    HAL_UART_IRQHandler(&uart3.uart);
    
    //if(__HAL_UART_GET_FLAG(&uart3.uart, UART_FLAG_IDLE)){
    //    __HAL_UART_CLEAR_IDLEFLAG(&uart3.uart);
    //    uart3.RxCounter += (U3_RX_MAX - __HAL_DMA_GET_COUNTER(&uart3.dmarx));
    //    HAL_UART_AbortReceive_IT(&uart3.uart);
    //}
}
void DMA1_Channel4_IRQHandler(void)
{
    HAL_DMA_IRQHandler(&uart1.dmatx);
}
void DMA1_Channel5_IRQHandler(void)
{
    HAL_DMA_IRQHandler(&uart1.dmarx);
}
void DMA1_Channel7_IRQHandler(void)
{
    HAL_DMA_IRQHandler(&uart2.dmatx);
}
void DMA1_Channel6_IRQHandler(void)
{
    HAL_DMA_IRQHandler(&uart2.dmarx);
}
void DMA1_Channel2_IRQHandler(void)
{
    HAL_DMA_IRQHandler(&uart3.dmatx);
}
void DMA1_Channel3_IRQHandler(void)
{
    HAL_DMA_IRQHandler(&uart3.dmarx);
}

//定时器中断处理函数
void TIM4_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&htim4);
}
/*-------------------------------------------------*/
/*函数名:不可屏蔽中断处理函数                     */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void NMI_Handler(void)
{

}

/*-------------------------------------------------*/
/*函数名:硬件出错后进入的中断处理函数             */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void HardFault_Handler(void)
{

}
/*-------------------------------------------------*/
/*函数名:软中断,SWI 指令调用的处理函数           */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void SVC_Handler(void)
{
    
}
/*-------------------------------------------------*/
/*函数名:可挂起的系统服务处理函数                 */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void PendSV_Handler(void)
{
    
}
/*-------------------------------------------------*/
/*函数名:SysTic系统嘀嗒定时器处理函数             */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void SysTick_Handler(void)
{  
    HAL_IncTick();	
}

timer.c

/*-----------------------------------------------------*/
/*                     程序结构                        */
/*-----------------------------------------------------*/
/*USER   :包含程序的 main 函数,是整个程序的入        */
/*HW     :包含开发板各种功能外设的驱动程序            */
/*LIB    :官方提供的 HAL 库文件                       */
/*CMSIS  :CM3 内核相关的启动文件系统文件              */
/*-----------------------------------------------------*/
/*                                                     */
/*                实现定时器功能的源文件               */
/*                                                     */
/*-----------------------------------------------------*/

#include "stm32f1xx_hal.h"  
#include "timer.h"            
#include "uart.h"  

TIM_HandleTypeDef htim4;    //定时器4总控制结构体

/*-------------------------------------------------*/
/*函数名:定时器4 定时初始化                       */
/*参  数:arr:自动重装值                          */
/*参  数:psc:时钟预分频数                        */
/*返回值:无                                       */
/*-------------------------------------------------*/
void TIM4_TimerInit(uint16_t arr, uint16_t psc)
{
    htim4.Instance = TIM4;                                         //设置使用哪个定时器
    htim4.Init.Prescaler = psc - 1;                                //设置预分频器的值
    htim4.Init.Period = arr - 1;                                   //设置自动重载值
    htim4.Init.CounterMode = TIM_COUNTERMODE_UP;                   //设置计数模式
    htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; //自动重载预装载 禁止
    HAL_TIM_Base_Init(&htim4);                                     //配置,如果失败进入if

    __HAL_TIM_CLEAR_IT(&htim4, TIM_IT_UPDATE);                     //清除定时器4的中断标志
    __HAL_TIM_ENABLE_IT(&htim4, TIM_IT_UPDATE);                    //打开更新中断
}
/*-------------------------------------------------*/
/*函数名:定时器底层驱动,开启时钟,设置中断优先级 */
/*参  数:htim:定时器句柄                         */
/*返回值:无                                       */
/*说  明:此函数会被HAL_TIM_Base_Init()函数调用    */
/*-------------------------------------------------*/
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
    if(htim->Instance==TIM4){	                   //判断是哪个定时器	
        __HAL_RCC_TIM4_CLK_ENABLE();               //使能定时器时钟
        HAL_NVIC_SetPriority(TIM4_IRQn,4,0);       //设置中断优先级,中断分组在HAL_Init()函数中,被设置为4
        HAL_NVIC_EnableIRQ(TIM4_IRQn);             //开启定时器中断   
    }
}
/*---------------------------------------------------*/
/*函数名:定时器中断回调函数                         */
/*参  数:htim:定时器句柄                           */
/*返回值:无                                         */
/*说  明:此函数会被HAL_TIM_IRQHandler()中断函数调用 */
/*---------------------------------------------------*/
//超时回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim->Instance==TIM4){	          //判断是哪个定时器
        __HAL_TIM_DISABLE(htim);          //关闭定时器4的计数
        __HAL_TIM_SET_COUNTER(htim,0);    //清零定时器4计数器
        uart3.RxState = 0;  //恢复首字节接收标志位
        uart3.RxCounter += (U3_RX_MAX - __HAL_DMA_GET_COUNTER(&uart3.dmarx));   //记录剩余未发送
        HAL_UART_AbortReceive_IT(&uart3.uart);  //终止接收
    }
}

stm32f1xx_hal_uart.c

void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
  uint32_t isrflags   = READ_REG(huart->Instance->SR);
  uint32_t cr1its     = READ_REG(huart->Instance->CR1);
  uint32_t cr3its     = READ_REG(huart->Instance->CR3);
  uint32_t errorflags = 0x00U;
  uint32_t dmarequest = 0x00U;

  /* If no error occurs */
  errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));
    //删除  RXNE中断
  //if (errorflags == RESET)
  //{
  //  /* UART in mode Receiver -------------------------------------------------*/
  //  if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
  //  {
  //    UART_Receive_IT(huart);
  //    return;
  //  }
  //}

  /* If some errors occur */
  if ((errorflags != RESET) && (((cr3its & USART_CR3_EIE) != RESET) || ((cr1its & (USART_CR1_RXNEIE | USART_CR1_PEIE)) != RESET)))
  {
    /* UART parity error interrupt occurred ----------------------------------*/
    if (((isrflags & USART_SR_PE) != RESET) && ((cr1its & USART_CR1_PEIE) != RESET))
    {
      huart->ErrorCode |= HAL_UART_ERROR_PE;
    }

    /* UART noise error interrupt occurred -----------------------------------*/
    if (((isrflags & USART_SR_NE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
    {
      huart->ErrorCode |= HAL_UART_ERROR_NE;
    }

    /* UART frame error interrupt occurred -----------------------------------*/
    if (((isrflags & USART_SR_FE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
    {
      huart->ErrorCode |= HAL_UART_ERROR_FE;
    }

    /* UART Over-Run interrupt occurred --------------------------------------*/
    if (((isrflags & USART_SR_ORE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
    {
      huart->ErrorCode |= HAL_UART_ERROR_ORE;
    }

    /* Call UART Error Call back function if need be --------------------------*/
    if (huart->ErrorCode != HAL_UART_ERROR_NONE)
    {
      /* UART in mode Receiver -----------------------------------------------*/
      if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
      {
        UART_Receive_IT(huart);
      }

      /* If Overrun error occurs, or if any error occurs in DMA mode reception,
         consider error as blocking */
      dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR);
      if (((huart->ErrorCode & HAL_UART_ERROR_ORE) != RESET) || dmarequest)
      {
        /* Blocking error : transfer is aborted
           Set the UART state ready to be able to start again the process,
           Disable Rx Interrupts, and disable Rx DMA request, if ongoing */
        UART_EndRxTransfer(huart);

        /* Disable the UART DMA Rx request if enabled */
        if (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR))
        {
          CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);

          /* Abort the UART DMA Rx channel */
          if (huart->hdmarx != NULL)
          {
            /* Set the UART DMA Abort callback :
               will lead to call HAL_UART_ErrorCallback() at end of DMA abort procedure */
            huart->hdmarx->XferAbortCallback = UART_DMAAbortOnError;
            if (HAL_DMA_Abort_IT(huart->hdmarx) != HAL_OK)
            {
              /* Call Directly XferAbortCallback function in case of error */
              huart->hdmarx->XferAbortCallback(huart->hdmarx);
            }
          }
          else
          {
            /* Call user error callback */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
            /*Call registered error callback*/
            huart->ErrorCallback(huart);
#else
            /*Call legacy weak error callback*/
            HAL_UART_ErrorCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
          }
        }
        else
        {
          /* Call user error callback */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
          /*Call registered error callback*/
          huart->ErrorCallback(huart);
#else
          /*Call legacy weak error callback*/
          HAL_UART_ErrorCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
        }
      }
      else
      {
        /* Non Blocking error : transfer could go on.
           Error is notified to user through user error callback */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
        /*Call registered error callback*/
        huart->ErrorCallback(huart);
#else
        /*Call legacy weak error callback*/
        HAL_UART_ErrorCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */

        huart->ErrorCode = HAL_UART_ERROR_NONE;
      }
    }
    return;
  } /* End if some error occurs */

  /* UART in mode Transmitter ------------------------------------------------*/
  //删除  发送缓冲区空的中断
//  if (((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
//  {
//    UART_Transmit_IT(huart);
//    return;
//  }

  /* UART in mode Transmitter end --------------------------------------------*/
  if (((isrflags & USART_SR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET))
  {
    UART_EndTransmit_IT(huart);
    return;
  }
  /* 写自己的中断回调,现在只能进入我们这个了。 */
  #include "uart.h"
  #include "timer.h"
  else
  {
    if(uart3.RxState == 0){ /* 首字节 */
        __HAL_TIM_ENABLE(&htim4);  //打开tim4的计数
        uart3.RxStat = 1;   //标记接收
    }else{/* 后续字节 */
        __HAL_TIM_SET_COUNTER(&htim4, 0)//清除tim4的计数
    
    }
  
  }
}

main.c

#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "sw.h"
#include "uart.h"

int main(void){

    HAL_Init();
    RccClock_Init();
    SW_Init_IT(0);
    LED_Init();
    U1_Init(921600);
    U2_Init(921600);
    U3_Init(921600);
    
    while(1){
        //串口1收发
        if(uart1.RxOutPtr != uart1.RxInPtr){
            
            if(((uart1.RxOutPtr->end - uart1.RxOutPtr->start + 1)==6)&&(memcmp(uart1.RxOutPtr->start,"LED_ON",6) == 0)){
                LED_ON();
            }else if(((uart1.RxOutPtr->end - uart1.RxOutPtr->start + 1)==7)&&(memcmp(uart1.RxOutPtr->start,"LED_OFF",7) == 0)){
                LED_OFF();
            }
            
            uart1.RxOutPtr++;
            if(uart1.RxOutPtr == uart1.RxEndPtr){
                uart1.RxOutPtr = &uart1.RxLocation[0];
            }
        }
        if((uart1.TxOutPtr != uart1.TxInPtr)&&(uart1.TxState==0)){
            uart1.TxState = 1;
            HAL_UART_Transmit_DMA(&uart1.uart,uart1.TxOutPtr->start,uart1.TxOutPtr->end - uart1.TxOutPtr->start + 1);
            uart1.TxOutPtr++;
            if(uart1.TxOutPtr == uart1.TxEndPtr){
                uart1.TxOutPtr = &uart1.TxLocation[0];
            }
        }
        //串口2收发
        if(uart2.RxOutPtr != uart2.RxInPtr){
                    
            if(((uart2.RxOutPtr->end - uart2.RxOutPtr->start + 1)==7)&&(memcmp(uart2.RxOutPtr->start,"\\x81S1_LED",7) == 0)){
                LED_Toggle();
            }
            
            uart2.RxOutPtr++;
            if(uart2.RxOutPtr == uart2.RxEndPtr){
                uart2.RxOutPtr = &uart2.RxLocation[0];
            }
        }
        if((uart2.TxOutPtr != uart2.TxInPtr)&&(uart2.TxState==0)){
            uart2.TxState = 1;
            HAL_UART_Transmit_DMA(&uart2.uart,uart2.TxOutPtr->start,uart2.TxOutPtr->end - uart2.TxOutPtr->start + 1);
            uart2.TxOutPtr++;
            if(uart2.TxOutPtr == uart2.TxEndPtr){
                uart2.TxOutPtr = &uart2.TxLocation[0];
            }
        }
        //串口3收发
        if(uart3.RxOutPtr != uart3.RxInPtr){
            
            if(((uart3.RxOutPtr->end - uart3.RxOutPtr->start + 1)==7)&&(memcmp(uart3.RxOutPtr->start,"\\x82S2_LED",7) == 0)){
                LED_Toggle();
            }
            
            uart3.RxOutPtr++;
            if(uart3.RxOutPtr == uart3.RxEndPtr){
                uart3.RxOutPtr = &uart3.RxLocation[0];
            }
        }
        if((uart3.TxOutPtr != uart3.TxInPtr)&&(uart3.TxState==0)){
            uart3.TxState = 1;
            HAL_UART_Transmit_DMA(&uart3.uart,uart3.TxOutPtr->start,uart3.TxOutPtr->end - uart3.TxOutPtr->start + 1);
            uart3.TxOutPtr++;
            if(uart3.TxOutPtr == uart3.TxEndPtr){
                uart3.TxOutPtr = &uart3.TxLocation[0];
            }
        }
    }
        
}

十一、HAL库:多主机通信 空闲检测唤醒 定时器超时 DMA不定长接收

1. 空闲总线检测

空闲唤醒没有硬件从机地址,需要自己在程序中加入从机地址,并进行管理

RWU被写入1时,USART进入静默模式。当检测到 一空闲帧时,它被唤醒。然后RWU被硬件清零,

所以,在空闲总线唤醒模式下HAL_MultiProcessor_Init 多设备初始化的第二个参数(从机地址)时无效的

2. 思路:

因为空闲总线检测没有从机没有硬件地址,那么思路可以为下:

  1. 从机默认为正常模式,如果地址匹配,那么继续执行后续操作。
  2. 如果地址未匹配,那么在应用程序中,调用子函数,将这个从机的RWU变为高电平。静默模式。不对后续的数据进行接收
  3. 当这一段数据接收完毕,空闲帧出现时,就会重新把从机的RWU拉低为低电平。变为正常模式
  4. 总结理解:大部分时间为正常模式,当判断地址之后,如果不是自己的地址就进入静默模式,不接收。当这一段数据完毕之后,空闲帧出现,硬件自动拉低RWU。变会正常模式

3. 程序

相较上一节:”HAL库:多主机通信 地址检测唤醒 定时器超时 DMA不定长接收“

主机部分:

  • 仅改变了发送数据,由 0x81 变为0x01 .因为此时不是地址检测唤醒,不需要告诉从机这段字节为地址(bit7 为 1)

从机部分:

  • 修改主程序判断接收数据的地址由0x81-> 0x01
  • 仅在初始化时,改变了下HAL_MultiProcessor_Init 的第三个参数(唤醒方式)为UART_WAKEUPMETHOD_IDLELINE (第二个参数为无效参数) 初始化时和接收完成后不需要进入静默模式,(因为空闲帧会立刻把RWU置位为0,进入正常模式)
  • 在stm32f1xx_hal_uart.c中,添加判断地址并进入或不进入静默模式的程序。
  /* 写自己的中断回调,现在只能进入我们这个了。 */
    if(uart2.RxState == 0){ /* 首字节 */
        __HAL_TIM_ENABLE(&htim4);  //打开tim4的计数
        uart2.RxState = 1;   //标记接收
        
        /* 判断地址 */
        if(*uart2.RxInPtr->start != 0x01){//判断第一个字节是不是自己的地址
            HAL_MultiProcessor_EnterMuteMode(&uart1.uart);  //进入静默模式
        }
        
        
    }else{/* 后续字节 */
        __HAL_TIM_SET_COUNTER(&htim4, 0);//清除tim4的计数 
    }

十二、串口1 2 3 Printf 格式化输出

void U3_Printf(char* format, ...){
    uint8_t tempbuff[256];
    
    va_list ap;
    va_start(ap, format);
    vsprintf((char*)tempbuff, format, ap);
    va_end(ap);
    
    uint16_t i;
    for(i = 0; i < strlen((char*)tempbuff); i++){
        while(!__HAL_UART_GET_FLAG(&uart3.uart, UART_FLAG_TXE));    //发送寄存器空,才开始发送
        uart3.uart.Instance->DR = tempbuff[i];          //把数据依次放入DR 寄存器,发送出去
    }
     while(!__HAL_UART_GET_FLAG(&uart3.uart, UART_FLAG_TC));    //发送完成,退出printf
}

代码解析:

  1. 这个函数有一个参数format,它是一个指向字符的指针,代表格式化字符串 在 C 语言中,函数参数中的 “...” 表示可变参数列表,也称为可变参数。
  2. 首先定义了一个大小为 256 的无符号 8 位整数数组 tempbuff,用于存储格式化后的字符串。
  3. 使用可变参数列表的机制。
    • va_list ap; 定义一个可变参数列表指针。
    • va_start(ap, format); 初始化可变参数列表指针,使其指向第一个可变参数,这里 format 是格式化字符串,后面的参数可以是任意类型和数量。
    • vsprintf((char*)tempbuff, format, ap); 使用可变参数列表将格式化后的字符串存储到 tempbuff 数组中。
    • va_end(ap); 标记可变参数列表结束。
  4. 然后通过一个循环逐个字符地将 tempbuff 中的内容发送到 UART3。
    • 在循环中,使用 while(!__HAL_UART_GET_FLAG(&uart3.uart, UART_FLAG_TXE)); 等待发送寄存器为空,即可以发送下一个字符。
    • 当发送寄存器为空时,将 tempbuff 中的字符逐个放入 UART3 的数据寄存器 uart3.uart.Instance->DR 进行发送。
  5. 最后,使用 while(!__HAL_UART_GET_FLAG(&uart3.uart, UART_FLAG_TC)); 等待发送完成标志位,确保所有数据都已发送完毕后退出函数。

十三、通信双方,参数不匹配时会出现哪些错误

这里用到了错误回调函数HAL_UART_ErrorCallback

我们利用两个实验板,测试通信参数不匹配时,产生哪些错误

利用串口2 相互通信

利用串口1 printf输出提示信息

  • 波特率不匹配:噪声错误,不是每次每次都会发生,会伴随无效数据
  • 数据字长不匹配时:一个8位 一个9位 帧错误
  • 校验不匹配时:PE 校验错误

一旦错误产生,会终止当前的数据传输。


http://www.niftyadmin.cn/n/5743527.html

相关文章

几种QQuickWidget与Qml交互数据的方法

QQuickWidget底层继承的是QWidget&#xff0c;但它可以加载Qml文件(组件)&#xff0c;但我们有时候需要和Qml文件(组件)数据交互使用&#xff0c;本文介绍几种QQuickWidget与Qml交互数据的方法。 1. 通过设置上下文属性 setContextProperty可以将变量设置到Qml环境中。 C代码&…

了解聚簇索引和非聚簇索引

在关系型数据库中,索引是提高查询效率的重要手段。索引类似于书籍中的目录,能够帮助数据库快速定位到所需的数据。而在数据库中,最常用的两种索引类型是聚簇索引(Clustered Index)和非聚簇索引(Non-clustered Index)。本文将详细介绍这两种索引类型,帮助读者更好地理解…

React 前端通过组件实现 “下载 Excel模板” 和 “上传 Excel 文件读取内容生成对象数组”

文章目录 一、Excel 模板下载01、代码示例 二、Excel 文件上传01、文件展示02、示例代码03、前端样式展示04、数据结果展示 三、完整代码 本文的业务需求是建立在批量导入数据的情况下&#xff0c;普通组件只能少量导入&#xff0c;数据较多的情况都会选择 Excel 数据导入&…

Vue 项目中为何选择 TSX 而非传统 .vue 文件

近年来&#xff0c;Vue 项目中使用 TSX&#xff08;TypeScript JSX&#xff09;的写法逐渐增多&#xff0c;尤其在 TypeScript 项目中。 1. TSX 与 Vue 的结合背景 1、Vue 3 和 TypeScript Vue 3 从设计之初便更好地支持 TypeScript。Vue 3 使用了 TypeScript 重写核心&…

qt QErrorMessage详解

1、概述 QErrorMessage是Qt框架中用于显示错误消息的一个对话框类。它提供了一个简单的模态对话框&#xff0c;用于向用户显示错误或警告消息。QErrorMessage通常用于应用程序中&#xff0c;当需要向用户报告错误但不希望中断当前操作时。它提供了一个标准的错误消息界面&…

Neo4j 和 Python 初学者指南:如何使用可选关系匹配优化 Cypher 查询

Neo4j 和 Python 初学者指南&#xff1a;如何使用可选关系匹配优化 Cypher 查询 查询需求分析目标查询结构 编写 Cypher 查询查询解析OPTIONAL MATCH 和 COALESCE 的作用 在 Python 中使用 Neo4j 驱动执行查询使用 neo4j 驱动的 Python 示例代码代码解析示例输出 总结 在使用 N…

漏洞分析 | Spring Framework路径遍历漏洞(CVE-2024-38816)

漏洞概述 VMware Spring Framework是美国威睿&#xff08;VMware&#xff09;公司的一套开源的Java、JavaEE应用程序框架。该框架可帮助开发人员构建高质量的应用。 近期&#xff0c;网宿安全演武实验室监测到Spring Framework在特定条件下&#xff0c;存在目录遍历漏洞&…

【SQL实验】高级查询(难点.三)含附加数据库操作

完整代码在文章末尾【代码是自己的解答&#xff0c;并非标准答案&#xff0c;也有可能写错&#xff0c;文中可能会有不准确或待完善之处&#xff0c;恳请各位读者不吝批评指正&#xff0c;共同促进学习交流】 将素材中的“学生管理”数据库附加到SQL SERVER中&#xff0c;完成以…