基于STM32_HAL库的DMA应用

article/2025/6/29 20:26:27

基于STM32_HAL库的DMA应用

文章目录

  • 基于STM32_HAL库的DMA应用
    • 一、DMA介绍
      • 1.1 DMA的核心作用
      • 1.2 DMA数据传输方向
        • 1. 外设到内存(Peripheral-to-Memory)
        • 2. 内存到外设(Memory-to-Peripheral)
        • 3. 内存到内存(Memory-to-Memory)
      • 1.3 DMA数据传输方式
        • 1. 正常模式(Normal Mode)
        • 2. 循环模式(Circular Mode)
      • 1.4 DMA控制器通道
      • 1.5 DMA控制器的优先级
        • 1. 优先级分类
        • 2. 优先级仲裁规则
    • 二、DMA控制器相关API函数
      • 2.1 初始化指定的 DMA 通道函数HAL_DMA_Init()原型及功能
      • 2.2 停止|重置DMA通道函数HAL_DMA_DeInit()原型及功能
      • 2.3 启动 DMA 传输(非中断方式)函数HAL_DMA_Start()原型及功能
      • 2.4 启动 DMA 并启用中断函数HAL_DMA_Start_IT()原型及功能
      • 2.5 立即中止正在进行的 DMA 传输函数HAL_DMA_Abort()原型及功能
      • 2.6 以中断方式中止 DMA函数HAL_DMA_Abort_IT()原型及功能
      • 2.7 阻塞式等待 DMA 传输完成函数HAL_DMA_PollForTransfer()原型及功能
      • 2.8 判断 DMA 中断标志是否被置位宏函数__HAL_DMA_GET_FLAG()原型及功能
      • 2.9 DMA方式串口发送数据函数HAL_UART_Transmit_DMA()原型及功能
      • 2.10 DMA方式串口接收数据函数HAL_UART_Receive_DMA()原型及功能
      • 2.11 启用某个 UART 中断功能函数__HAL_UART_ENABLE_IT()原型及功能
      • 2.12 检查指定的 UART 状态标志位是否被置位函数__HAL_UART_GET_FLAG()原型及功能
      • 2.13 清除 UART 的 IDLE(空闲)标志位函数__HAL_UART_CLEAR_IDLEFLAG()原型及功能
      • 2.14 停止通过 DMA 进行的 UART 发送或接收操作函数HAL_UART_DMAStop()原型及功能
      • 2.15 获取当前 DMA 传输还剩下多少个数据单位尚未完成函数__HAL_DMA_GET_COUNTER()原型及功能
    • 三、内存👉内存搬运
      • 3.1 CubeMX配置
      • 3.2 代码实现
    • 四、内存👉外设搬运
      • 4.1 CubeMX配置
      • 4.2 代码实现
    • 五、外设👉内存搬运
      • 5.1 CubeMX配置
      • 5.2 代码实现

一、DMA介绍

STM32 的 DMA(Direct Memory Access,直接存储器访问)是一种硬件模块,用于在 外设(如ADC、USART、SPI、I2C等)与 内存(RAM) 之间,或在 内存与内存之间,实现 无需CPU干预 的数据传输。

1.1 DMA的核心作用

不通过CPU,自动搬运数据,减少CPU负担,提高效率。例如:

  • 从ADC采集数据直接写入内存
  • 接收串口数据后直接存入缓冲区
  • 内存中大块数据搬运

1.2 DMA数据传输方向

在STM32F103C8T6的DMA控制器中,三种数据传输方向决定了数据流动的路径,是DMA配置的核心要素之一。以下是清晰的分类和说明:

1. 外设到内存(Peripheral-to-Memory)

特点

  • 数据源:外设寄存器(如ADC、USART的DR寄存器)。
  • 数据目标:内存(如数组、变量)。
  • 典型应用
    • ADC采集数据存入内存数组。
    • 串口接收数据到缓冲区。

2. 内存到外设(Memory-to-Peripheral)

特点

  • 数据源:内存(如待发送的数据数组)。
  • 数据目标:外设寄存器(如SPI/I2C的数据寄存器)。
  • 典型应用
    • 通过USART发送字符串。
    • SPI驱动显示屏批量写入数据。

3. 内存到内存(Memory-to-Memory)

特点

  • 数据源和目标:均为内存地址(如数组间复制)。
  • 仅DMA1支持:需手动触发,无硬件外设请求。
  • 典型应用
    • 快速初始化大块内存(如清零RAM)。
    • 数据备份或格式转换。

1.3 DMA数据传输方式

在STM32F103C8T6的DMA控制器中,数据搬运模式主要分为两种核心模式,它们决定了DMA传输的连续性和工作方式。以下是详细的介绍:

1. 正常模式(Normal Mode)

特点

  • 单次触发,单次传输
    每次使能DMA后,仅完成一次设定的数据传输(DMA_BufferSize),之后自动关闭DMA通道。
  • 需手动重启
    传输完成后需重新配置并启动DMA(或由外设再次触发),适合非连续数据场景。
  • 中断标志
    传输完成会置位TC(Transfer Complete)标志,可触发中断。

典型应用

  • 单次ADC采样数据搬运。
  • 非周期性的串口数据发送(如按键触发发送)。

2. 循环模式(Circular Mode)

特点

  • 自动循环,无需干预
    传输完成后自动重置地址和计数器,无限循环传输数据,形成闭环。
  • 双缓冲技巧
    结合传输完成(TC)和半传输完成(HT)中断,可实现双缓冲(Ping-Pong Buffer),提升实时性。
  • 外设持续触发
    适合外设连续产生数据(如ADC连续采样、串口接收数据流)。

典型应用

  • 实时音频信号采集(ADC+DMA循环模式)。
  • 高速传感器数据流(如陀螺仪SPI通信)。
  • 串口接收不定长数据(配合IDLE中断)。

1.4 DMA控制器通道

STM32F103 有 2 个 DMA 控制器DMA1 有 7 个通道,DMA 2 有 5 个通道一个通道每次只能搬运一个外设的数据!! 如果同时有多个外设的 DMA 请求,则按照优先级进行响应。STM32F103C8T6 只有 DMA1

  • DMA1有7个通道

    在这里插入图片描述

  • DMA2有5个通道

    在这里插入图片描述


