Arduino stm32 串口中断 DMA接收例程
时间: 2025-05-25 19:20:16 浏览: 26
### Arduino 和 STM32 使用串口中断及 DMA 接收的示例代码
以下是针对 Arduino 和 STM32 的串口中断与 DMA 接收功能的具体实现方法。
#### STM32 串口接收 (基于 IDLE 中断和 DMA)
STM32 提供了一种高效的机制,利用串口空闲中断 (IDLE Interrupt) 配合 DMA 来完成数据接收。这种方式能够显著降低 CPU 占用率并提升系统的实时性能[^2]。
```c
#include "stm32f0xx.h"
#define DMA_USART1_RECEIVE_LEN 18
// 定义全局变量用于存储接收到的数据
uint8_t USART1_RECEIVE_DMABuffer[DMA_USART1_RECEIVE_LEN];
uint8_t Uart2_Buffer[DMA_USART1_RECEIVE_LEN];
void UART_Init(void) {
// 初始化串口配置...
}
void DMA_Configuration(void) {
DMA_InitTypeDef DMA_InitStructure;
// 启动 DMA 控制器
DMA_DeInit(DMA1_Channel5);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(USART1->DR); // 外设地址为 DR 寄存器
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART1_RECEIVE_DMABuffer; // 存储到缓冲区
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; // 数据方向:外设 -> 内存
DMA_InitStructure.DMA_BufferSize = DMA_USART1_RECEIVE_LEN; // 缓冲区大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 不增加外设地址
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // 增加内存地址
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // 字节宽度
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; // 字节宽度
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // 循环模式
DMA_InitStructure.DMA_Priority = DMA_Priority_High; // 高优先级
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // 禁用内存到内存传输
DMA_Init(DMA1_Channel5, &DMA_InitStructure);
DMA_Cmd(DMA1_Channel5, ENABLE); // 开启 DMA 通道
}
void USART1_IRQHandler(void) {
u32 temp = 0;
if (USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) { // 判断是否为空闲中断
USART1->SR; // 清除 SR 寄存器中的标志位
USART1->DR; // 清除 DR 寄存器中的标志位
// 计算实际接收到的数据长度
temp = DMA_USART1_RECEIVE_LEN - DMA_GetCurrDataCounter(DMA1_Channel5);
for (int i = 0; i < temp; i++) {
Uart2_Buffer[i] = USART1_RECEIVE_DMABuffer[i]; // 将数据复制到另一个缓冲区
}
// 设置新的传输数据长度
DMA_SetCurrDataCounter(DMA1_Channel5, DMA_USART1_RECEIVE_LEN);
// 重新开启 DMA
DMA_Cmd(DMA1_Channel5, ENABLE);
}
}
```
---
#### Arduino 上调整串口缓存大小并启用中断接收
对于 Arduino 平台上的 STM32 设备,可以通过修改 `usart_dev` 结构体定义来调整串口缓存大小,并结合硬件中断处理程序实现高效的数据接收[^4]。
```cpp
#ifndef USART_RX_BUF_SIZE
#define USART_RX BUF_SIZE 512 // 调整接收缓存大小
#endif
#ifndef USART_TX_BUF_SIZE
#define USART_TX BUF_SIZE 64 // 调整发送缓存大小
#endif
typedef struct usart_dev {
usart_reg_map *regs; /**< 注册表映射 */
ring_buffer *rb; /**< RX 环形缓冲区 */
ring_buffer *wb; /**< TX 环形缓冲区 */
uint32 max_baud; /**< 最大波特率 */
uint8 rx_buf[USART_RX_BUF_SIZE]; /**< 实际使用的 RX 缓冲区 */
uint8 tx_buf[USART_TX_BUF_SIZE]; /**< 实际使用的 TX 缓冲区 */
} usart_dev;
void setup() {
Serial.begin(9600); // 初始化串口通信
attachInterrupt(digitalPinToInterrupt(0), serialRXHandler, FALLING); // 绑定外部中断
}
volatile bool dataAvailable = false;
char receivedData[USART_RX_BUF_SIZE];
int dataIndex = 0;
void serialRXHandler() {
while (Serial.available()) {
char c = Serial.read();
if (dataIndex >= USART_RX_BUF_SIZE - 1) break; // 防止溢出
receivedData[dataIndex++] = c;
dataAvailable = true;
}
}
void loop() {
if (dataAvailable) {
receivedData[dataIndex] = '\0'; // 添加字符串终止符
Serial.println(receivedData); // 打印接收到的内容
dataIndex = 0; // 重置索引
dataAvailable = false; // 清理标记
}
}
```
---
#### 关键技术点解析
- **STM32 DMA 配置**: 在初始化阶段设置了循环模式 (`DMA_Mode_Circular`) 和高优先级 (`DMA_Priority_High`),从而确保即使在大量数据流的情况下也能稳定运行[^3]。
- **IDLE 中断优化**: 当检测到串口空闲信号时触发中断服务程序,在此期间计算已接收数据的实际数量并将它们保存至目标缓冲区中。
- **Arduino 缓存管理**: 修改默认的串口缓冲区尺寸以适应特定应用场景需求,同时通过附加中断处理器捕获异步事件[^4]。
阅读全文
相关推荐


















