Проблемы записи EEPROM в UNO

pav2000
Offline
Зарегистрирован: 15.12.2014

Есть плата UNO. Необходимо записать структуру в eeprom (структура Eeprom). Бьюсь уже неделю. Пробовал различными способами, везде наблюдаю схожие проблемы. Проблемы три:

1. Вызов функции записи (Hour()) работает только в цикле loop, в других местах запись приводит к сбросу контроллера в момент записи. Мне надо писать каждый час (сейчас для отладки сделано раз в минуту).

2. Пишется только первая переменная структуры, все остальные не менеются.

3. Первые две переменные (Eeprom.GlobalEnergyP и Eeprom.GlobalEnergyG) принимают бредовые знаения.

Сам скейтч (при компиляии занимает 28042 и 1432 байт соответственно). Функция записи 0 (AllResetEeprom())  работает корректно

#if defined(ARDUINO) && ARDUINO >= 100
  #include "Arduino.h"
#else
  #include "WProgram.h"
#endif

#define DEMO                   // Признак демонстрации
#define READVCC_CALIBRATION_CONST 1103782L // Калибровка встроенного АЦП (встроенный ИОН) по умолчанию 1126400 дальше измеряем питание и смотрим на дисплей 
#define NUM_SCREEN                4        // Число экранов
#define CALIBRATION_CONST_220     147.13   // Калибровка датчика напряжения 220 В 
#define CALIBRATION_CONST_220_I   10.03    // Калибровка датчика тока 220 A
#define EE_SAVED_ADDRESS   0 



// Дополнительные библиотеки
#include <OneWire.h>           // OneWire библиотека
#include <EEPROM.h>            // Запись во флеш
#include <leOS2.h>             // Шедуллер задач
#include "U8glib.h"            // Экран ЖКИ 128х64 по SPI
#include "rusFont.h"	       // Ресурс дополнительных фонтов
#include "BitMap.h"	       // Ресурс картинки для вывода на дисплей
#include "emonLib.h"
#include <avr/pgmspace.h>      // библиотека для использования  PROGMEM и F  - строковые константы в rom
// ----------------------------------------------------------------------   

byte fStart = 0;                            // Какой текущий экран вывода 0-стартовый
volatile int count=0;                       // Счетчик вемени для записи в eeprom
	
const char ver[] = "Ver. leOS2 0.61 130315";// Текущая верстия
const byte statusLed  = 13;                 // Нога куда прицеплено реле потока (если замкнуто то поток есть) - светодиод и реле к ТП 1-2
const byte sensorKey =12;                   // Нога куда прицеплена кнопка
const byte Relay2 =6;                       // Нога куда прицеплено второе реле (пока не используется)
const int  TimeMeasurement=9850;            // Длительность цикла измерения мсек  !! неточно дискретность 16 мксек
const int  TimeInterview=120;               // Длительность цикла опроса кнопок мсек
const unsigned int  TimeChart=59500;        // Длительность цикла рисования графика не более 65000 (unsigned int)
const unsigned long  TimeHour=59500;        // Длительность цикла час - для записи в ЕЕПРОМ
const int  ONE_WIRE_BUS = 10;               // Нога на которой весят датчики температуры
const int  TEMPERATURE_PRECISION =12;       // разрешение датчика темературы в битах 9-12 бит
const float calibrationFactor = 0.435;      // Калибровочный коэфициент датчика потока 2-0.439 3-431
const float heat_capacity=4.191;            // Теплоемкость теплоносителя (вода 4.191)
 
volatile unsigned long oldTime=0;           // переменная для расчета interval
volatile long interval;                     // реальный интервал измерения (чуть больше TimeMeasurement особенность leOS2)
volatile long ChartInterval;                // реальный интервал вывода графика (чуть больше TimeChart особенность leOS2)
volatile unsigned long ChartOldTime=0;      // переменная для расчета ChartInterval
char buf[12];                               // буфер для вывода чисел на экран
byte oldKey=0;                              // Предыдущее знаение клавиши 
byte flagKey=1;                             // Флаг нажатия клавиши

// Электросчетчик -----------------------------
const int eConst=1000;                       // Число импульсов на киловат/час
volatile unsigned long eCount=0;             // Счетчик импульсов от электросчетчика
volatile float ePower=0;                     // Пиковая мощность за TimeMeasurement
volatile float eEnergy=0;                    // Потребленная энергия
byte pChart[60];                             // Данные графика потеблемой мощности (датчики)
byte ChartCOP[60];                           // Данные графика COP
volatile float pPower=0;                     // Пиковая мощность за TimeMeasurement
volatile float pEnergy=0;                    // Потребленная энергия

