Считывание данных с SD карты и сохранение их в виде переменных

snowsuslik
Offline
Зарегистрирован: 14.01.2013

Здравствуйте.

Есть задача, на Sd карте записан текстовый файл в котором записаны параметры которые используются в программе. Примерной вид текстового файла 10,0,20,20,1.

Код который разбивает эти данные по переменным и сохраняет их:

byte h=0;        // считываем массив входящего конфигурвционного файла
byte array[]={}; // массив выходящих значений конфигурационного файла

configFile = SD.open("config.txt");
  if (configFile) { 
    Serial.println("configFile.txt open OK");
    
    while (configFile.available()) {
      // считываем байт входящего файла
      symbol = configFile.read();
      array[h]=symbol;
      h=h++;              
    }
    configFile.close();

byte outputArray [] [5] ={ /// массив с выходящими значениями в который записываются побайтово цифры из конфигурвционного файла
    {},
    {},
    {}};

byte t=0; // переменная которая в массиве outputArray [t] [] переключает строки
byte z=0; // переменная которая содержит  значение i, используется для возвращения намера столца outputArray[t][i-z] в нулевое положение
byte x=0; // определяет количество параметров которое мы задаем с SD карты.
byte u=0; // количество символов считываемого значения   

for(int i = 0; i<=h; i++){  
   symbol = array[i]; 
   if ( symbol == 44 && x == 0 ){     /// Начинаем обрабатывать первое значение из входящего массива данных
         // Часть кода которая отвечает за сохранение параметров которые мы считываем с SD карты
         u = i;
         // если у нас параметр состоит из двух числе
         if (u == 2){
         SolenoidTime = outputArray[0][i-z-1]+ outputArray[0][i-z-2]*10;
         }
         // если у нас параметр состоит из трёх чисел
         else if (u == 3){
         SolenoidTime = outputArray[0][i-z-1]+ outputArray[0][i-z-2]*10+outputArray[0][i-z-3]*100;
         }
         // если первый пареметр состоит из четырёх символов
         else if (u == 4){
         SolenoidTime = outputArray[0][i-z-1]+ outputArray[0][i-z-2]*10+outputArray[0][i-z-3]*100+outputArray[0][i-z-4]*1000;
         }
         t = t + 1;
         x = 1;
         z = i + 1; // пееменная z сдвигает номер столбца выходного массива в ноль    
   } 
   else if ( symbol == 44 && x == 1){     /// Начинаем обрабатывать второе значение из входящего массива данных
         u = i-z;
         // если у нас параметр состоит из двух числе
         if (u == 2){
         DelayTime = outputArray[1][i-z-1]+ outputArray[1][i-z-2]*10;
         }
         // если у нас параметр состоит из трёх чисел
         else if (u == 3){
         DelayTime = outputArray[1][i-z-1]+ outputArray[1][i-z-2]*10+outputArray[1][i-z-3]*100;
         }
         // если первый пареметр состоит из четырёх символов
         else if (u == 4){
         DelayTime = outputArray[1][i-z-1]+ outputArray[1][i-z-2]*10+outputArray[1][i-z-3]*100+outputArray[1][i-z-4]*1000;
         }
         t = t + 1;
         z = i + 1;
         x = 2;
         
   }
   else if ( symbol == 44 && x == 2){     /// Начинаем обрабатывать третье значение из входящего массива данных
   
         u = i-z;
         // если у нас параметр состоит из двух числе
         if (u == 2){
         KerningTime = outputArray[2][i-z-1] + outputArray[2][i-z-2]*10;
         }
        // если у нас параметр состоит из трёх чисел
         else if (u == 3){
         KerningTime = outputArray[2][i-z-1] + (outputArray[2][i-z-2]*10) + (outputArray[2][i-z-3]*100);
          }
        // если первый пареметр состоит из четырёх символов
         else if (u == 4){
         KerningTime = outputArray[2][i-z-1] + (outputArray[2][i-z-2]*10) + (outputArray[2][i-z-3]*100) + (outputArray[2][i-z-4]*1000);
         }
         t=t+1; z=i+1;x=3;
         
   }
else if ( symbol == 44 && x == 3){     /// Начинаем обрабатывать четвёртое значение из входящего массива данных
   
         u = i-z;
         // если у нас параметр состоит из двух числе
         if (u == 1){
         loopcycle = outputArray[3][i-z-1];
         }
         t=t+1; z=i+1;x=4;
         }
  
  else if ( symbol == 44 && x == 4){     /// Начинаем обрабатывать третье значение из входящего массива данных
   
         u = i-z;
         // если у нас параметр состоит из двух числе
         if (u == 2){
         looptime = outputArray[4][i-z-1] + outputArray[4][i-z-2]*10;
         }
        // если у нас параметр состоит из трёх чисел
         else if (u == 3){
         looptime = outputArray[4][i-z-1] + (outputArray[4][i-z-2]*10) + (outputArray[4][i-z-3]*100);
          }
        // если первый пареметр состоит из четырёх символов
         else if (u == 4){
         looptime = outputArray[4][i-z-1] + (outputArray[4][i-z-2]*10) + (outputArray[4][i-z-3]*100) + (outputArray[4][i-z-4]*1000);
         }
         t=t+1; z=i+1;x=5;   
   }
   else if ( symbol == 46 && x == 5){     /// Начинаем обрабатывать четвёртое значение из входящего массива данных
   
         u = i-z;
         // если у нас параметр состоит из двух числе
         if (u == 1){
         system = outputArray[5][i-z-1];
         Serial.print("sys");Serial.print(system);

         }
         t=t+1; z=i+1;x=6;
         }
         
   else if ( symbol == 48){ outputArray[t][i-z] = 0;  }     //  0
   else if ( symbol == 49){ outputArray[t][i-z] = 1;  }     //  1
   else if ( symbol == 50){ outputArray[t][i-z] = 2;  }     //  2
   else if ( symbol == 51){ outputArray[t][i-z] = 3;  }     //  3
   else if ( symbol == 52){ outputArray[t][i-z] = 4;  }     //  4
   else if ( symbol == 53){ outputArray[t][i-z] = 5;  }     //  5
   else if ( symbol == 54){ outputArray[t][i-z] = 6;  }     //  6
   else if ( symbol == 55){ outputArray[t][i-z] = 7;  }     //  7
   else if ( symbol == 56){ outputArray[t][i-z] = 8;  }     //  8
   else if ( symbol == 57){ outputArray[t][i-z] = 9;  }     //  9
   else {}  //  Если вводиться что-то не преднамеренное
   

  }
              
  } 
  else {
    // Если файл не открылся соощаем об ошибке:
    Serial.println("error configFile.txt");
  }  
  
  Serial.print("Solenoid ");Serial.println(SolenoidTime);
  Serial.print("Delay ");   Serial.println(DelayTime);
  Serial.print("Kerning ");  Serial.println(KerningTime);
  Serial.print("Loop");         Serial.println(loopcycle);
  Serial.print("Loop");    Serial.println(looptime);
  Serial.print("font");       
                if (system == 0){
                                   Serial.println("ENG");
                }
                else if (system == 1){
                                   Serial.println("RUS");
                }
                else {}

