Вывод данных из массива

vvadim
Offline
Зарегистрирован: 23.05.2012

Записываю показания двух потенциометров на sd карту

 String dataString = String(val) + "  ,  " + String(val1);
 File dataFile = SD.open("log.txt", FILE_WRITE);
    if (dataFile)
    {
      dataFile.println(dataString);
      dataFile.close();
      Serial.println(dataString);
    }

Читаю массив с карты

 File dataFile = SD.open("log.txt", FILE_READ);
  if (dataFile)
  {
    Serial.println("log.txt:");
    while (dataFile.available())
    {
      Serial.write(dataFile.read());
    }
    dataFile.close();
  }

 

Как вывести данные из массива?

 

Geronimo
Offline
Зарегистрирован: 06.05.2013

Во втором вашем коде вы аыводите данные из фаила

vvadim
Offline
Зарегистрирован: 23.05.2012

Я имел ввиду как получить значения двух переменных, наприме value1 и value2 при чтении

Geronimo
Offline
Зарегистрирован: 06.05.2013

Прочитать строку и расрарсить

vvadim
Offline
Зарегистрирован: 23.05.2012

где хоть почитать и посмотреть примеры?

Geronimo
Offline
Зарегистрирован: 06.05.2013

Если так хочешь хранить в строковом виде почитай про конечные автоматы. Но я бы для хранения выбрал двоичный формат так проще

vvadim
Offline
Зарегистрирован: 23.05.2012

Я если честно ни с конечными автоматами ни с двоичным форматом ещё не сталкивался.

vvadim
Offline
Зарегистрирован: 23.05.2012

Глянул про конечные автоматы - тёмный лес и про работу со строками ничего не нашёл. 

Какая то секретная тема (если честно задолбался гуглить - нашёл только на си  и др. языках.). Дальше ардуино не лезу, а примеров нет вообще более менее доступных .

Как прочитать строку и вытащить из неё два числа????????????????

Про парсить почитал - везде пишут большой тормоз, не подходит.

toly
Offline
Зарегистрирован: 17.05.2014

Читать строку в String, использовать её indexOf() чтобы получить позицию запятой, потом два раза substr() - вырезать то что до запятой и то что после (это и будут ваши 2 числа). Если нужно перевести в long/int, использовать atol/atoi (не забыть только про нуль терминатор в каждой подстроке).

vvadim
Offline
Зарегистрирован: 23.05.2012

Нашёл на форуме такой пример

#include <string.h>

String Str="10 0 125";
char buffer[11];
int s1, s2, s3;
void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly: 
  Str.toCharArray(buffer,11);
  s1=atoi(strtok(buffer," "));
  s2=atoi(strtok(NULL," "));
  s3=atoi(strtok(NULL," "));
  Serial.println(s1);
  Serial.println(s2);
  Serial.println(s3);
  delay(5000);
}

переделал под себя

#include <string.h>

int pot = A0;
int pot1 = A1;
int val = 0;
int val1 = 0;

char buffer[11];
int s1, s2;

void setup() {
  Serial.begin(9600);
}

void loop() {
  val = analogRead(pot);
  val = map(val, 0, 1023, 0, 255);
  val1 = analogRead(pot1);
  val1 = map(val1, 0, 1023, 0, 255);
  String Str = String(val) + "  " + String(val1);
  Str.toCharArray(buffer,11);
  s1=atoi(strtok(buffer," "));
  s2=atoi(strtok(NULL," "));
  Serial.print(s1);
  Serial.print("   ");
  Serial.println(s2);
}

Работает.

Записываю на sd карту



File dataFile = SD.open("log.txt", FILE_WRITE); 
    if (dataFile)
    {
      dataFile.println(Str);
      dataFile.close();
      Serial.println(Str);
    } 

В сериале пишет как нужно

