STM32F103 实例应用(11)——DMA接收不定长串口数据


一、DMA 简介

DMA(Direct Memory Access)—直接存储器存取,是单片机的一个外设,它的主要功能是用来搬数据,但是不需要占用 CPU,即在传输数据的时候,CPU 可以干其他的事情,好像是多线程一样。

数据传输支持从外设到存储器或者存储器到存储器,这里的存储器可以是 SRAM 或者是 FLASH

DMA 控制器包含了 DMA1DMA2,其中 DMA1 有 7 个通道,DMA2 有 5 个通道,这里的通道可以理解为传输数据的一种管道。要注意的是 DMA2 只存在于大容量的单片机中。

二、DMA 功能框图

DMA 控制器独立于内核,属于一个单独的外设,结构比较简单,从编程的角度来看,我们只需掌握功能框图中的三部分内容即可,具体见下图:
在这里插入图片描述

  1. ①DMA 请求

如果外设要想通过 DMA 来传输数据,必须先给 DMA 控制器发送 DMA 请求,DMA收到请求信号之后,控制器会给外设一个应答信号,当外设应答后且 DMA 控制器收到应答信号之后,就会启动 DMA 的传输,直到传输完毕。
DMA 有 DMA1 和 DMA2 两个控制器,DMA1 有 7 个通道,DMA2 有 5 个通道,不同的 DMA 控制器的通道对应着不同的外设请求,这决定了我们在软件编程上该怎么设置,具体见 DMA 请求映像表。
在这里插入图片描述

  1. ②通道
    DMA 具有 12 个独立可编程的通道,其中 DMA1 有 7 个通道,DMA2 有 5 个通道,每个通道对应不同的外设的 DMA 请求。虽然每个通道可以接收多个外设的请求,但是同一时间只能接收一个,不能同时接收多个。

  2. ③仲裁器
    当发生多个 DMA 通道请求时,就意味着有先后响应处理的顺序问题,这个就由仲裁器也管理。仲裁器管理 DMA 通道请求分为两个阶段。第一阶段属于软件阶段,可以在DMA_CCRx 寄存器中设置,有 4 个等级:非常高、高、中和低四个优先级。第二阶段属于硬件阶段,如果两个或以上的 DMA 通道请求设置的优先级一样,则他们优先级取决于通 道编号,编号越低优先权越高,比如通道 0 高于通道 1。在大容量产品和互联型产品中,
    DMA1 控制器拥有高于 DMA2 控制器的优先级。

三、设计实例

本示例使用串口1打印并接收电脑端发来的指令,串口3作为与4G通信的渠道。
bsp_usart.h

/**===========================================================================
  @file bsp_usart.h
  @brief 本文件是用于usart驱动
  @author   青梅煮久
  @version  r0.1
  @date 2021/02/20
----------------------------------------------------------------------------
  Remark: (备注描述)
	串口1、3的驱动。
	串口1:用于日志打印、指令配置
	串口3:用于4G模块通讯
---------------------------------------------------------------------------- History
----------------------------------------------------------------------------
  <Date> | <Version> | <Author> | <Description>
-------------|-----------|----------------|---------------------------------
  2021/02/20 | r0.1 | 青梅煮久 | 创建
-------------|-----------|----------------|--------------------------------- | | |
-------------|-----------|----------------|--------------------------------- | | |
-------------|-----------|----------------|--------------------------------- | | |
============================================================================*/
#ifndef __USART_H
#define	__USART_H

/*********************************************************************
 * INCLUDES
 */
#include "stm32f10x.h"
#include <stdio.h>

/*********************************************************************
 * DEFINITIONS
 */	
/** * 串口宏定义,不同的串口挂载的总线和IO不一样,移植时需要修改这几个宏
	* 1-修改总线时钟的宏,uart1挂载到apb2总线,其他uart挂载到apb1总线
	* 2-修改GPIO的宏
  */
	
// 串口1-USART1
#define  DEBUG_USARTx USART1
#define  DEBUG_USART_CLK RCC_APB2Periph_USART1
#define  DEBUG_USART_APBxClkCmd RCC_APB2PeriphClockCmd
#define  DEBUG_USART_BAUDRATE 115200