// Первый канал ---------------------------
const byte sensorInterrupt1 = 0;             // Первый датчик потока адрес прерывания
const byte sensorPin1       = 2;             // Первый датчик потока ножка на которую вешается датчик
//const long totalLitresAdr1=0;                // Адрес объема в литрах  во флеше
const float errOut1=0.05;                    // Ошибка первого датчика - вычитается из показаний 0.05
const float errIn1=0.09;                     // Ошибка второго датчика - вычитается из показаний 0.17
unsigned char ThermOut1[8] = {0x28,0xFF,0x37,0x7F,0x4A,0x04,0x00,0xCF};  // ТП обратка адрес датчика DS18B20 28FF377F4A0400CF закругленный конец 
byte ThermIn1 [8] = {0x28,0xBC,0x6B,0x3D,0x06,0x00,0x00,0x01};  // ТП подача адрес датчика DS18B20 28BC6B3D06000001 прямой конец  синий кембрик
volatile unsigned int pulseCount1=0;         // Счетчик импульсов первого датчика
volatile float flowRate1=0.0;                // Поток литров в минуту измеряется раз в минуту
volatile float totalLitres1=0.0;             // Общий объем прошедшей житкости в литрах Пишется во флеш каждый час
volatile float totalPower1=0.0;              // Общий объем тепла
volatile unsigned int count1 = 0;            // Число импульсов от датчика полученное за интервал измерения
volatile float HZ1=0.0;                      // Частота           
volatile float P1=0.0;                       // Мощность за секунду 
volatile float tOut1,tIn1;                   // текущие температуры
byte Chart1[60];                             // Данные первого графика (ТП)

// Второй канал ---------------------------
const byte sensorInterrupt2 = 1;             // Второй датчик потока адрес прерывания
const byte sensorPin2       = 3;             // Второй датчик потока ножка на которую вешается датчик
//const long totalLitresAdr2=0+6;              // Адрес объема в литрах  во флеше
const float errOut2=0.00;                    // Ошибка первого датчика - вычитается из показаний
const float errIn2=0.00;                     // Ошибка второго датчика - вычитается из показаний
byte ThermOut2 [8]= {0x28,0xFF,0x37,0x7F,0x4A,0x04,0x00,0xCF};  // ТП обратка адрес датчика DS18B20 28FF377F4A0400CF закругленный конец 
byte ThermIn2 [8] = {0x28,0xBC,0x6B,0x3D,0x06,0x00,0x00,0x01};  // ТП подача адрес датчика DS18B20 28BC6B3D06000001 прямой конец
volatile unsigned int pulseCount2=0;         // Счетчик импульсов первого датчика
volatile float flowRate2=0.0;                // Поток литров в минуту измеряется раз в минуту
volatile float totalLitres2=0.0;             // Общий объем прошедшей житкости в литрах Пишется во флеш каждый час
volatile float totalPower2=0.0;              // Общий объем тепла
volatile unsigned int count2 = 0;            // Число импульсов от датчика полученное за интервал измерения
volatile float HZ2=0.0;                      // Частота           
volatile float P2=0.0;                       // Мощность за секунду 
volatile float tOut2,tIn2;                   // текущие температуры
byte Chart2[60];                             // Данные второго графика (ГК)

// Структура для записи в EEPROM
volatile struct my_EEPROM
{
unsigned long GlobalEnergyP;                          //  Потребленная энергия с момента старта ТН - не сбрасывается
unsigned long GlobalEnergyG;                          //  Выработанная энергия с момента старта ТН - не сбрасывается
unsigned long YearEnergyP;                            //  Потребленная энергия с начала сезона отопления ТН - сбрасывается
unsigned long YearEnergyG;                            //  Выработанная энергия с начала сезона отопления ТН - сбрасывается
unsigned long GlobalHour;                             //  Мото часы общие с момента старта ТН - не сбрасывается
unsigned long YearHour;                               //  Мото часы общие с начала сезона отопления ТН - сбрасывается
} Eeprom;
const uint32_t AdrrEeprom=0;             // Адрес записи стуктуры во флеш
volatile unsigned long EnergyP=0,EnergyG=0;  // промежуточные переменные
volatile unsigned long TimeEeprom=0; 
//long int EE_SAVED_ADDRESS EEMEM=0;
int32_t EEMEM SAVED_ADDRESS;

// ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ БИБЛИОТЕК
U8GLIB_ST7920_128X64 u8g(4, 9, 8, U8G_PIN_NONE);   // Дисплей SPI E = 4, RW = 9, RS = 8
leOS2 myOS;                                        // многозадачность
OneWire ds(ONE_WIRE_BUS);                          // поддержка температурных датчиков
EnergyMonitor emon1;                               // Мониторинг электросети

