嵌入式面试高频题第5弹:DMA原理、看门狗机制、低功耗模式,这3个搞不懂简历直接被筛

嵌入式面试中DMA、看门狗、低功耗是必考三大件。本文从原理到代码到面试话术一网打尽,附追问预判和回答模板。

面试官:"你用过DMA吗?说说它和中断传输有什么区别?"

你:"呃...DMA就是...不用CPU?"

面试官:(微笑,低头写了个C)

别笑,这是真实发生过的。 DMA、看门狗、低功耗这三样东西,面试问到的概率极高------因为它们代表了嵌入式开发的三个核心能力:效率、可靠性、功耗管理

这篇文章帮你把这三个知识点讲透,附带面试追问预判和回答模板。

💬 你面试被问过这三个问题吗?评论区说说你被问懵的瞬间!


1. DMA(Direct Memory Access)

问题:什么是DMA?和中断传输有什么区别?

回答

DMA是直接内存访问 ,它允许外设和内存之间直接搬运数据,不需要CPU参与每一个字节的传输

对比三种数据传输方式:

复制代码
┌─────────────────────────────────────────────────────────┐
│  方式1:轮询(Polling)                                    │
│  CPU一直在等,干不了别的事                                    │
│  while(!flag);  ← CPU在这空转                              │
│  适合:数据量小、对实时性要求不高                               │
├─────────────────────────────────────────────────────────┤
│  方式2:中断(Interrupt)                                   │
│  每传完一个字节/一组数据,中断通知CPU                           │
│  CPU被打断 → 保存现场 → 处理 → 恢复现场                      │
│  适合:数据量中等、需要CPU及时响应                             │
├─────────────────────────────────────────────────────────┤
│  方式3:DMA                                                │
│  DMA控制器直接搬运,CPU完全不参与                              │
│  搬完了才通知CPU(一次中断)                                   │
│  适合:大数据量、高速传输(ADC连续采集、串口大批量、SPI刷屏)      │
└─────────────────────────────────────────────────────────┘

一句话总结:轮询是CPU一直盯着,中断是搬一个叫一次CPU,DMA是全搬完了才叫CPU。

面试官可能的追问

Q:DMA传输的具体流程是什么?

  1. CPU配置DMA源地址、目标地址、传输长度、传输方向
  2. CPU启动DMA传输,然后去干别的事
  3. DMA控制器逐字节/半字/字搬运数据
  4. 传输完成后,DMA产生一个中断通知CPU
  5. CPU在中断回调中处理数据

Q:DMA有什么限制?

  • DMA只能在内存和外设之间 、或内存和内存之间搬运数据,不能做计算
  • DMA需要占用总线,频繁使用会和CPU争抢总线带宽
  • 源地址和目标地址必须在同一地址空间

Q:你在项目中怎么用DMA的?

"我在做ADC连续采集时用了DMA。ADC每采完一轮(比如8个通道),DMA自动把结果搬到内存数组,不用CPU逐个读取。配合定时器触发ADC,实现了精确的周期性采样,CPU空出来做数据滤波和通信。"

代码示例:ADC+DMA连续采集(CubeMX配置+HAL库)

c 复制代码
/* CubeMX配置:
   - ADC1: 连续扫描模式,扫描3个通道
   - DMA: ADC1 → Memory, Circular模式, Half-Word
*/

#define ADC_CHANNELS  3
uint16_t adc_buffer[ADC_CHANNELS];  /* DMA搬运目标 */

/* 启动ADC+DMA采集 */
HAL_ADC_Start_DMA(&hadc1, (uint32_t *)adc_buffer, ADC_CHANNELS);

/* DMA传输完成回调------一轮采集完成 */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) {
    if (hadc->Instance == ADC1) {
        /* 此时 adc_buffer[0]~[2] 已经是最新数据 */
        float voltage_ch0 = adc_buffer[0] * 3.3f / 4096;
        float voltage_ch1 = adc_buffer[1] * 3.3f / 4096;
        float voltage_ch2 = adc_buffer[2] * 3.3f / 4096;

        printf("ADC: %.2fV | %.2fV | %.2fV\r\n",
               voltage_ch0, voltage_ch1, voltage_ch2);
    }
}

2. 看门狗(Watchdog)

问题:什么是看门狗?为什么需要它?

回答

看门狗本质是一个定时器 ,如果你不在规定时间内"喂狗"(重置计数器),它就会强制复位整个系统

复制代码
正常运行:
  CPU ──▶ 正常工作 ──▶ 喂狗 ──▶ 正常工作 ──▶ 喂狗 ──▶ ...
  看门狗:  计数→0    重新计数     计数→0    重新计数
                                      ✅ 系统不死