// USART GPIO 引脚宏定义
#define  DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA)
#define  DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd #define  DEBUG_USART_TX_GPIO_PORT GPIOA   
#define  DEBUG_USART_TX_GPIO_PIN GPIO_Pin_9
#define  DEBUG_USART_RX_GPIO_PORT GPIOA
#define  DEBUG_USART_RX_GPIO_PIN GPIO_Pin_10

#define  DEBUG_USART_IRQ USART1_IRQn
#define  DEBUG_USART_IRQHandler USART1_IRQHandler


// 串口2-USART2
//#define  DEBUG_USARTx USART2
//#define  DEBUG_USART_CLK RCC_APB1Periph_USART2
//#define  DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
//#define  DEBUG_USART_BAUDRATE 115200

 USART GPIO 引脚宏定义
//#define  DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA)
//#define  DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
// 
//#define  DEBUG_USART_TX_GPIO_PORT GPIOA   
//#define  DEBUG_USART_TX_GPIO_PIN GPIO_Pin_2
//#define  DEBUG_USART_RX_GPIO_PORT GPIOA
//#define  DEBUG_USART_RX_GPIO_PIN GPIO_Pin_3

//#define  DEBUG_USART_IRQ USART2_IRQn
//#define  DEBUG_USART_IRQHandler USART2_IRQHandler

// 串口3-USART3
#define  LTE_USARTx USART3
#define  LTE_USART_CLK RCC_APB1Periph_USART3
#define  LTE_USART_APBxClkCmd RCC_APB1PeriphClockCmd
#define  LTE_USART_BAUDRATE 115200

// USART GPIO 引脚宏定义
#define  LTE_USART_GPIO_CLK (RCC_APB2Periph_GPIOB)
#define  LTE_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd #define  LTE_USART_TX_GPIO_PORT GPIOB   
#define  LTE_USART_TX_GPIO_PIN GPIO_Pin_10
#define  LTE_USART_RX_GPIO_PORT GPIOB
#define  LTE_USART_RX_GPIO_PIN GPIO_Pin_11

#define  LTE_USART_IRQ USART3_IRQn
#define  LTE_USART_IRQHandler USART3_IRQHandler

// 串口4-UART4
//#define  DEBUG_USARTx UART4
//#define  DEBUG_USART_CLK RCC_APB1Periph_UART4
//#define  DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
//#define  DEBUG_USART_BAUDRATE 115200

 USART GPIO 引脚宏定义
//#define  DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOC)
//#define  DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
// 
//#define  DEBUG_USART_TX_GPIO_PORT GPIOC   
//#define  DEBUG_USART_TX_GPIO_PIN GPIO_Pin_10
//#define  DEBUG_USART_RX_GPIO_PORT GPIOC
//#define  DEBUG_USART_RX_GPIO_PIN GPIO_Pin_11

//#define  DEBUG_USART_IRQ UART4_IRQn
//#define  DEBUG_USART_IRQHandler UART4_IRQHandler


// 串口5-UART5
//#define  DEBUG_USARTx UART5
//#define  DEBUG_USART_CLK RCC_APB1Periph_UART5
//#define  DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
//#define  DEBUG_USART_BAUDRATE 115200

 USART GPIO 引脚宏定义
//#define  DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD)
//#define  DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
// 
//#define  DEBUG_USART_TX_GPIO_PORT GPIOC   
//#define  DEBUG_USART_TX_GPIO_PIN GPIO_Pin_12
//#define  DEBUG_USART_RX_GPIO_PORT GPIOD
//#define  DEBUG_USART_RX_GPIO_PIN GPIO_Pin_2

//#define  DEBUG_USART_IRQ UART5_IRQn
//#define  DEBUG_USART_IRQHandler UART5_IRQHandler

/*********************************************************************
* API FUNCTIONS
*/
void USART_Config(void);
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch);
void Usart_SendString( USART_TypeDef * pUSARTx, char *str);
void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch);

#endif /* __USART_H */


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144

bsp_usart.c

/**===========================================================================
  @file bsp_usart.c
  @brief 本文件是用于usart驱动
  @author   青梅煮久
  @version  r0.1
  @date 2021/02/20
----------------------------------------------------------------------------
  Remark: (备注描述)
	串口1、3的驱动。
	串口1:用于日志打印、指令配置
	串口3:用于4G模块通讯
---------------------------------------------------------------------------- History
----------------------------------------------------------------------------
  <Date> | <Version> | <Author> | <Description>
-------------|-----------|----------------|---------------------------------
  2021/02/20 | r0.1 | 青梅煮久 | 创建
-------------|-----------|----------------|--------------------------------- | | |
-------------|-----------|----------------|--------------------------------- | | |
-------------|-----------|----------------|--------------------------------- | | |
============================================================================*/