1.5 DMA控制器的优先级

在STM32F103系列单片机中,DMA控制器的优先级管理是一个关键功能,它决定了当多个DMA请求同时发生时,哪个请求会被优先处理。以下是关于DMA优先级的详细介绍:

1. 优先级分类

STM32F103的DMA控制器支持两种优先级管理机制

(1) 软件可编程优先级

每个DMA通道可以独立配置以下4个优先级等级(通过DMA_InitStruct.DMA_Priority设置):

  • 最高优先级(DMA_Priority_VeryHigh)
  • 高优先级(DMA_Priority_High)
  • 中优先级(DMA_Priority_Medium)
  • 低优先级(DMA_Priority_Low)

(2) 硬件固定优先级(自然优先级)

当多个通道的软件优先级相同时,硬件根据通道编号自动仲裁:

  • 通道编号越小,优先级越高(通道1 > 通道2 > … > 通道7)。

2. 优先级仲裁规则
  1. 软件优先级优先
    不同优先级的请求中,更高软件优先级的通道总是先被处理。
    例如:通道3(高优先级)会抢占通道1(低优先级),即使通道1编号更小。
  2. 硬件优先级补充
    若多个通道的软件优先级相同,则按通道编号决定顺序。
    例如:通道2和通道4均为中优先级时,通道2优先。
  3. 传输中的抢占
    • 低优先级传输可被高优先级请求打断(当前传输完成后切换)。
    • 同优先级请求需等待当前传输完成。

二、DMA控制器相关API函数

2.1 初始化指定的 DMA 通道函数HAL_DMA_Init()原型及功能

📌 函数原型:

HAL_StatusTypeDef HAL_DMA_Init(DMA_HandleTypeDef *hdma);

✅ 参数:

参数类型说明
hdmaDMA_HandleTypeDef *指向 DMA 通道句柄的指针,包含初始化结构体配置

🔁 返回值:

  • HAL_OK: 成功
  • HAL_ERROR: 错误(通常为参数错误)
  • HAL_BUSY: 控制器忙

🎯 功能:

初始化指定的 DMA 通道,并配置:

  • 数据方向
  • 数据宽度
  • 地址增量
  • 优先级
  • 模式(普通、循环)

2.2 停止|重置DMA通道函数HAL_DMA_DeInit()原型及功能

📌 函数原型:

HAL_StatusTypeDef HAL_DMA_DeInit(DMA_HandleTypeDef *hdma);

✅ 参数:

参数类型说明
hdmaDMA_HandleTypeDef *指定要释放的 DMA 通道句柄

🔁 返回值:

  • HAL_OK: 成功
  • HAL_ERROR: 错误(通常为参数错误)
  • HAL_BUSY: 控制器忙

🎯 功能:

  • 停止 DMA 通道
  • 重置为默认状态
  • 清除中断标志

2.3 启动 DMA 传输(非中断方式)函数HAL_DMA_Start()原型及功能

📌 函数原型:

HAL_StatusTypeDef HAL_DMA_Start(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength);

✅ 参数:

参数含义
hdmaDMA 通道句柄
SrcAddress源地址
DstAddress目的地址
DataLength数据项数量(以数据宽度计)

🔁 返回值:

  • HAL_OK: 成功
  • HAL_ERROR: 错误(通常为参数错误)
  • HAL_BUSY: 控制器忙

🎯 功能:

  • 启动 DMA 传输(非中断方式)
  • 手动启动一次传输

2.4 启动 DMA 并启用中断函数HAL_DMA_Start_IT()原型及功能

📌 函数原型:

HAL_StatusTypeDef HAL_DMA_Start_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength);

✅ 参数:

参数含义
hdmaDMA 通道句柄
SrcAddress源地址
DstAddress目的地址
DataLength数据项数量(以数据宽度计)

🔁 返回值:

  • HAL_OK: 成功
  • HAL_ERROR: 错误(通常为参数错误)
  • HAL_BUSY: 控制器忙

🎯 功能:

  • 启动 DMA 并启用中断
  • 完成时调用中断回调(非阻塞)

2.5 立即中止正在进行的 DMA 传输函数HAL_DMA_Abort()原型及功能

📌 函数原型:

HAL_StatusTypeDef HAL_DMA_Abort(DMA_HandleTypeDef *hdma);

✅ 参数:

参数类型说明
hdmaDMA_HandleTypeDef *指定要中止的 DMA 通道句柄

🔁 返回值:

  • HAL_OK: 成功中止
  • HAL_ERROR: 中止失败

🎯 功能:

  • 立即中止正在进行的 DMA 传输
  • 清除使能位

2.6 以中断方式中止 DMA函数HAL_DMA_Abort_IT()原型及功能

📌 函数原型:

HAL_StatusTypeDef HAL_DMA_Abort_IT(DMA_HandleTypeDef *hdma);

✅ 参数:

参数类型说明
hdmaDMA_HandleTypeDef *指定要中止的 DMA 通道句柄

🔁 返回值:

  • HAL_OK: 成功中止
  • HAL_ERROR: 中止失败

🎯 功能:

  • 以中断方式中止 DMA
  • 中止后触发 HAL_DMA_AbortCpltCallback

2.7 阻塞式等待 DMA 传输完成函数HAL_DMA_PollForTransfer()原型及功能

📌 函数原型:

HAL_StatusTypeDef HAL_DMA_PollForTransfer(DMA_HandleTypeDef *hdma, HAL_DMA_LevelTypeDef CompleteLevel, uint32_t Timeout);

✅ 参数:

参数含义
hdmaDMA 句柄
CompleteLevelHAL_DMA_FULL_TRANSFERHAL_DMA_HALF_TRANSFER
Timeout等待超时(ms)

🔁 返回值:

  • HAL_OK, HAL_TIMEOUT

🎯 功能:

  • 阻塞式等待 DMA 传输完成
  • 适合不使用中断场景

2.8 判断 DMA 中断标志是否被置位宏函数__HAL_DMA_GET_FLAG()原型及功能

✅ 1. 宏原型:

#define __HAL_DMA_GET_FLAG(__HANDLE__, __FLAG__)  (((__HANDLE__)->Instance->ISR & (__FLAG__)) != 0U)

