Я начинаю играть с Arduino IoT (ESP32). Я прочитал конфигурацию GPIO из файла на SD-карте. У меня проблема с внешними прерываниями. Мне нужно посчитать количество прерываний для данного 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){
Я просмотрел ваш код несколько раз и не могу найти ваш ISR. Я знаю, как справиться с такой проблемой в простом C-коде: вы просто определяете массив с одним элементом для каждого контакта прерывания и увеличиваете этот элемент из соответствующего ISR. Я не знаю, как связать это с тем, что вы показали.
Часть, которая часто вызывает проблемы, состоит в том, что вам обычно нужно определить переменные, общие для основного кода и ISR, как volatile. Невыполнение этого требования может вызвать проблемы, которые действительно трудно найти из-за того, что компилятор оптимизирует все, что он решает, не изменилось (в ISR или основном коде).
С наилучшими пожеланиями,
Других решений пока нет …