Читаю по аналогии


  File dataFile = SD.open("log.txt", FILE_READ);
  if (dataFile)
  {
    Serial.println("log.txt:");
    while (dataFile.available())
    {
      Serial.write(dataFile.read());
      Str.toCharArray(buffer,11);
      s1=atoi(strtok(buffer," "));
      s2=atoi(strtok(NULL," "));
      Serial.print(s1);
      Serial.print("   ");
      Serial.println(s2);
    }
    dataFile.close();
  }

Ругается  error: 'Str' was not declared in this scope

vvadim
Offline
Зарегистрирован: 23.05.2012

Пробую читать так

File dataFile = SD.open("log.txt", FILE_READ);
  if (dataFile)
  {
    Serial.println("log.txt:");
    while (dataFile.available())
    {
      Serial.write(dataFile.read());
      String string ;
      string.toCharArray(buffer,11);
      s1=atoi(strtok(buffer," "));
      s2=atoi(strtok(NULL," "));
      Serial.print(s1);
      Serial.print("   ");
      Serial.println(s2);
    }
    dataFile.close();
  }

В сериал выводится необычно (для меня)

Вот так выглядят числа 122 и 15

tmr
Offline
Зарегистрирован: 19.05.2014

Вот этого куска я не понял:
String string ; // создали пустой объект
string.toCharArray(buffer,11); // скопировали нечто из пустого объекта

vvadim
Offline
Зарегистрирован: 23.05.2012

Переделал

File dataFile = SD.open("log.txt", FILE_READ);
  if (dataFile)
  {
    Serial.println("log.txt:");
    while (dataFile.available())
    {
      dataFile.read();
      String string = String(val) + "  " + String(val1);
      string.toCharArray(buffer,11);
      s1=atoi(strtok(buffer," "));
      s2=atoi(strtok(NULL," "));
      Serial.print(s1);
      Serial.print("\t");
      Serial.println(s2);
    }
    dataFile.close();
  }

Теперь в сериал выводятся только последние значения.

tmr
Offline
Зарегистрирован: 19.05.2014

strtok возвращает указатель на элемент следующий за разделителем, у вас в s1 возвращается второй элемент, а в s2 вообще беда

vvadim
Offline
Зарегистрирован: 23.05.2012
#include <string.h>

int pot = A0;
int pot1 = A1;
int val = 0;
int val1 = 0;

char buffer[11];
int s1, s2;

void setup() {
  Serial.begin(9600);
}

void loop() {
  val = analogRead(pot);
  val = map(val, 0, 1023, 0, 255);
  val1 = analogRead(pot1);
  val1 = map(val1, 0, 1023, 0, 255);
  String Str = String(val) + "  " + String(val1);
  Str.toCharArray(buffer,11);
  s1=atoi(strtok(buffer," "));
  s2=atoi(strtok(NULL," "));
  Serial.print(s1);
  Serial.print("   ");
  Serial.println(s2);
}

Здесь всё нормально. Знаний не хватает. Сделал по подобию

tmr
Offline
Зарегистрирован: 19.05.2014

Прошу прощения, прочитал рефайренс по диагонали, strtok работает не так как я написал, а ваш вариант выглядит рабочим

vvadim
Offline
Зарегистрирован: 23.05.2012

Без карты памяти всё ок, а вот при чтении с карты фигня какая то

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

На всякий случай, strtok портит содержимое buffer, это я к тому, что если вдруг Вы захотите содержимое buffer использовать после strtok, то будете удивлены содержимым (он заменяет разделитель на '\0'). В данном скетче всё нормально, невлияет.

Кстати, а почему так сложно то, вот тоже самое только без извратов лишних преобразований:

int pot = A0;
int pot1 = A1;
int val = 0;
int val1 = 0;

void setup() {
  Serial.begin(9600);
}

void loop() {
  val = analogRead(pot);
  val = map(val, 0, 1023, 0, 255);
  val1 = analogRead(pot1);
  val1 = map(val1, 0, 1023, 0, 255);
  Serial.print(val);
  Serial.print("   ");
  Serial.println(val1);
}