💡 这是一个 宏定义(不是函数),用于读取 DMA 状态寄存器中的某个标志位是否被置位

✅ 2. 参数说明:

参数类型说明
__HANDLE__DMA_HandleTypeDef *指向 DMA 通道的句柄(通常是 &hdma_xxx
__FLAG__uint32_t要检查的标志位宏定义(如下表)

常见标志位如下(适用于 DMA1 的各个通道):

宏定义含义
DMA_FLAG_TCx通道 x 的传输完成标志(Transfer Complete)
DMA_FLAG_HTx通道 x 的半传输完成标志(Half Transfer)
DMA_FLAG_TEx通道 x 的传输错误标志(Transfer Error)
DMA_FLAG_GIx通道 x 的全局中断标志(全局中断 = TC + HT + TE) 例如 DMA_FLAG_TC1DMA_FLAG_HT3DMA_FLAG_TE2

💡 其中 x 是通道号(17,F1 系列为 DMA1_Channel17)

🔁 3. 返回值:

返回类型说明
uint32_t(0 或 1)如果指定标志位被置位 → 返回 1,否则返回 0

🎯 4. 功能说明:

  • 用于判断 DMA 中断标志是否被置位。
  • 可在中断服务函数或轮询中使用。
  • 一般配合 __HAL_DMA_CLEAR_FLAG() 使用来手动清除中断标志位(如果 HAL 没有自动清除)。

🧪 示例用法:

if (__HAL_DMA_GET_FLAG(&hdma_memtomem_dma1_channel1, DMA_FLAG_TC1))
{// 通道1的传输完成__HAL_DMA_CLEAR_FLAG(&hdma_memtomem_dma1_channel1, DMA_FLAG_TC1);// 执行接下来的操作...
}

2.9 DMA方式串口发送数据函数HAL_UART_Transmit_DMA()原型及功能

📌 1. 函数原型:

HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

✅ 2. 参数说明:

参数名类型说明
huartUART_HandleTypeDef *指向 UART 句柄的指针(例如:&huart1
pDatauint8_t *指向要发送的数据缓冲区
Sizeuint16_t要发送的数据长度(单位:字节)

🔁 3. 返回值:

返回值含义
HAL_OK操作成功
HAL_BUSYUART 当前正在忙于另一项传输
HAL_ERROR参数错误或初始化失败
HAL_TIMEOUT(不适用于本函数,一般不会返回)

🎯 4. 功能说明:

  • 启动一个 UART 数据发送过程,由 DMA 自动完成传输。
  • 使用 DMA 可以大幅减轻 CPU 负担,适用于高速或大批量数据发送。
  • 在传输完成后,HAL 会调用回调函数 HAL_UART_TxCpltCallback()(需要用户自己实现)。
  • 非阻塞方式,函数调用后立即返回,不等待传输完成。

🧪 5. 使用示例:

示例 1:简单发送字符串

uint8_t message[] = "Hello DMA UART!\r\n";HAL_UART_Transmit_DMA(&huart1, message, sizeof(message) - 1);

💡 提示:

  • 如果串口未配置 DMA,函数会失败。
  • 如果正在发送其他数据,函数会返回 HAL_BUSY

🔁 6. 配合中断回调使用(推荐):

你可以定义 HAL_UART_TxCpltCallback() 来处理传输完成后的任务:

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{if (huart->Instance == USART1){// 发送完成,执行后续动作HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);  // 比如闪灯提示}
}

2.10 DMA方式串口接收数据函数HAL_UART_Receive_DMA()原型及功能

📌 1. 函数原型:

HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

✅ 2. 参数说明:

参数名类型说明
huartUART_HandleTypeDef *指向 UART 外设的句柄(例如 &huart1
pDatauint8_t *接收数据的缓冲区指针(DMA 将接收到的数据放入此内存)
Sizeuint16_t要接收的数据长度(单位:字节)

🔁 3. 返回值:

返回值说明
HAL_OK操作成功
HAL_BUSYUART 当前正忙于接收其他数据
HAL_ERROR初始化或参数错误

🎯 4. 功能说明:

  • 启动一次 DMA 接收过程,UART 接收到的数据会被 DMA 自动搬运到内存缓冲区
  • 非阻塞方式,即函数调用后立即返回,不会等待数据接收完成。
  • 接收完成时,会自动调用回调函数 HAL_UART_RxCpltCallback()(需要用户实现)。
  • 可以实现大容量或高速串口数据的接收,CPU 开销小。

🧪 5. 使用示例:

示例 1:接收 10 字节数据

uint8_t rxBuffer[10];HAL_UART_Receive_DMA(&huart1, rxBuffer, 10);

💡 提示:接收完成后会触发中断,调用 HAL_UART_RxCpltCallback()

示例 2:实现回调函数

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if (huart->Instance == USART1){// 数据接收完成后的处理逻辑,例如处理 rxBuffer 中的数据process_received_data(rxBuffer);}
}

2.11 启用某个 UART 中断功能函数__HAL_UART_ENABLE_IT()原型及功能

📌 1. 宏原型:

#define __HAL_UART_ENABLE_IT(__HANDLE__, __INTERRUPT__) ((__HANDLE__)->Instance->CR1 |= (__INTERRUPT__))

⚠️ 注意:这是一个宏定义,不是普通函数。

✅ 2. 参数说明:

参数名类型说明
__HANDLE__UART_HandleTypeDef *UART 句柄指针(如 &huart1
__INTERRUPT__uint32_t要启用的中断类型宏(见下表)

常用的 UART 中断类型:

宏定义说明
UART_IT_TXE发送数据寄存器为空中断(Transmit Data Register Empty)
UART_IT_TC发送完成中断(Transmission Complete)
UART_IT_RXNE接收寄存器非空中断(Received Data Ready to Be Read)
UART_IT_IDLE空闲线路中断(Idle Line Detected)
UART_IT_ERR错误中断(帧错误、过载、噪声等)

🎯 3. 功能说明:

  • 宏通过设置 UART 的控制寄存器来启用某个 UART 中断功能
  • 启用中断后,若对应条件发生(如接收到数据),则会触发 UART 的中断服务函数 USARTx_IRQHandler()
  • 中断处理程序中会进一步调用 HAL 的中断处理函数,例如 HAL_UART_IRQHandler()
  • 宏本身不会启用 NVIC 中的中断通道(需单独调用 HAL_NVIC_EnableIRQ())。

🧪 4. 示例代码:

示例:启用 UART1 的接收中断(RXNE)和空闲中断(IDLE)

// 启用 RXNE 和 IDLE 中断
__HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);// 同时,确保在 NVIC 中打开了中断通道(通常在初始化时)
HAL_NVIC_EnableIRQ(USART1_IRQn);

示例:中断服务函数中调用 HAL 的统一中断处理

void USART1_IRQHandler(void)
{HAL_UART_IRQHandler(&huart1);  // HAL 会自动处理 RXNE、IDLE、TC 等事件
}

2.12 检查指定的 UART 状态标志位是否被置位函数__HAL_UART_GET_FLAG()原型及功能

📌 1. 宏原型:

#define __HAL_UART_GET_FLAG(__HANDLE__, __FLAG__) (((__HANDLE__)->Instance->SR & (__FLAG__)) == (__FLAG__))

📘 说明:这是一个宏定义,用于读取 UART 状态寄存器(SR)中的特定位。

✅ 2. 参数说明:

参数名类型说明
__HANDLE__UART_HandleTypeDef *指向 UART 外设句柄的指针(如 &huart1
__FLAG__uint32_t需要检查的标志位(如 UART_FLAG_RXNE

常用 UART 标志位(可作为 __FLAG__ 传入):

宏定义含义
UART_FLAG_TXE发送数据寄存器为空
UART_FLAG_TC发送完成
UART_FLAG_RXNE接收寄存器非空,有数据可读
UART_FLAG_IDLE空闲线路检测标志
UART_FLAG_ORE溢出错误
UART_FLAG_NE噪声错误
UART_FLAG_FE帧格式错误
UART_FLAG_PE奇偶校验错误

🔎 这些标志来源于 UART 的状态寄存器 SR(Status Register)。

🔁 3. 返回值:

返回值类型含义
true (非零)uint32_t标志位置位,表示事件已发生
false (0)uint32_t标志位未被置位,事件未发生

🎯 4. 功能说明:

  • 检查指定的 UART 状态标志位是否被置位
  • 本质是对 UART 的 SR(Status Register)寄存器执行按位与判断。
  • 可用于判断是否发生了某些事件,例如:
    • 是否接收到数据?
    • 是否发送完成?
    • 是否出现错误?

🧪 5. 示例代码:

示例 1:判断是否收到数据

if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE))
{uint8_t data = (uint8_t)(huart1.Instance->DR);  // 读取接收数据
}

示例 2:判断 UART1 是否发送完成

if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TC))
{// 数据已完全发送完毕HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
}

2.13 清除 UART 的 IDLE(空闲)标志位函数__HAL_UART_CLEAR_IDLEFLAG()原型及功能

📌 1. 宏原型:

#define __HAL_UART_CLEAR_IDLEFLAG(__HANDLE__)  \do { __IO uint32_t tmpreg; tmpreg = (__HANDLE__)->Instance->SR; \tmpreg = (__HANDLE__)->Instance->DR; UNUSED(tmpreg); } while(0)

📌 说明:这是一个宏,用于清除 UART 的 IDLE(空闲)标志位。

✅ 2. 参数说明:

参数名类型说明
__HANDLE__UART_HandleTypeDef *UART 外设句柄指针(如 &huart1

🎯 3. 功能说明:

  • UART 接收到数据后,如果检测到 一段时间内 RX 引脚没有继续接收数据,会设置 IDLE(空闲)标志位
  • 当启用了 UART_IT_IDLE 中断后,接收到 IDLE 中断后必须手动清除 IDLE 标志,否则该中断会不断触发。
  • 清除 IDLE 标志的方式是:
    • 先读取 UART 的状态寄存器 SR
    • 再读取 数据寄存器 DR
  • 这个宏就是封装了这一操作。

🧪 4. 示例代码:

示例:使用 DMA + 空闲中断接收串口变长数据帧

void USART1_IRQHandler(void)
{HAL_UART_IRQHandler(&huart1);  // HAL 处理其他 UART 中断// 手动处理 IDLE 中断(需要先启用 UART_IT_IDLE 中断)if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE)){__HAL_UART_CLEAR_IDLEFLAG(&huart1);  // 清除 IDLE 标志位// 此处可调用用户的帧处理逻辑,比如判断实际接收长度uint16_t len = BUFFER_SIZE - __HAL_DMA_GET_COUNTER(huart1.hdmarx);handle_uart_frame(rxBuffer, len);}
}

__HAL_DMA_GET_COUNTER() 返回 DMA 剩余传输字节数,配合可得出实际接收长度。


2.14 停止通过 DMA 进行的 UART 发送或接收操作函数HAL_UART_DMAStop()原型及功能

📌 1. 函数原型:

HAL_StatusTypeDef HAL_UART_DMAStop(UART_HandleTypeDef *huart);

✅ 2. 参数说明:

参数名类型说明
huartUART_HandleTypeDef *指向 UART 外设句柄的指针,例如 &huart1

🔁 3. 返回值:

返回值枚举含义
HAL_OK操作成功
HAL_ERROR发生错误
HAL_BUSY外设正在忙
HAL_TIMEOUT操作超时(通常不会在此函数中返回)

🎯 4. 功能说明:

HAL_UART_DMAStop() 的主要功能是:

  • 停止通过 DMA 进行的 UART 发送或接收操作(无论是 TX 还是 RX)。
  • 禁用 DMA 请求
    • 清除 UART 控制寄存器中的 DMATDMAR 位(关闭发送/接收 DMA 请求)。
  • 停止 DMA 通道
    • 停止 huart->hdmarxhuart->hdmatx 中的 DMA 操作。
  • 释放资源,为下一次操作做准备。

🧪 5. 示例代码:

示例:接收到一帧变长数据后停止 DMA 接收

#define RX_BUF_LEN 64
uint8_t rx_buf[RX_BUF_LEN];void USART1_IRQHandler(void)
{HAL_UART_IRQHandler(&huart1);if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE)){__HAL_UART_CLEAR_IDLEFLAG(&huart1);  // 清除空闲标志HAL_UART_DMAStop(&huart1);  // ✅ 停止 DMA 接收// 获取实际接收长度uint16_t recv_len = RX_BUF_LEN - __HAL_DMA_GET_COUNTER(huart1.hdmarx);process_uart_frame(rx_buf, recv_len);  // 处理接收到的数据// 重新启动 DMA 接收HAL_UART_Receive_DMA(&huart1, rx_buf, RX_BUF_LEN);}
}

2.15 获取当前 DMA 传输还剩下多少个数据单位尚未完成函数__HAL_DMA_GET_COUNTER()原型及功能

📌 1. 宏原型:

#define __HAL_DMA_GET_COUNTER(__HANDLE__) ((__HANDLE__)->Instance->CNDTR)

📌 它实际上是读取 DMA 控制器的当前剩余传输数量寄存器(CNDTR)

✅ 2. 参数说明:

参数名类型说明
__HANDLE__DMA_HandleTypeDef *指向 DMA 通道的句柄,比如 huart1.hdmarx

🔁 3. 返回值:

类型说明
uint16_t返回 DMA 通道尚未完成传输的字节数(即 CNDTR 的当前值)

🎯 4. 功能说明:

  • DMA 在传输过程中,CNDTR 寄存器会不断减少,表示还有多少数据尚未传输。
  • __HAL_DMA_GET_COUNTER() 宏返回的是DMA 剩余数据量,因此你可以据此计算出:
    • 实际已经接收到(或发送出)的数据字节数。
  • 这个宏非常适合用于 DMA + 空闲中断 模式下判断已接收的数据长度。

🧪 5. 示例代码:

示例:计算 DMA 实际接收的数据长度

#define RX_BUF_LEN 64
uint8_t rx_buf[RX_BUF_LEN];void USART1_IRQHandler(void)
{HAL_UART_IRQHandler(&huart1);if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE)){__HAL_UART_CLEAR_IDLEFLAG(&huart1);HAL_UART_DMAStop(&huart1);// ❗ 计算接收的数据长度uint16_t received_len = RX_BUF_LEN - __HAL_DMA_GET_COUNTER(huart1.hdmarx);process_uart_data(rx_buf, received_len);// 重新启动 DMA 接收HAL_UART_Receive_DMA(&huart1, rx_buf, RX_BUF_LEN);}
}

三、内存👉内存搬运

实现需求:使用DMA的方式将数组A中的数据拷贝到数组B中,搬运完之后将数组B中的内容打印到屏幕

3.1 CubeMX配置

  1. 配置Debug

    在这里插入图片描述

  2. 打开RCC配置时钟,将高速时钟配置成Crystal/Ceramic Resonator

    在这里插入图片描述

  3. 点击配置时钟选项,把时钟配置成高速外部时钟HSE,并且通过PLLCLK倍频到72MHZ按下回车之后就为芯片内部的功能分配好了对应的时钟频率。

    在这里插入图片描述

  4. 打开左侧的DMA选项,首先选择:内存到内存,然后点击Add添加一个,接着配置通道、方向和优先级,然后配置DMA数据传输方式为:正常模式,然后配置指针递增模式为:源地址 和 目标地址 同时递增。

    在这里插入图片描述

  5. 接着我们打开USART1,配置为:异步通信模式,配置:波特率、数据位、停止位、奇偶校验位

    在这里插入图片描述

  6. 接着对我们的工程进行配置,配置完成之后点击右上角的 GENERATE CODE 生成工程

    在这里插入图片描述


3.2 代码实现

#include "main.h"
#include "dma.h"
#include "usart.h"
#include "gpio.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
/* USER CODE END Includes *//* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
#define BUF_SIZE 16
/* USER CODE END PM *//* Private variables ---------------------------------------------------------*//* USER CODE BEGIN PV */
uint32_t srcBuffer[BUF_SIZE] = {	// 源数组0x00000000, 0x11111111, 0x22222222, 0x33333333,0x44444444, 0x55555555, 0x66666666, 0x77777777, 0x88888888, 0x99999999, 0xAAAAAAAA, 0xBBBBBBBB, 0xCCCCCCCC, 0xDDDDDDDD, 0xEEEEEEEE, 0xFFFFFFFF
};uint32_t desBuffer[BUF_SIZE];		// 目标数组/* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
int fputc(int ch, FILE *f)
{unsigned char temp[1]={ch};HAL_UART_Transmit(&huart1,temp,1,0xffff);return ch;
}
/* USER CODE END 0 */int main(void)
{/* USER CODE BEGIN 1 */int i = 0;/* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* Initialize all configured peripherals */MX_GPIO_Init();MX_DMA_Init();MX_USART1_UART_Init();/* USER CODE BEGIN 2 */// DMA开启数据传输HAL_DMA_Start(&hdma_memtomem_dma1_channel1, (uint32_t)srcBuffer, (uint32_t)desBuffer, sizeof(uint32_t) * BUF_SIZE);	// 等待数据传输完成while(__HAL_DMA_GET_FLAG(&hdma_memtomem_dma1_channel1, DMA_FLAG_TC1));													// 打印数组内容for(i = 0; i< BUF_SIZE; i++){printf("BUF[%d] = %x\r\n", i, desBuffer[i]);}/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}

业务代码写完之后,我们把它编译并且烧录进MCU里面,硬件连接USB-TTL模块,软件打开串口调试助手,就会发现我们成功实现了:使用DMA搬运方式内存到内存之间的数据搬运哈哈👏

在这里插入图片描述

四、内存👉外设搬运

实现需求:使用DMA的方式将内存数据搬运到串口1发送寄存器,同时闪烁LED1。

4.1 CubeMX配置

  1. 配置Debug

    在这里插入图片描述

  2. 打开RCC配置时钟,将高速时钟配置成Crystal/Ceramic Resonator

    在这里插入图片描述

  3. 点击配置时钟选项,把时钟配置成高速外部时钟HSE,并且通过PLLCLK倍频到72MHZ按下回车之后就为芯片内部的功能分配好了对应的时钟频率。

    在这里插入图片描述

  4. 打开USART1,配置为:异步通信模式,配置:波特率、数据位、停止位、奇偶校验位

    在这里插入图片描述

  5. 将PB8配置成GPIO_Output模式,PB8连接的是LED,并设置PB8初始化为高电平

    在这里插入图片描述

  6. 打开左侧的DMA选项,首先选择:内存到外设,然后点击Add添加一个,接着配置通道、方向和优先级,然后配置DMA数据传输方式为:正常模式,然后配置指针递增模式为:内存地址(源地址)递增,目标地址不递增。

    在这里插入图片描述

  7. 接着对我们的工程进行配置,配置完成之后点击右上角的 GENERATE CODE 生成工程

    在这里插入图片描述


4.2 代码实现

#include "main.h"
#include "dma.h"
#include "usart.h"
#include "gpio.h"/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
#define BUF_SIZE 1000
/* USER CODE END PM *//* Private variables ---------------------------------------------------------*//* USER CODE BEGIN PV */
unsigned char sendBuf[BUF_SIZE] = {0};	// 发送数据缓冲区
/* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP *//* USER CODE END PFP */int main(void)
{/* USER CODE BEGIN 1 */int i = 0;/* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_DMA_Init();MX_USART1_UART_Init();/* USER CODE BEGIN 2 */for(i = 0; i < BUF_SIZE; i++){sendBuf[i] = 'A';}// 将数据通过串口DMA发送HAL_UART_Transmit_DMA(&huart1, sendBuf, BUF_SIZE);/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */// 主函数一直运行LED闪烁HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_8);	HAL_Delay(100);}/* USER CODE END 3 */
}

业务代码写完之后,我们把它编译并且烧录进MCU里面,硬件连接USB-TTL模块,软件打开串口调试助手,就会发现串口助手接收到1000个数据的同时LED也在闪烁,实现了使用DMA的方式内存到外设之间的数据搬运。
在这里插入图片描述

五、外设👉内存搬运

实现需求:使用DMA的方式将串口接收缓存寄存器的值搬运到内存中,同时闪烁LED。

5.1 CubeMX配置

  1. 配置Debug

在这里插入图片描述

  1. 打开RCC配置时钟,将高速时钟配置成Crystal/Ceramic Resonator

    在这里插入图片描述

  2. 点击配置时钟选项,把时钟配置成高速外部时钟HSE,并且通过PLLCLK倍频到72MHZ按下回车之后就为芯片内部的功能分配好了对应的时钟频率。

    在这里插入图片描述

  3. 打开USART1,配置为:异步通信模式,配置:波特率、数据位、停止位、奇偶校验位等,并使能USART1中断。

    在这里插入图片描述

  4. 将PB8配置成GPIO_Output模式,PB8连接的是LED,并设置PB8初始化为高电平

    在这里插入图片描述

  5. 打开左侧的DMA选项,首先选择:DMA1,然后点击Add添加两个,接着配置通道、方向和优先级,然后配置DMA数据传输方式为:正常模式,然后配置指针递增模式为:内存地址(源地址)递增,目标地址不递增。

    在这里插入图片描述

  6. 接着对我们的工程进行配置,配置完成之后点击右上角的 GENERATE CODE 生成工程

    在这里插入图片描述

5.2 代码实现

/* main.c */
#include "main.h"
#include "dma.h"
#include "usart.h"
#include "gpio.h"/* USER CODE BEGIN PV */
uint8_t rcvBuf[BUF_SIZE] = {0};		// 接收数据缓冲区
uint8_t rcvLen = 0;					// 接收一帧数据长度
/* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_DMA_Init();MX_USART1_UART_Init();/* USER CODE BEGIN 2 */__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);		// 使能USART1空闲中断HAL_UART_Receive_DMA(&huart1, rcvBuf, BUF_SIZE);	// 使能DMA方式接收串口数据中断/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE */HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_8);HAL_Delay(300);/* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}
/* main.h */
#define BUF_SIZE 100
/* stm32f1xx_it.c */
#include "main.h"
#include "stm32f1xx_it.h"/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
extern uint8_t rcvBuf[BUF_SIZE];		// 接收数据缓冲区
extern uint8_t rcvLen;					// 接收一帧数据长度
/* USER CODE END PV *//* External variables --------------------------------------------------------*/
extern DMA_HandleTypeDef hdma_usart1_rx;
extern DMA_HandleTypeDef hdma_usart1_tx;
extern UART_HandleTypeDef huart1;
/* USER CODE BEGIN EV *//* USER CODE END EV *//******************************************************************************/
/*           Cortex-M3 Processor Interruption and Exception Handlers          */
/******************************************************************************/
/*** @brief This function handles Non maskable interrupt.*/
void NMI_Handler(void)
{/* USER CODE BEGIN NonMaskableInt_IRQn 0 *//* USER CODE END NonMaskableInt_IRQn 0 *//* USER CODE BEGIN NonMaskableInt_IRQn 1 */while (1){}/* USER CODE END NonMaskableInt_IRQn 1 */
}/*** @brief This function handles Hard fault interrupt.*/
void HardFault_Handler(void)
{/* USER CODE BEGIN HardFault_IRQn 0 *//* USER CODE END HardFault_IRQn 0 */while (1){/* USER CODE BEGIN W1_HardFault_IRQn 0 *//* USER CODE END W1_HardFault_IRQn 0 */}
}/*** @brief This function handles Memory management fault.*/
void MemManage_Handler(void)
{/* USER CODE BEGIN MemoryManagement_IRQn 0 *//* USER CODE END MemoryManagement_IRQn 0 */while (1){/* USER CODE BEGIN W1_MemoryManagement_IRQn 0 *//* USER CODE END W1_MemoryManagement_IRQn 0 */}
}/*** @brief This function handles Prefetch fault, memory access fault.*/
void BusFault_Handler(void)
{/* USER CODE BEGIN BusFault_IRQn 0 *//* USER CODE END BusFault_IRQn 0 */while (1){/* USER CODE BEGIN W1_BusFault_IRQn 0 *//* USER CODE END W1_BusFault_IRQn 0 */}
}/*** @brief This function handles Undefined instruction or illegal state.*/
void UsageFault_Handler(void)
{/* USER CODE BEGIN UsageFault_IRQn 0 *//* USER CODE END UsageFault_IRQn 0 */while (1){/* USER CODE BEGIN W1_UsageFault_IRQn 0 *//* USER CODE END W1_UsageFault_IRQn 0 */}
}/*** @brief This function handles System service call via SWI instruction.*/
void SVC_Handler(void)
{/* USER CODE BEGIN SVCall_IRQn 0 *//* USER CODE END SVCall_IRQn 0 *//* USER CODE BEGIN SVCall_IRQn 1 *//* USER CODE END SVCall_IRQn 1 */
}/*** @brief This function handles Debug monitor.*/
void DebugMon_Handler(void)
{/* USER CODE BEGIN DebugMonitor_IRQn 0 *//* USER CODE END DebugMonitor_IRQn 0 *//* USER CODE BEGIN DebugMonitor_IRQn 1 *//* USER CODE END DebugMonitor_IRQn 1 */
}/*** @brief This function handles Pendable request for system service.*/
void PendSV_Handler(void)
{/* USER CODE BEGIN PendSV_IRQn 0 *//* USER CODE END PendSV_IRQn 0 *//* USER CODE BEGIN PendSV_IRQn 1 *//* USER CODE END PendSV_IRQn 1 */
}/*** @brief This function handles System tick timer.*/
void SysTick_Handler(void)
{/* USER CODE BEGIN SysTick_IRQn 0 *//* USER CODE END SysTick_IRQn 0 */HAL_IncTick();/* USER CODE BEGIN SysTick_IRQn 1 *//* USER CODE END SysTick_IRQn 1 */
}/******************************************************************************/
/* STM32F1xx Peripheral Interrupt Handlers                                    */
/* Add here the Interrupt Handlers for the used peripherals.                  */
/* For the available peripheral interrupt handler names,                      */
/* please refer to the startup file (startup_stm32f1xx.s).                    */
/******************************************************************************//*** @brief This function handles DMA1 channel4 global interrupt.*/
void DMA1_Channel4_IRQHandler(void)
{/* USER CODE BEGIN DMA1_Channel4_IRQn 0 *//* USER CODE END DMA1_Channel4_IRQn 0 */HAL_DMA_IRQHandler(&hdma_usart1_tx);/* USER CODE BEGIN DMA1_Channel4_IRQn 1 *//* USER CODE END DMA1_Channel4_IRQn 1 */
}/*** @brief This function handles DMA1 channel5 global interrupt.*/
void DMA1_Channel5_IRQHandler(void)
{/* USER CODE BEGIN DMA1_Channel5_IRQn 0 *//* USER CODE END DMA1_Channel5_IRQn 0 */HAL_DMA_IRQHandler(&hdma_usart1_rx);/* USER CODE BEGIN DMA1_Channel5_IRQn 1 *//* USER CODE END DMA1_Channel5_IRQn 1 */
}/*** @brief This function handles USART1 global interrupt.*/
void USART1_IRQHandler(void)
{/* USER CODE BEGIN USART1_IRQn 0 *//* USER CODE END USART1_IRQn 0 */HAL_UART_IRQHandler(&huart1);/* USER CODE BEGIN USART1_IRQn 1 */if((__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE) == SET)) 	// 判断IDLE标志位是否被置位{__HAL_UART_CLEAR_IDLEFLAG(&huart1);						// 清除标志位HAL_UART_DMAStop(&huart1); 								// 停止DMA传输,防止干扰uint8_t temp=__HAL_DMA_GET_COUNTER(&hdma_usart1_rx);rcvLen = BUF_SIZE - temp; 								//计算数据长度HAL_UART_Transmit_DMA(&huart1, rcvBuf, rcvLen);			//发送数据HAL_UART_Receive_DMA(&huart1, rcvBuf, BUF_SIZE);		//开启DMA}/* USER CODE END USART1_IRQn 1 */
}/* USER CODE BEGIN 1 *//* USER CODE END 1 */

