以下是基于 STC8H8K64U 单片机使用 DMA(非循环模式) 实现串口3(UART3)不定长接收的完整代码方案。通过 DMA传输完成中断 和 串口空闲中断(IDLE) 结合,实现高效的不定长数据接收。
1. 核心思路
- DMA单次模式:每次接收固定长度后触发中断。
- 串口空闲中断(IDLE):检测到总线空闲时提前处理数据。
- 双缓冲区机制:避免处理数据时被新数据覆盖。
2. 硬件配置
#include "stc8h.h"
#include <intrins.h>
#define UART3_BUF_SIZE 128 // DMA接收缓冲区大小
uint8_t uart3_rx_buf[UART3_BUF_SIZE];
volatile uint16_t rx_len = 0; // 实际接收长度
volatile uint8_t rx_flag = 0; // 接收完成标志
void UART3_Init(void) {
P_SW2 |= 0x80; // 允许访问扩展寄存器(XFR)
// --- 串口3配置 ---
S3CON = 0x10; // 8位数据,无校验位,1位停止位
T3L = (65536 - (FOSC/4/115200)); // 波特率115200(根据实际时钟调整)
T3H = (65536 - (FOSC/4/115200)) >> 8;
T4T3M |= 0x20; // Timer3作为波特率发生器
S3CON |= 0x01; // 使能串口3接收
IE2 |= 0x08; // 使能UART3中断(用于IDLE检测)
}
void DMA_UART3_RX_Init(void) {
DMA_URCFG &= ~0x80; //关闭DMA_UART_RX
DMA_URTSA = (uint16_t)&S3BUF; //源地址:串口收据缓存器
DMA_URTDA= (uint16_t)uart_r x_buf;//目标地址:用户缓冲区
DAM URTCNT= UAR TBUF SIZE ; ///传输长度
DAM UR CFG|=((1<<5)|(1<<4)); ///使能DMA&完成中断
///方向:外设->内存
///单次模式(非循环)
EA=1; ///开启总中断
}
关键点说明
(1) DMA初始化
- 单次模式:
DMA_URCFG
不设置循环模式标志。 - 触发源:自动检测串口接收到数据后触发DMA传输。
(2) IDLE中断处理
void UART3_ISR() interrupt UART3_VECTOR {
if(S CON&0 x02){ ///检查IDLE标志
rx_len=D MA _UR TC NT-DM A _URT C NT;//计算实际接收长度
r x_fl ag=1; ///标记帧接收完成
S CON&=~ x02; ///清除IDLE标志
DM A _UR CFG&=~ x80; ///关闭当前通道以重新配置
DM A _UR TD A=(uin t6 )ua rt_r x_bu f;//重置目标地址
DM A _UR TC NT=UA RT_B UF_S IZE ;//重置计数器
DM A _UR CFG|= x80; ///重新使能DM通道
}
}
(4)主程序逻辑示例
void main(){
UAR_TIni t();
DAM_U ART_R X_In it();
while(1){
if(rx_fl ag){ ///收到完整帧数据
ProcessDa ta(uar t_rxb uf,rxl en);///自定义数据处理函数
rxf lag=0; /清除标志继续下一次接收
}
}
}
###常见问题排查:
如果无法进入中断请检查以下项
*确认已正确设置所有相关的中断向量和优先级.
*确保在调试时启用了全局中断(EA=1
).
*验证波特率和时钟源配置是否正确.
如果需要进一步优化或添加其他功能(如超时机制),可以在当前框架基础上扩展。
内容由零声教学AI助手提供,问题来源于学员提问