void setup(void) {
  u8g.setFont(my5x7rus);
  u8g.setRot180();                   //Перевернул экран
  pinMode(statusLed, OUTPUT);        // Индикация потока светодиод и реле
  digitalWrite(statusLed, HIGH);  
  pinMode(sensorPin1, INPUT);        //  Подключение датчика потока 1
  digitalWrite(sensorPin1, HIGH);
  pinMode(sensorPin2, INPUT);        //  Подключение датчика потока 2
  digitalWrite(sensorPin2, HIGH);
  pinMode(sensorKey, INPUT);         //  Включена кнопка
  digitalWrite(sensorKey, HIGH);
  pinMode(5, INPUT);                 //  Электросчетчик
  digitalWrite(5, HIGH);
 
  // Установка начальных переменных
  interval=TimeMeasurement;
  ChartInterval=TimeChart;  
  attachInterrupt(sensorInterrupt1, pulseCounter1, CHANGE);  // Прерывания
  attachInterrupt(sensorInterrupt2, pulseCounter2, CHANGE);
  
  myOS.begin();
  myOS.addTask(measurement,myOS.convertMs(TimeMeasurement));
  myOS.addTask(Chart,myOS.convertMs(TimeChart));
 // myOS.addTask(Hour,myOS.convertMs(TimeHour));
     
// Программирование 1 таймера на подсчет событий на D5 (туда заводится электросчетчик)
  TCCR1A = 0;   // reset Timer 1 
  TCCR1B = 0; 
  TCNT1 = 0;  
  // start Timer 1 External clock source on T1 pin (D5). Clock on rising edge.
  TCCR1B =  bit (CS10) | bit (CS11) | bit (CS12);
  
  emon1.voltage(0,CALIBRATION_CONST_220,1.7);  // Инициализация датчика напряжения 220
  emon1.current(1, CALIBRATION_CONST_220_I);   // Инициализация датчика тока 220
  
  // Чтение счетчиков из флеша
 AllResetEeprom();
  readEeprom();
  	  }
// --------------------------------------------- LOOP ------------------------------------	 
void loop(void) {
  float t;

    // Старт преобразования датчиков
    StartDS1820(ThermOut1);
    StartDS1820(ThermIn1);
    StartDS1820(ThermOut2);
    StartDS1820(ThermIn2);
  
    u8g.firstPage(); 
     do {
       // Общая часть для каждого экрана (для экономии длины кода) - заголовок экрана
       if (fStart!=0)
        { 
          u8g.drawBox(0,0,128,9);  // Закрашиваем прямоугольник белым 
          u8g.setColorIndex(0);    // Черные чернила, Белый  фон
          u8g.setPrintPos(1, 7);
          u8g.print(int(fStart));
          u8g.drawLine(118, 0, 118, 8);  // Индикатор потока на экран и на реле
          u8g.setPrintPos(121, 7);
          if ((flowRate1>0)&&(flowRate2>0)) {digitalWrite(statusLed, HIGH);u8g.print(F("+"));}// Светодиод и реле показывает что поток есть реле идет к ТН (1-2)
          else {digitalWrite(statusLed, LOW); u8g.print(F("-"));}
          u8g.drawLine(98, 0, 98, 8);  // Индикатор потока на экран и на реле
          u8g.setPrintPos(100, 7);
          u8g.print(dtostrf(count,3,0,buf)); // Вывод напряжения в стоке состояния
      // u8g.print(dtostrf(emon1.Vrms,3,0,buf)); // Вывод напряжения в стоке состояния
          u8g.setPrintPos(8, 7);   // Далее сразу можно печатать заголовок
        }
       switch (fStart)
        {
        case 0: ScreenStart(); break;
        case 1: Screen1(); break;
        case 2: Screen2(); break;
        case 3: Screen3(); break;
        case 4: Screen4(); break;
        default:Screen1();
        }
         
       } while( u8g.nextPage() );
       
       if (fStart==0) 
         { delay(3000); myOS.addTask(scanKey,myOS.convertMs(TimeInterview)); } // Клавиатура активируется, начинается сканирование
        
       if (count>=1) { Hour();  count=0;  Eeprom.GlobalEnergyP++;}
             
        delay(500);
        emon1.calcVI(20,4000);  
        t=getTempDS1820(ThermOut1);
        if (t>-30&&t<80) tOut1=t-errOut1;   // Иногда считывает глюки
        t=getTempDS1820(ThermIn1);
        if (t>-30&&t<70) tIn1=t-errIn1;     // Иногда считывает глюки
        t=getTempDS1820(ThermOut2);
        if (t>-30&&t<30) tOut2=t-errOut2;   // Иногда считывает глюки
        t=getTempDS1820(ThermIn2);
        if (t>-30&&t<30) tIn2=t-errIn2;     // Иногда считывает глюки
    
      	}