程序跑飞:
  CPU ──▶ 死循环/卡死 ──▶ 没人喂狗 ──▶ 计数到0 ──▶ 复位!
  看门狗:  计数→0                        🔥 强制重启

为什么需要看门狗? 嵌入式系统可能跑在无人值守的环境(工业控制、户外设备),程序死机了没人按重启按钮。看门狗就是自动重启机制,保证系统在异常时能恢复。

STM32的两种看门狗

对比项 IWDG(独立看门狗) WWDG(窗口看门狗)
时钟源 LSI(~40kHz,内部RC) APB1时钟
精度 较低(LSI有±30%偏差) 较高
喂狗限制 任何时候都可以喂 必须在"窗口"内喂,太早太晚都复位
适用场景 防死机、基本保护 对时序有严格要求的场合
典型超时 100ms ~ 26s 几ms ~ 几十ms

面试官可能的追问

Q:IWDG和WWDG的核心区别是什么?

IWDG只要在超时前喂狗就行,喂早了没事 。WWDG有"窗口"概念------必须在计数器降到某个值之前、又不能太早喂,喂早了也复位。WWDG能检测到程序"跑得太快"(不正常地频繁喂狗)。

Q:在FreeRTOS中怎么用看门狗?

"我会创建一个专门的看门狗任务,优先级设最高。这个任务通过任务通知等待其他关键任务的'心跳'信号。只有当所有关键任务都正常运行并发送了心跳,才喂狗。任何一个任务卡死,看门狗就不会被喂,系统自动复位。"

代码示例:IWDG + FreeRTOS多任务看门狗

c 复制代码
/* CubeMX配置:
   - IWDG: 预分频=64, 重载值=625 → 超时 ≈ 1s
*/

/* FreeRTOS任务心跳标志 */
#define TASK_COUNT  3
volatile uint8_t task_alive[TASK_COUNT] = {0};

/* 各任务中定期发送心跳 */
void sensor_task(void *param) {
    while (1) {
        /* 执行传感器读取... */
        task_alive[0] = 1;  /* 标记"我还活着" */
        vTaskDelay(pdMS_TO_TICKS(200));
    }
}

void comm_task(void *param) {
    while (1) {
        /* 执行通信处理... */
        task_alive[1] = 1;
        vTaskDelay(pdMS_TO_TICKS(300));
    }
}

void display_task(void *param) {
    while (1) {
        /* 执行显示刷新... */
        task_alive[2] = 1;
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}

/* 看门狗任务------优先级最高 */
void watchdog_task(void *param) {
    while (1) {
        vTaskDelay(pdMS_TO_TICKS(800));  /* 在超时前检查 */

        uint8_t all_alive = 1;
        for (int i = 0; i < TASK_COUNT; i++) {
            if (!task_alive[i]) {
                printf("[WDG] 任务 %d 卡死!准备复位...\r\n", i);
                all_alive = 0;
                break;  /* 不喂狗,等复位 */
            }
            task_alive[i] = 0;  /* 清标志,下一轮重新检测 */
        }

        if (all_alive) {
            HAL_IWDG_Refresh(&hiwdg);  /* 喂狗 */
        }
    }
}

3. 低功耗模式

问题:STM32有哪些低功耗模式?怎么选?

回答

STM32有三种低功耗模式,功耗从低到高:

复制代码
┌───────────────────────────────────────────────────────────┐
│  Sleep(睡眠)                                              │
│  • CPU停止,外设继续运行                                      │
│  • 任意中断唤醒                                               │
│  • 功耗:~mA级                                               │
│  • 适合:等数据的时候让CPU歇会儿                                 │
├───────────────────────────────────────────────────────────┤
│  Stop(停止)                                                │
│  • CPU停止,大部分时钟关闭                                      │
│  • 只有EXTI(外部中断)能唤醒                                   │
│  • 功耗:~几十μA                                              │
│  • 适合:电池供电设备,长时间等待外部事件                           │
├───────────────────────────────────────────────────────────┤
│  Standby(待机)                                             │
│  • 几乎全关,只保留唤醒电路                                      │
│  • WKUP引脚 / RTC闹钟 / 看门狗唤醒                             │
│  • 功耗:~几μA(最低)                                        │
│  • 适合:极端省电,类似"关机但能定时醒来"                          │
└───────────────────────────────────────────────────────────┘

面试官可能的追问

Q:Stop模式和Standby模式的核心区别?

Stop模式保留了SRAM和寄存器的内容,唤醒后从断点继续执行 。Standby模式会清空大部分寄存器,唤醒后相当于系统复位,从main函数重新开始。所以Stop模式适合需要保持状态的场景,Standby适合对功耗极致敏感的场景。

Q:FreeRTOS中怎么实现低功耗?

"FreeRTOS提供了Tickless Idle模式。当所有任务都阻塞时(都在等vTaskDelay或信号量),调度器会自动进入Sleep/Stop模式,并在下一个任务唤醒时间点之前醒来。这样CPU空闲的时间段就被低功耗模式覆盖了,而不是空转。"
进阶补充:在FreeRTOSConfig.h中开启:

c 复制代码
#define configUSE_TICKLESS_IDLE    1

还可以重写 portSUPPRESS_TICKS_AND_SLEEP() 函数,自定义进入哪种低功耗模式。

Q:低功耗设计中有哪些常见坑?

  1. 唤醒源没配对:进Stop模式前要确保EXTI中断配置正确,否则醒不过来
  2. 外设时钟被关了:Stop模式会关HSI/HSE,唤醒后需要重新配置时钟
  3. 串口还在发数据 :进低功耗前要等串口发送完成(__HAL_UART_FLUSH_DRREGISTER
  4. DMA还在跑:进低功耗前停止DMA传输,否则数据会丢

代码示例:Stop模式 + RTC唤醒

c 复制代码
/* CubeMX配置:
   - RTC: 唤醒定时器,内部时钟
   - 按键: PA0 → EXTI0,下降沿触发(唤醒源之一)
*/

/* 进入Stop模式,RTC 10秒后唤醒 */
void enter_stop_mode(void) {
    /* 1. 确保串口发送完成 */
    while (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TC) == RESET);

    /* 2. 配置RTC唤醒定时器(10秒) */
    HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 10, RTC_WAKEUPCLOCK_CK_SPRE_16BITS);

    /* 3. 进入Stop模式 */
    printf("进入Stop模式,10秒后或按键唤醒...\r\n");
    HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);

    /* 4. 被唤醒后从这里继续执行 */
    SystemClock_Config();  /* 重新配置时钟 */
    printf("已唤醒!\r\n");
}