Как вы видите моя программа обрабатывает побайтово входящий массив значений, определяет что за цифра скрывается за ASCII кодом, и знаки препинания разделяющие сами параметры, являются флагами и сообщают о том что один параметр закончился и начался новый.

Вопрос, как можно сделать это ещё лучше?

Возможно я не знаю, чего-то.

Как можно сократить объем используемой памяти?

mixail844
Offline
Зарегистрирован: 30.04.2012

 так понял из кода и ваших пояснений к нему,что у вас львиная доля кода уходит на то что бы расшифровать какое значение вы считали из файла ? 

советую почитать про функции strtok(); и atoi();

то есть я предлагаю вместо того что бы определять из скольких цифр состоит число и т.д. и т.п. ...считывать число из файла как массив символов,а затем сразу же переводить его в тип int и сохранять в нужный вам массив

int h=0;        // считываем массив входящего конфигурвционного файла
char buffer[5]; //так как в кажде данное не больше 4 цифр
int num,i=0;
configFile = SD.open("config.txt");
  if (configFile) { 
    Serial.println("configFile.txt open OK");
    char array[ConfigFile.size()];  // массив выходящих значений конфигурационного файла
    while (configFile.available()) {
      // считываем байт входящего файла
      symbol = configFile.read();
      array[h]=symbol;
      h++;  
    }
    array[h]='\0';
    configFile.close();

do
   {
      buffer=strtok(array,",");
      num  =atoi(buffer);
       outputArray[i]=num; //тут особо не обращайте внимание,остюда уже идут операции размещения считанных данных куда вам надо по массивам
       i++;
    }   
  while(buffer!=NULL);

как то примерно так,просто с SD карточками особо не заморачивался

snowsuslik
Offline
Зарегистрирован: 14.01.2013

mixail844, спасибо Вам большое за помощь. буду разбираться

snowsuslik
Offline
Зарегистрирован: 14.01.2013

Переделал код, он сйечас выглядит так:


int h=0;        // считываем массив входящего конфигурвционного файла
int num,i=0;
char array[]={};
char *outArray[]={};
char *buffer;
//char conf;
configFile = SD.open("config.txt");
  if (configFile) {
    Serial.println("configFile.txt open OK");
    while (configFile.available()) {
      // считываем байт входящего файла
      symbol = configFile.read();
      array[h] = symbol;
      //Serial.println(array[h]);
      h++;
      delay(1);
    }
    //array[h]='\0';
    configFile.close();
    //Serial.println("configFile.txt END");
  }
  else {//Serial.println("configFile.txt open ERROR");
 }

char *p; 
byte t = 0;

for( buffer = strtok_r(array, ",.", &p); 
     buffer;
     buffer = strtok_r(NULL, ",.", &p)
   )
{
Serial.print(t);Serial.print(" = ");Serial.println(buffer);
delay(1);
outArray[t]=buffer;
t++;
} 

  Serial.print("Solenoid ");Serial.println(SolenoidTime);
  Serial.print("Delay ");   Serial.println(DelayTime);
  Serial.print("Kerning ");  Serial.println(KerningTime);
  Serial.print("Loop");         Serial.println(loopcycle);
  Serial.print("Loop time ");    Serial.println(looptime);

 

При выполнении кода получаем: 

 

configFile.txt open OK
0 = Ø
1 = 0
2 = 30
3 = 1
4 = 10
5 = ¿config
6 = txt
 
 
Значения отображаются некорректно.
mixail844
Offline
Зарегистрирован: 30.04.2012
















configFile = SD.open("config.txt");//считывание и присваивание адресса файлу
if (configFile) 
    Serial.println("configFile.txt open OK");
else 
    Serial.println("configFile.txt open ERROR");
 
char buffer[5];//малый буффер для strtok();
char symbol;
char array[configFile.size()+1]; //создание "большого" буффера для данных,насчет этой строчки не уверен так как примеров как работает команда file.size(); невидел,в принципе,по идее можно заменить на char array[configFile.avialable()+1];
char OutArray[configFile.size()/2+1][4];//двумерный массив данных.для принемаемых значений,по желанию можно изменить его в массив типа int для мат пераций над данными.и естественно пользоваться функцией atoi
int h=0,i=0;//вспомогательные переменные
while (configFile.available()) {
      // считываем байт входящего файла
      symbol = configFile.read();//присваивание символа символу
      array[h] = symbol; //присваивание символа символу
      //Serial.println(array[h]);
      h++;
      delay(1);
	  }
	  array[h]= '\0'; //добавления символа окончания строки для функции strtok() поэтому и "+1" при обьявлении array
	  configFile.close();
buffer=strtok(array,",");//если нужно что бы разделение было и по признаку "." тогда перепишите     strtok(array,",.");
h=0;
while(buffer!=NULL){ //для этого и добавлялся  '\0'в конце array
{
Serial.println(buffer);
strcpy(OutArray[h][0],buffer)//компирование "строчки в строчку",простым "=" тут не обойтись,надеюсь с "0" я не перемудрил
h++;
}
for(i=0;i<h;i++)
Serial.println(OutArray[i][0]);

 

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

функция strtok() сама в себе использует фунцию strcpy(),и сама же продвивает указатель по "большому" массиву символов

snowsuslik
Offline
Зарегистрирован: 14.01.2013

Михаил, спасибо Вам большое за помощь. Разобрался.

мой финальный код, выглядит так:

int h = 0;        // считываем массив входящего конфигурвционного файла
int num,i=0;
char array[]={};
char *buffer;
char symbol2 = 0;
configFile = SD.open("config.txt");
  if (configFile) {
    //Serial.println("configFile.txt open OK");
    while (configFile.available()) {
      // считываем байт входящего файла
      symbol2 = configFile.read();
      array[h] = symbol2;
      h++;
      delay(1);
    }
    array[h]='\0';
    configFile.close();
    }

char *p; 
byte t = 0;

for( buffer = strtok_r(array, ",.", &p); buffer; buffer = strtok_r(NULL, ",.", &p)
   )
{
Serial.print(t);Serial.print(" = ");Serial.println(atoi(buffer));
delay(1);
outArray[t]=atoi(buffer);
t++;
} 
}

 

snowsuslik
Offline
Зарегистрирован: 14.01.2013

Благодара Вам, код сократился в 5 раз!! Ура!

dardik
Offline
Зарегистрирован: 09.03.2013

Здравствуйте.

Подскажите, а если задача похожа (есть текстовый файл, но в нем несколько строк - например 48), как считать данные из последней строки -48й, 47й, 46й итд.. или из любой строки и занести эти данные в массив? 48строк - это максимальное количество строк в файле, добавляются по мере поступления данных от датчиков. На самом деле может быть и 10 строк и 1 строка...

Данные будут записываться в массив int p_g[48];

Например: из 48 строки последняя цифра -749  p_g[0]=749;

                  из 47 строки последняя цифра - 748 p_g[1]=748;

                  из   46                                                  p_g[2]=748;

                  из 45                                                    p_g[3]=747;

 

файл имеет структуру:

............................

0,0,26,35,745
0,30,26,35,745
1,0,26,35,745
1,30,26,35,745
10,0,23,33,747
10,30,24,33,747
11,0,24,32,748                     -46 строка
11,30,25,31,748                   -47 строка
12,0,25,31,749                     -48 строка

 

 

 

Andrey_Y_Ostanovsky
Offline
Зарегистрирован: 03.12.2012

dardik пишет:

есть текстовый файл, но в нем несколько строк - например 48), как считать данные из последней строки -48й, 47й, 46й итд..

