Как записать и прочитать из файла SPIFFS как данные объекта на ESP8266

Я пытаюсь записать четырехзначное число в файл SPIFFS, прочитать эту четырехзначную цифру из файла SPIFFS и отобразить ее на семисегментном дисплее.

Код, который я пишу, как показано ниже, я получил "0" на каждом сегменте, но если вручную сделать число = 4567; то семь сегментов показывают правильное число на каждом сегменте.

Пожалуйста, помогите мне узнать больше о том, как читать и записывать и преобразовывать объектные данные.

Вот мой код;

#include <FS.h>

const char* filename = "/InputInt.txt";
int digit_1 = 0;
int digit_2 = 0;
int digit_3 = 0;
int digit_4 = 0;

int Anode_1 = 16;
int Anode_2 = 14;
int Anode_3 = 5;
int Anode_4 = 4;
int count = 0;
int digits[4] ;
int AnodePins[4] = {4, 5, 14, 16};


int clockPin = 12;
int latchPin = 13;
int dataPin = 15;


int number = 0;

byte numbers[10] {B00000011, B10011111, B00100101, B00001101, B10011001, B01001001, B01000001, B00011111, B00000001, B00001001};


void setup() {
  Serial.begin(115200);
  Serial.println();

  bool success = SPIFFS.begin();

  if (!success) {
    Serial.println("Error mounting the file system");
    return;
  }
  SPIFFS.format();
  File fw = SPIFFS.open(filename, "w");

  if (!fw) {
    Serial.println("Error opening file for writing");
    return;
  }
  char Written = fw.print("1234");

  if (Written == 0) {
    Serial.println("File write failed");
    return;
  }
  fw.close();

  pinMode(Anode_1, OUTPUT);
  pinMode(Anode_2, OUTPUT);
  pinMode(Anode_3, OUTPUT);
  pinMode(Anode_4, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);

} //End of setup

void loop() {
  int i;
  File fr = SPIFFS.open(filename, "r");

  if (!fr) {
    Serial.println("Failed to open file for reading");
    return;
  }

  for (i = 0; i < 4; i++) {
    byte number = (Serial.write(fr.read()));
  }
  fr.close();
  break_number(number);
  display_number();
  delay(3000);
} // End of loop

// seperate the input number into 4 single digits
void break_number(int num) {
  Serial.println("");
  digit_1 = num / 1000;
  digits[0] = digit_1;
  Serial.print(" Digit_1: ");
  Serial.println(digit_1);
  int dig_1_remove = num - (digit_1 * 1000);

  digit_2 = dig_1_remove / 100;
  digits[1] = digit_2;
  Serial.print(" Digit_2: ");
  Serial.println(digit_2);
  int dig_2_remove = dig_1_remove - (digit_2 * 100);

  digit_3 = dig_2_remove / 10;
  digits[2] = digit_3;
  Serial.print(" Digit_3: ");
  Serial.println(digit_3);
  digit_4 = dig_2_remove - (digit_3 * 10);

  digits[3] = digit_4;
  Serial.print(" Digit_4: ");
  Serial.println(digit_4);
}

void display_number() {                                             //сканирование
  digitalWrite(AnodePins[count], HIGH);                            //включить соответствующие цифры
  digitalWrite(latchPin, LOW);                                      //поставить сдвиговый регистр чтения
  shiftOut(dataPin, clockPin, LSBFIRST, numbers[digits[count]]);    //отправить данные
  digitalWrite(latchPin, HIGH);                                     //поставить сдвиговый регистр, в режим записи 
  delay(0);
  digitalWrite(AnodePins[count], LOW);                            //включить соответствующий счетчик цифр
  count++;                                                          //подсчитать цифру
  if (count == 4) {                                                 //держать счет между 0-3
    count = 0;
  }
}

Вот результат;

1234
 Digit_1: 0
 Digit_2: 0
 Digit_3: 0
 Digit_4: 0
1234
 Digit_1: 0
 Digit_2: 0
 Digit_3: 0
 Digit_4: 0
1234
 Digit_1: 0
 Digit_2: 0
 Digit_3: 0
 Digit_4: 0

Спасибо,

, 👍1


1 ответ


Лучший ответ:

1

