Беспорядочное поведение OLED-дисплея — вмешательство в другие части кода?

Отказ от ответственности: я новичок в Arduino, поэтому, пожалуйста, простите меня, если вопрос может показаться тривиальным, я изо всех сил стараюсь учиться :)

Я работаю над небольшим проектом, в котором у меня есть датчик отпечатков пальцев, сервопривод и OLED-дисплей. Цель состоит в том, чтобы иметь возможность зарегистрировать отпечаток пальца, а затем использовать его для перемещения сервопривода, в то время как OLED-дисплей выводит инструкции/сообщения пользователю.

Несколько дней назад я заметил проблему, из-за которой мой OLED-экран просто не переставал работать, если в моем коде был какой-то Serial.println. Не понимая первопричины, методом проб и ошибок я пришел к выводу, что проблема связана с этой конкретной функцией, поэтому я удалил ее, и все прошло нормально.

Затем я заметил, что дисплей перестал работать также из-за добавления очень простых фрагментов кода, которые НИКАК не должны быть связаны с тем, как работает OLED (по крайней мере, насколько я знаю).

Приведенный ниже код работает так, как ожидалось, каждый вызов функции oledPrint дает ожидаемый результат на самом OLED-дисплее.

#include <EEPROM.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_RESET -1
Adafruit_SSD1306 display(OLED_RESET);

#include <Adafruit_Fingerprint.h>
#include <SoftwareSerial.h>

#define ISPRESSED LOW
#define BASE_MAX 200
#define MASTER_MAX 200

SoftwareSerial mySerial(2, 3);

Adafruit_Fingerprint finger = Adafruit_Fingerprint(&mySerial);

uint8_t id;

const int buttonRegisterPin = 8; // номер вывода кнопки - ПРИМЕЧАНИЕ: КРАСНАЯ КНОПКА
const int buttonRegisterMasterPin = 7; // номер штифта кнопки - ПРИМЕЧАНИЕ: ЗЕЛЕНАЯ КНОПКА
const int buttonClearPin = 6; // номер штифта кнопки - ПРИМЕЧАНИЕ: ЧЕРНАЯ КНОПКА
const int buttonClearMasterPin = 12; // номер вывода кнопки - ПРИМЕЧАНИЕ: ЖЕЛТАЯ КНОПКА

const int baseState = HIGH;
int ledStatus = HIGH;

int baseCount; 
int masterCount; 

void setup() {
  //Серийный.начало (9600);
  Serial.begin (115200);

  // инициализируем счетчики
  initializeCounters();

  // инициализируем кнопки
  initializeButton(buttonRegisterPin);
  initializeButton(buttonRegisterMasterPin);
  initializeButton(buttonClearPin);
  initializeButton(buttonClearMasterPin);


  // инициализируем датчик отпечатков пальцев
  initializeFingerPrintSensor();

  // инициализируем OLED-дисплей
  initializeOledDisplay();

}

void loop() {

  bool skip = false;
  oledPrint("Welcome to your fingerprint locker");
  //базовый случай регистрации
  if(digitalRead(buttonRegisterPin) == ISPRESSED && skip == false){


    while(!baseRegistration());
    skip = true;
  }

  //основной регистрационный случай
  if(digitalRead(buttonRegisterMasterPin) == ISPRESSED && skip == false){


    while(!masterRegistration());
    skip = true;
  }

  //базовый чистый регистр
  if(digitalRead(buttonClearPin) == ISPRESSED && skip == false){
    clearRegistrations(false);
    // делаем что-то для базовой очистки
    skip = true;
  }

  //освоить четкий регистр
  if(digitalRead(buttonClearMasterPin) == ISPRESSED && skip == false){

    //делаем что-то для мастера ясно
    skip = true;
  }
}

/**
 * Initializes a button
 * @Param: buttonPin = number of the pin used by the button
 */
void initializeButton(int buttonPin){
  pinMode(buttonPin, INPUT_PULLUP);
}


/**
 * Initializes the OLED display
 */
void initializeOledDisplay(){
  Wire.begin();
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Адрес 0x3D для 128x64
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  }
  delay(2000);
  display.clearDisplay();

  display.setTextSize(2);
  display.setTextColor(WHITE); 
  display.setCursor(0, 10);
}

/**
 * initializes the fingerprint sensor
 */
void initializeFingerPrintSensor(){
  finger.begin(57600);

  if (finger.verifyPassword()) {
    Serial.println("Found fingerprint sensor!");
  } 
  else {
    Serial.println("Did not find fingerprint sensor :(");
    while (1) { delay(1); }
  }
}

boolean baseRegistration(){
  boolean check = false;
  int tempBaseCount = baseCount + 1;
/*
  if(tempBaseCount > BASE_MAX){
    oledPrint("Too many users already registered");
    return true;
  }*/
  oledPrint("Starting registration");
  while(check == false){

    oledPrint("Please put your finger on the reader");


    id = tempBaseCount;
    if (id == 0) {// ID #0 не разрешен, попробуйте еще раз!
       return;
    }

    if(getFingerprintEnroll(tempBaseCount, false)){  
      check = true;
    }
  }
  return check;
}