/*********************************************************************
 * INCLUDES
 */
#include "bsp_usart.h"
#include "bsp_dma.h"
#include "stm32f10x.h"

static void NVIC_Configuration(void);

/*********************************************************************
 * PUBLIC FUNCTIONS
 */
/**
 @brief  USART GPIO 配置,工作参数配置
 @param  无
 @retval 无
*/
void USART_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;

	// 打开串口GPIO的时钟
	DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);
	LTE_USART_GPIO_APBxClkCmd(LTE_USART_GPIO_CLK, ENABLE); // 打开串口外设的时钟
	DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);
	LTE_USART_APBxClkCmd(LTE_USART_CLK, ENABLE);

	/*
	*  配置串口
	*  USART1_TX -> PA9 , USART1_RX ->	PA10
	*/	
	// 将USART Tx的GPIO配置为推挽复用模式
	GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);

	// 将USART Rx的GPIO配置为浮空输入模式
	GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure); USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_Parity = USART_Parity_No ;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_Init(DEBUG_USARTx, &USART_InitStructure); /*
	*  4G
	*  USART3_TX -> PB10 , USART3_RX ->	PB11
	*/ GPIO_InitStructure.GPIO_Pin = LTE_USART_TX_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
	GPIO_Init(LTE_USART_TX_GPIO_PORT, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = LTE_USART_RX_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(LTE_USART_RX_GPIO_PORT, &GPIO_InitStructure); USART_InitStructure.USART_BaudRate = 115200;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//8位数据
	USART_InitStructure.USART_StopBits = USART_StopBits_1;//1位停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;//无校验
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //硬件流控制失能
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //发送和接受使能
	USART_Init(LTE_USARTx, &USART_InitStructure); // 串口中断优先级配置
	NVIC_Configuration(); // 使能串口接收中断
	USART_ITConfig(DEBUG_USARTx, USART_IT_IDLE, ENABLE);	
	USART_ITConfig(LTE_USARTx, USART_IT_IDLE, ENABLE); // 使能串口
	USART_Cmd(DEBUG_USARTx, ENABLE); USART_Cmd(LTE_USARTx, ENABLE); USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);  //使能串口1的DMA发送  USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);  //使能串口1的DMA接收   USART_DMACmd(USART3,USART_DMAReq_Tx,ENABLE);  //使能串口1的DMA发送  USART_DMACmd(USART3,USART_DMAReq_Rx,ENABLE);  //使能串口1的DMA接收  

}

/**
 @brief 发送一个字节
 @param pUSARTx -[in] 串口
 @param ch -[in] 发送数据
 @retval 无
*/
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
{
	/* 发送一个字节数据到USART */
	USART_SendData(pUSARTx,ch); /* 等待发送数据寄存器为空 */
	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);	
}

/**
 @brief 发送8位的数组
 @param pUSARTx -[in] 串口
 @param array -[in] 发送数据
 @param num -[in] 发送长度
 @retval 无
*/
void Usart_SendArray( USART_TypeDef * pUSARTx, uint8_t *array, uint16_t num)
{
  uint8_t i; for(i=0; i<num; i++)
  { /* 发送一个字节数据到USART */ Usart_SendByte(pUSARTx,array[i]); }
	/* 等待发送完成 */
	while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET);
}

/**
 @brief 发送字符串
 @param pUSARTx -[in] 串口
 @param str -[in] 发送数据
 @retval 无
*/
void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
{
	unsigned int k=0;
  do { Usart_SendByte( pUSARTx, *(str + k) ); k++;
  } while(*(str + k)!='\0'); /* 等待发送完成 */
  while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET)
  {}
}

/**
 @brief 发送一个16位数
 @param pUSARTx -[in] 串口
 @param ch -[in] 发送数据
 @retval 无
*/
void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch)
{
	uint8_t temp_h, temp_l; /* 取出高八位 */
	temp_h = (ch&0XFF00)>>8;
	/* 取出低八位 */
	temp_l = ch&0XFF; /* 发送高八位 */
	USART_SendData(pUSARTx,temp_h);	
	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET); /* 发送低八位 */
	USART_SendData(pUSARTx,temp_l);	
	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);	
}

