You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ATtiny816(MegaTinyCore)待机模式比较器中断唤醒失效求助

ATtiny816待机模式下比较器唤醒方案(Arduino + MegaTinyCore)

问题背景

在Arduino平台使用MegaTinyCore驱动ATtiny816时,需实现基于内置比较器的压电敲击检测休眠唤醒方案。已完成比较器配置(可正常触发tapInterrupt中断),但将芯片置于待机模式后,比较器中断无法触发。

查阅ATtiny816手册得知:待机模式下AC默认禁用,即使设置ACn.CTRLA的RUNSTDBY位为1,若无其他模块请求CLK_PER时钟,AC不会更新状态寄存器,仅能更新事件和引脚输出,无法产生中断。尝试过PIT轮询(响应性不足)、启用RTC(未解决问题),现需解决待机模式下比较器持续触发中断且低功耗的配置方法,并明确RUNSTDBY位的作用。

解决方案

一、核心模块选择原理

要实现待机模式下比较器触发中断,有两种低功耗方案:

  • 事件系统唤醒(最优低功耗):利用ATtiny816事件系统,让比较器触发事件直接唤醒芯片,无需CLK_PER时钟,功耗最低。
  • 保持CLK_PER运行(兼容原有中断逻辑):启用低功耗模块(如RTC PIT)持续请求CLK_PER,让AC能更新状态寄存器并产生中断,功耗略高于事件方案,但适配现有中断代码。

优先推荐事件系统方案,符合低功耗设计需求。

二、Arduino具体配置代码

方案1:事件系统唤醒(最优低功耗)

此方案无需依赖CLK_PER,直接通过比较器事件触发芯片唤醒,中断逻辑在唤醒后执行:

#include <Comparator.h>
#include <avr/io.h>
#include <avr/sleep.h>

void tapInterrupt() {
  // 唤醒后的中断处理逻辑
  // 示例:触发LED、读取传感器等
}

void setup() {
  // 1. 配置比较器参数
  Comparator.input_p = comparator::in_p::in0;
  Comparator.reference = comparator::ref::vref_0v55;
  Comparator.input_n = comparator::in_n::vref;
  Comparator.hysteresis = comparator::hyst::large;
  Comparator.init();
  
  // 2. 绑定比较器输出到事件系统,设置事件为唤醒源
  EVSYS.CHANNEL0 = EVSYS_CHANNEL0_AC0_OUT_gc; // AC0输出映射到事件通道0
  EVSYS.USER_WAKEUP = EVSYS_USER_CHANNEL0_gc; // 事件通道0作为芯片唤醒源
  
  // 3. 配置AC待机运行+低功耗模式,启用事件输出
  AC_t& AC_struct = Comparator.getPeripheral();
  AC_struct.CTRLA |= AC_LPMODE_bm | AC_RUNSTDBY_bm;
  AC_struct.EVCTRL |= AC_EVOUT_bm;
  
  // 4. 启用待机模式唤醒功能
  SLPCTRL.CTRLA = SLPCTRL_SMODE_STDBY_gc | SLPCTRL_SEN_bm;
  
  // 5. 启动比较器
  Comparator.start();
  
  // 6. 配置唤醒后执行的中断(可选,根据需求调整引脚)
  attachInterrupt(digitalPinToInterrupt(0), tapInterrupt, RISING);
}

void loop() {
  // 进入待机模式
  wdt_disable();
  set_sleep_mode(SLEEP_MODE_STANDBY);
  sleep_enable();
  sleep_cpu();
  sleep_disable();
  
  // 唤醒后执行逻辑(可直接调用tapInterrupt或自定义)
  tapInterrupt();
}

方案2:保持CLK_PER运行(兼容原有中断)

若需保留原比较器中断逻辑,需启用RTC PIT持续请求CLK_PER,确保AC能更新状态寄存器产生中断:

#include <Comparator.h>
#include <avr/io.h>
#include <avr/sleep.h>

void tapInterrupt() {
  // 原有比较器中断处理逻辑
}

void setup() {
  // 1. 配置比较器(保留原有逻辑)
  Comparator.input_p = comparator::in_p::in0;
  Comparator.reference = comparator::ref::vref_0v55;
  Comparator.input_n = comparator::in_n::vref;
  Comparator.hysteresis = comparator::hyst::large;
  Comparator.init();
  Comparator.attachInterrupt(tapInterrupt, RISING);
  
  // 2. 配置AC待机运行+低功耗模式
  AC_t& AC_struct = Comparator.getPeripheral();
  AC_struct.CTRLA |= AC_LPMODE_bm | AC_RUNSTDBY_bm;
  
  // 3. 配置RTC PIT持续运行,请求CLK_PER
  while (RTC.STATUS > 0); // 等待寄存器同步
  RTC.CLKSEL = RTC_CLKSEL_INT32K_gc; // 使用内部32kHz超低功耗振荡器
  RTC.PITCTRLA = RTC_PERIOD_CYC1_gc | RTC_PITEN_bm; // 最短周期持续运行
  RTC.CTRLA = RTC_RUNSTDBY_bm; // RTC在待机模式保持运行
  
  // 4. 启动比较器
  Comparator.start();
}

void loop() {
  // 进入待机模式
  wdt_disable();
  set_sleep_mode(SLEEP_MODE_STANDBY);
  sleep_enable();
  sleep_cpu();
  sleep_disable();
}

注:此方案RTC PIT持续运行会增加少量功耗,但远低于芯片正常工作模式。

三、RUNSTDBY位的实际作用

ACn.CTRLA中的RUNSTDBY位核心作用:

  • 允许比较器在待机(Standby)模式下继续运行,而非被硬件自动关闭。
  • 它无法单独维持CLK_PER时钟:若没有其他模块请求CLK_PER,AC仅能执行基础比较操作,更新引脚输出和事件信号,但无法更新自身状态寄存器(如ACn.STATUS),因此无法触发硬件中断。
  • 仅当CLK_PER时钟运行时,AC才能更新状态寄存器并产生中断;若使用事件系统唤醒,则无需CLK_PER,RUNSTDBY仅需保证AC在待机模式下能生成事件信号。

内容的提问来源于stack exchange,提问作者KG-DROID

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 15:22:32