Если речь идет о файле и файловой системе - то почти всегда он читается целиком от начала, просто часть данных пропускается по определенному сценарию. Тут надо знать: каким символом заканчивается строка и по нему отсчитывать нужное количество строк, достигнув которое начинаем помещать строчки в массив переменных.

dardik
Offline
Зарегистрирован: 09.03.2013

ок, идею я понял, спасибо.

dardik
Offline
Зарегистрирован: 09.03.2013

Попробовал ваш код применительно своей задачи. У меня несколько строк, я подумал, что с помощью вашего кода смогу сделать массив всех своих данных, так как считываются все строчки по байтам, однако почему-то максимум что удается занести в массив outarray[t] - 40 значений. Подскажите, как исправить, чтобы заносились все данные из всех строк?

0,0,26,27,756.       ----заносятся

7,0,23,30,757.     ----заносятся

8,0,14,34,755.    ----заносятся

8,30,20,33,755.   ----заносятся

9,0,22,29,755.   ----заносятся

9,30,22,30,755.   ----заносятся

10,0,22,30,755.    ----заносятся

10,30,23,30,755.    ----заносятся

11,0,23,30,755. ---------уже не заносятся

11,30,23,30,755.  ---------уже не заносятся

12,0,23,29,755.   ---------уже не заносятся