/**
 @brief 重定向c库函数printf到串口,重定向后可使用printf函数
*/
int fputc(int ch, FILE *f)
{
		/* 发送一个字节数据到串口 */
		USART_SendData(DEBUG_USARTx, (uint8_t) ch); /* 等待发送完毕 */
		while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET); return (ch);
}

/**
 @brief 重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
*/
int fgetc(FILE *f)
{
		/* 等待串口输入数据 */
		while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) == RESET); return (int)USART_ReceiveData(DEBUG_USARTx);
}

/**
 @brief USART1中断
 @param 无
 @retval 无
*/
void USART1_IRQHandler(void)  
{ uint16_t data; if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET) { DMA_Cmd(DMA1_Channel5, DISABLE); //关闭DMA,防止处理其间有数据   data = USART1->SR; data = USART1->DR; g_uart1ReceiveSize =RECEIVE_BUF_SIZE - DMA_GetCurrDataCounter(DMA1_Channel5); if(g_uart1ReceiveSize !=0) { // OSSemPost(DMAReceiveSize_Sem);   printf("shoudao1:%s", g_uart1ReceiveBuff); } DMA_ClearFlag(DMA1_FLAG_TC5 | DMA1_FLAG_TE5 | DMA1_FLAG_HT5);//清除DMA2_Steam7传输完成标志  DMA_SetCurrDataCounter(DMA1_Channel5, RECEIVE_BUF_SIZE); DMA_Cmd(DMA1_Channel5, ENABLE); //打开DMA,   }  
} 

/**
 @brief USART3中断
 @param 无
 @retval 无
*/ 
void USART3_IRQHandler(void)  
{ uint16_t data; if(USART_GetITStatus(USART3,USART_IT_IDLE) != RESET) { DMA_Cmd(DMA1_Channel3, DISABLE); //关闭DMA,防止处理其间有数据   data = USART3->SR; data = USART3->DR; g_uart3ReceiveSize =RECEIVE_BUF_SIZE - DMA_GetCurrDataCounter(DMA1_Channel3); if(g_uart3ReceiveSize !=0) { // OSSemPost(DMAReceiveSize_Sem);   printf("shoudao3:%s", g_uart3ReceiveBuff); } DMA_ClearFlag(DMA1_FLAG_TC3 | DMA1_FLAG_TE3 | DMA1_FLAG_HT3);//清除DMA2_Steam7传输完成标志  DMA_SetCurrDataCounter(DMA1_Channel3, RECEIVE_BUF_SIZE); DMA_Cmd(DMA1_Channel3, ENABLE); //打开DMA,   }  
}

/*********************************************************************
 * LOCAL FUNCTIONS
 */
/**
 @brief  配置嵌套向量中断控制器NVIC
 @param  无
 @retval 无
*/
static void NVIC_Configuration(void)
{
	NVIC_InitTypeDef NVIC_InitStructure; /* 嵌套向量中断控制器组选择 */
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); /* 4G NVIC设置*/
	/* 配置USART为中断源 */
	NVIC_InitStructure.NVIC_IRQChannel = LTE_USART_IRQ;
	/* 抢断优先级*/
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	/* 子优先级 */
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	/* 使能中断 */
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	/* 初始化配置NVIC */
	NVIC_Init(&NVIC_InitStructure); /* 配置串口的 NVIC设置*/
	NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	
}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316

bsp_dma.h

/**===========================================================================
  @file bsp_dma.h
  @brief 本文件是用于DMA驱动
  @author   青梅煮久
  @version  r0.1
  @date 2021/02/19
----------------------------------------------------------------------------
  Remark: (备注描述)
	串口1、3的接收。 DMA1各个通道请求映像
外设 通道1   通道2 通道3 通道4 通道5 通道6 通道7
USART   - 	 USART3_TX  USART3_RX  USART1_TX  USART1_RX  USART2_RX  USART2_TX
---------------------------------------------------------------------------- History
----------------------------------------------------------------------------
  <Date> | <Version> | <Author> | <Description>
-------------|-----------|----------------|---------------------------------
  2021/02/19 | r0.1 | 青梅煮久 | 创建
-------------|-----------|----------------|--------------------------------- | | |
-------------|-----------|----------------|--------------------------------- | | |
-------------|-----------|----------------|--------------------------------- | | |
============================================================================*/
#ifndef __DMA_H
#define	__DMA_H	

