Wire SlaveReceiver : будет ли зарегистрированная функция в onRecieve прерывать/конфликтовать с блоком цикла?
В настоящее время я изучаю I2C, и я создал конфигурацию, в которой есть MasterWriter, который передает данные в SlaveReceiver, который будет хранить данные, полученные от Master, на SD-карту, а затем передавать ту же строку данных по GPRS на мой сервер.
Теперь новое требование должен какую-то систему кэширования, так что если GPRS не удалось передать, то вместо этого сохранить на SD карту под другим именем (в предыдущем шаге сохранения на SD-карту по-прежнему делается, но это для другой цели), поэтому, когда сигнал GSM необходимо восстановился он будет читать кэшированные/резервную копию данных, а затем передавать данные резервной копии. Таким образом, это означает, что я буду использовать блок цикла (который в настоящее время имеет только одну строку функции задержки).
Мой вопрос в том, будет ли запущенная функция "receiveEvent" зарегистрирована в настройке для проводного ведомого устройства :
Wire.onReceive(получатель);
конфликт с блоком текущего цикла, в котором система считывает резервные копии данных и отправляет резервные копии данных?
Вот мой код получателя рабов :
#define ONLINE_MODE 1 // turn on for GSM.
#define CACHE_MODE 1 // turn on for SD-based caching
#define I2C_MODE 1 // turn on for I2C mode SDA-SCL
#include <Arduino.h>
#include "Slave_GSM_SD.h"
#if ONLINE_MODE
// Sim900
#include "GSM.h"
SIM900 gprs;
#endif
#if I2C_MODE
#include <Wire.h>
#endif
#if CACHE_MODE
//SD Card
#include <SPI.h>
#include <SD.h>
#define DEBUG_SD 1
#define SD_CS_PIN 4
File cacheFile;
#endif
void setup()
{
console.begin(9600);
while (!console);
#if CACHE_MODE
//SD Card
Serial.print(F("Initializing SD card..."));
if (!SD.begin(SD_CS_PIN)) {
Serial.println(F("initialization failed!"));
while (1);
}
// open the file. note that only one file can be open at a time,
// so you have to close this one before opening another.
cacheFile = SD.open("CACHE.txt", FILE_WRITE);
Serial.println(F("SD Card initialization done."));
#endif
#if ONLINE_MODE
gprsSetup();
#endif
#if I2C_MODE
Wire.begin(8); // join i2c bus with address #8
Wire.onReceive(receiveEvent); // register event
#endif
console.println(F("SLAVE GSM SD READY"));
}
// function that executes whenever data is received from master
// this function is registered as an event, see setup()
// [Q] : will this interrupt/conflict with loop() if loop is still ongoing?
void receiveEvent(int howMany) {
#if DEBUG_I2C
Serial.print(F("available bytes : "));
Serial.print(howMany);
Serial.print(F(" or "));
Serial.println(Wire.available());
#endif
#if I2C_MODE
char jsonData[128]="";
while (Wire.available()) { // loop through all but the last
char c = Wire.read(); // receive byte as a character
int len = strlen(jsonData);
jsonData[len] = c;
jsonData[len+1] = '\0';
#if DEBUG_I2C
Serial.print(c); // print the character
#endif
if (c == '}'){
#if CACHE_MODE
writeToSd(jsonData);
#endif
#if ONLINE_MODE
gprsSequence(jsonData);
#endif
#if DEBUG_I2C
Serial.println(F("SAVING TRIGGERED"));
Serial.println(jsonData);
#endif
}
}
#endif
}
void writeToSd(char *jsonToWrite){
#if CACHE_MODE
// open the file. note that only one file can be open at a time,
// so you have to close this one before opening another.
cacheFile = SD.open("CACHE.txt", FILE_WRITE);
if (cacheFile) {
cacheFile.write(jsonToWrite);
cacheFile.close();
}
#if DEBUG_SD
Serial.println(F(" << "));
// re-open the file for reading:
cacheFile = SD.open("CACHE.txt");
if (cacheFile) {
Serial.println("CACHE.txt:");
// read from the file until there's nothing else in it:
while (cacheFile.available()) {
Serial.write(cacheFile.read());
}
// close the file:
cacheFile.close();
} else {
// if the file didn't open, print an error:
Serial.println(F("error opening CACHE.txt"));
}
#endif
#endif
}
void loop() {
// i wanted to code the cached-data sending here
delay(2000);
}
void gprsSetup() {
//... cleared for brevity
}
void gprsSequence(char *jsonData) {
//... cleared for brevity. the point is, this function is to send the jsonData by GPRS
}
@aharahap3112, 👍3
1 ответ
Как правило, функция обратного вызова onReceive вызывается из ISR в
проводной
библиотеке. Это означает, что никакие другие прерывания не могут быть обработаны в течение этого времени. По этой причине ISR всегда должен быть как можно короче. Запись на SD-карту-довольно длительный процесс, и он также использует прерывания, поэтому при использовании в ISR он может блокироваться навсегда (хотя я не уверен, так как я не просматривал библиотеку SD). Вы должны использовать SD-карту за пределами ISR. В ISR вы можете получить сообщение I2C, а затем установить переменную флага, которая сообщит коду в функции loop ()
, что доступны новые данные и что он может начать их обработку. Таким образом, ваш ISR останется коротким, и другие операции не будут заблокированы им. Сделайте то же самое с прямой отправкой данных GPRS.
Также обратите внимание, что передача последовательных данных внутри ISR также не работает по той же причине (последовательная передача зависит от прерываний). Вызовы Serial.print()
или Serial.write()
будут заполнять только внутренний буфер библиотеки. Данные будут переданы после того, как ISR был оставлен. Если вы попытаетесь распечатать/записать данные в последовательный, когда буфер заполнится, библиотека будет блокироваться до тех пор, пока в буфере снова не останется места для отправки данных, чего никогда не произойдет внутри ISR. Поэтому вам следует быть осторожным с написанием серийного номера внутри ISR. Немного не больно, но это может стать большой проблемой.
будет ли запущенная функция "receiveEvent" зарегистрирована в настройке для Wire Slave
Wire.onReceive(receiveEvent);
конфликтует с текущим блок цикла, в котором система считывает резервные копии данных и отправляет резервные копии данных?
Исходя из общей логики, на SD-карте не может одновременно выполняться более 1 конкретной операции с данными. Если вы в настоящее время записываете один файл, вы не можете просто прервать передачу через прерывание и записать другой файл, ничего не нарушив. Транзакция должна быть завершена, иначе вы быстро повредите свою файловую систему. Но, как я писал выше, это на самом деле невозможно в любом случае, потому что вызовы SD-карты не будут работать должным образом внутри ISR. Поэтому просто введите весь код GPRS и SD-карты в функцию loop()
и запустите соответствующие блоки кода с флагом ISR. Таким образом, здесь ничто не может конфликтовать.
- Отправка и получение различных типов данных через I2C в Arduino
- Как выбрать альтернативные контакты I2C на ESP32?
- Альтернативы библиотеке Wire для I2C
- Библиотека Wire.h работает на Uno, но не компилируется для ATtiny85
- Вызов I2C во время Wire.requestFrom
- I2C связь между Arduino Uno и Nodemcu32-s (ESP32)
- Как обнаружить ошибки I2C с помощью requestFrom()
- Проблемы с I2C и Wire.Available()