А при чтении с SD у Вас чтение либо в Serial выводится, либо никуда. При чтении нужно считать в буфер, например:

dataFile.read( buffer, 11 );

это если Вы знаете какой длины файл, либо в цикле:

byte i = 0;
while( dataFile.available() )
{
  buffer[ i ] = dataFile.read();
  i++;
  if( i >= 10 ) break;
}
buffer[ 10 ] = '\0';

А String Str Вам вообще не нужен, поскольку в этом случае у Вас все данные в buffer.

 

vvadim
Offline
Зарегистрирован: 23.05.2012

А как теперь из буфера вытянуть обе переменные?

vvadim
Offline
Зарегистрирован: 23.05.2012

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

File dataFile = SD.open("log.txt", FILE_READ);
 if (dataFile)
 {
   Serial.println("log.txt:");
   while (dataFile.available())
   {
     Serial.write(dataFile.read());
   }
   dataFile.close();
 }

Получить числа не могу. Сижу в тёмном лесу, мыкаюсь в строки, двоичные коды, буфер (всё впервые) и только шишки на лбу.

Наверно непрограммист сильно в густые дебри полез.

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Я в сообщении #17 в последнем исходнике написал, как считать данные в buffer. А дальше воспользуйтесь Вашим же текстом, чтобы разобрать и отобразить:

  s1=atoi(strtok(buffer," "));
  s2=atoi(strtok(NULL," "));
  Serial.print(s1);
  Serial.print("   ");
  Serial.println(s2);

 

vvadim
Offline
Зарегистрирован: 23.05.2012

Пробую так

 char buffer[10];

  File dataFile = SD.open("log.txt", FILE_READ);
  if (dataFile)
  {
    Serial.println("log.txt:");
    while (dataFile.available())
    {
      dataFile.read( buffer, 10 );
      s1=atoi(strtok(buffer," "));
      s2=atoi(strtok(NULL," "));
      Serial.print(s1);
      Serial.print("\t");
      Serial.println(s2);
      POTMODE = 0;
    }
    dataFile.close();
  }

Проблема вероятно с величиной буфера

Пробую в цикле

byte i = 0;
while( dataFile.available() )
{
  buffer[ i ] = dataFile.read();
  i++;
  if( i >= 10 ) break;
}
buffer[ 10 ] = '\0';

какая то ерунда получается.

Как вообще правильно определить величину буфера для записи двух переменных от 0 до 255?

 

tmr
Offline
Зарегистрирован: 19.05.2014

Для переменной от 0 до 255 подойдет byte (uint8_t), у вас объявлен char он принимает значение от -128 до 127, соответственно при значении <-128 и >127 происходит переполнение по знаку.

toly
Offline
Зарегистрирован: 17.05.2014
char inBuffer[] = "0 255";

void setup() {
Serial.begin(9600);
}

void loop() {

  sendPair(inBuffer);
  delay(1000);
}

void sendPair(const char* inString){
  byte s1, s2;
  char tmpBuffer[8];  
  strcpy(tmpBuffer, inBuffer);
  s1=atoi(strtok(tmpBuffer," "));
  s2=atoi(strtok(NULL," "));

  Serial.print(s1);
  Serial.print('\t');
  Serial.print(s2);
  Serial.print('\n');
}

 

Вот, функция принимает строку, в которой два числа, разделенные пробелом, и печатает их в сериал...числа от 0 до 255

vvadim
Offline
Зарегистрирован: 23.05.2012

Читаю

void sendPair(const char* inString)

{
  File dataFile = SD.open("log.txt", FILE_READ);
  if (dataFile)
  {
    Serial.println("log.txt:");
    while (dataFile.available())
    {
      byte s1, s2;
      char tmpBuffer[8]; 
      strcpy(tmpBuffer, inBuffer);
      s1=atoi(strtok(tmpBuffer," "));
      s2=atoi(strtok(NULL," "));
      Serial.print(s1);
      Serial.print("\t");
      Serial.println(s2);
      //Serial.print('\n');
      POTMODE = 0;
      //  delay (10);
    }
    dataFile.close();
  }
} 