Andrey_Y_Ostanovsky
Offline
Зарегистрирован: 03.12.2012

dardik пишет:

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

То, что в массив попадает всего ВОСЕМЬ строк - ни на какие мысли не наталкивает? "Переменная типа char занимает 1 байт памяти". Скорее всего отсюда и ногти растут... Объявите длину массива с запасом - и посмотрите что получится.

Evgeny_Ry
Offline
Зарегистрирован: 04.05.2013

 

Здравствуйте, подскажите пожалуйста, как реализовать данный алгоритм:

Есть файл на SD-карте следующего вида:

1234567

9999999

3231321

1234123

И так далее. Т.е. набор чисел в столбик. С RFID ридера приходят данные, типа "0000000" необходимо сравнить входящее число со всеми числами из файла на флешке. Если есть совпадение, то сделать определенные действия, если нет - то другие действия.

Вся сложность сводится к тому, что не удается реализовать считывание с карты каждой строки в массив. 

С уважением, Евгений. Знающих людей прошу помощи.

mishgan
Offline
Зарегистрирован: 25.04.2014

написал когд парсинга данных из файла на флешке

void SD_recepies() {
if (!SD.begin(chipSelect)) {
myGLCD.setFont(SmallFont);
myGLCD.print("Card failed, or not present", CENTER, 50);
  }
int h = 0;        
int q=0;
char array[10][100];
char *buffer;
char symbol2 = 0;
File configFile = SD.open("config.txt");
if (configFile) {
    //Serial.println("configFile.txt open OK");
      while  (configFile.available())   {
      // считываем байт входящего файла
      symbol2 = configFile.read();
      if (symbol2==';') {array[q][h]='\0'; q++; h=0; kol_receptov++;}
      else {array[q][h] = symbol2; h++;}
     
      delay(1);
    }
    configFile.close();
}
char *p;
byte t;
for (int j=0; j <kol_receptov ; j++) {
t = 0;
for( buffer = strtok_r(array[j], ",", &p); buffer; buffer = strtok_r(NULL, ",", &p) ){
recepies[j][t]=buffer;
t++;} 
}
}