// Стартовый экран --------------------------------------
void ScreenStart()
{
 u8g.setColorIndex(1);
 u8g.drawXBM(0, 0, 56, 56, u8g_logo_bits); 
// u8g.drawXBM(0, 0, 51, 51, aLogo); 
 u8g.setPrintPos(73, 10);
 u8g.print(F("Контроль"));
 u8g.setPrintPos(70, 20);
 u8g.print(F("Теплового"));
 u8g.setPrintPos(78, 30);
 u8g.print(F("Насоса")); 
 u8g.setPrintPos(66, 40);
 u8g.print(F("Arduino UNO")); 
 u8g.setPrintPos(1, 63);  
 u8g.print(ver); 
}

// Отображение типа 1 -------------------------------------
void Screen1()
{
  byte x1,y1,i;
  u8g.print(F("Теплые Полы")); 
 
  u8g.setColorIndex(1);    // белые чернила, черный фон
  u8g.setPrintPos(0, 16);
  u8g.print(F("Поток:         Част:")); 
  u8g.setPrintPos(32, 16);
  u8g.print(dtostrf(flowRate1*60.0/1000.0,4, 3, buf));
  u8g.setPrintPos(95, 16);
  u8g.print(HZ1); 
  
  u8g.drawXBM(58, 10, 9, 7, cub);
  u8g.drawXBM(120, 10, 8, 7, Hz);
  
  u8g.drawLine(0, 18, 127, 18); 
  
  u8g.drawXBM(0, 20, 21, 25, T123); // Термометр и значки
  
  x1=8; y1=26; 
  u8g.setPrintPos(x1+14, y1); // Подача
  u8g.print(dtostrf(tOut1,4, 2, buf)); 
  u8g.drawXBM(x1+45, y1-6, 9, 7, C0);
  
  u8g.setPrintPos(x1+14, y1+9); // Обратка
  u8g.print(dtostrf(tIn1,4, 2, buf)); 
  u8g.drawXBM(x1+45, y1-6+9, 9, 7, C0);
 
  if (tOut1-tIn1<0) u8g.setPrintPos(x1+13, y1+9+9); // Разность температур
  else  u8g.setPrintPos(x1+14+6, y1+9+9); 
  u8g.print(dtostrf(tOut1-tIn1,4, 2, buf)); 
  u8g.drawXBM(x1+45, y1-6+9+9, 9, 7, C0);
  
  u8g.drawLine(63, 18, 63, 63); 
 
  u8g.setFont(u8g_font_courB10);
  u8g.setPrintPos(107, 30);
  u8g.print(F("kW"));
  u8g.setPrintPos(70, 30);
  u8g.print(dtostrf(P1,3, 1, buf));
  u8g.setFont(my5x7rus);
  
  u8g.drawLine(0, 46, 63, 46);
      
  u8g.setPrintPos(0, 54);
  u8g.print(F("V:"));
  u8g.setPrintPos(12, 54);
  u8g.print(dtostrf(totalLitres1/60/1000,11, 3, buf)); 
  u8g.setPrintPos(0, 63);
  u8g.print(F("G:"));
  u8g.setPrintPos(12, 63);
  u8g.print(dtostrf(totalPower1,11, 3, buf)); 
  
  // График
  // for(i=0;i<60;i++) u8g.drawPixel(65+i,63-Chart1[i]);     // Точки
  for(i=0;i<60;i++) u8g.drawLine(65+i,64,65+i,64-Chart1[i]); // Линия 0 не выводится
   
}
// Отображение типа 2 -------------------------------------
void Screen2()
{
  byte x1,y1,i;
  u8g.print(F("Гео контур")); 
  
  u8g.setColorIndex(1);    // белые чернила, черный фон
  u8g.setPrintPos(0, 16);
  u8g.print(F("Поток:         Част:")); 
  u8g.setPrintPos(32, 16);
  u8g.print(dtostrf(flowRate2*60.0/1000.0,4, 3, buf));
  u8g.setPrintPos(95, 16);
  u8g.print(HZ2); 
  
  u8g.drawXBM(58, 10, 9, 7, cub);
  u8g.drawXBM(120, 10, 8, 7, Hz);
  
  u8g.drawLine(0, 18, 127, 18); 
  
  u8g.drawXBM(0, 20, 21, 25, T123); // Термометр и значки
  
  x1=8; y1=26; 
  u8g.setPrintPos(x1+14, y1); // Подача
  u8g.print(dtostrf(tOut2,4, 2, buf)); 
  u8g.drawXBM(x1+45, y1-6, 9, 7, C0);
  
  u8g.setPrintPos(x1+14, y1+9); // Обратка
  u8g.print(dtostrf(tIn2,4, 2, buf)); 
  u8g.drawXBM(x1+45, y1-6+9, 9, 7, C0);
 
  if (tOut2-tIn2<0) u8g.setPrintPos(x1+13, y1+9+9); // Разность температур
  else  u8g.setPrintPos(x1+14+6, y1+9+9); 
  u8g.print(dtostrf(tOut2-tIn2,4, 2, buf)); 
  u8g.drawXBM(x1+45, y1-6+9+9, 9, 7, C0);
  
  u8g.drawLine(63, 18, 63, 63); 
 
  u8g.setFont(u8g_font_courB10);
  u8g.setPrintPos(107, 30);
  u8g.print(F("kW"));
  u8g.setPrintPos(70, 30);
  u8g.print(dtostrf(P2,3, 1, buf));
  u8g.setFont(my5x7rus);
  
  u8g.drawLine(0, 46, 63, 46);
      
  u8g.setPrintPos(0, 54);
  u8g.print(F("V:"));
  u8g.setPrintPos(12, 54);
  u8g.print(dtostrf(totalLitres2/60/1000,11, 3, buf)); 
  u8g.setPrintPos(0, 63);
  u8g.print(F("G:"));
  u8g.setPrintPos(12, 63);
  u8g.print(dtostrf(totalPower2,11, 3, buf));
  
   // График
  // for(i=0;i<60;i++) u8g.drawPixel(65+i,63-Chart2[i]); 
  for(i=0;i<60;i++) u8g.drawLine(65+i,64,65+i,64-Chart2[i]); // 0 не выводится
   
}

