首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ESP32 +深度睡眠+ I2C中断问题

ESP32 +深度睡眠+ I2C中断问题
EN

Stack Overflow用户
提问于 2019-03-22 08:08:21
回答 1查看 933关注 0票数 1

我在中断模式下执行深度睡眠和i2c通信时遇到问题。

我使用这个库在Arduino IDE中对其进行编码:

https://github.com/espressif/arduino-esp32

https://techtutorialsx.com/2017/09/30/esp32-arduino-external-interrupts/

当我在void loop()函数中运行它时,它在i2c上工作得很好(比如打开发光二极管),但是当我把它移植到中断时,它就不能工作了。

与深度睡眠一样,我不能在中断模式下执行它。我绕过它的方法是在中断模式下设置一个标志,以表明我想要深度睡眠,然后在void loop()函数中执行它。

有没有人有任何解决方案来解决这个问题呢?(代码仅适用于i2c和esp32)

代码语言:javascript
复制
#include <Wire.h>

#if defined(ARDUINO_ARCH_SAMD)
// for Zero, output on USB Serial  console, remove line below if using programming port to program the Zero!
   #define Serial SerialUSB
#endif

// Interrupt Setup - TIMER
hw_timer_t * timer = NULL; //configure the timer, need pointer to a variable type of hw_timer_t
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; // used to sync main loop and ISR
RTC_DATA_ATTR bool should_sleep = false;

// Setting ADC Properties - BATTERY
int voltage_amplifier = 0; 
int battery_percentage = 0; 

// Set i2c Address - I/O EXPANDER
const int address = 0x20;
uint16_t led_status = word(B11111111,B11111111);

// INTERRUPT MODE - INSERT INBETWEEN portENTER and portEXIT
void IRAM_ATTR onTimer() {
  portENTER_CRITICAL_ISR(&timerMux);
  // led_battery();        led doesn't update if used here
  portEXIT_CRITICAL_ISR(&timerMux);
}

void led_battery(){
    voltage_amplifier = analogRead(34);
    Serial.println(voltage_amplifier);
    int bit_max = 4096;
    int battery_percentage = voltage_amplifier*100/bit_max;

    // If battery is below 20%
    if (battery_percentage <= 20){
      led_status &= word(B00111111,B11111111); // clearing the bits that we want to change whilst preserving the other unchanged bits
      led_status |= ~word(B11000000,B00000000); // setting up the bits that we want to change
      pf575_write(led_status);
    }

    else if (battery_percentage <= 40){
      led_status &= word(B00011111,B11111111); // clearing the bits that we want to change whilst preserving the other unchanged bits
      led_status |= ~word(B11100000,B00000000); // setting up the bits that we want to change
      pf575_write(led_status);
    }

    else if (battery_percentage <= 60){
      led_status &= word(B00001111,B11111111); // clearing the bits that we want to change whilst preserving the other unchanged bits
      led_status |= ~word(B11110000,B00000000); // setting up the bits that we want to change
      pf575_write(led_status);
    }

    else if (battery_percentage <= 80){
      led_status &= word(B00000111,B11111111); // clearing the bits that we want to change whilst preserving the other unchanged bits
      led_status |= ~word(B11111000,B00000000); // setting up the bits that we want to change
      pf575_write(led_status);
    }

    else if (battery_percentage <= 100){
      led_status &= word(B00000011,B11111111); // clearing the bits that we want to change whilst preserving the other unchanged bits
      led_status |= ~word(B11111100,B00000000); // setting up the bits that we want to change
      pf575_write(led_status);
    }
}

void ioexpander_setup(){
  while (!Serial);             // Leonardo: wait for serial monitor
  Serial.println("\n Blinker Ready");
  Wire.begin();
}

void pf575_write(uint16_t data) {
  Wire.beginTransmission(address);
  Wire.write(lowByte(data));
  Wire.write(highByte(data));
  Wire.endTransmission();
}

void timer_setup(){
  // Base Clock Frequency = 80MHz ; Timer Frequency = 1MHz | Clock Cycle = 1us [in this case]
  timer = timerBegin(0,80,true); // return a pointer to a structure of type hw_timer_t

  // Timer binded to a handling function
  timerAttachInterrupt(timer, &onTimer, true); // Parameter : (timer_initialization, address_interrupt,flag_to_activate - true(edge)/false(level))

  // Specify the counter value in which the timer interrupt will be generated (set every 10 ms)
  timerAlarmWrite(timer, 10000, true); // Parameter : (timer_initialization, when_to_interrupt (us), flag_to_reload)

  // Enable the timer
  timerAlarmEnable(timer);
}

void setup() {
  Serial.begin(115200);

  // IO Expander
  ioexpander_setup();

  // Timer
  timer_setup();

}

void loop() {  
  led_battery();    //led update if used here
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-03-23 05:43:39

当你从中断处理程序调用led_battery()时,你在那里做了太多的工作。

中断可以中断任何没有锁定中断的东西。

假设您的代码正在使用Serial输出某些内容,并且发生了计时器中断。现在你的代码在Serial内部的某个地方运行,你再次调用Serial ...而软件和硬件可能处于不一致的状态。

这是从中断处理程序进行的每个子例程和硬件访问的情况。防止这种情况的唯一方法是在您的代码可能正在访问硬件或修改数据结构时禁用中断。

不幸的是,禁用中断很容易出错--如果你忘记这样做,你会发生神秘的崩溃。如果你忘记重新启用它们,你就有大麻烦了--你的网络、定时器和串行都会停止工作。这也给你的代码增加了很多开销。而且它会降低您的整体系统性能-它将延迟或导致您错过网络和计时器事件。您可以从串行端口删除字符。您可以肯定的是,Arduino核心中的任何代码都不会为您做这件事。

因此,长话短说,锁定中断以便您可以在中断处理程序中做很多事情是不切实际的。

您还希望最小化在中断处理程序中花费的时间,因为这会抢占网络堆栈、计时器、串行和其他硬件处理,并可能会阻塞其他

您在最初的帖子中指出了我们处理此问题的方法:在中断处理程序中设置一个标志(确保它是volatile),并在任务中处理它。除非你真的,真的知道你在做什么,你的系统中所有的软件是如何工作的,这是处理这个问题的唯一实用的方法。如果你试图做大量的工作,并从中断处理程序调用你正在调用的东西,你的程序将会出现故障和崩溃。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55290996

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档