免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

STM32 ADC/DAC/DMA核心外设联动配置与实时信号处理实战

STM32 ADC/DAC/DMA核心外设联动配置与实时信号处理实战 1. 项目概述深入理解STM32的三大核心外设在嵌入式开发尤其是基于STM32这类主流MCU的项目中ADC模数转换器、DAC数模转换器和DMA直接内存访问是三个绕不开的核心技术点。它们共同构成了连接模拟世界与数字世界的桥梁以及实现高效数据搬运的“高速公路”。很多新手朋友在初次接触时可能会觉得每个概念单独看都懂但一旦需要将它们组合起来实现一个稳定、高效的实时数据采集或输出系统时就感到无从下手配置寄存器时更是如履薄冰。我最初接触STM32时也经历过这个阶段。比如想用ADC采集一个传感器的电压用DMA把数据悄无声息地搬到内存再用DAC实时还原这个波形整个过程要求CPU干预越少越好。听起来简单但实际调起来采样率不对、DMA传输完成中断不触发、数据错位等问题层出不穷。今天我就结合自己踩过的坑和项目经验把这三大外设的核心原理、联动配置以及实战中的那些“魔鬼细节”系统地梳理一遍。无论你是正在做毕业设计的学生还是需要快速上手产品开发的工程师这篇文章都能帮你建立起清晰、实用的知识框架让你在代码配置时心里有底在调试问题时思路清晰。2. 核心需求解析为什么需要ADC、DAC和DMA在深入代码之前我们必须先想清楚在一个真实的STM32项目中我们到底在解决什么问题为什么要同时用到这三个家伙2.1 模拟信号的数字化处理闭环绝大多数物理世界的信息如温度、压力、声音、光照最初都是连续的模拟信号。STM32作为数字处理器无法直接理解这些连续变化的电压或电流。这时ADC就扮演了“翻译官”的角色它以固定的时间间隔采样率对模拟信号进行“拍照”采样并将每次“拍照”得到的电压值转换成一个数字量比如12位ADC输出0-4095。这样连续的模拟波形就被离散化为一串数字序列MCU才能对其进行计算、分析和存储。处理完的数字信号有时需要重新影响物理世界。例如你想控制一个电机的转速模拟量或者播放一段音频也是模拟信号。这时DAC这个“逆向翻译官”就出场了。它接收MCU给出的数字量并输出一个对应的、精确的模拟电压。于是数字世界的指令得以重新转化为模拟世界的动作。2.2 解放CPU的关键DMA现在想象一个场景你需要以10kHz的频率即每100微秒一次用ADC采集数据并以同样的频率用DAC输出处理后的数据。如果不用DMACPU就必须在每次转换完成后立刻执行中断服务程序从ADC数据寄存器读取数值再写入DAC数据寄存器。这意味著CPU每100微秒就要被中断两次大量时间浪费在繁琐的数据搬运上根本无法执行复杂的控制算法或业务逻辑。DMA就是为了解决这个核心矛盾而生的。你可以把它理解为一个“智能数据搬运工”。一旦配置好源地址如ADC数据寄存器、目标地址如内存数组或DAC数据寄存器和数据量DMA控制器就能在后台自动完成大批量的数据传输完全不需要CPU参与。只有在传输完成或半程时它才会通知CPU一声“老板货搬完了您来处理一下吧。” 这样CPU就被彻底解放出来专注于更有价值的计算任务。2.3 典型应用场景串联让我们用一个完整的例子把三者串起来基于STM32的简易音频处理器。ADC采集麦克风将声音信号转换为模拟电压STM32的ADC在定时器触发下以44.1kHz的采样率持续采集此电压。DMA搬运ADC每转换完成一个数据DMA就自动将这个数据从ADC数据寄存器搬运到内存中一个预先定义好的环形缓冲区Circular Buffer。CPU处理CPU的主循环并不关心数据怎么来的它只负责检查缓冲区是否有新数据。一旦有它就读取这些数据进行例如均衡、降噪等数字信号处理虽然简单但原理如此。DMA搬运输出处理后的数据由另一个DMA通道自动从内存缓冲区搬运到DAC的数据寄存器。DAC输出DAC根据接收到的数字量输出对应的模拟电压经过功率放大后驱动扬声器还原处理后的声音。整个过程ADC和DAC的“节奏”由定时器精确控制数据流动由DMA全权负责CPU只在需要施加算法时才介入。这就是一个高效、实时的嵌入式信号处理系统的典型架构。3. ADC模数转换器深度剖析与实战配置ADC是信号链的入口它的性能和使用方式直接决定了整个系统能“看”到什么样的世界。3.1 STM32 ADC的核心特性与关键参数不同系列的STM32其ADC性能差异很大。F1系列常见12位ADCF3/F4系列有16位ADC的型号而H7系列则支持更高精度和速度。我们需要关注几个核心参数分辨率比如12位。这决定了ADC能区分的最小电压变化。对于3.3V参考电压12位ADC的1个LSB最低有效位代表的电压是 3.3V / 4096 ≈ 0.8mV。这意味着如果输入电压变化小于0.8mVADC可能无法检测到。采样率ADC每秒能进行多少次转换。它受限于ADC本身的时钟和采样周期设置。过高的采样率会导致精度下降。采样时间ADC内部采样保持电容对输入信号充电的时间。对于高阻抗的信号源必须延长采样时间否则电容充电不足转换结果会严重偏低。这是新手最容易忽略导致采样值不准的坑。3.2 单通道与多通道采集模式详解单通道单次转换最简单模式。启动一次转换一个通道然后停止。适用于不频繁的、手动触发的测量如按键读取某个传感器。单通道连续转换启动后ADC会不停地对同一个通道进行转换数据寄存器里总是最新结果。适合监控一个快速变化的信号。多通道扫描Scan模式这是最常用的模式之一。ADC会按照预先配置好的通道序列如通道1, 5, 8自动依次转换每一个通道。通常我们会结合DMA使用让DMA在每次通道转换完成后自动把数据搬运到内存中对应的数组位置。注意在多通道扫描模式下必须为每个通道单独配置采样时间。如果你用同一个采样时间去采集一个温度传感器高输出阻抗和一个运放输出的信号低输出阻抗温度传感器的读数很可能不准。3.3 触发源选择软件触发与硬件触发如何告诉ADC“开始转换”软件触发在代码中调用HAL_ADC_Start()或类似函数。简单但时序不精确。硬件触发强烈推荐在需要精确时序的场合使用。可以由定时器TIM、外部引脚EXTI等来触发。例如设置定时器每100us产生一个触发事件ADC就会严格以10kHz的频率进行采样这对于数字信号处理如音频至关重要。3.4 基于CubeMX与HAL库的ADC多通道DMA采集配置实战理论说再多不如一行配置。我们以STM32F4系列配置ADC1扫描采集通道0、通道1、通道2并使用DMA将数据搬运到内存为例。CubeMX图形化配置ADC1设置在“Analog”下找到ADC1。模式选择“Independent mode”。参数设置Resolution: 12位。Scan Conversion Mode: 启用Enable。这是多通道的关键。Continuous Conversion Mode: 禁用Disable。我们用定时器触发所以不需要连续。DMA Continuous Requests: 启用。这保证了在循环模式下DMA请求会持续产生。End Of Conversion Selection: 选择“EOC after each conversion”每次转换后产生EOC。这样DMA才能在每次转换后搬运数据。通道配置在“Rank”中依次添加Channel 0, 1, 2。为每个Channel设置Sampling Time比如对于普通传感器设为“Cycles 84”或更高以保证精度。触发源在“Trigger”选项选择“Timer 2 Trigger Out event”或其他你配置的定时器。DMA配置在ADC1的DMA Settings中点击“Add”。Mode: “Circular”循环模式。这样DMA会在传输完预定数据量后自动从头开始实现不间断的数据流。Data Width: 都选择“Word”32位因为ADC数据寄存器是32位的但实际有效数据是低12位或16位。关键代码解析// 定义存储ADC值的数组大小要足够大避免DMA覆盖未处理的数据 #define ADC_BUFF_SIZE 1024 uint32_t adc_buffer[ADC_BUFF_SIZE]; // 启动ADC的DMA采集 HAL_ADC_Start_DMA(hadc1, (uint32_t*)adc_buffer, ADC_BUFF_SIZE); // 此时ADC会在定时器的驱动下严格按照 Ch0 - Ch1 - Ch2 的顺序循环转换。 // DMA会自动将 Ch0 的值放到 adc_buffer[0], Ch1 放到 adc_buffer[1], Ch2 放到 adc_buffer[2], // 然后 Ch0 的值放到 adc_buffer[3]... 如此循环。 // 你的主程序或中断中只需要直接读取 adc_buffer 数组即可。3.5 ADC实战中的“避坑指南”电源与参考电压噪声ADC的精度极度依赖一个干净、稳定的参考电压VREF。如果系统中有数字电路如GPIO翻转、PWM产生噪声会通过电源耦合到ADC导致采样值跳动。解决方案是使用独立的LDO为模拟部分供电并在VREF引脚加π型滤波如10Ω电阻10μF钽电容0.1μF陶瓷电容。信号调理不可少MCU的ADC输入范围通常是0-3.3V。如果你的传感器信号是0-5V必须用电阻分压如果是负电压或交流信号则需要运放搭建电平移位和缩放电路。直接接入超出范围的电压会损坏ADC引脚。过采样提升有效分辨率如果你需要比硬件分辨率如12位更高的精度可以采用过采样技术。例如以4倍速率采样然后将4个结果累加求平均理论上可以增加1位有效分辨率。但这会降低有效采样率需要权衡。软件滤波是最后防线即使硬件设计完美采样值仍会有微小抖动。在软件端对连续采样值进行滑动平均滤波、中值滤波或一阶低通滤波可以极大地稳定最终读数这是产品化的必备步骤。4. DAC数模转换器原理与应用进阶DAC的工作是ADC的逆过程它将数字代码转换为模拟电压。STM32内部的DAC通常是电阻串或电容阵列型分辨率常见为12位。4.1 DAC的两种输出模式与缓冲器输出缓冲STM32的DAC内部集成了一个输出运放作为缓冲器。启用缓冲器Buffer Enable后DAC具有较低的输出阻抗和较强的带负载能力可以直接驱动一些外部电路。但是缓冲器的引入会带来一定的偏移误差和增益误差并且输出电压范围被限制在约0.2V至VREF - 0.2V之间。无缓冲输出禁用缓冲器后DAC输出阻抗很高输出电压范围可以接近0V到VREF精度理论上更高。但你必须外接一个高输入阻抗的运放如电压跟随器来驱动后续电路否则任何负载都会导致输出电压严重失真。实操心得在需要高精度、全量程输出的场合例如波形生成我通常选择禁用内部缓冲器然后外接一颗精密运放如OPA2188做缓冲。虽然多了个元件但性能提升是显著的。4.2 触发与数据格式和ADC类似DAC的转换也可以由软件或硬件定时器触发。在需要生成连续、精确频率的波形如正弦波、三角波时必须使用定时器触发。DAC的数据寄存器宽度是固定的如32位但数据对齐方式需要注意。对于12位DAC你可以选择右对齐数据放在低12位或左对齐数据放在高12位。HAL库通常帮我们处理好了但自己写寄存器时一定要查数据手册确认。4.3 使用DMA生成任意波形实战这是DAC最经典的应用。我们想用DMA定时器触发让DAC自动输出一个正弦波完全不需要CPU干预。预计算波形表在程序初始化时预先计算好一个正弦周期内的采样点数组。#define WAVE_TABLE_SIZE 128 uint32_t dac_sine_wave[WAVE_TABLE_SIZE]; for(int i0; iWAVE_TABLE_SIZE; i) { // 生成幅度为2047偏置为2047的正弦波对应0-3.3V中间值上下波动 float value 2047.0f * sinf(2 * M_PI * i / WAVE_TABLE_SIZE) 2047.0f; // 确保值在0-4095之间12位DAC并转换为DAC寄存器格式此处假设右对齐 dac_sine_wave[i] (uint32_t)(value) 0xFFF; }CubeMX配置使能DAC通道如DAC1, Channel1。在“Trigger”中选择一个定时器如TIM6作为触发源。使能DAC的DMA请求。DMA配置为DAC1添加DMA流。Mode: “Circular”循环模式。这是实现连续波形输出的关键。Data Width: 根据DAC数据寄存器格式选择通常是“Word”。关键代码// 启动DAC并启动DMA传输波形表到DAC HAL_DAC_Start_DMA(hdac1, DAC_CHANNEL_1, (uint32_t*)dac_sine_wave, WAVE_TABLE_SIZE, DAC_ALIGN_12B_R); // 配置定时器TIM6的自动重载值ARR以产生所需的触发频率。 // 输出频率 定时器触发频率 / 波形表大小 // 例如想要生成1kHz的正弦波定时器触发频率需设置为 1kHz * 128 128kHz。 // 假设系统时钟为84MHz定时器分频PSC设为0则 ARR 84MHz / 128kHz - 1 ≈ 655。 HAL_TIM_Base_Start(htim6);一旦这段代码执行一个纯净的1kHz正弦波就会从DAC引脚输出。CPU在启动后就不再参与所有工作由定时器和DMA协作完成。5. DMA直接内存访问机制精讲DMA是提升系统效率的“神器”但配置不当也是“坑神”。理解其工作机制至关重要。5.1 DMA控制器结构与通道流概念以STM32F4为例它有两个DMA控制器DMA1, DMA2每个控制器有多个流Stream每个流有多个通道Channel。这三者的关系是控制器DMAx物理实体。流Stream数据传输的管道。每个流一次只能服务一个外设请求。通道Channel用于选择是哪个外设如ADC1、USART1_TX向这个流发出请求。配置时你需要为某个外设源选择一个可用的流并在这个流上选择对应此外设的通道号。CubeMX通常会帮你自动分配但当你手动配置或遇到冲突时必须查阅数据手册中的“DMA请求映射表”。5.2 传输模式普通模式 vs 循环模式普通模式NormalDMA传输完预设的数据量NDTR寄存器值后会自动停止并产生传输完成中断。需要软件重新启动才能进行下一次传输。适用于传输已知长度的数据块如从串口接收一帧定长数据。循环模式Circular这是ADC/DAC连续传输的灵魂。传输完预设数据量后NDTR寄存器会自动重载为初始值源/目标地址也会根据配置自动复位或循环然后立即开始下一轮传输永不停止。非常适合连续不断的数据流场景。5.3 数据宽度、地址增量与对齐问题这是DMA配置中最容易出错的地方之一。数据宽度Data Width指单次传输操作的数据位数8位/16位/32位。源和目标的宽度可以不同DMA控制器会自动进行打包或拆包但这会增加复杂性。最佳实践是保持源、目标和存储变量三者的数据宽度一致。例如ADC是12位数据存于32位寄存器我们定义uint32_t数组DMA宽度设为“Word”。地址增量Increment对于内存地址无论是源还是目标通常需要开启地址增量这样DMA在每次传输后会自动移动到下一个内存位置。对于外设数据寄存器地址如ADC-DR则必须关闭地址增量因为我们要一直从这个固定的寄存器地址读取数据。内存对齐如果使用32位传输Word确保你的内存数组地址是4字节对齐的。编译器通常会对全局数组进行对齐但如果是动态分配的内存或结构体成员就需要小心。不对齐的访问在某些MCU上会导致硬件错误。5.4 中断的有效利用半传输与传输完成DMA提供了两个非常有用的中断点半传输完成中断HT当传输完一半数据量时触发。传输完成中断TC当传输完所有数据量时触发。在**双缓冲Double Buffer**技术中这两个中断是核心。你可以分配两个大小相等的缓冲区BufA和BufB。配置DMA目标地址指向BufA数据量为总长度的一半。当DMA填满BufA半传输完成中断时CPU可以安全地处理BufA中的数据同时DMA继续向BufB填充数据。当BufB也填满传输完成中断时CPU处理BufBDMA又回到BufA。 这种方式几乎完全消除了CPU处理数据时DMA覆盖数据的风险是高速连续数据采集的黄金方案。5.5 DMA与Cache一致性问题针对Cortex-M7等带Cache内核在STM32H7等高性能系列中CPU有数据缓存D-Cache。这引入了一个致命问题DMA直接将数据写入物理内存RAM但CPU读取的是缓存中的数据副本导致CPU看不到DMA刚写入的新数据反之CPU处理完的数据在缓存中DMA直接从物理内存读走的却是旧数据。解决方案是必须维护Cache一致性对于DMA作为写入方如ADC采集到内存在CPU读取DMA目标内存区域之前需要执行SCB_InvalidateDCache_by_Addr()函数使该内存区域的CPU缓存失效强制CPU从物理内存重新加载数据。对于DMA作为读取方如内存数据通过DAC输出在启动DMA传输之前需要执行SCB_CleanDCache_by_Addr()函数将CPU缓存中已修改的数据写回物理内存确保DMA拿到的是最新数据。忽略Cache操作是H7系列开发中最常见的“玄学”Bug来源现象就是数据时对时错毫无规律。6. 综合实战三合一数据采集与波形生成系统现在我们把ADC、DAC、DMA和定时器全部组合起来构建一个完整的信号“采集-处理-回放”系统。目标是用ADC以固定频率采集外部信号CPU对信号进行一个简单的处理比如放大2倍或滤波再用DAC以同样的频率回放出去实现一个实时性极高的模拟信号处理器。6.1 系统架构设计时钟与触发使用一个高级定时器如TIM2同时输出两个触发事件TRGO。触发事件1如更新事件触发ADC开始转换。触发事件2如比较事件触发DAC开始转换。通过调整两个事件的相位可以精确控制ADC采样和DAC输出之间的延迟这对于某些需要固定延迟补偿的应用很重要。数据流ADC通过DMA1的某个流以循环模式将多通道数据搬运到内存的输入缓冲区Input Buffer。在主循环或定时中断中CPU从输入缓冲区读取最新数据进行算法处理然后将结果写入输出缓冲区Output Buffer。DAC通过DMA2的某个流以循环模式将输出缓冲区的数据搬运到DAC数据寄存器。缓冲区设计采用双缓冲机制。为ADC输入和DAC输出各设置两个缓冲区InBufA/B, OutBufA/B。利用DMA的半传输和传输完成中断来切换CPU正在处理和DMA正在读写的缓冲区实现无锁、无冲突的数据交换。6.2 CubeMX关键配置步骤定时器配置配置TIM2。Prescaler和Counter Period计算得出所需的采样频率。在Master/Slave Mode中将Master Mode设为 “Update Event” 或 “Compare Pulse”。在Trigger Output中使能TRGO2等。ADC配置如前所述选择TIM2作为触发源使能扫描模式和DMA循环请求。DAC配置选择TIM2的另一路输出作为触发源使能DMA。DMA配置为ADC和DAC分别配置两个DMA流均设为循环模式。正确配置外设和内存的数据宽度、地址增量。6.3 核心代码逻辑示意// 定义双缓冲 #define BUF_SIZE 512 uint32_t adc_buf_A[BUF_SIZE], adc_buf_B[BUF_SIZE]; uint32_t dac_buf_A[BUF_SIZE], dac_buf_B[BUF_SIZE]; volatile uint32_t *adc_current_target_buf adc_buf_A; // DMA当前正在写入的ADC缓冲 volatile uint32_t *cpu_current_process_buf NULL; // CPU当前正在处理的ADC缓冲 volatile uint32_t *dac_current_source_buf dac_buf_A; // DMA当前正在读取的DAC缓冲 void HAL_ADC_ConvHalfCpltCallback(DMA_HandleTypeDef *hdma) { // DMA半传输完成已填满半个缓冲区例如A的前半部分 // 此时可以安全处理另一个缓冲区B的后半部分如果已满 // 更常见的策略是在传输完成中断中切换整个缓冲区 } void HAL_ADC_ConvCpltCallback(DMA_HandleTypeDef *hdma) { // ADC DMA传输完成中断整个缓冲区填满 // 1. 将 cpu_current_process_buf 指向刚刚被DMA填满的缓冲区 cpu_current_process_buf (adc_current_target_buf adc_buf_A) ? adc_buf_A : adc_buf_B; // 2. 切换DMA的目标到另一个缓冲区 adc_current_target_buf (adc_current_target_buf adc_buf_A) ? adc_buf_B : adc_buf_A; // 重新配置DMA目标地址HAL库中在循环模式下通常不需要手动重配这里示意逻辑 // __HAL_DMA_SET_COUNTER(hdma_adc, BUF_SIZE); // if(adc_current_target_buf adc_buf_A) { // __HAL_DMA_SET_MEMORY_ADDR(hdma_adc, (uint32_t)adc_buf_A); // } else { // __HAL_DMA_SET_MEMORY_ADDR(hdma_adc, (uint32_t)adc_buf_B); // } } // 主循环或定时中断中 void Process_Data() { if(cpu_current_process_buf ! NULL) { for(int i0; iBUF_SIZE; i) { // 1. 从ADC缓冲区读取原始数据 uint32_t raw_adc_value cpu_current_process_buf[i]; // 2. 进行算法处理例如放大2倍并限制在0-4095 uint32_t processed_value raw_adc_value * 2; if(processed_value 4095) processed_value 4095; // 3. 写入到DAC的输出缓冲区对应位置 // (这里需要根据双缓冲逻辑判断写入哪个DAC缓冲区的哪个位置代码略复杂需同步DAC DMA的缓冲区索引) // dac_output_buf[write_index] processed_value; } cpu_current_process_buf NULL; // 处理完成释放缓冲区 } } // 同样地DAC DMA也需要配置类似的完成中断来切换其数据源缓冲区。这个框架是一个高度简化的示意真实实现中需要精细地管理缓冲区索引和同步标志可能使用环形缓冲区和读写指针会更清晰。但它清晰地展示了ADC、DMA、CPU、DMA、DAC如何协同工作构成一个高效的数据流管道。7. 调试技巧与常见问题排查实录即使配置看起来完美实际调试中依然会遇到各种问题。下面是我总结的一些常见“症状”和“药方”。7.1 ADC采样值不准或跳动大检查清单参考电压测量VREF引脚电压是否稳定在3.3V或你使用的值。噪声是否过大采样时间对于高阻抗源如温度传感器NTC分压电路将采样时间调到最大如480个周期试试。信号源阻抗用示波器查看ADC输入引脚的实际波形是否干净如果信号源阻抗太高可以增加一个电压跟随器运放进行缓冲。电源去耦AVDD和VREF引脚附近的0.1μF和1-10μF电容是否焊接良好布局是否靠近引脚软件滤波即使硬件有噪声一个简单的滑动平均滤波也能让读数稳定下来。7.2 DMA传输不启动或数据不对现象ADC/DAC配置好了DMA也启动了但内存里没有数据或者全是0。排查步骤时钟使能首先确认DMA控制器的时钟已经使能__HAL_RCC_DMA1_CLK_ENABLE()。CubeMX生成的代码通常包含这个但自己写寄存器时容易漏。流与通道匹配双击检查CubeMX中是否为ADC1选择了正确的DMA流和请求通道Channel。对照数据手册的映射表核对。传输完成中断在DMA初始化后、启动外设DMA之前先使能DMA流的传输完成中断__HAL_DMA_ENABLE_IT(hdma, DMA_IT_TC)并在中断回调函数里设置一个标志或翻转一个测试引脚。这是判断DMA是否真的在工作的最直接方法。内存地址检查传递给HAL_ADC_Start_DMA的缓冲区地址是否有效。如果是局部数组确保其生命周期。数据对齐与宽度确认DMA配置的数据宽度Word/Half Word/Byte与你的缓冲区元素类型uint32_t/uint16_t/uint8_t以及外设数据寄存器宽度是否匹配。7.3 DAC无输出或波形失真现象DAC引脚没有电压变化或者输出的波形频率、幅度不对。排查步骤引脚复用确认DAC输出引脚如PA4, PA5是否正确配置为模拟模式Analog而不是推挽输出等数字模式。触发源如果使用硬件触发确认定时器是否已经启动HAL_TIM_Base_Start()。用示波器查看定时器的触发输出引脚如果有或使用调试器查看定时器计数寄存器是否在变化。DMA传输参考上一条确认DAC的DMA传输是否正常发生。可以在DAC DMA传输完成中断里翻转引脚测试。输出缓冲与负载如果禁用内部缓冲器必须外接运放。如果使能内部缓冲器注意其驱动能力有限约几十mA且输出电压范围受限。接一个过重的负载会导致波形削顶或变形。波形表数据检查你预计算的波形表数据是否正确。可以用调试器查看数组内存里的值或者通过串口打印出来验证。确保数据没有超出DAC的数据范围如0-4095。7.4 系统运行一段时间后卡死可能原因DMA传输完成中断服务程序ISR处理时间过长或者发生了中断嵌套冲突。解决方案中断优化遵循“快进快出”原则。在DMA中断回调函数中只做最必要的操作如设置标志位、切换缓冲区指针。复杂的处理如滤波、算法放到主循环中基于标志位去执行。中断优先级如果系统中有多个中断如ADC、DAC、串口、定时器需要合理配置它们的抢占优先级和子优先级。确保高实时性要求的中断如定时器触发能及时响应。缓冲区溢出检查你的数据处理速度是否跟得上数据产生速度。如果CPU处理一个缓冲区数据的时间超过了DMA填满一个缓冲区的时间就会导致数据被覆盖。解决方法是增大缓冲区大小、提高CPU主频、优化处理算法或降低采样率。调试这类多外设协同的系统逻辑分析仪和示波器是必不可少的。用逻辑分析仪同时抓取定时器触发信号、ADC转换完成信号和DMA传输完成中断对应的GPIO翻转信号可以非常直观地看到整个数据流的时序关系快速定位是哪个环节出现了延迟或停滞。
返回列表