Зависает программа после нескольких килобайт логирования

maxvalin
Offline
Зарегистрирован: 22.02.2016

Добрый День уважаемые гуру.

Мучаслся все с логированием, все никак не определялась карта SD.  Установил библиотеку SdFat-master, дело пошло. Логирует прекрасно. НО!  Как всегда есть но.  После нескольких килобайт - программа зависает.  Причем стабильно. Два раза файлик лога удалял, он исправно создавался вновь, немного позаписывав опять удачно зависал всю прогу. Вытаскиваю карту памяти, ресет меге- и все работает нормально, вставляю карту - ресет меге, завис. Удаляю лог файлик, вставляю карту памяти, ресет меге- все работает и логирует.

 Возможно сама карта виновата, но хотелось бы чтоб сначала специалисты посмотрели на сам скетч. Возможно в нем что-то..   



#include <LiquidCrystal.h>
#include <LcdBarGraph.h>
//#include <LineDriver.h>

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// класс титановый велосипед для тактовой кнопки.
// фильтр дребезга, отслеживание событий: нажатие, отпускание, двойное нажатие(doubleclick),
//нажато и удерживается в течении определённого времени, отпущено и неактивно в течении определённого времени.
///~~~~~~~~~~~~~~~~~~~~
// здесь код приведённого выше класса class BUTTON {}; 
/*

BUTTON BUTTON_01(3); // объявляем объект класса BUTTON кнопку с именем BUTTON_01, подключенную к пину 3.
BUTTON BUTTON_02(4); // объявляем объект класса BUTTON кнопку с именем BUTTON_02, подключенную к пину 4.

void setup () {}

void loop() {

BUTTON_01.read(); // обновляем состояние переменных кнопки BUTTON_01.
BUTTON_02.read(); // обновляем состояние переменных кнопки BUTTON_02.

/* работаем с переменными кнопки BUTTON_01.
if (BUTTON_01.click_down) {что-то делаем при нажатии}
if (BUTTON_01.click_up) {что-то делаем при отпускании}
if (BUTTON_01.doubleclick) {что-то делаем при двойном нажатии(doubleclick)}
if (BUTTON_01.timer) {что-то делаем, если кнопка отпущена и неактивна в течении определённого времени}
if (BUTTON_01.retention) {что-то делаем при нажатии и удержании в течении определённого времени}

// работаем с переменными кнопки BUTTON_02.
if (BUTTON_02.click_down) {}
if (BUTTON_02.click_up) {}
if (BUTTON_02.doubleclick) {}
if (BUTTON_02.timer) {}
if (BUTTON_02.retention) {}

}*/
class BUTTON {
public:
//================================================================
static const byte bounce_              =   50; // длительность отслеживания дребезга.
static const byte doubleclick_         =  200; // длительность отслеживания двойного клика.
static const unsigned long timer_      = 5000; // длительность отслеживания неактивности.
static const unsigned int retention_   = 2000; // длительность отслеживания нажатия и удержания.
//================================================================
boolean click_down;
boolean click_up;
boolean doubleclick;
boolean timer;
boolean retention;
//=================================
unsigned long m;
boolean  p;
boolean  b;
boolean dc;
byte     c;
boolean  t;
boolean  r;
//=================================
byte _pb;
//=================================
BUTTON(byte pb) {
_pb = pb;
pinMode(_pb, INPUT);
digitalWrite(_pb, 1);
//====
click_down      = 0;
click_up        = 0;
doubleclick     = 0;
timer           = 0;
retention       = 0;
//====
m  =      millis();
p  = digitalRead(_pb);
b  =                0;
dc =                0;
c  =                0;
t  =                0;
r  =                0;
//====
}

void read() {
//=======================================================
unsigned long nm =      millis();
boolean       np = digitalRead(_pb);
//=================
boolean nb  = 0;
boolean ndc = 0;
boolean nt  = 0;
boolean nr  = 0;
//================
click_down  = 0;
click_up    = 0;
doubleclick = 0;
timer       = 0;
retention   = 0;
//=================
if (np != p) {p = np; m = nm; }
//=======================================================
if (nm - m > bounce_) {nb = 1;}
if (nm - m > doubleclick_) {ndc = 1;}
if (ndc != dc) {dc = ndc; if (dc == 1) {c = 0;}}
if (nb != b) {b = nb;
if (p == 0 && b == 0) {click_down = 1;
++c;      if (c == 2) {c = 0; doubleclick = 1;}
}
if (p == 1 && b == 1) {click_up = 1;}
}
//=======================================================
if (nm - m > timer_) {nt = 1;}
if (nt != t) {t = nt;
if (p == 1 && t == 1) {timer = 1;}
}
//=======================================================
if (nm - m > retention_) {nr = 1;}
if (nr != r) {r = nr;
if (p == 0 && r == 1) {retention = 1;}
}
//=======================================================
}
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // таймер
#include <SimpleTimer.h>
SimpleTimer timer;
volatile uint8_t minut=0;
volatile uint8_t chas=0;
volatile uint8_t sec=0;

LiquidCrystal lcd(16, 17, 23, 25, 27, 29); // для экрана  RS, E, DB4, DB5, DB6, DB7
unsigned long zamerV = 1000;  // интервал для змеров показаний
unsigned long startlog = 5000; // интервал для логирования показний
unsigned long pauseOff = 60000; // интервал для паузы перед выключением заряда
unsigned long previousMillis = 0; // время последнего задействования замеров
unsigned long previousMillis2 = 0; // время последнего задействования логирования
unsigned long previousMillis3 = 0; //время последнего задействования паузы перед отключением зарядки
float Vin = 0; // переменная для напряжения(для замера) 
float Uin = 0; // переменная для тока(для замера)
   // для карты памяти SD
#include <SPI.h> 
#include "SdFat.h"
SdFat SD;
#define SD_CS_PIN SS
File myFile; // создаю мой файл для карты памяти

float VinOld,VinSmooth;  // переменные для усреднения напряжения
float UinOld,UinSmooth;  // переменные для усреднения тока
float UinShkal; // переменная для шкалы
float Uinzaryad = 40;    // переменная для контроля зарядки, отключение пускателя
#define relay1  46   //реле на 46 пине 
byte nomerP = 0; //флаг , определяет номер програмы, какой аккумулятор нужно заряжать.
boolean vse = false; //флаг , определяет заряжен ли аккум до своего максимума

BUTTON Akkum1(32);     // кнопка запуска заряда акумулятора 1 на пине 1
BUTTON Akkum2(34);     // кнопка запуска заряда акумулятора 2 на пине 2
BUTTON Akkum3(36);     // кнопка запуска заряда акумулятора 3 на пине 3



LcdBarGraph lbg(&lcd, 16, 0, 1);  // -- создаю графбар: перая цифра-количество полных кубиков в шкале, вторая:от куда начинается, третья: по высоте номер строки  (column 1)




void setup()
{ 
  pinMode (46, OUTPUT); //выход на реле№1 основное включает зарядку
  digitalWrite(relay1, HIGH);
  TCCR1A=(1<<WGM11); //режим14 FAST PWM  это для часов
  TCCR1B=(1<<CS12)|(1<<WGM13)|(1<<WGM12); //делить частоту CPU на 256 это для часов
  ICR1=62499;  // (16000000MHz /div256) -1 = 1 раз в секунду это для часов
  TIMSK1=(1<<TOIE1); //разрешить прерывание это для часов
  lcd.begin(16, 2);
  
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print(" PROVER UROVEN ");
  lcd.setCursor(1, 1);
  lcd.print("  DISTILATA! ");
  delay (5000);
  lcd.clear();
  analogReference(INTERNAL1V1); // переключаю на внутренее опорное 1.1в
  pinMode(53, OUTPUT); // специально иначе логировать не будет
  Serial.begin(9600); 
  while (!Serial) // если открывается порт на пк
  {
    ; //Ждём инициализации серийного порта. Нужно для Leonardo
  }

  Serial.print("Initializing SD card...");
  if (!SD.begin(SD_CS_PIN)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");
  
}
ISR (TIMER1_OVF_vect) { 
sec++ ; //инкремент переменной каждую секунду
if (sec>59){sec=0; minut++; }
if (minut>59){minut=0; chas++; }
if (chas>23){chas=0;}
}

void loop()
{ 
    timer.run();
    Akkum1.read(); // обновляем состояние переменных кнопки первого акума
    Akkum2.read(); // обновляем состояние переменных кнопки второго
    Akkum3.read(); // обновляем состояние переменных кнопки третьего
    
        //////ПРИМЕР формулы АЦП
    /*(analogRead(A5) * 1.1) / 10.23;
     float переменная = (читаем нужный аналоговый вход, умножаем на опорное напряжение)
     делим на коефициент делителя
     
     С усреднением совсем просто. Вводим две переменных для усреднённого значения
     и по простой формуле усредняем. 15 и 16 это глубина усреднения (N и N-1).
     Чем больше N тем лучше усредняется,но тем медленнее реакция. Начать эксперементы
     с усреднением можно с 4 (3 и 4 вместо 15 и 16)
     Vin = (analogRead(A5) * 1.1) / 10.23;
    VinOld=VinSmooth;
    VinSmooth=(15.0*VinOld+Vin)/16.0; 

    
ПРИМЕР ИСПОЛЬЗОВАНИЯ ДВУХ МИЛИС:
    long previousMillis = 0; 
    long previousMillis2 = 0; 
    int val=0;
     
 void setup()    
 { 
   pinMode(13, OUTPUT);         
   pinMode(8, OUTPUT);        
 } 

 void loop() 

 { 
      if (millis() -previousMillis >500)    
     { 
        previousMillis = millis();     
      digitalWrite(13,!digitalRead(13));
     } 
     
        if (millis() -previousMillis2 >500)    
     { 
        previousMillis2 = millis();     
      digitalWrite(8,!digitalRead(8));
     }        
 } 
     */
     
    //unsigned long currentMillis = millis();
    if(millis() - previousMillis > zamerV)
    {
    previousMillis = millis();      
    float Vin = (analogRead(A5) * 1.1) / 10.23; // вычисление ацп напряжение на А5
    VinOld=VinSmooth;   // приравнивание переменных друг другу
    VinSmooth=(3.0*VinOld+Vin)/4.0; // формула для усреднения показания  
    float Uin = (analogRead(A10) *1.1/1023)/0.00075;  //// вычисление тока на А10
    UinOld=UinSmooth;
    UinSmooth=(6.0*UinOld+Uin)/7.0;
    }
    lcd.setCursor(0, 0);
    lcd.print("Vt=");  
    lcd.print(VinSmooth,1); // вывожу усредненные показания для напряжения.
    lcd.print(" ");
    lcd.setCursor(8, 0);
    lcd.print("Am=");
    lcd.print(UinSmooth,1); // вывожу усредненные показания для тока
    lcd.print(" ");
    lcd.setCursor(14, 0);
    lcd.print("N");
    lcd.print(nomerP);
    UinShkal = 100 - UinSmooth;
    lbg.drawValue( UinShkal, 100); // -- рисую график из данных по току, после формул усреднения от 

       
    if(millis() - previousMillis2 > startlog)
     {
      previousMillis2 = millis();
      myFile = SD.open("1.csv", FILE_WRITE);
      if (myFile)       // Если файл открылся, пишем в него:
    { 
     myFile.print(VinSmooth);
     myFile.write(";");
     myFile.print(UinSmooth);
     myFile.write(";");
     myFile.print(nomerP);
     myFile.write(";");
     myFile.print(chas);  
     myFile.write(";");
     myFile.print(minut);
     myFile.println("");
     // Закрываем файл:
     myFile.close();
     Serial.println("done.");
     } 
   else 
     {
     // если файл не открылся, сообщает об ошибке:
     Serial.println("error opening LOG1.csv");
     }

      // открываем файл только для чтения
      myFile = SD.open("1.csv");
  if (myFile) 
     {
      Serial.println("1.csv:");
      // читаем файл посимвольно до конца:
  while (myFile.available()) 
     {
      Serial.write(myFile.read());
     }
     // закрываем файл:
     myFile.close();
     } 
  else 
     {
     // если файл не открылся, сообщает об ошибке:
     Serial.println("error opening 1.csv");
     }
     }
/////// обработка кнопок
 if (Akkum1.click_down)     // если нажата кнопка первого аккумулятора то включаю пускатель и включаю флаг первой программы               
   {
   digitalWrite(relay1, LOW);
   nomerP = 1; //определяем что включен первый аккумулятор на зарядку
   }

 if (Akkum2.click_down)     // если нажата кнопка второго аккумулятора то включаю пускатель и включаю флаг второй программы               
   {
   digitalWrite(relay1, LOW);
   nomerP = 2; //определяем что включен второй аккумулятор на зарядку
   }

 if (Akkum3.click_down)     // если нажата кнопка третьего аккумулятора то включаю пускатель и включаю флаг третьей программы               
   {
   digitalWrite(relay1, LOW);
   nomerP = 3; //определяем что включен третий аккумулятор на зарядку
    
    }
  /////////// запуск флага для паузы при отключении конца зарядки первого аккумулятора  №1
  if ((nomerP == 1) && (UinSmooth < 10))// если ток заряда меньше 21 ампер- флаг вкл на отсчет времени для отключения заряда 
   {
    vse = true;
    }
  else if ((nomerP == 1) && (UinSmooth > 10))// если ток заряда опять больше 21го тогда отбой, заряжается дальше
   {
     vse = false;
    }
  /////////// запуск флага для паузы при отключении конца зарядки второго аккумулятора  №2
  if ((nomerP == 2) && (UinSmooth < 10))// если ток заряда меньше 31 ампер- флаг вкл на отсчет времени для отключения заряда 
   {
    vse = true;
    }
  else if ((nomerP == 2) && (UinSmooth > 10))// если ток заряда опять больше 21го тогда отбой, заряжается дальше
   {
     vse = false;
    }

//////// оключение зарядки при достижения конца паузы для каждого аккумулятора
 
  if(( vse == true) && (millis() - previousMillis3 > pauseOff) )
  {
    previousMillis3 = millis();
    digitalWrite(relay1, HIGH);
    
    }
     
                  
}


 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

maxvalin пишет:

SdFat-master

Где брали?

Ссылку в студию.

А также ссылки на все остальные используемые библиотеки.

Иначе как смотреть?

maxvalin
Offline
Зарегистрирован: 22.02.2016

https://github.com/greiman/SdFat

здесь качал, ну а остальные библиотеки уже не соберу, давно было((  

-Но зависать стало именно после sdfat.  До этого стандартной SD, в этом же скетче получалось несколько раз записать на карту, логировало нормально. Но настолько не стабильно что последний раз вообще не смог заставить писать, сам себе писал памятку как танцевать и куда бить в бубен, сделал так же но карта определяется а логировать в притык не хочет. Вот и восспользовался  SdFat. Пошло сразу, но увы.. не долго.

p/s  (в первом посте не верно написал! она определялась но в нее не писало)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

maxvalin пишет:

а остальные библиотеки уже не соберу, давно было((  

Ну, тогда выкладывайте их тексты сюда.

Ну, вот, предположим, я хочу Вам помочь. И как Вы себе это видите? Откуда мне знать, что там написано в Ваших библиотеках?

GarryC
Offline
Зарегистрирован: 08.08.2016

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

А что касается посмотреть на скетч - глянул по диагонали, там много есть чего, все и не перечислишь, но к зависанию, наверное, не относится.

maxvalin
Offline
Зарегистрирован: 22.02.2016

тему не запускаю, решил разобраться сам пока что, чтоб не напрягать без причины вас и написать причину)) Есть большое подозрение на выброс большого напряжения идущего на A5 (где измеряется само напряжение) Сейчас хочу подобрать варистор на 100 вольт, ну или стабилитрон хотя он наврят ли выдержит индукцию вторички трансформатора расчитанного на 80А, даже после выпрямительных диодов.