Храню данные в следующем формате

IPA,10,20,30,40;
STAUT,30,40,50,60,70,80,90;
BITTER,30,40,50,70,80,90;
 
Но при выводе на TFT экран  первых значений получаются кракозябры. Я так понимаю, что это символ возврата коретки
Но вот как его победить я не придумал. Пробовал менять строчку if (symbol2==';') {array[q][h]='\0'; q++; h=0; kol_receptov++;}
на следующие
if (symbol2==';\n') {array[q][h]='\0'; q++; h=0; kol_receptov++;}
if (symbol2==';\r') {array[q][h]='\0'; q++; h=0; kol_receptov++;}
Подскажите где подшаманить?
TEXTRON
Offline
Зарегистрирован: 19.12.2015

Всем привет) Четвертый день мучаюсь с кодом... Подскажите в чем ошибка.

Задача проекта: есть файл ardu.txt на флешке. В нем записи типа:

10;h

20;l

30;h

E

Числа - время в секундах включений/выключений (в данном случае светодиода на ардуино), "h" и "l" - команды (HIGH, LOW), E - символ конца файла.

Нужно включать, или выключать светодиод по времени, прописанному в файле (потом, по аналогии, добавлю еще светодиоды... пока так)

#include <SPI.h>
#include <SD.h>

File myFile;//инициализируем myFile
char PinCommand;//переменной задается команда на ВКЛ/ВЫКЛ на пине 13
long ActionTime;//переменной задается время ВКЛ/ВЫКЛ на пине 13
int i = 0;//переменной задается объем буфера чтения
char End = 'E';//пееменной задается символ конца файла
char buffer []{};//инициализируется буфер