业务代码写完之后,我们把它编译并且烧录进MCU里面,硬件连接USB-TTL模块,软件打开串口调试助手,就会发现我们成功实现了我们的需求:

在这里插入图片描述


http://www.hkcw.cn/article/LGojFSihkJ.shtml

相关文章

阿富汗已有357人死于麻疹 疫苗缺乏与营养不足加剧疫情

世界卫生组织报告显示,截至5月25日,阿富汗今年已记录了超过55000例麻疹疑似病例,其中已有357人死亡,死者大部分是儿童。当地医务系统专家指出,疫苗缺乏和营养不足是疾病快速传播的重要原因。目前阿富汗有1580万人面临饥饿问题,大量儿童营养不良,难以抵御疾病侵袭,需要获…

中国汽车工业协会发布公平竞争倡议 反对无序“价格战”

近年来,我国新能源汽车产业快速发展,新能源汽车新车销售占比已经超过40%。行业整体运行呈现稳中向好态势,市场活力持续释放。然而,一段时间以来,行业盈利水平下降,无序“价格战”成为主要表现形式的“内卷式”竞争,严重影响企业正常经营,冲击产业链供应链安全,把产业发…

乖猫记账 2.2.1 | 完全免费 AI聊天记账~自动记账

乖猫记账是一款完全免费的小清新风格记账软件&#xff0c;适用于安卓、iPhone 和 iPad。它不仅颜值高&#xff0c;而且功能完善&#xff0c;整体记账体验出色。该应用支持AI聊天记账和语音智能识别&#xff0c;用户可以通过文字聊天对话或语音输入进行记账操作。语音识别特别准…