boolean masterRegistration(){
  boolean check = false;
  int tempMasterCount = baseCount + 1;
/*
  if(tempMasterCount > MASTER_MAX){
    oledPrint("Too many master keys already registered");
    return true;
  }
  */
  oledPrint("Starting master key registration");

  while(check == false){

    oledPrint("Please put your finger on the reader");

    id = tempMasterCount;
    if (id == 0) {// ID #0 не разрешен, попробуйте еще раз!
       return;
    }

    if(getFingerprintEnroll(tempMasterCount, true)){
      check = true;
    }
  }
  return check;
}

boolean clearRegistrations(bool master){
  if(master){
    //делать
  }
  else{
    // увеличить базовый счетчик (0);
    id = 900;
    int p = finger.deleteModel(id);
    if(p == FINGERPRINT_OK){
     // Serial.println("успех");
     // Serial.println(p);
      return true;
    }
   // Serial.println("FAIL");
   // Serial.println(p);
    return false;
  }
}

// возвращает -1 в случае неудачи, иначе возвращает ID #
int getFingerprintIDez() {
  uint8_t p = finger.getImage();
  if (p != FINGERPRINT_OK)  return -1;

  p = finger.image2Tz();
  if (p != FINGERPRINT_OK)  return -1;

  p = finger.fingerFastSearch();
  if (p != FINGERPRINT_OK)  return -1;

  // найдено совпадение!
  oledPrint2Lines("Match found, ID #", finger.fingerID);
 /* Serial.print("Found ID #"); 
  Serial.print(finger.fingerID); 
  Serial.print(" with confidence of "); 
  Serial.println(finger.confidence);*/
  return finger.fingerID; 
}

uint8_t getFingerprintEnroll(int count, bool master) {
  int p = -1;
  while (p != FINGERPRINT_OK) {
    p = finger.getImage();
    switch (p) {
    case FINGERPRINT_OK:
      //oledPrint("Изображение сделано");
      break;
    case FINGERPRINT_NOFINGER:
      break;
    case FINGERPRINT_PACKETRECIEVEERR:
      oledPrint("Communication error");
      break;
    case FINGERPRINT_IMAGEFAIL:
      oledPrint("Imaging error");
      break;
    default:
      oledPrint("Unknown error");
      break;
    }
  }

  // ОК, успех!

  p = finger.image2Tz(1);
  switch (p) {
    case FINGERPRINT_OK:
      //oledPrint("Изображение преобразовано");
      break;
    case FINGERPRINT_IMAGEMESS:
      oledPrint("Image too messy");
      return p;
    case FINGERPRINT_PACKETRECIEVEERR:
      oledPrint("Communication error");
      return p;
    case FINGERPRINT_FEATUREFAIL:
      oledPrint("Could not find fingerprint features");
      return p;
    case FINGERPRINT_INVALIDIMAGE:
      oledPrint("Could not find fingerprint features");
      return p;
    default:
      oledPrint("Unknown error");
      return p;
  }

  oledPrint("Remove finger");
  delay(2000);
  p = 0;
  while (p != FINGERPRINT_NOFINGER) {
    p = finger.getImage();
  }
  p = -1;
  oledPrint("Place the same finger again");
  while (p != FINGERPRINT_OK) {
    p = finger.getImage();
    switch (p) {
    case FINGERPRINT_OK:
      //oledPrint("Изображение сделано");
      break;
    case FINGERPRINT_NOFINGER:
      break;
    case FINGERPRINT_PACKETRECIEVEERR:
      oledPrint("Comunication error");
      break;
    case FINGERPRINT_IMAGEFAIL:
      oledPrint("Imaging error");
      break;
    default:
      oledPrint("Unknown error");
      break;
    }
  }

  // ОК, успех!

  p = finger.image2Tz(2);
  switch (p) {
    case FINGERPRINT_OK:
      //oledPrint("Изображение преобразовано");
      break;
    case FINGERPRINT_IMAGEMESS:
      oledPrint("Image too messy");
      return p;
    case FINGERPRINT_PACKETRECIEVEERR:
      oledPrint("Communication error");
      return p;
    case FINGERPRINT_FEATUREFAIL:
      oledPrint("Could not find fingerprint features");
      return p;
    case FINGERPRINT_INVALIDIMAGE:
      oledPrint("Could not find fingerprint features");
      return p;
    default:
      oledPrint("Unknown error");
      return p;
  }

  // ОК сконвертировано!

  //oledPrint2Lines("Создание номера модели:", count);

  p = finger.createModel();
  if (p == FINGERPRINT_OK) {
    //oledPrint("Отпечатки совпали!");
  } else if (p == FINGERPRINT_PACKETRECIEVEERR) {
    oledPrint("Communication error");
    return p;
  } else if (p == FINGERPRINT_ENROLLMISMATCH) {
    oledPrint("Fingerprints did not match");
    return p;
  } else {
    oledPrint("Unknown errro");
    return p;
  }   

  p = finger.storeModel(id);
  if (p == FINGERPRINT_OK) {
    if(master == false){
      oledPrint2Lines("Registered with id number:", count);
      increaseBaseCounter(count);      
    }
    else{
      oledPrint2Lines("Registered master key number:", count - 50);
      increaseMasterCounter(count);
    }
    return 1;
  } else if (p == FINGERPRINT_PACKETRECIEVEERR) {
    oledPrint("Communication error");
    return p;
  } else if (p == FINGERPRINT_BADLOCATION) {
    oledPrint("Could not store in that location");
    return p;
  } else if (p == FINGERPRINT_FLASHERR) {
    oledPrint("Error writing to flash");
    return p;
  } else {
    oledPrint("Unknown error");
    return p;
  }   
}