/*********************************************************************
 * INCLUDES
 */
#include "stm32f10x.h"

/*********************************************************************
 * DEFINITIONS
 */ #define  RECEIVE_BUF_SIZE 255
#define  SEND_BUF_SIZE 255

/*********************************************************************
 * GLOBAL VARIABLES
 */
extern uint8_t g_uart1ReceiveBuff[RECEIVE_BUF_SIZE]; //接收缓冲  
extern uint8_t g_uart1SendBuff[SEND_BUF_SIZE]; //发送数据缓冲区  
extern uint16_t g_uart1ReceiveSize; extern uint8_t  g_uart3ReceiveBuff[RECEIVE_BUF_SIZE]; //接收缓冲  
extern uint8_t  g_uart3SendBuff[SEND_BUF_SIZE]; //发送数据缓冲区  
extern uint16_t g_uart3ReceiveSize; /*********************************************************************
* API FUNCTIONS
*/
void DMA_Config(void);
void DmaSendDataProc(DMA_Channel_TypeDef *DMA_Streamx,uint16_t ndtr);
void Uart1DmaSendByte(uint8_t nSendInfo);
void Uart1DmaSendString(uint8_t* pSendInfo, uint16_t nSendCount);
void Uart3DmaSendByte(uint8_t nSendInfo);
void Uart3DmaSendString(uint8_t* pSendInfo, uint16_t nSendCount);

#endif /* __DMA_H */


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62

bsp_dma.c

/**===========================================================================
  @file bsp_dma.c
  @brief 本文件是用于DMA驱动
  @author   青梅煮久
  @version  r0.1
  @date 2021/02/19
----------------------------------------------------------------------------
  Remark: (备注描述)
	串口1、3的接收。 DMA1各个通道请求映像
外设 通道1   通道2 通道3 通道4 通道5 通道6 通道7
USART   - 	 USART3_TX  USART3_RX  USART1_TX  USART1_RX  USART2_RX  USART2_TX
---------------------------------------------------------------------------- History
----------------------------------------------------------------------------
  <Date> | <Version> | <Author> | <Description>
-------------|-----------|----------------|---------------------------------
  2021/02/19 | r0.1 | 青梅煮久 | 创建
-------------|-----------|----------------|--------------------------------- | | |
-------------|-----------|----------------|--------------------------------- | | |
-------------|-----------|----------------|--------------------------------- | | |
============================================================================*/

/*********************************************************************
 * INCLUDES
 */
#include "bsp_dma.h"
#include <stdio.h>

static void NVIC_Configuration(void);

/*********************************************************************
 * GLOBAL VARIABLES
 */
uint8_t  g_uart1ReceiveBuff[RECEIVE_BUF_SIZE];   //接收缓冲  
uint8_t  g_uart1SendBuff[SEND_BUF_SIZE]; //发送数据缓冲区  
uint16_t g_uart1ReceiveSize = 0; uint8_t  g_uart3ReceiveBuff[RECEIVE_BUF_SIZE];   //接收缓冲  
uint8_t  g_uart3SendBuff[SEND_BUF_SIZE]; //发送数据缓冲区  
uint16_t g_uart3ReceiveSize = 0; /*********************************************************************
 * LOCAL VARIABLES
 */

/*********************************************************************
 * PUBLIC FUNCTIONS
 */