Nat. Commun|结合视觉基础模型与大语言模型,直接从病理图像生成病理报告

小罗碎碎念 这篇文章聚焦于医学AI领域的前沿研究&#xff0c;提出了一种名为HistoGPT的视觉语言模型&#xff0c;旨在解决传统组织病理学报告生成耗时、标准化不足的问题。 模型通过结合视觉基础模型&#xff08;如CTransPath和UNI&#xff09;与大型语言模型&#xff08;BioGP…

中方为何派国防大学代表团参加香会 阐释理念增信释疑

5月29日下午,国防部举行例行记者会。国防部新闻发言人张晓刚大校宣布,从5月29日至6月2日,中国人民解放军国防大学代表团将应邀前往新加坡参加第22届香格里拉对话会,并访问新加坡的军事和相关机构。在记者会上,有记者询问为何此次中方没有派遣更高层级官员出席香格里拉对话…

马斯克回应眼角淤青 儿子的“杰作”

据法新社等媒体报道,美国总统特朗普和美国企业家、政府效率部负责人马斯克于5月30日在白宫举行新闻发布会。当天是马斯克在政府任职的最后一天,他的眼角淤青引起了媒体关注。马斯克解释说,这是他五岁的儿子小X打的。当时他在和儿子闹着玩,让儿子打他的脸,结果真的被打了一…

