Проблемы записи EEPROM в UNO
- Войдите на сайт для отправки комментариев
Сб, 14/03/2015 - 08:49
Есть плата 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);
}
void eeprom_write_dword (uint32_t *__p, uint32_t __value);
Я не спец, но второй параметр "обычный" а не указатель. А у Вас там чёрт ногу сломит, и разименование и указатель всё в одном флаконе.
Причём далее у Вас идет YearResetEeprom там используется просто значение как и должно быть...
Пробовал и такой код (он закоментированн), так сказать явно
long a;
a=Eeprom.GlobalEnergyP;
eeprom_write_dword((uint32_t *)(EE_SAVED_ADDRESS), a);
Результат аналогичный
Нашел свой косяк и исправил третью проблему. Первые две остались
Воощем разобрался самостоятельно.
Было много моих ошибок в коде. Но главное что я нарыл -
Работа с eeprom не должна производится в обработчиках прерываний (любых). Я использую LEos 2 а она использует вачдог таймер (пытался на нее повесить запись раз в час). При вызове процедур работы eeprom из loop все стало работать. Да это не удобно но по другому никак. Да и в момент работы надо запрещать прерывания.
Сейчас все работает.