/**
 @brief DMA配置
 @param 无
 @return 无
*/
void DMA_Config(void)
{
	DMA_InitTypeDef  DMA_InitStructure; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);	//使能DMA传输 /****************************配置UART1发送***********************/ DMA_DeInit(DMA1_Channel4); DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR;//DMA外设地址   DMA_InitStructure.DMA_MemoryBaseAddr = (u32)g_uart1SendBuff;//DMA 存储器0地址   DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//存储器到外设模式   DMA_InitStructure.DMA_BufferSize = SEND_BUF_SIZE;//数据传输量    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设非增量模式   DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器增量模式   DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设数据长度:8位   DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//存储器数据长度:8位   DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;// 使用普通模式    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//中等优先级   DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输 DMA_Init(DMA1_Channel4, &DMA_InitStructure);//初始化DMA Stream
	DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE); /****************************配置UART1接收***********************/ DMA_DeInit(DMA1_Channel5); DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR;//DMA外设地址   DMA_InitStructure.DMA_MemoryBaseAddr = (u32)g_uart1ReceiveBuff;//DMA 存储器0地址   DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC ;//外设到存储器模式   DMA_InitStructure.DMA_BufferSize = RECEIVE_BUF_SIZE;//数据传输量    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设非增量模式   DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器增量模式   DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设数据长度:8位   DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//存储器数据长度:8位   DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;// 使用普通模式    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//中等优先级   DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输 DMA_Init(DMA1_Channel5, &DMA_InitStructure);//初始化DMA Stream   /****************************配置UART3发送***********************/ DMA_DeInit(DMA1_Channel2); DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART3->DR;//DMA外设地址   DMA_InitStructure.DMA_MemoryBaseAddr = (u32)g_uart3SendBuff;//DMA 存储器0地址   DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//存储器到外设模式   DMA_InitStructure.DMA_BufferSize = SEND_BUF_SIZE;//数据传输量    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设非增量模式   DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器增量模式   DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设数据长度:8位   DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//存储器数据长度:8位   DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;// 使用普通模式    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//中等优先级   DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输 DMA_Init(DMA1_Channel2, &DMA_InitStructure);//初始化DMA Stream
	DMA_ITConfig(DMA1_Channel2,DMA_IT_TC,ENABLE); /****************************配置UART3接收***********************/ DMA_DeInit(DMA1_Channel3); DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART3->DR;//DMA外设地址   DMA_InitStructure.DMA_MemoryBaseAddr = (u32)g_uart3ReceiveBuff;//DMA 存储器0地址   DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC ;//外设到存储器模式   DMA_InitStructure.DMA_BufferSize = RECEIVE_BUF_SIZE;//数据传输量    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设非增量模式   DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器增量模式   DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设数据长度:8位   DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//存储器数据长度:8位   DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;// 使用普通模式    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//中等优先级   DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输 DMA_Init(DMA1_Channel3, &DMA_InitStructure);//初始化DMA Stream   /****************************配置NVIC***********************/
	NVIC_Configuration();
	/**********************2个串口接收使能DMA*******************/
	DMA_Cmd(DMA1_Channel5, ENABLE);  //开启DMA传输
	DMA_Cmd(DMA1_Channel3, ENABLE);  //开启DMA传输 DMA_ITConfig(DMA1_Channel5,DMA_IT_TC,ENABLE); DMA_ITConfig(DMA1_Channel3,DMA_IT_TC,ENABLE);  
}

/**
 @brief 开启一次DMA传输 
 @param DMA_Streamx -[in] DMA数据流,通道
 @param ndtr -[in] 数据传输量
 @return 无
*/  
void DmaSendDataProc(DMA_Channel_TypeDef *DMA_Streamx,uint16_t ndtr)  
{ DMA_Cmd(DMA_Streamx, DISABLE); //关闭DMA传输    DMA_SetCurrDataCounter(DMA_Streamx,ndtr); //数据传输量  DMA_Cmd(DMA_Streamx, ENABLE); //开启DMA传输   
}

/**
 @brief 串口1使用DMA发送单字节
 @param nSendInfo -[in] 发送数据
 @return 无
*/ 
void Uart1DmaSendByte(uint8_t nSendInfo)  
{ uint8_t *pBuf = NULL; //指向发送缓冲区 pBuf = g_uart1SendBuff; *pBuf++ = nSendInfo; DmaSendDataProc(DMA1_Channel4, 1); //开始一次DMA传输! 
} 

/**
 @brief 串口1使用DMA发送多字节
 @param nSendInfo -[in] 发送数据
 @param nSendCount -[in] 发送长度
 @return 无
*/ 
void Uart1DmaSendString(uint8_t* pSendInfo, uint16_t nSendCount)  
{ uint16_t i = 0; uint8_t *pBuf = NULL; //指向发送缓冲区   pBuf = g_uart1SendBuff; for (i=0; i<nSendCount; i++) { *pBuf++ = pSendInfo[i]; } //DMA发送方式   DmaSendDataProc(DMA1_Channel4, nSendCount); //开始一次DMA传输! 
} /**
 @brief 串口3使用DMA发送单字节
 @param nSendInfo -[in] 发送数据
 @return 无
*/ 
void Uart3DmaSendByte(uint8_t nSendInfo)  
{ uint8_t *pBuf = NULL; //指向发送缓冲区 pBuf = g_uart3SendBuff; *pBuf++ = nSendInfo; DmaSendDataProc(DMA1_Channel2, 1); //开始一次DMA传输! 
} 