世界首富回去探索太空了 美国政府的黑洞怎么办

var chan_v_w = 960,chan_v_h = 540,chan_v_p = https://mts-audio.huawangzhixun.com/image/20250531/news/61f786aa-351b-4360-b93b-d1a53824c148.jpg,chan_v_s = https://vmts.china.com/api/video/onaliyun/query?id=3101100&ttype=mp4;当地时间5月30日埃隆马斯克卸任…

老外最近流行带着空箱子来中国 网友:箱子也可以在中国买! “中国购”成新趋势

“一定要带空箱子去中国!”这一实用建议近期在海外社交平台引起广泛关注。从“中国游”到“中国购”,外国人来华购物成为新的跨境旅游趋势。支付平台数据显示,外国游客在中国消费时,本土商超、潮流文创和特色美食等的占比显著提升。“中国购”走红的原因是多方面的。退税政…

MySQL 8.0 OCP 英文题库解析(十)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题81~90 试题81:…

增长放缓的理想能否靠纯电突围 纯电转型成关键

近日,理想汽车L系列的焕新发布会上给新能源市场带来一场不小的震撼。L系列全系车型进行升级,在辅助驾驶、智慧座舱以及底盘性能等方面都有大提升,但价格上没有变动。理想此次加量不加价的原因在于L系列的销量已经疲软,而纯电动车的能力还没有释放出来,保量成为理想汽车的首…