// Отображение типа 3  Напряжение Ток-------------------------------------
void Screen3()
{
  int i;
  u8g.print(F("Напряжение&Ток"));
  u8g.setColorIndex(1);    // белые чернила, черный фон
  
  u8g.setPrintPos(0, 16);
  u8g.print(F("V rms:"));
  u8g.setPrintPos(31, 16);
  u8g.print(dtostrf(emon1.Vrms,4,1,buf));
 // u8g.setPrintPos(66, 16);
  u8g.setPrintPos(0, 24);
  u8g.print(F("I rms:"));
  u8g.setPrintPos(31, 24);
//  u8g.setPrintPos(105, 16);
  u8g.print(dtostrf(emon1.Irms,4,1,buf));
  
  u8g.setPrintPos(65, 16);
  u8g.print(F("Pow_f:"));
  u8g.setPrintPos(102, 16);
  u8g.print(dtostrf(emon1.powerFactor,3,2,buf));
  
  u8g.setPrintPos(0, 34);
  u8g.print(F("PW кВт:"));
  u8g.setPrintPos(39,34);
  #ifdef  DEMO    // Демка
    u8g.print(dtostrf(pPower,4, 2, buf));
  #else
    u8g.print(dtostrf(emon1.realPower/1000.0,4, 2, buf));
   #endif
//  u8g.print(dtostrf(emon1.realPower/1000.0,4, 2, buf));
//   u8g.print(dtostrf(pPower,4, 2, buf));
  
  u8g.setPrintPos(75, 26);
  u8g.print(F("COP:"));
  u8g.setPrintPos(98, 26);
  if (emon1.realPower>500)  u8g.print(dtostrf(P1/(emon1.realPower/1000),3,2,buf));
  else u8g.print(dtostrf(0.0,3,2,buf));
   
  u8g.drawLine(63, 18, 63, 63); 
  u8g.drawLine(0, 26, 63, 26);
  u8g.drawLine(64, 18, 127, 18);
  
  //  for(i=0;i<=6;i++) u8g.drawPixel(62,64-i*4);  // Шкала мощность
  for(i=0;i<=5;i++)
  { u8g.drawPixel(64,64-i*7);   // Шкала СОР
    u8g.drawPixel(65,64-i*7);
  }
 
 for(i=0;i<60;i++) // График
    { 
     u8g.drawLine(i,64,i,64-pChart[i]);   
     u8g.drawLine(67+i,64,67+i,64-ChartCOP[i]); 
    }
}

