I2C OLED конфликтует с прерыванием
Я использую Nmradcc.h в сочетании с OLED I2C.
Файл nrmadcc.h использует прерывание 0 на контакте 2, OLED использует A4 и A5.
После инициализации OLED и функции
Проблема в том, что я могу использовать Funktion с Interrupt или OLED, но не вместе. Но я хочу. Могу ли я остановить функцию прерывания с помощью nointerrupt, а не I2C и иначе, или есть лучшая война?
Спасибо, Берт
#include <SPI.h> ////
#include <Wire.h> ////
#include <Adafruit_GFX.h> ////
#include <Adafruit_SSD1306.h> ////
#include <DCC_Decoder.h>
#define kDCC_INTERRUPT 0
Adafruit_SSD1306 display(128, 64, &Wire, -1); ////
////////////////////////////////////////////////// ////////////////////////////////////////////////// ///////////////////
// Введите количество аксессуаров/функций, которыми вы хотите управлять
////////////////////////////////////////////////// ////////////////////////////////////////////////// ///////////////////
const byte maxaccessories=1;
////////////////////////////////////////////////// ////////////////////////////////////////////////// ///////////////////
typedef struct {
int address; // Адрес для ответа
byte mode; // 0=непрерывный, 1=одноразовый, 2=мигающий
byte output; // Состояние аксессуара: 1=включено, 0=выключено (только для внутреннего использования)
int outputPin; // Выходной контакт Arduino
byte highlow; // Состояние выходного контакта: 1=ВЫСОКИЙ, 0=НИЗКИЙ
boolean finished; // Ячейка памяти, в которой говорится, что ваншот завершен
int durationonMilli; // время включения oneshot или flasher в мс
int durationoffMilli; // время выключения ваншота или флешера в мс
boolean isAnalog; // false=цифровой, true=аналоговый, отправляет AnalogValue на выходной контакт.
byte analogValue; // импульс со значением модуляции (ШИМ), который записывается на вывод. Диапазон: 0–255
// перейдите на http://arduino.cc/en/Reference/AnalogWrite, чтобы узнать, какие контакты поддерживают аналоговый выход ШИМ
unsigned long onMilli; // для внутреннего использования
unsigned long offMilli; // для внутреннего использования
}
DCCAccessoryAddress;
DCCAccessoryAddress accessory[maxaccessories];
////////////////////////////////////////////////// ////////////////////////////////////////////////// ///////////////////
// Заполняем атрибуты для каждого аксессуара/функции
// КОПИРУЕМ - ВСТАВЛЯЕМ столько раз, сколько у вас есть функций. Сумма должна быть такой же, как в строке 17 выше!
////////////////////////////////////////////////// ////////////////////////////////////////////////// ///////////////////
void ConfigureDecoderFunctions() // Количество аксессуаров должно быть таким же, как в строке 26 выше!
{
accessory[0].address = 1; // адрес ДКК
accessory[0].mode = 0; // Непрерывно. HIGH, пока DCC снова не выключит адрес.
accessory[0].outputPin = 13; // Пин Arduino, к которому подключена функция.
accessory[0].output = 0; // Исходное состояние (0 или 1) вывода после запуска.
for(int i=0; i<maxaccessories; i++)
{
if (accessory[i].outputPin)
{
pinMode( accessory[i].outputPin, OUTPUT );
// Установить начальное состояние (только для режима 0, непрерывно)
if (!accessory[i].mode && accessory[i].output) digitalWrite(accessory[i].outputPin, HIGH);
else digitalWrite (accessory[i].outputPin, LOW);
}
}
} // КОНЕЦ Конфигурации функций декодера
////////////////////////////////////////////////// ////////////////////////////////////////////////// ///////////////////
// обработчик дополнительных пакетов DCC
////////////////////////////////////////////////// ////////////////////////////////////////////////// ///////////////////
void BasicAccDecoderPacket_Handler(int address, boolean activate, byte data)
{
// Преобразование формата адреса пакета NMRA в человеческий адрес
address -= 1;
address *= 4;
address += 1;
address += (data & 0x06) >> 1;
boolean enable = (data & 0x01) ? 1 : 0;
for (int i=0; i<maxaccessories; i++)
{
if (address == accessory[i].address)
{
if (enable) accessory[i].output = 1;
else accessory[i].output = 0;
}
}
} //END BasicAccDecoderPacket_Handler
////////////////////////////////////////////////// ////////////////////////////////////////////////// ///////////////////
// Настройка (выполнить один раз)
////////////////////////////////////////////////// ////////////////////////////////////////////////// ///////////////////
void setup()
{
DCC.SetBasicAccessoryDecoderPacketHandler(BasicAccDecoderPacket_Handler, true);
ConfigureDecoderFunctions();
DCC.SetupDecoder( 0x00, 0x00, kDCC_INTERRUPT );
pinMode(2,INPUT_PULLUP); //Прерывание 0 внутренним подтягивающим резистором (можно избавиться от внешнего 10k)
pinMode(13,OUTPUT);
digitalWrite(13,LOW); // выключаем светодиод Arduino при запуске
for (int n=0; n<maxaccessories; n++) accessory[n].output = 0; //все сервоприводы на минимальный угол и функции на 0
display.display();
display.clearDisplay();
} // КОНЕЦ настройки
////////////////////////////////////////////////// ////////////////////////////////////////////////// ///////////////////
// Основной цикл (непрерывный)
////////////////////////////////////////////////// ////////////////////////////////////////////////// ///////////////////
void loop()
{
static int addr = 0;
DCC.loop(); // Библиотека цикла DCC
if( ++addr >= maxaccessories ) addr = 0; // Следующий адрес для проверки
if (accessory[addr].output == 1)
{
if (accessory[addr].mode == 0) accessory[addr].highlow=1; // непрерывно
if (accessory[addr].mode == 1) // одноразовый
{
if (!accessory[addr].highlow && !accessory[addr].finished)
{
accessory[addr].highlow = 1;
accessory[addr].offMilli = millis() + accessory[addr].durationonMilli;
}
if (accessory[addr].highlow && millis() > accessory[addr].offMilli)
{
accessory[addr].highlow = 0;
accessory[addr].finished = true;
}
}
if (accessory[addr].mode == 2) // прошивальщик
{
if (!accessory[addr].highlow && millis() > accessory[addr].onMilli)
{
accessory[addr].highlow = 1;
accessory[addr].offMilli = millis() + accessory[addr].durationonMilli;
}
if (accessory[addr].highlow && millis() > accessory[addr].offMilli)
{
accessory[addr].highlow=0;
accessory[addr].onMilli = millis() + accessory[addr].durationoffMilli;
}
}
display.setCursor(90, 50); ////
display.setTextSize(2); ////
display.print(F("ON")) ; ////
}
else // аксессуар[адрес].output == 0
{
accessory[addr].highlow=0;
if (accessory[addr].mode == 1) accessory[addr].finished = false;
display.setCursor(90, 50); ////
display.setTextSize(2); ////
display.print(F("OFF")) ; ////
}
if (accessory[addr].highlow)
{
if (accessory[addr].isAnalog) analogWrite (accessory[addr].outputPin, accessory[addr].analogValue);
else digitalWrite (accessory[addr].outputPin, HIGH);
}
else
{
if (accessory[addr].isAnalog) analogWrite (accessory[addr].outputPin, 0);
else digitalWrite( accessory[addr].outputPin, LOW);
}
display.display();
} //КОНЕЦ цикла
В этом примере OLED-экран I2C не работает. Когда я меняю место
Adafruit_SSD1306 display(128, 64, &Wire, -1);
и
DCC.SetupDecoder( 0x00, 0x00, kDCC_INTERRUPT );
Прерывание DCC не работает, OLED работает.
@Bert Booltink, 👍1
Обсуждение1 ответ
Для работы I2C требуется точное время. Если прерывания срабатывают, когда Arduino пытается прочитать или записать шину I2C, произойдет сбой. Я подозреваю, что вам придется отключать прерывания каждый раз, когда вы читаете/записываете в шину I2C, а затем снова включаете их, когда закончите.
Спасибо, поэтому все, что вызывалось отображением, мне нужно использовать nointerrupts ()?, @Bert Booltink
- Какой правильный способ запроса устройства I2C из процедуры обслуживания прерывания?
- Arduino использует задержку в I2C ReceiveEvent
- Проблема стабильности кода прерываний, связанного с датчиком расхода
- проблемы с кодированием
- Целесообразно ли использовать Serial.write в ISR, когда loop() обычно использует Serial.read?
- Объект класса внутри ISR
- Отправка и получение различных типов данных через I2C в Arduino
- Использование millis() и micros() внутри процедуры прерывания
Пожалуйста, отредактируйте вопрос, если у вас есть дополнительная информация или обновления., @VE7JRO