12周岁未成年人故意杀人 检方追诉 彰显法律公正与权威

湖北省人民检察院在5月30日举办的“携手关爱 共护未来”检察开放日活动上透露,一起12周岁未成年人故意杀人案已报请最高检核准追诉,目前案件正在法院依法审理中。湖北检察机关执行宽严相济的刑事政策,针对情节较轻、社会危害性较小的犯罪行为,特别是初犯和偶犯,采取从宽处…

特朗普为何指责中国违反关税协议 称曾试图拯救中方经济

5月30日,美国总统特朗普表示,中国完全违反了贸易协议。他称签署这项协议是为了在美国加征高额关税后拯救中方经济免于崩溃。特朗普在社交平台“真实社交”上写道,中国当时处于严重的经济困境中,美国实施的关税实际上使其失去了与美国这个世界最大市场开展贸易的能力。据他介…

尊界S800是华为真正从0到1的产品吗 向超豪华市场冲击

尊界S800向超豪华汽车市场发起冲击。5月30日,华为联合安徽江淮汽车集团股份有限公司发布尊界S800。这款车定位为超豪华D级行政轿车,售价70.8万至101.8万元,是华为智选车体系下售价最高的产品。去年11月该车首次亮相,今年2月华为方面介绍了数项新车技术。华为常务董事、终端…