В сериал пишет  0   255

vvadim
Offline
Зарегистрирован: 23.05.2012

tmr пишет:

Для переменной от 0 до 255 подойдет byte (uint8_t), у вас объявлен char он принимает значение от -128 до 127, соответственно при значении <-128 и >127 происходит переполнение по знаку.

Замени char на byte - ругается error: initializing argument 1 of 'char* strtok(char*, const char*)'

tmr
Offline
Зарегистрирован: 19.05.2014

Покажи пожалуйста содержимое log.txt

vvadim
Offline
Зарегистрирован: 23.05.2012

log.txt это просто инфострока. А как читает с карты памяти сериал в сообщении #21

toly
Offline
Зарегистрирован: 17.05.2014

В строке 12 в tmpBuffer нужно скопировать то что прочитали из файла. В моем примере туда копируется inBuffer с содержимым "0 255", поэтому вы это и видите.

vvadim
Offline
Зарегистрирован: 23.05.2012

 inBuffer = dataFile.read();

тут несоответствие типов...

tmr
Offline
Зарегистрирован: 19.05.2014

vvadim, вы всетаки покажите log.txt. Так будет понятно что и какого размера у вас на входе

vvadim
Offline
Зарегистрирован: 23.05.2012

Записал

Читаю

File dataFile = SD.open("log.txt", FILE_READ);
  if (dataFile)
  {
    Serial.println("log.txt:");
    while (dataFile.available())
    {
      dataFile.read( buffer, 10 );
      s1=atoi(strtok(buffer," "));
      s2=atoi(strtok(NULL," "));
      Serial.print(s1);
      Serial.print("\t");
      Serial.println(s2);
      POTMODE = 0;
      //  delay (10);
    }
    dataFile.close();
  }

tmr
Offline
Зарегистрирован: 19.05.2014

vvadim, я имел ввиду реальное содержимое текстового файла, а не то, что в порт выводится

vvadim
Offline
Зарегистрирован: 23.05.2012

Там ничего нет, только строка log.txt.  Это  просто взял из примера работы с sd картой. Можно вообще убрать

toly
Offline
Зарегистрирован: 17.05.2014

Проблема с длинной, вы читаете из файла по 10 байт, а записи разной длинны, поэтому и каша на выходе.  Есть два решения, либо читать в цикле посимвольно до разделителя \n (перевод строки), либо использовать фиксированную длинну. Первый способ предпочтительнее, т.к. позволит не хранить лишние пробелы и файле.

tmr
Offline
Зарегистрирован: 19.05.2014

Всмыле ничего нет? Вы же в коде открываете файл log.txt и читаете из него данные...

toly
Offline
Зарегистрирован: 17.05.2014

Вообще, если уж на то пошло, нечего тут возиться со строками, в файле лучше хранить бинарное (байтовое) представление двух чисел, просто одно за другим, не нужно будет никакого разбора строки и никаих дополнительных символов - разделителей.

vvadim
Offline
Зарегистрирован: 23.05.2012

У меня нескромный вопрос - как это сделать (записать и прочитать)?

toly
Offline
Зарегистрирован: 17.05.2014

Для записи в фаил два раза используйте функцию write, ей нужно дать ей 2 байта (которые считаны с аналоговых входов) один за другим. Чтение в цикле, пока не -1 (это окончание данных в файле), read два раза подряд в две переменные byte, и их потом напрямую печатаем в сериал без всяких преобразований.

toly
Offline
Зарегистрирован: 17.05.2014

Да, для входов нужно будет сделать маппинг, чтобы изменить диаппазон с 0....1023 в 0...255 (здесть по моему есть это в примере выше)

vvadim
Offline
Зарегистрирован: 23.05.2012