/**
 @brief 串口3使用DMA发送多字节
 @param nSendInfo -[in] 发送数据
 @param nSendCount -[in] 发送长度
 @return 无
*/ 
void Uart3DmaSendString(uint8_t* pSendInfo, uint16_t nSendCount)  
{ uint16_t i = 0; uint8_t *pBuf = NULL; //指向发送缓冲区   pBuf = g_uart3SendBuff; for (i=0; i<nSendCount; i++) { *pBuf++ = pSendInfo[i]; } //DMA发送方式   DmaSendDataProc(DMA1_Channel2, nSendCount); //开始一次DMA传输! 
}

/**
 @brief 串口1使用DMA发送完成中断
 @param 无
 @return 无
*/
void DMA1_Channel4_IRQHandler(void)  
{ //清除标志   if(DMA_GetFlagStatus(DMA1_FLAG_TC4)!=RESET)//等待传输完成   { DMA_ClearFlag(DMA1_FLAG_TC4);//清除传输完成标志   }  
} 

/**
 @brief 串口1使用DMA接完成中断
 @param 无
 @return 无
*/ 
void DMA1_Channel5_IRQHandler(void)  
{ //清除标志   if(DMA_GetFlagStatus(DMA1_FLAG_TC5)!=RESET)//等待传输完成   { DMA_Cmd(DMA1_Channel5, DISABLE); //关闭DMA,防止处理其间有数据   g_uart1ReceiveSize =RECEIVE_BUF_SIZE - DMA_GetCurrDataCounter(DMA1_Channel5); if(g_uart1ReceiveSize !=0) { // 此处不处理数据,uart处理 } DMA_ClearFlag(DMA1_FLAG_TC5 | DMA1_FLAG_TE5 | DMA1_FLAG_HT5);//清除DMA2_Steam7传输完成标志   DMA_SetCurrDataCounter(DMA1_Channel5, RECEIVE_BUF_SIZE); DMA_Cmd(DMA1_Channel5, ENABLE); //打开DMA,   }  
} /**
 @brief 串口3使用DMA发送完成中断
 @param 无
 @return 无
*/
void DMA1_Channel2_IRQHandler(void)  
{ //清除标志   if(DMA_GetFlagStatus(DMA1_FLAG_TC2)!=RESET)//等待传输完成   { DMA_ClearFlag(DMA1_FLAG_TC2);//清除传输完成标志   }  
} 

/**
 @brief 串口3使用DMA接完成中断
 @param 无
 @return 无
*/ 
void DMA1_Channel3_IRQHandler(void)  
{ //清除标志   if(DMA_GetFlagStatus(DMA1_FLAG_TC3)!=RESET)//等待传输完成   { DMA_Cmd(DMA1_Channel3, DISABLE); //关闭DMA,防止处理其间有数据   g_uart3ReceiveSize =RECEIVE_BUF_SIZE - DMA_GetCurrDataCounter(DMA1_Channel3); if(g_uart3ReceiveSize !=0) { // 此处不处理数据,uart处理 } DMA_ClearFlag(DMA1_FLAG_TC3 | DMA1_FLAG_TE3 | DMA1_FLAG_HT3);//清除DMA2_Steam7传输完成标志   DMA_SetCurrDataCounter(DMA1_Channel3, RECEIVE_BUF_SIZE); DMA_Cmd(DMA1_Channel3, ENABLE); //打开DMA,   }  
} 

/*********************************************************************
 * LOCAL FUNCTIONS
 */
/**
 @brief 配置嵌套向量中断控制器NVIC
 @param 无
 @return 无
*/
static void NVIC_Configuration(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;

	/* 嵌套向量中断控制器组选择 */
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); // 配置UART1发送  
	NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); // 配置UART1接收  NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel5_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); // 配置UART3发送  
	NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); // 配置UART3接收  NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel3_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 4; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); }


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347

main.c

int main()
{
	...
	USART_Config();
	DMA_Config();
	...
}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

• 由 青梅煮久 写于 2021 年 02 月 20 日

文章来源: blog.csdn.net,作者:青梅煮久,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/qq_34118600/article/details/112850800

(完)