// Отображение типа 4  Счетчики -------------------------------------
void Screen4()
{
  u8g.print(F("Счетчики.")); 
  u8g.setColorIndex(1);    // белые чернила, черный фон
  
  u8g.drawLine(28, 9, 28, 63);
  u8g.drawLine(79, 9, 79, 63);
  
  u8g.setPrintPos(0, 16);
  u8g.print(F("        За сезон   Общий"));
   
  u8g.setPrintPos(0, 24);
  u8g.print(F("P кВт"));
  u8g.setPrintPos(31, 24);
  u8g.print(long(Eeprom.YearEnergyP));
  u8g.setPrintPos(82, 24);
  u8g.print(long(Eeprom.GlobalEnergyP));
 
  u8g.setPrintPos(0, 32);
  u8g.print(F("G кВт"));
  u8g.setPrintPos(31, 32);
  u8g.print(long(Eeprom.YearEnergyG));
  u8g.setPrintPos(82, 32);
  u8g.print(long(Eeprom.GlobalEnergyG));
  
  u8g.setPrintPos(0, 40);
  u8g.print(F("COP"));
  u8g.setPrintPos(31, 40);
  u8g.print(dtostrf((float)Eeprom.YearEnergyG/(float)Eeprom.YearEnergyP,4,2, buf));
  u8g.setPrintPos(82, 40);
  u8g.print(dtostrf((float)Eeprom.GlobalEnergyG/(float)Eeprom.GlobalEnergyP,4,2, buf));

  u8g.setPrintPos(0, 48);
  u8g.print(F("Часы"));
  u8g.setPrintPos(31, 48);
  u8g.print(int(Eeprom.YearHour));
  u8g.setPrintPos(82, 48);
  u8g.print(int(Eeprom.GlobalHour));

}
// Прерывание подсчет импульсов от первого канала
void pulseCounter1() {   pulseCount1++; }
// Прерывание подсчет импульсов от второго канала
void pulseCounter2() {   pulseCount2++; }

// Цикл измерения интервал задается -----------------------------------
void measurement()
{
  cli();  // Запретить прерывания TimeMeasurement
 count1=pulseCount1;  pulseCount1 = 0;
 count2=pulseCount2;  pulseCount2 = 0;
 sei();  // разрешить прерывания
 
 interval=millis()-oldTime; // Точное определение интервала ----------------------------
 oldTime= interval+oldTime;  
 if (interval<=0) interval=TimeMeasurement; // Через 50 дней millis() сбросится по этому после этого первая итерация расчетная

 #ifdef  DEMO    // Демка
     count1=random(190,240); 
     count2=random(160,200);
     TCNT1=random(5,9);
     emon1.realPower=random(1700,2700);
   #endif

 // Первый канал 
 HZ1=(count1*1000.0)/interval/2; // делить на 2 - это т.к. прерывания работает на оба фронта импульса CHANGE
 flowRate1 = HZ1/calibrationFactor; // рассчитать поток в литрах за минуту
 totalLitres1 = totalLitres1 + flowRate1*(interval/1000.0); 
 P1=(flowRate1/60) // литры/килограммы в секунду
                   *heat_capacity*(tOut1-tIn1); 
 totalPower1 = totalPower1 + P1*(interval/1000.0)/3600; 
 
 // Второй канал 
 HZ2=(count2*1000.0)/interval/2; // делить на 2 - это т.к. прерывания работает на оба фронта импульса CHANGE
 flowRate2 = HZ2/calibrationFactor; // рассчитать поток в литрах за минуту
 totalLitres2 = totalLitres2 + flowRate2*(interval/1000.0); 
 P2=(flowRate2/60) // литры/килограммы в секунду
                   *heat_capacity*(tOut2-tIn2); 
 totalPower2 = totalPower2 + P2*(interval/1000.0)/3600; 
 
 // Электросчетчик
 eCount=eCount+TCNT1; // Общий счетчик
 ePower=(float)TCNT1*3600.0/(float)eConst/(interval/1000.0); // Пиковый счетчик
 eEnergy=(float)eCount/(float)eConst;
 TCNT1 = 0;
 
 // Датчик напряжения и тока
 pPower=emon1.realPower/1000.0;
 pEnergy=pEnergy+emon1.realPower*(3600.0*interval/1000.0);
  
 }

// Сканирование клавиш ------------------------------------------
void scanKey()
{
byte key;  
key=digitalRead(sensorKey);
if ((key==1)&&(oldKey==1)&&(flagKey==1)) {fStart++;flagKey=0;}  // Клавиша нажита
if ((key==0)&&(oldKey==1)) flagKey=1;                           // Начало (по заднему фронту) ожидания нового нажатия 
oldKey=key;
if (fStart > NUM_SCREEN) fStart=1;
}