一票难求的“苏超”联赛:江苏人用热爱和幽默,把足球玩成了全民狂欢 球迷热情高涨引发关注

最近,江苏省城市足球联赛受到广泛关注。江苏人用热爱和幽默将足球变成了一场全民狂欢。有球迷表示“苏超”联赛一票难求,希望主办方能增加门票供应。6月1日,2025年江苏省城市足球联赛第3轮南京队对阵无锡队的比赛将在南京五台山体育场举行。球迷孟先生想去现场支持自己喜欢的…

不管多忙 端午别忘“做三事”“吃四物” 养生正当时

每年一到端午,家家户户粽叶飘香,门前也插起了艾草。这个节气不仅是民俗节日,更是养生的重要时刻。端午过后,阳气大盛,湿邪容易趁虚而入。这几天是调整体质、打通阳脉的关键期。除了吃粽子外,端午养生还可以通过“做三事”和“吃四物”来实现。将艾草挂在门外不仅能驱蚊虫…

哪里有封锁哪里就有突围 科技创新持续升级

中国驻美大使谢锋在华盛顿的一次活动中谈及中国的科技创新历程时提到,面对封锁和挑战,中国总能找到突围之路。5月28日,中国驻美国大使馆举办了一场“我的中国相册——我的中国足迹”影片首映会暨现代化的中国体验活动。谢锋在致辞中表示,中国的科技创新经历了重重困难,但通…

北京地铁今起启动双温车厢模式,强冷、弱冷车厢差2℃ 满足不同乘客需求

从今天开始,北京地铁公司所辖各线(首都机场线除外)列车将全面启动双温车厢模式。强冷车厢和弱冷车厢的温度设置相差2℃,以满足不同乘客在夏季的出行需求。根据各条线路车辆的不同情况,双温车厢的具体设置位置也有所区别。例如,5号线、亦庄线前3节车厢为强冷车厢,后3节车…

C++--string的使用及其模拟实现

1. 问题引入 C语言中&#xff0c;字符串是以’\0’结尾的若干个字符的集合&#xff0c;为了操作方便&#xff0c;C语言 string.h 头文件提供了一些系列的库函数&#xff0c;但是这些库函数与字符串是分离开的&#xff0c;不符合面向对象的思想&#xff0c;而且底层空间需要用户…

租三金结婚的年轻人开始退租了 租赁经济悄然变化

金项链、金耳环和金戒指是中国传统婚礼中女方的重要嫁妆之一,象征着吉祥与富贵。近期,随着金价不断攀升,不少年轻人开始选择“租三金”作为婚礼道具,以降低经济负担,“以租代买”在婚庆市场悄然走红。共享经济进入婚庆领域,这种现象引发了不同意见。网上“租三金”的价格…

intra-mart执行java方法笔记

一、前言 最近在用intra-mart&#xff0c;感觉官方文档不明不白的&#xff0c;很难搜。 想在intra-mart里执行java&#xff0c;找了半天&#xff0c;终于试出来了。 在此总结一下。 想看官网文档&#xff0c;这个是地址&#xff1a; https://document.intra-mart.jp/library…