Arduino如何计算对象数组内的外部中断?

时间:2018-01-03 09:54:06

标签: c++ arduino interrupt-handling esp32

问题

我开始玩Arduino IoT(ESP32)。我从SD卡上的文件中读取GPIO配置。外部中断有问题。我需要计算给定GPIO上的中断数。

我编写了一个存储GPIO配置的类,并将此类的对象放在全局数组中。如何计算给定引脚上的中断,以便通过使用适当的对象方法获得结果?

我尝试了不同的解决方案,但问题在于ISR方法,它必须是静态的。此方法无法访问对象字段,因此我不知道在何处以及如何增加中断计数器。

我将代码分成了几个文件。我只附加了解决这个问题的必要条件。

这就是我的项目。请帮忙。

主档案:

#define GPIO_CONFIG_FILE "cfg/gpio.txt"
#define WIFI_AP_CONFIG_FILE "cfg/ap.txt"
#define WIFI_STA_CONFIG_FILE "cfg/sta.txt"
#define AVAILABLE_GPIO_CNT 7
#define LED_BUILTIN_OLIMEX 33
#define BTN_BUILTIN_OLIMEX 34

#include "FS.h"
#include "SD_MMC.h"
#include "GPIO_CONFIG.h"

GPIO_CONFIG gpio[AVAILABLE_GPIO_CNT];
uint32_t gpio_int_cnt[AVAILABLE_GPIO_CNT] = {0};

void setup() {
  if (checkSdCard()) {
    setUpPinsFromFile(GPIO_CONFIG_FILE);
  }
}

void loop() {
}

GPIO_CONFIG.h

#ifndef GPIO_CONFIG_h
#define GPIO_CONFIG_h

#include "Arduino.h"
#define ID_LENGTH 7

class GPIO_CONFIG {
  public:
    GPIO_CONFIG();
    void setUp(const char * key);
    void printConfig();
    uint8_t number();
    uint8_t mode();
    uint16_t multiplier();
    bool inversion();
    char * id();
    static void isr();
    static uint32_t int_cnt();

  private:
    uint8_t gp_number;
    uint8_t gp_mode;
    uint16_t gp_multiplier;
    uint32_t gp_init_value;
    bool gp_inversion;
    char gp_id[ID_LENGTH];
    //    const uint8_t gp_mode_array[4] = {INPUT, OUTPUT, INPUT_PULLUP};
};
#endif

GPIO_CONFIG.cpp

#include "GPIO_CONFIG.h"
GPIO_CONFIG::GPIO_CONFIG() {
  gp_number = 0;
  gp_multiplier = 1;
  gp_inversion = false;
  gp_init_value = 0;
}

void GPIO_CONFIG::setUp(const char * key) {
  //nr|id|name|mode|multi|inv|init
  char cfg[sizeof(key)];
  for (uint8_t b = 0; b < sizeof(key); ++b) {
    cfg[b] = key[b];
  }

  //PIN_NUMBER
  char * tok = strtok(cfg, "|");
  gp_number = atoi(tok);

  //ID
  tok = strtok(NULL, "|");
  for (int b = 0; b < sizeof(tok); b++) {
    if (b < ID_LENGTH) {
      gp_id[b] = tok[b];
    } else {
      break;
    }
  }
  gp_id[ID_LENGTH - 1] = '\0';

  //NAME
  strtok(NULL, "|");

  //MODE
  tok = strtok(NULL, "|");
  gp_mode = atoi(tok);

  //MULTIPLIER
  tok = strtok(NULL, "|");
  gp_multiplier = atoi(tok);

  //INVERSION
  tok = strtok(NULL, "|");
  gp_inversion = (atoi(tok) > 0);

  //INITIAL VALUE
  tok = strtok(NULL, "|");
  gp_init_value = atoi(tok);

  //0-in; 1-out; 2-int
  if (gp_mode != 1) {
    if (gp_inversion) { //sterowanie podstawowe przez vcc
      pinMode(gp_number, INPUT_PULLUP);
    } else {
      pinMode(gp_number, INPUT);
    }
    if (gp_mode > 2) {
      attachInterrupt(digitalPinToInterrupt(gp_number), isr, FALLING);
    }
  } else {
    pinMode(gp_number, OUTPUT);
  }
}

void GPIO_CONFIG::printConfig() {
#ifdef DEBUG
  Serial.print("GPIO_CONFIG:");
  Serial.print(" -no:");
  Serial.print(gp_number);
  Serial.print(" -id:");
  Serial.print(gp_id);
  Serial.print(" -mode:");
  Serial.print(gp_mode);
  Serial.print(" -multi:");
  Serial.print(gp_multiplier);
  Serial.print(" -inv:");
  Serial.print(gp_inversion);
  Serial.println("");
#endif
}

uint8_t GPIO_CONFIG::number() {
  return gp_number;
}

uint8_t GPIO_CONFIG::mode() {
  return gp_mode;
}

uint16_t GPIO_CONFIG::multiplier() {
  return gp_multiplier;
}

bool GPIO_CONFIG::inversion() {
  return gp_inversion;
}

char * GPIO_CONFIG::id() {
  return gp_id;
}

void GPIO_CONFIG::isr() {
//  gpio_int_cnt[0]++;
}

uint32_t GPIO_CONFIG::int_cnt() {
//  return gpio_int_cnt[0];
}

@EDIT 2018/01/04 08:10 我在文件中添加了一些更改:

主.ino文件

isr_ptr isrptr[AVAILABLE_GPIO_CNT];

GPIO_CONFIG.h

#define AVAILABLE_GPIO_CNT 7

class GPIO_CONFIG;
typedef /*static*/ void (*isr_ptr)();
extern isr_ptr isrptr[AVAILABLE_GPIO_CNT];
extern GPIO_CONFIG gpio[AVAILABLE_GPIO_CNT];

(...)

public:
  void setIndex(const uint8_t * i);
  uint8_t index();

(...)

private:
  uint8_t gp_index;
  uint32_t gp_cnt_value;

GPIO_CONFIG.cpp

void GPIO_CONFIG::setIndex(const uint8_t * i){
  gp_index = *i;
  isrptr[gp_index] = &isr;
}

uint8_t GPIO_CONFIG::index(){
  return gp_index;
}

void GPIO_CONFIG::setUp(const char * key) {
  (...)
  attachInterrupt(digitalPinToInterrupt(gp_number), isrptr[gp_index], FALLING);
  (...)
}

void GPIO_CONFIG::isr() {
  for(uint8_t i=0; i<AVAILABLE_GPIO_CNT; ++i){
    if(&isrptr[i] == &gpio[i].isr()){ //here is my actualy problem. how can i compare this?
      gpio[i].increment_cnt_value();
      break;
    }
  }
}

uint32_t GPIO_CONFIG::int_cnt() {
  return gp_cnt_value;
}

这里我放置了需要修改的短片段:

GPIO_CONFIG.cpp

isrptr[gp_index] = &isr;isrptr[gp_index] = isr;

if(&isrptr[i] == &gpio[i].isr){if(isrptr[i] == gpio[i].isr){

1 个答案:

答案 0 :(得分:0)

我已多次查看您的代码,无法找到您的ISR。我知道如何在简单的C代码中处理这类问题:您只需为每个中断引脚定义一个包含一个元素的数组,并从其各自的ISR中增加该元素。我不知道如何将其与你所展示的内容联系起来。

经常导致问题的部分是您通常需要将主代码和ISR之间共享的变量定义为volatile。由于编译器优化了它决定不改变的东西(在ISR或主代码中),因此未能做到这一点会导致很难找到的问题。

致以最诚挚的问候,