Я прямо вижу 3 проблемы с вашим кодом:

  1. Функция Serial.write() возвращает не записанные данные, а количество отправленных байтов. Это означает, что в цикле for вы присваиваете переменной только записанное количество байтов, а не данные. Но я предполагаю, что вы хотите отобразить фактические данные, которые были прочитаны из файла. Вы должны присвоить возвращаемое значение fr.read() переменной. Затем вы можете отправить его через Serial.write() и все еще использовать эту переменную для других вещей позже (например, для отображения).

  2. Вам нужно заглянуть в область переменных. У вас есть номер глобальной переменной. Но в цикле for вы определяете локальную переменную с тем же именем через

     byte number = ...
    

    Эта переменная действительна только в той конкретной итерации цикла for. Когда итерация заканчивается, переменная выбрасывается и повторно объявляется на следующей итерации. Его больше не будет, когда вы покинете цикл for. Таким образом, в настоящее время вы сохраняете свои данные в переменной, локальной для цикла for. Он не касается глобальной переменной. Таким образом, другие функции видят только нулевое значение, которым была инициализирована глобальная переменная number. Вы можете удалить байт типа перед переменной в цикле for. Это превращает его в задание, а не в определение. Таким образом, вы действительно записываете данные в глобальную переменную.

  3. Кодировка данных: Очевидно, что ваш номер находится в файле в виде текста в кодировке ASCII. Но вы, похоже, обращаетесь с ними как с двоичными данными. Это не может сработать. Например: Когда вы читаете первый символ 1234 (который записан в файле), то получаете " 1 " (символ, а не число). Если посмотреть на таблицу ASCII, то можно увидеть, что этот символ соответствует десятичному числу 49 (или 0x31 в шестнадцатеричном формате). Вы можете преобразовать цифру в кодировке ASCII в действительное число, вычитая значение символа "0":

     int number = fr.read() - '0';
    

    или

     int number = fr.read() - 48;
    

    (оба эквивалентны).

    Кроме того, в настоящее время вы просто сохраняете считанный символ в одну переменную. Это означает, что после цикла for остается только последний символ. Поскольку это составное число, вы должны что-то сделать, чтобы составить его. Вот так:

     number = 0;
     int factor = 1000;
     for(int i = 0; i<4; i++){
         number += (fr.read() - '0') * factor;
         factor /= 10;
     }
    

    Примечание: Это непроверенный способ, он не самый лучший, но самый простой на данный момент, и он работает только для чисел от 1000 до 9999 (4-значные числа). Вы можете реализовать это более универсально.

    Сначала мы сбрасываем переменную number, чтобы старые значения не мешали нам. Мы используем переменную, удерживающую текущий коэффициент (начиная с 1000, так как это цифра, в которой лежит первая цифра). Затем мы проходим через 4 символа, читая их. Мы вычитаем символ " 0 " (как описано выше), а затем умножим на коэффициент. Это результирующее число добавляется к переменному числу. Затем делим коэффициент на 10 (получаем от 1000 до 100, затем на 10 и, наконец, на 1). В конце мы можем использовать число как любую другую целочисленную переменную.


Альтернативная реализация чтения числа, которая подходит для разного количества цифр:

number = 0;
// Подготовить символьный буфер для чтения числа
char buffer[10] = ""; // пробел максимум для 9 цифр
int pos = 0; // переменная позиции в буфере
while(fr.available() && pos < 9){ // loop while there is data left to read in the file or we have no pace left in buffer (leaving one character for the terminating null character
    char c = fr.read(); // read character into variable
    if(isDigit(c)){
        buffer[pos] = c; // сохранить цифру в буфере
        pos++; // increment position for the next character
    } else {
       break; //выйти из цикла, если прочитанный символ не является цифрой (мы не хотим читать дальше, когда появляется нецифровый символ)
    }
}
buffer[pos] = 0; // завершить буфер нулевым символьным
number = atoi(buffer); // использовать стандартную функцию для преобразования в целое число

Примечание:

  • Этот код не тестируется, хотя компилируется без ошибок
  • Вы видите, что он не меньше, чем другой, но может обрабатывать разное количество цифр.
  • Вы все еще можете использовать первую версию с меньшими числами, если вы всегда дополняете их нулями. Поэтому вместо 991 вы бы написали 0991 в файл. Это заставит работать первую версию.
,

Спасибо Крисл, я отредактировал то, что вы упомянули, теперь все работает хорошо, вы абсолютно правы., @Ali Morawej

Пожалуйста, дайте мне знать, как сохранить число в виде четырехзначного числа (ОКТ), число равно 1000, а минута 4 должна отображать 0996, но отображать 9911., @Ali Morawej

Извините, я не совсем понимаю. Пожалуйста объясните яснее, @chrisl

Хорошо, запишите номер 1008 в файл, затем прочитайте его правильно на дисплее, я добавляю какой-то код в цикл окончательного number = number -4; и снова отобразите номер, начните правильно со 1008, 1004, 1000 и перейдите к 9911 вместо 0996., @Ali Morawej

Вы почти наверняка не заполняете число нулями до 4 цифр, когда записываете его в файл. Как я уже писал, это сломает фрагмент кода. Я добавил еще один способ чтения числа, который также поддерживает другие цифровые числа., @chrisl