// Подготовка массива точек для графиков ----------------------------------------
void Chart()
{
 int i;
  count++;
 ChartInterval=millis()-ChartOldTime; // Точное определение интервала показа графика----------------------------
 ChartOldTime= ChartInterval+ChartOldTime;  
 if (ChartInterval<=0) ChartInterval=TimeMeasurement; // Через 50 дней millis() сбросится по этому после этого первая итерация расчетная
  // Сдвиг графиков и запись новых данных
  for(i=0;i<60;i++) 
     {  
      Chart1[i]=Chart1[i+1]; 
      Chart2[i]=Chart2[i+1];
      pChart[i]=pChart[i+1];
      ChartCOP[i]=ChartCOP[i+1];
     }
    Chart1[59]=P1*2.5;
    Chart2[59]=P2*2.5;
    pChart[59]=9*emon1.realPower/1000; 
    if (emon1.realPower>500) ChartCOP[59]=(P1/(emon1.realPower/1000))*7.0; else ChartCOP[59]=0;
}
// Вызывается раз в час используется для сохранения показаний счетчиков в еепром------------------------------
void Hour()
{
unsigned long dP,dG,dT;
//  Электричество
 dP= pEnergy-EnergyP; // Прирост за час
 EnergyP=pEnergy;      // запоминание для нового цикла
 Eeprom.GlobalEnergyP =Eeprom.GlobalEnergyP+dP;
 Eeprom.YearEnergyP=Eeprom.YearEnergyP+dP;
 
 // Тепло
 dG= totalPower1-EnergyG; // Прирост за час
 EnergyG=totalPower1;      // запоминание для нового цикла
 Eeprom.GlobalEnergyG =Eeprom.GlobalEnergyG+dG;
 Eeprom.YearEnergyG=Eeprom.YearEnergyG+dG;
 
 // Мото часы
 dT=millis()-TimeEeprom;
 if (dT<=0) dT=0;
 TimeEeprom=millis();
 Eeprom.GlobalHour=Eeprom.GlobalHour+TimeEeprom/1000/60/60;
 Eeprom.YearHour=Eeprom.YearHour+TimeEeprom/1000/60/60;
//Eeprom.YearHour=Eeprom.YearHour+TimeEeprom;

 // Запись во флеш
writeEeprom();
}  

// Старт преобразования одного датчика -----------------------------------------------
void StartDS1820(byte *addr)
{
   ds.reset();
   ds.select(addr);
   ds.write(0x44,0);  
}
// Чтение температуры одного датчика -----------------------------------------------
float getTempDS1820(unsigned char *addr)
{
    byte i;
    byte type_s;
    byte present = 0;
    byte data[12];
    // Запрос уже послан ранее StartDS1820
    present = ds.reset();
    ds.select(addr);
    ds.write(0xBE); // Команда на чтение регистра температуры
    for ( i = 0; i < 9; i++) { data[i] = ds.read();}
    int16_t raw = (data[1] << 8) | data[0];
    if (type_s) {
     raw = raw << 3; // 9 bit resolution default
     if (data[7] == 0x10) {
      // "count remain" gives full 12 bit resolution
      raw = (raw & 0xFFF0) + 12 - data[6];
    }
  } else {
    byte cfg = (data[4] & 0x60);
    // at lower res, the low bits are undefined, so let's zero them
    if (cfg == 0x00) raw = raw & ~7;      // 9 bit resolution, 93.75 ms
    else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
    else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
    //// default is 12 bit resolution, 750 ms conversion time
  }
  return (float)raw / 16.0;       
}

// Чтение внутреннего датчика температуры ---------------------------------------
double GetTemp(void)
{
  unsigned int wADC;
  double t;
  ADMUX = (_BV(REFS1) | _BV(REFS0) | _BV(MUX3));
  ADCSRA |= _BV(ADEN);  
  delay(20);           
  ADCSRA |= _BV(ADSC);  
  while (bit_is_set(ADCSRA,ADSC));
  wADC = ADCW;
  t = (wADC - 324.31 ) / 1.22;
  return (t); 
}

//----------------------------EEPROM FUNCTION--------------------------------------------------