А где можно хоть примеры посмотреть, если можно ссылку

dataFile.write(val);

dataFile.write(val1);

Как выделить 2 байта?

toly
Offline
Зарегистрирован: 17.05.2014

Примеры так на вскидку даже не знаю где такие есть...все правильно написали, выделять ничего не надо, читаете точно также последовательно, сначала будет первый байт, потом второй, в том же самом порядке. (val и val1 должны быть типа byte)

vvadim
Offline
Зарегистрирован: 23.05.2012

Попробую

vvadim
Offline
Зарегистрирован: 23.05.2012

Получилось, ура, вот спасибки!!!!!!!!!!!!!!!!!!!

Теперь более сложная задачка стоит передо мной - прочитать с последнего до первого байта.

Со строками читал так


  File dataFile = SD.open("log.txt", FILE_READ);
  unsigned long i;
  if (dataFile)
  {
    Serial.println("log.txt:");
    i = dataFile.size() - 1;
    while(i>0)
    {
      dataFile.seek(i--);
      Serial.write(dataFile.read());
    }
    dataFile.close();
  }

В сериал всё выводилось, только задом наперёд. 

Как теперь сначала прочитать последний байт, потом предыдущий?

toly
Offline
Зарегистрирован: 17.05.2014

В смысле, а зачем нужно читать в обратную сторону ?

vvadim
Offline
Зарегистрирован: 23.05.2012

Ну задача у меня такая. Пример -потенциометром изменяю яркость светодиода, весь процесс записал на карту памяти. Нажал кнопку - светодиод изменил яркость как записано на карту (допустим увеличил с 0 до максимума), нажал другую кнопку - загорелся на максимуме и потом яркость уменьшилась до 0.

С одним у меня получается, а вот ради двух эту тему и завёл. Вообще то мне надо управлять четырьмя, но думаю, если два осилю, то с четырьмя по аналогии справлюсь.

toly
Offline
Зарегистрирован: 17.05.2014

Не до конца понял задачу...в обратную сторону читать тоже можно, использовать seek, в начале установить его на конец файла минус 2 байта (на начало последней пары значений), прочитать два байта, потом сдвинуть на 4 байта назад (начало предпоследней пары), и так до тех пор, пока он не достигнет 0 (это будет первая пара байт и начало файла), прочитать её и выйти из цикла.

vvadim
Offline
Зарегистрирован: 23.05.2012

Читаю с конца файла

File dataFile = SD.open("log.txt", FILE_READ);
  unsigned long i;
  if (dataFile)
  {
    Serial.println("log.txt:");
    i = dataFile.size() - 2;
    while(i>0)
    {
      value =dataFile.read();
      value1 = dataFile.read();
      dataFile.seek(i--);
      Serial.print(value);
      Serial.print("\t");
      Serial.println(value1);
      delay (10);
    }
    dataFile.close();
  }

В сериале

Должно быть 0   234

vvadim
Offline
Зарегистрирован: 23.05.2012

Сделал так 

File dataFile = SD.open("log.txt", FILE_READ);
  unsigned long i;
  if (dataFile)
  {
    Serial.println("log.txt:");
    i = dataFile.size() - 2;
    while(i>0)
    {
      value =dataFile.read();
      value1 = dataFile.read();
      dataFile.seek(i=i-4);
      Serial.print(value);
      Serial.print("\t");
      Serial.println(value1);
      delay (10);
    }
    dataFile.close();
  }

Теперь читает назад как надо, только не останавливается при достижении первого байта

toly
Offline
Зарегистрирован: 17.05.2014
dataFile.seek(i);
i=i-2;

В цикле сдвигать надо на 2 байта назад, а не на 1...вместо 11 строки напишите вот так

 

 

 

toly
Offline
Зарегистрирован: 17.05.2014

Внешний индекс сдвигать нужно только на 2 байта, а не на 4, ведь вызов read двигает только внутреную позицию в файле, а не i...