void setup()
{
  pinMode(13, OUTPUT);//задается канал на светодиод
  Serial.begin(9600);//задается Serial-соединение
  unsigned long CurrentTime = millis()/1000;//переменной CurrentTime задается текущее время в секундах
  myFile = SD.open ("ardu.txt", FILE_READ);//задаем значение myFile
  //пока не будет доступно Serial-соединение ничего не произойдет...
  while (Serial.available())
  {
    //если myFile открыт, то...
    if (myFile)
    {
      //если myFile доступен, то...
      while (myFile.available())
      {
        //если при чтении myFile текущий символ не равен End ("E"), то
        while (myFile.read() != End)
        {
          //если при чтении myFile текущий символ это не символ конца строки, то...
          if (myFile.read() != '\0')
          {
            buffer [i++] = myFile.read();//заносим в буфер читаемый символ
          }
          else
          {
            sscanf (buffer, "%[^';'],%s", &ActionTime, &PinCommand);//иначе разбираем буфер на ActionTime и PinCommand
          }
          //если текущее время = времени в текущей строке в файле, то
          if (CurrentTime == ActionTime)
          {
            switch (PinCommand)
            {
              case 'h':
              digitalWrite(13, HIGH);//если PinCommand = h, то включаем светодиод
              break;
              case 'l':
              digitalWrite(13, LOW);//если PinCommand = l, то выключаем светодиод
              break;
            }
          }
        }
      }
    }
  }
}

 

Gr5
Offline
Зарегистрирован: 26.03.2015

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

#include <SD.h>
02 #include <SimpleTimer.h>
03 File myFile;
04 int timewalkcurrent=0;
05 long int globalruntime;
06 SimpleTimer timer2;
07 void setup(){
08  timer2.setInterval(1000,  timerrunglobal );
09  
10 {
11   Serial.begin(9600);
12   Serial.println(SD_CHIP_SELECT_PIN); //53
13   Serial.println(SPI_MOSI_PIN);       //51
14   Serial.println(SPI_MISO_PIN);       //50
15   Serial.println(SPI_SCK_PIN);        //52
16    while (!Serial) {
17     ;
18   }
19  
20 void timerrunglobal(){
21 timerrunglobal++;
22 }
23 void refreshsd(){
24   
25    pinMode(53, OUTPUT); 
26     myFile = SD.open("time.txt");
27    if (myFile) {
28     while (myFile.available()) {
29        globalruntime=myFile.read();
30          }
31        myFile.close();
32   }
33   long int prof=globalruntime;
34   globalruntime=prof+timerrunglobal;
35   timerrunglobal==zero;
36    SD.remove("time.txt");
37     pinMode(53, OUTPUT); 
38      myFile = SD.open("time.txt", FILE_WRITE);
39      if (myFile) {
40      
41         myFile.write(globalruntime);
42          myFile.close();  
43  
44 }}
45 void loop(void)
46 {
47  
48       unsigned long currentMillis = millis();
49       if (currentMillis - previousMillis >= interval) {
50      previousMillis = currentMillis;
51          refreshsd();
52      }
53         
54      
55      const long interval = 0; }
56   
57    Serial.println("");
58    Serial.println(globalruntime);
59    Serial.println("");
60 }

 

zur
Offline
Зарегистрирован: 18.04.2017

доброго времени суток...

у мения тоже самое интересуеть... помогите пожалуйста...

в тхт фаиле в ручную записанны строки пример 0123456789... нужно найдти определную строку и делат какието деиствия пример нужно искать 0123456789 и при совпадении выдат сообшения например "Ok".

для тестирования Arduino подключен теминалу и спомошю терминала ввожу 10 цифр и при совпадении выдает сообшение "Ok" при отсувствии "Error"

hard виглидить так SD Card+Arduino+Uart

я мало знаю програмировании а то не беспокоил

заранее благодаоень...