/* 唤醒后会进入RTC Wakeup中断或EXTI中断 */
void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc) {
    /* RTC唤醒,什么都不做,程序会从HAL_PWR_EnterSTOPMode之后继续 */
}

总结:三个知识点怎么串起来理解?

复制代码
┌───────────┐    ┌───────────┐    ┌───────────┐
│   DMA     │    │  看门狗    │    │  低功耗    │
│   效率    │    │  可靠性    │    │  功耗      │
│           │    │           │    │           │
│ CPU不搬砖  │    │ 程序死了   │    │ CPU闲着    │
│ 让DMA干   │    │ 自动重启   │    │ 就去睡觉   │
└─────┬─────┘    └─────┬─────┘    └─────┬─────┘
      │               │               │
      └───────────────┼───────────────┘
                      ▼
              一个优秀的嵌入式系统:
              高效(DMA)+ 可靠(看门狗)+ 省电(低功耗)

面试回答模板:先说是什么 → 再说为什么需要 → 最后说你在哪里用过。有项目经验加分巨大。


📌 下期预告:嵌入式面试高频题第6弹------SPI vs I2C对比、Flash读写、Bootloader原理

👉 关注我不迷路,持续更新嵌入式面试题 + FreeRTOS笔记

💬 评论区来聊聊:

  • DMA、看门狗、低功耗这三个,你最熟的是哪个?
  • 面试中有没有被问到过"低功耗怎么设计"这种开放题?
  • 你用过看门狗吗?遇到过什么坑?
相关推荐
AI人工智能+电脑小能手1 小时前
【大白话说Java面试题 第93题】【Mysql篇】第23题:从查找速度来看,聚集索引和非聚集索引哪个更快?
java·开发语言·数据库·mysql·面试
浮午3 小时前
字节AI Agent开发面试全解析:15道高频问题+深度答案
人工智能·面试·职场和发展
JustHappy3 小时前
古法编程秘籍(四):函数究竟是什么?把函数最重要的能力一次讲清楚
前端·后端·面试
Byron__3 小时前
RabbitMQ 面试核心精讲
java·面试·rabbitmq
卷帘依旧3 小时前
setState是同步的还是异步的
前端·面试
卷帘依旧3 小时前
讲一下useEffect和useLayoutEffect
前端·面试
JAVA面经实录9174 小时前
MQ高频面试题标准答案(Java后端/架构面试背诵版)
java·面试·架构·kafka·rabbitmq
QING6184 小时前
Android面试 —— 八股文之app启动流程
android·面试·app
叶修_A4 小时前
【CP-11】复杂驱动设计 - AUTOSAR CP驱动架构与实现
架构·嵌入式·autosar·cp·驱动设计