uint8_t readnumber(void) {
  uint8_t num = 0;

  while (num == 0) {
    while (! Serial.available());
    num = Serial.parseInt();
  }
  return num;
}

void oledPrint(char* text){

  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.println(text);
  display.display();
  delay(2000);
}

void oledPrint2Lines(char* text, int val){

  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.print(text);
  display.print(val);
  display.display();
  delay(2000);
}

void initializeCounters(){
  //адрес 0 является БАЗОВЫМ
  baseCount = EEPROM.read(0);
  Serial.println(baseCount);
  //адрес 1 является ГЛАВНЫМ
  masterCount = EEPROM.read(1);
  if(masterCount < 50)
    masterCount = 50; // доберёмся до 51 после первой регистрации - 51 = мастер-ключ #1
  Serial.println(masterCount);
}

void increaseBaseCounter(int count){
  baseCount = count;
  EEPROM.write(0, baseCount);
}


void increaseMasterCounter(int count){
  masterCount = count;
  EEPROM.write(1, masterCount);
}

Однако, если я раскомментирую код в функциях baseRegistration и/или masterRegistration (см. фрагмент кода ниже), отображение начинает барахлить: какой-то текст отображается, какой-то нет, какой-то снова отображается частично. Я просто нигде не могу найти разумного объяснения, а поскольку я привык работать на гораздо более высоких уровнях абстракции, это для меня совершенно абсурдно :D

boolean baseRegistration(){
  boolean check = false;
  int tempBaseCount = baseCount + 1;
// ЧАСТЬ, ВЫЗЫВАЮЩАЯ ПРОБЛЕМЫ - STARTRT
  if(tempBaseCount > BASE_MAX){
    oledPrint("Too many users already registered");
    return true;
  }
// ЧАСТЬ, ВЫЗЫВАЮЩАЯ ПРОБЛЕМЫ - КОНЕЦ
  oledPrint("Starting registration");
  while(check == false){

    oledPrint("Please put your finger on the reader");


    id = tempBaseCount;
    if (id == 0) {// ID #0 не разрешен, попробуйте еще раз!
       return;
    }

    if(getFingerprintEnroll(tempBaseCount, false)){  
      check = true;
    }
  }
  return check;
}

Что еще более странно, если я уберу вышеуказанную часть из этих двух функций и у меня будет еще один простой вызов датчика отпечатков пальцев в функции цикла, OLED просто перестанет работать (и опять же, для меня это просто безумие :P) . См. ниже функцию цикла с добавлением строки, которая полностью разрушает OLED:

void loop() {

  bool skip = false;
  oledPrint("Welcome to your fingerprint locker");
  //базовый случай регистрации
  if(digitalRead(buttonRegisterPin) == ISPRESSED && skip == false){


    while(!baseRegistration());
    skip = true;
  }

  //основной регистрационный случай
  if(digitalRead(buttonRegisterMasterPin) == ISPRESSED && skip == false){


    while(!masterRegistration());
    skip = true;
  }

  //базовый чистый регистр
  if(digitalRead(buttonClearPin) == ISPRESSED && skip == false){
    clearRegistrations(false);
    // делаем что-то для базовой очистки
    skip = true;
  }

  //освоить четкий регистр
  if(digitalRead(buttonClearMasterPin) == ISPRESSED && skip == false){

    //делаем что-то для мастера ясно
    skip = true;
  }

  int fingerprintID = getFingerprintIDez(); // ЭТО ЛИНИЯ
  delay(50);

}

Я просто не знаю, как поступить, если кто-то из вас будет так любезен помочь новичку, я буду очень признателен! Заранее спасибо всем, кто может указать мне правильное направление!!

Для полноты картины я использую библиотеки adafruit для датчика отпечатков пальцев, а также для OLED-дисплея.

, 👍2

Обсуждение

Библиотека SSD1306 использует *много* оперативной памяти. У вас могут быть проблемы из-за этого. Возможно, вам лучше использовать библиотеку «только для текста»: https://github.com/greiman/SSD1306Ascii., @Majenko


1 ответ


1

Похоже, ваша программа хорошо вписывается в память Arduino Uno. Если ваши выходные данные правильно отображаются через последовательный монитор, то, похоже, нет ничего плохого в ваших данных, отправленных на дисплей. Вы пробовали подключать подтягивающие резисторы к линиям SDA и SCL? Резисторы номиналом около 3,9 кОм прекрасно работают при использовании OLED-дисплеев.

,