void writeEeprom()
{ 
//  byte *x = (byte *)&Eeprom;
//  for(int i = 0; i < 6*4; i++) EEPROM.write(i, x[i]);
  
// eeprom_write_dword(0,32);
// eeprom_write_dword(4,33);

 eeprom_write_dword((uint32_t *)(EE_SAVED_ADDRESS),  *(uint32_t *)&Eeprom.GlobalEnergyP); 
 eeprom_write_dword((uint32_t *)(EE_SAVED_ADDRESS+4),  *(uint32_t *)&Eeprom.GlobalEnergyG);
 eeprom_write_dword((uint32_t *)(EE_SAVED_ADDRESS+8),  *(uint32_t *)&Eeprom.YearEnergyP);
 eeprom_write_dword((uint32_t *)(EE_SAVED_ADDRESS+12), *(uint32_t *)&Eeprom.YearEnergyG);
 eeprom_write_dword((uint32_t *)(EE_SAVED_ADDRESS+16), *(uint32_t *)&Eeprom.GlobalHour);
 eeprom_write_dword((uint32_t *)(EE_SAVED_ADDRESS+18), *(uint32_t *)&Eeprom.YearHour);


/*long a;
 a=Eeprom.GlobalEnergyP;
 eeprom_write_dword((uint32_t *)(EE_SAVED_ADDRESS), a);
 a=Eeprom.GlobalEnergyG; 
 eeprom_write_dword((uint32_t *)(EE_SAVED_ADDRESS+4),a);
 a=Eeprom.YearEnergyP;
 eeprom_write_dword((uint32_t *)(EE_SAVED_ADDRESS+8),a);
 a=Eeprom.YearEnergyG;
 eeprom_write_dword((uint32_t *)(EE_SAVED_ADDRESS+12),a);
 a=Eeprom.GlobalHour;
 eeprom_write_dword((uint32_t *)(EE_SAVED_ADDRESS+16),a);
 a=Eeprom.YearHour;
 eeprom_write_dword((uint32_t *)(EE_SAVED_ADDRESS+18),a); 
*/
}
// Полный сброс делается только один раз
void AllResetEeprom()
{
 eeprom_write_dword((uint32_t *)EE_SAVED_ADDRESS, 0);
 eeprom_write_dword((uint32_t *)EE_SAVED_ADDRESS+4, 0);
 eeprom_write_dword((uint32_t *)EE_SAVED_ADDRESS+8, 0);
 eeprom_write_dword((uint32_t *)EE_SAVED_ADDRESS+12, 0);
 eeprom_write_dword((uint32_t *)EE_SAVED_ADDRESS+16, 0);
 eeprom_write_dword((uint32_t *)EE_SAVED_ADDRESS+18, 0);
}
// Сброс только последнего сезона
void YearResetEeprom()
{
 eeprom_write_dword((uint32_t *)EE_SAVED_ADDRESS, Eeprom.GlobalEnergyP);
 eeprom_write_dword((uint32_t *)EE_SAVED_ADDRESS+4, Eeprom.GlobalEnergyG);
 eeprom_write_dword((uint32_t *)EE_SAVED_ADDRESS+8, 0);
 eeprom_write_dword((uint32_t *)EE_SAVED_ADDRESS+12, 0);
 eeprom_write_dword((uint32_t *)EE_SAVED_ADDRESS+16, Eeprom.GlobalHour);
 eeprom_write_dword((uint32_t *)EE_SAVED_ADDRESS+18, 0);
}

//read
void readEeprom()
{
 Eeprom.GlobalEnergyP=eeprom_read_dword((const uint32_t *)EE_SAVED_ADDRESS);                       
 Eeprom.GlobalEnergyG=eeprom_read_dword((const uint32_t *)EE_SAVED_ADDRESS+4);                        
 Eeprom.YearEnergyP  =eeprom_read_dword((const uint32_t *)EE_SAVED_ADDRESS+8);                          
 Eeprom.YearEnergyG  =eeprom_read_dword((const uint32_t *)EE_SAVED_ADDRESS+12);                         
 Eeprom.GlobalHour   =eeprom_read_dword((const uint32_t *)EE_SAVED_ADDRESS+16);                          
 Eeprom.YearHour     =eeprom_read_dword((const uint32_t *)EE_SAVED_ADDRESS+18);       
}

 

 

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

void eeprom_write_dword (uint32_t *__p, uint32_t __value);

Я не спец, но второй параметр "обычный" а не указатель. А у Вас там чёрт ногу сломит, и разименование и указатель всё в одном флаконе.

Причём далее у Вас идет YearResetEeprom там используется просто значение как и должно быть...

pav2000
Offline
Зарегистрирован: 15.12.2014

Пробовал и такой код (он закоментированн), так сказать явно

long a;
a=Eeprom.GlobalEnergyP;
eeprom_write_dword((uint32_t *)(EE_SAVED_ADDRESS), a);

Результат аналогичный

Нашел свой косяк и исправил третью проблему. Первые две остались

 

pav2000
Offline
Зарегистрирован: 15.12.2014

Воощем разобрался самостоятельно.

Было много моих ошибок в коде. Но главное что я нарыл -

Работа с eeprom не должна производится в обработчиках прерываний (любых). Я использую LEos 2  а она использует вачдог таймер (пытался на нее повесить запись раз в час). При вызове процедур работы eeprom из loop все стало работать. Да это не удобно но по другому никак. Да и в момент работы надо запрещать прерывания.

Сейчас все работает.