Проблемы записи EEPROM в UNO
- Войдите на сайт для отправки комментариев
Сб, 14/03/2015 - 08:49
Есть плата UNO. Необходимо записать структуру в eeprom (структура Eeprom). Бьюсь уже неделю. Пробовал различными способами, везде наблюдаю схожие проблемы. Проблемы три:
1. Вызов функции записи (Hour()) работает только в цикле loop, в других местах запись приводит к сбросу контроллера в момент записи. Мне надо писать каждый час (сейчас для отладки сделано раз в минуту).
2. Пишется только первая переменная структуры, все остальные не менеются.
3. Первые две переменные (Eeprom.GlobalEnergyP и Eeprom.GlobalEnergyG) принимают бредовые знаения.
Сам скейтч (при компиляии занимает 28042 и 1432 байт соответственно). Функция записи 0 (AllResetEeprom()) работает корректно
001 | #if defined(ARDUINO) && ARDUINO >= 100 |
002 | #include "Arduino.h" |
003 | #else |
004 | #include "WProgram.h" |
005 | #endif |
006 |
007 | #define DEMO // Признак демонстрации |
008 | #define READVCC_CALIBRATION_CONST 1103782L // Калибровка встроенного АЦП (встроенный ИОН) по умолчанию 1126400 дальше измеряем питание и смотрим на дисплей |
009 | #define NUM_SCREEN 4 // Число экранов |
010 | #define CALIBRATION_CONST_220 147.13 // Калибровка датчика напряжения 220 В |
011 | #define CALIBRATION_CONST_220_I 10.03 // Калибровка датчика тока 220 A |
012 | #define EE_SAVED_ADDRESS 0 |
013 |
014 |
015 |
016 | // Дополнительные библиотеки |
017 | #include <OneWire.h> // OneWire библиотека |
018 | #include <EEPROM.h> // Запись во флеш |
019 | #include <leOS2.h> // Шедуллер задач |
020 | #include "U8glib.h" // Экран ЖКИ 128х64 по SPI |
021 | #include "rusFont.h" // Ресурс дополнительных фонтов |
022 | #include "BitMap.h" // Ресурс картинки для вывода на дисплей |
023 | #include "emonLib.h" |
024 | #include <avr/pgmspace.h> // библиотека для использования PROGMEM и F - строковые константы в rom |
025 | // ---------------------------------------------------------------------- |
026 |
027 | byte fStart = 0; // Какой текущий экран вывода 0-стартовый |
028 | volatile int count=0; // Счетчик вемени для записи в eeprom |
029 | |
030 | const char ver[] = "Ver. leOS2 0.61 130315" ; // Текущая верстия |
031 | const byte statusLed = 13; // Нога куда прицеплено реле потока (если замкнуто то поток есть) - светодиод и реле к ТП 1-2 |
032 | const byte sensorKey =12; // Нога куда прицеплена кнопка |
033 | const byte Relay2 =6; // Нога куда прицеплено второе реле (пока не используется) |
034 | const int TimeMeasurement=9850; // Длительность цикла измерения мсек !! неточно дискретность 16 мксек |
035 | const int TimeInterview=120; // Длительность цикла опроса кнопок мсек |
036 | const unsigned int TimeChart=59500; // Длительность цикла рисования графика не более 65000 (unsigned int) |
037 | const unsigned long TimeHour=59500; // Длительность цикла час - для записи в ЕЕПРОМ |
038 | const int ONE_WIRE_BUS = 10; // Нога на которой весят датчики температуры |
039 | const int TEMPERATURE_PRECISION =12; // разрешение датчика темературы в битах 9-12 бит |
040 | const float calibrationFactor = 0.435; // Калибровочный коэфициент датчика потока 2-0.439 3-431 |
041 | const float heat_capacity=4.191; // Теплоемкость теплоносителя (вода 4.191) |
042 | |
043 | volatile unsigned long oldTime=0; // переменная для расчета interval |
044 | volatile long interval; // реальный интервал измерения (чуть больше TimeMeasurement особенность leOS2) |
045 | volatile long ChartInterval; // реальный интервал вывода графика (чуть больше TimeChart особенность leOS2) |
046 | volatile unsigned long ChartOldTime=0; // переменная для расчета ChartInterval |
047 | char buf[12]; // буфер для вывода чисел на экран |
048 | byte oldKey=0; // Предыдущее знаение клавиши |
049 | byte flagKey=1; // Флаг нажатия клавиши |
050 |
051 | // Электросчетчик ----------------------------- |
052 | const int eConst=1000; // Число импульсов на киловат/час |
053 | volatile unsigned long eCount=0; // Счетчик импульсов от электросчетчика |
054 | volatile float ePower=0; // Пиковая мощность за TimeMeasurement |
055 | volatile float eEnergy=0; // Потребленная энергия |
056 | byte pChart[60]; // Данные графика потеблемой мощности (датчики) |
057 | byte ChartCOP[60]; // Данные графика COP |
058 | volatile float pPower=0; // Пиковая мощность за TimeMeasurement |
059 | volatile float pEnergy=0; // Потребленная энергия |
060 |
061 | // Первый канал --------------------------- |
062 | const byte sensorInterrupt1 = 0; // Первый датчик потока адрес прерывания |
063 | const byte sensorPin1 = 2; // Первый датчик потока ножка на которую вешается датчик |
064 | //const long totalLitresAdr1=0; // Адрес объема в литрах во флеше |
065 | const float errOut1=0.05; // Ошибка первого датчика - вычитается из показаний 0.05 |
066 | const float errIn1=0.09; // Ошибка второго датчика - вычитается из показаний 0.17 |
067 | unsigned char ThermOut1[8] = {0x28,0xFF,0x37,0x7F,0x4A,0x04,0x00,0xCF}; // ТП обратка адрес датчика DS18B20 28FF377F4A0400CF закругленный конец |
068 | byte ThermIn1 [8] = {0x28,0xBC,0x6B,0x3D,0x06,0x00,0x00,0x01}; // ТП подача адрес датчика DS18B20 28BC6B3D06000001 прямой конец синий кембрик |
069 | volatile unsigned int pulseCount1=0; // Счетчик импульсов первого датчика |
070 | volatile float flowRate1=0.0; // Поток литров в минуту измеряется раз в минуту |
071 | volatile float totalLitres1=0.0; // Общий объем прошедшей житкости в литрах Пишется во флеш каждый час |
072 | volatile float totalPower1=0.0; // Общий объем тепла |
073 | volatile unsigned int count1 = 0; // Число импульсов от датчика полученное за интервал измерения |
074 | volatile float HZ1=0.0; // Частота |
075 | volatile float P1=0.0; // Мощность за секунду |
076 | volatile float tOut1,tIn1; // текущие температуры |
077 | byte Chart1[60]; // Данные первого графика (ТП) |
078 |
079 | // Второй канал --------------------------- |
080 | const byte sensorInterrupt2 = 1; // Второй датчик потока адрес прерывания |
081 | const byte sensorPin2 = 3; // Второй датчик потока ножка на которую вешается датчик |
082 | //const long totalLitresAdr2=0+6; // Адрес объема в литрах во флеше |
083 | const float errOut2=0.00; // Ошибка первого датчика - вычитается из показаний |
084 | const float errIn2=0.00; // Ошибка второго датчика - вычитается из показаний |
085 | byte ThermOut2 [8]= {0x28,0xFF,0x37,0x7F,0x4A,0x04,0x00,0xCF}; // ТП обратка адрес датчика DS18B20 28FF377F4A0400CF закругленный конец |
086 | byte ThermIn2 [8] = {0x28,0xBC,0x6B,0x3D,0x06,0x00,0x00,0x01}; // ТП подача адрес датчика DS18B20 28BC6B3D06000001 прямой конец |
087 | volatile unsigned int pulseCount2=0; // Счетчик импульсов первого датчика |
088 | volatile float flowRate2=0.0; // Поток литров в минуту измеряется раз в минуту |
089 | volatile float totalLitres2=0.0; // Общий объем прошедшей житкости в литрах Пишется во флеш каждый час |
090 | volatile float totalPower2=0.0; // Общий объем тепла |
091 | volatile unsigned int count2 = 0; // Число импульсов от датчика полученное за интервал измерения |
092 | volatile float HZ2=0.0; // Частота |
093 | volatile float P2=0.0; // Мощность за секунду |
094 | volatile float tOut2,tIn2; // текущие температуры |
095 | byte Chart2[60]; // Данные второго графика (ГК) |
096 |
097 | // Структура для записи в EEPROM |
098 | volatile struct my_EEPROM |
099 | { |
100 | unsigned long GlobalEnergyP; // Потребленная энергия с момента старта ТН - не сбрасывается |
101 | unsigned long GlobalEnergyG; // Выработанная энергия с момента старта ТН - не сбрасывается |
102 | unsigned long YearEnergyP; // Потребленная энергия с начала сезона отопления ТН - сбрасывается |
103 | unsigned long YearEnergyG; // Выработанная энергия с начала сезона отопления ТН - сбрасывается |
104 | unsigned long GlobalHour; // Мото часы общие с момента старта ТН - не сбрасывается |
105 | unsigned long YearHour; // Мото часы общие с начала сезона отопления ТН - сбрасывается |
106 | } Eeprom; |
107 | const uint32_t AdrrEeprom=0; // Адрес записи стуктуры во флеш |
108 | volatile unsigned long EnergyP=0,EnergyG=0; // промежуточные переменные |
109 | volatile unsigned long TimeEeprom=0; |
110 | //long int EE_SAVED_ADDRESS EEMEM=0; |
111 | int32_t EEMEM SAVED_ADDRESS; |
112 |
113 | // ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ БИБЛИОТЕК |
114 | U8GLIB_ST7920_128X64 u8g(4, 9, 8, U8G_PIN_NONE); // Дисплей SPI E = 4, RW = 9, RS = 8 |
115 | leOS2 myOS; // многозадачность |
116 | OneWire ds(ONE_WIRE_BUS); // поддержка температурных датчиков |
117 | EnergyMonitor emon1; // Мониторинг электросети |
118 |
119 | void setup ( void ) { |
120 | u8g.setFont(my5x7rus); |
121 | u8g.setRot180(); //Перевернул экран |
122 | pinMode(statusLed, OUTPUT); // Индикация потока светодиод и реле |
123 | digitalWrite(statusLed, HIGH); |
124 | pinMode(sensorPin1, INPUT); // Подключение датчика потока 1 |
125 | digitalWrite(sensorPin1, HIGH); |
126 | pinMode(sensorPin2, INPUT); // Подключение датчика потока 2 |
127 | digitalWrite(sensorPin2, HIGH); |
128 | pinMode(sensorKey, INPUT); // Включена кнопка |
129 | digitalWrite(sensorKey, HIGH); |
130 | pinMode(5, INPUT); // Электросчетчик |
131 | digitalWrite(5, HIGH); |
132 | |
133 | // Установка начальных переменных |
134 | interval=TimeMeasurement; |
135 | ChartInterval=TimeChart; |
136 | attachInterrupt(sensorInterrupt1, pulseCounter1, CHANGE); // Прерывания |
137 | attachInterrupt(sensorInterrupt2, pulseCounter2, CHANGE); |
138 | |
139 | myOS.begin(); |
140 | myOS.addTask(measurement,myOS.convertMs(TimeMeasurement)); |
141 | myOS.addTask(Chart,myOS.convertMs(TimeChart)); |
142 | // myOS.addTask(Hour,myOS.convertMs(TimeHour)); |
143 | |
144 | // Программирование 1 таймера на подсчет событий на D5 (туда заводится электросчетчик) |
145 | TCCR1A = 0; // reset Timer 1 |
146 | TCCR1B = 0; |
147 | TCNT1 = 0; |
148 | // start Timer 1 External clock source on T1 pin (D5). Clock on rising edge. |
149 | TCCR1B = bit (CS10) | bit (CS11) | bit (CS12); |
150 | |
151 | emon1.voltage(0,CALIBRATION_CONST_220,1.7); // Инициализация датчика напряжения 220 |
152 | emon1.current(1, CALIBRATION_CONST_220_I); // Инициализация датчика тока 220 |
153 | |
154 | // Чтение счетчиков из флеша |
155 | AllResetEeprom(); |
156 | readEeprom(); |
157 | } |
158 | // --------------------------------------------- LOOP ------------------------------------ |
159 | void loop ( void ) { |
160 | float t; |
161 |
162 | // Старт преобразования датчиков |
163 | StartDS1820(ThermOut1); |
164 | StartDS1820(ThermIn1); |
165 | StartDS1820(ThermOut2); |
166 | StartDS1820(ThermIn2); |
167 | |
168 | u8g.firstPage(); |
169 | do { |
170 | // Общая часть для каждого экрана (для экономии длины кода) - заголовок экрана |
171 | if (fStart!=0) |
172 | { |
173 | u8g.drawBox(0,0,128,9); // Закрашиваем прямоугольник белым |
174 | u8g.setColorIndex(0); // Черные чернила, Белый фон |
175 | u8g.setPrintPos(1, 7); |
176 | u8g.print( int (fStart)); |
177 | u8g.drawLine(118, 0, 118, 8); // Индикатор потока на экран и на реле |
178 | u8g.setPrintPos(121, 7); |
179 | if ((flowRate1>0)&&(flowRate2>0)) {digitalWrite(statusLed, HIGH);u8g.print(F( "+" ));} // Светодиод и реле показывает что поток есть реле идет к ТН (1-2) |
180 | else {digitalWrite(statusLed, LOW); u8g.print(F( "-" ));} |
181 | u8g.drawLine(98, 0, 98, 8); // Индикатор потока на экран и на реле |
182 | u8g.setPrintPos(100, 7); |
183 | u8g.print(dtostrf(count,3,0,buf)); // Вывод напряжения в стоке состояния |
184 | // u8g.print(dtostrf(emon1.Vrms,3,0,buf)); // Вывод напряжения в стоке состояния |
185 | u8g.setPrintPos(8, 7); // Далее сразу можно печатать заголовок |
186 | } |
187 | switch (fStart) |
188 | { |
189 | case 0: ScreenStart(); break ; |
190 | case 1: Screen1(); break ; |
191 | case 2: Screen2(); break ; |
192 | case 3: Screen3(); break ; |
193 | case 4: Screen4(); break ; |
194 | default :Screen1(); |
195 | } |
196 | |
197 | } while ( u8g.nextPage() ); |
198 | |
199 | if (fStart==0) |
200 | { delay(3000); myOS.addTask(scanKey,myOS.convertMs(TimeInterview)); } // Клавиатура активируется, начинается сканирование |
201 | |
202 | if (count>=1) { Hour(); count=0; Eeprom.GlobalEnergyP++;} |
203 | |
204 | delay(500); |
205 | emon1.calcVI(20,4000); |
206 | t=getTempDS1820(ThermOut1); |
207 | if (t>-30&&t<80) tOut1=t-errOut1; // Иногда считывает глюки |
208 | t=getTempDS1820(ThermIn1); |
209 | if (t>-30&&t<70) tIn1=t-errIn1; // Иногда считывает глюки |
210 | t=getTempDS1820(ThermOut2); |
211 | if (t>-30&&t<30) tOut2=t-errOut2; // Иногда считывает глюки |
212 | t=getTempDS1820(ThermIn2); |
213 | if (t>-30&&t<30) tIn2=t-errIn2; // Иногда считывает глюки |
214 | |
215 | } |
216 | // Стартовый экран -------------------------------------- |
217 | void ScreenStart() |
218 | { |
219 | u8g.setColorIndex(1); |
220 | u8g.drawXBM(0, 0, 56, 56, u8g_logo_bits); |
221 | // u8g.drawXBM(0, 0, 51, 51, aLogo); |
222 | u8g.setPrintPos(73, 10); |
223 | u8g.print(F( "Контроль" )); |
224 | u8g.setPrintPos(70, 20); |
225 | u8g.print(F( "Теплового" )); |
226 | u8g.setPrintPos(78, 30); |
227 | u8g.print(F( "Насоса" )); |
228 | u8g.setPrintPos(66, 40); |
229 | u8g.print(F( "Arduino UNO" )); |
230 | u8g.setPrintPos(1, 63); |
231 | u8g.print(ver); |
232 | } |
233 |
234 | // Отображение типа 1 ------------------------------------- |
235 | void Screen1() |
236 | { |
237 | byte x1,y1,i; |
238 | u8g.print(F( "Теплые Полы" )); |
239 | |
240 | u8g.setColorIndex(1); // белые чернила, черный фон |
241 | u8g.setPrintPos(0, 16); |
242 | u8g.print(F( "Поток: Част:" )); |
243 | u8g.setPrintPos(32, 16); |
244 | u8g.print(dtostrf(flowRate1*60.0/1000.0,4, 3, buf)); |
245 | u8g.setPrintPos(95, 16); |
246 | u8g.print(HZ1); |
247 | |
248 | u8g.drawXBM(58, 10, 9, 7, cub); |
249 | u8g.drawXBM(120, 10, 8, 7, Hz); |
250 | |
251 | u8g.drawLine(0, 18, 127, 18); |
252 | |
253 | u8g.drawXBM(0, 20, 21, 25, T123); // Термометр и значки |
254 | |
255 | x1=8; y1=26; |
256 | u8g.setPrintPos(x1+14, y1); // Подача |
257 | u8g.print(dtostrf(tOut1,4, 2, buf)); |
258 | u8g.drawXBM(x1+45, y1-6, 9, 7, C0); |
259 | |
260 | u8g.setPrintPos(x1+14, y1+9); // Обратка |
261 | u8g.print(dtostrf(tIn1,4, 2, buf)); |
262 | u8g.drawXBM(x1+45, y1-6+9, 9, 7, C0); |
263 | |
264 | if (tOut1-tIn1<0) u8g.setPrintPos(x1+13, y1+9+9); // Разность температур |
265 | else u8g.setPrintPos(x1+14+6, y1+9+9); |
266 | u8g.print(dtostrf(tOut1-tIn1,4, 2, buf)); |
267 | u8g.drawXBM(x1+45, y1-6+9+9, 9, 7, C0); |
268 | |
269 | u8g.drawLine(63, 18, 63, 63); |
270 | |
271 | u8g.setFont(u8g_font_courB10); |
272 | u8g.setPrintPos(107, 30); |
273 | u8g.print(F( "kW" )); |
274 | u8g.setPrintPos(70, 30); |
275 | u8g.print(dtostrf(P1,3, 1, buf)); |
276 | u8g.setFont(my5x7rus); |
277 | |
278 | u8g.drawLine(0, 46, 63, 46); |
279 | |
280 | u8g.setPrintPos(0, 54); |
281 | u8g.print(F( "V:" )); |
282 | u8g.setPrintPos(12, 54); |
283 | u8g.print(dtostrf(totalLitres1/60/1000,11, 3, buf)); |
284 | u8g.setPrintPos(0, 63); |
285 | u8g.print(F( "G:" )); |
286 | u8g.setPrintPos(12, 63); |
287 | u8g.print(dtostrf(totalPower1,11, 3, buf)); |
288 | |
289 | // График |
290 | // for(i=0;i<60;i++) u8g.drawPixel(65+i,63-Chart1[i]); // Точки |
291 | for (i=0;i<60;i++) u8g.drawLine(65+i,64,65+i,64-Chart1[i]); // Линия 0 не выводится |
292 | |
293 | } |
294 | // Отображение типа 2 ------------------------------------- |
295 | void Screen2() |
296 | { |
297 | byte x1,y1,i; |
298 | u8g.print(F( "Гео контур" )); |
299 | |
300 | u8g.setColorIndex(1); // белые чернила, черный фон |
301 | u8g.setPrintPos(0, 16); |
302 | u8g.print(F( "Поток: Част:" )); |
303 | u8g.setPrintPos(32, 16); |
304 | u8g.print(dtostrf(flowRate2*60.0/1000.0,4, 3, buf)); |
305 | u8g.setPrintPos(95, 16); |
306 | u8g.print(HZ2); |
307 | |
308 | u8g.drawXBM(58, 10, 9, 7, cub); |
309 | u8g.drawXBM(120, 10, 8, 7, Hz); |
310 | |
311 | u8g.drawLine(0, 18, 127, 18); |
312 | |
313 | u8g.drawXBM(0, 20, 21, 25, T123); // Термометр и значки |
314 | |
315 | x1=8; y1=26; |
316 | u8g.setPrintPos(x1+14, y1); // Подача |
317 | u8g.print(dtostrf(tOut2,4, 2, buf)); |
318 | u8g.drawXBM(x1+45, y1-6, 9, 7, C0); |
319 | |
320 | u8g.setPrintPos(x1+14, y1+9); // Обратка |
321 | u8g.print(dtostrf(tIn2,4, 2, buf)); |
322 | u8g.drawXBM(x1+45, y1-6+9, 9, 7, C0); |
323 | |
324 | if (tOut2-tIn2<0) u8g.setPrintPos(x1+13, y1+9+9); // Разность температур |
325 | else u8g.setPrintPos(x1+14+6, y1+9+9); |
326 | u8g.print(dtostrf(tOut2-tIn2,4, 2, buf)); |
327 | u8g.drawXBM(x1+45, y1-6+9+9, 9, 7, C0); |
328 | |
329 | u8g.drawLine(63, 18, 63, 63); |
330 | |
331 | u8g.setFont(u8g_font_courB10); |
332 | u8g.setPrintPos(107, 30); |
333 | u8g.print(F( "kW" )); |
334 | u8g.setPrintPos(70, 30); |
335 | u8g.print(dtostrf(P2,3, 1, buf)); |
336 | u8g.setFont(my5x7rus); |
337 | |
338 | u8g.drawLine(0, 46, 63, 46); |
339 | |
340 | u8g.setPrintPos(0, 54); |
341 | u8g.print(F( "V:" )); |
342 | u8g.setPrintPos(12, 54); |
343 | u8g.print(dtostrf(totalLitres2/60/1000,11, 3, buf)); |
344 | u8g.setPrintPos(0, 63); |
345 | u8g.print(F( "G:" )); |
346 | u8g.setPrintPos(12, 63); |
347 | u8g.print(dtostrf(totalPower2,11, 3, buf)); |
348 | |
349 | // График |
350 | // for(i=0;i<60;i++) u8g.drawPixel(65+i,63-Chart2[i]); |
351 | for (i=0;i<60;i++) u8g.drawLine(65+i,64,65+i,64-Chart2[i]); // 0 не выводится |
352 | |
353 | } |
354 |
355 | // Отображение типа 3 Напряжение Ток------------------------------------- |
356 | void Screen3() |
357 | { |
358 | int i; |
359 | u8g.print(F( "Напряжение&Ток" )); |
360 | u8g.setColorIndex(1); // белые чернила, черный фон |
361 | |
362 | u8g.setPrintPos(0, 16); |
363 | u8g.print(F( "V rms:" )); |
364 | u8g.setPrintPos(31, 16); |
365 | u8g.print(dtostrf(emon1.Vrms,4,1,buf)); |
366 | // u8g.setPrintPos(66, 16); |
367 | u8g.setPrintPos(0, 24); |
368 | u8g.print(F( "I rms:" )); |
369 | u8g.setPrintPos(31, 24); |
370 | // u8g.setPrintPos(105, 16); |
371 | u8g.print(dtostrf(emon1.Irms,4,1,buf)); |
372 | |
373 | u8g.setPrintPos(65, 16); |
374 | u8g.print(F( "Pow_f:" )); |
375 | u8g.setPrintPos(102, 16); |
376 | u8g.print(dtostrf(emon1.powerFactor,3,2,buf)); |
377 | |
378 | u8g.setPrintPos(0, 34); |
379 | u8g.print(F( "PW кВт:" )); |
380 | u8g.setPrintPos(39,34); |
381 | #ifdef DEMO // Демка |
382 | u8g.print(dtostrf(pPower,4, 2, buf)); |
383 | #else |
384 | u8g.print(dtostrf(emon1.realPower/1000.0,4, 2, buf)); |
385 | #endif |
386 | // u8g.print(dtostrf(emon1.realPower/1000.0,4, 2, buf)); |
387 | // u8g.print(dtostrf(pPower,4, 2, buf)); |
388 | |
389 | u8g.setPrintPos(75, 26); |
390 | u8g.print(F( "COP:" )); |
391 | u8g.setPrintPos(98, 26); |
392 | if (emon1.realPower>500) u8g.print(dtostrf(P1/(emon1.realPower/1000),3,2,buf)); |
393 | else u8g.print(dtostrf(0.0,3,2,buf)); |
394 | |
395 | u8g.drawLine(63, 18, 63, 63); |
396 | u8g.drawLine(0, 26, 63, 26); |
397 | u8g.drawLine(64, 18, 127, 18); |
398 | |
399 | // for(i=0;i<=6;i++) u8g.drawPixel(62,64-i*4); // Шкала мощность |
400 | for (i=0;i<=5;i++) |
401 | { u8g.drawPixel(64,64-i*7); // Шкала СОР |
402 | u8g.drawPixel(65,64-i*7); |
403 | } |
404 | |
405 | for (i=0;i<60;i++) // График |
406 | { |
407 | u8g.drawLine(i,64,i,64-pChart[i]); |
408 | u8g.drawLine(67+i,64,67+i,64-ChartCOP[i]); |
409 | } |
410 | } |
411 |
412 | // Отображение типа 4 Счетчики ------------------------------------- |
413 | void Screen4() |
414 | { |
415 | u8g.print(F( "Счетчики." )); |
416 | u8g.setColorIndex(1); // белые чернила, черный фон |
417 | |
418 | u8g.drawLine(28, 9, 28, 63); |
419 | u8g.drawLine(79, 9, 79, 63); |
420 | |
421 | u8g.setPrintPos(0, 16); |
422 | u8g.print(F( " За сезон Общий" )); |
423 | |
424 | u8g.setPrintPos(0, 24); |
425 | u8g.print(F( "P кВт" )); |
426 | u8g.setPrintPos(31, 24); |
427 | u8g.print( long (Eeprom.YearEnergyP)); |
428 | u8g.setPrintPos(82, 24); |
429 | u8g.print( long (Eeprom.GlobalEnergyP)); |
430 | |
431 | u8g.setPrintPos(0, 32); |
432 | u8g.print(F( "G кВт" )); |
433 | u8g.setPrintPos(31, 32); |
434 | u8g.print( long (Eeprom.YearEnergyG)); |
435 | u8g.setPrintPos(82, 32); |
436 | u8g.print( long (Eeprom.GlobalEnergyG)); |
437 | |
438 | u8g.setPrintPos(0, 40); |
439 | u8g.print(F( "COP" )); |
440 | u8g.setPrintPos(31, 40); |
441 | u8g.print(dtostrf(( float )Eeprom.YearEnergyG/( float )Eeprom.YearEnergyP,4,2, buf)); |
442 | u8g.setPrintPos(82, 40); |
443 | u8g.print(dtostrf(( float )Eeprom.GlobalEnergyG/( float )Eeprom.GlobalEnergyP,4,2, buf)); |
444 |
445 | u8g.setPrintPos(0, 48); |
446 | u8g.print(F( "Часы" )); |
447 | u8g.setPrintPos(31, 48); |
448 | u8g.print( int (Eeprom.YearHour)); |
449 | u8g.setPrintPos(82, 48); |
450 | u8g.print( int (Eeprom.GlobalHour)); |
451 |
452 | } |
453 | // Прерывание подсчет импульсов от первого канала |
454 | void pulseCounter1() { pulseCount1++; } |
455 | // Прерывание подсчет импульсов от второго канала |
456 | void pulseCounter2() { pulseCount2++; } |
457 |
458 | // Цикл измерения интервал задается ----------------------------------- |
459 | void measurement() |
460 | { |
461 | cli(); // Запретить прерывания TimeMeasurement |
462 | count1=pulseCount1; pulseCount1 = 0; |
463 | count2=pulseCount2; pulseCount2 = 0; |
464 | sei(); // разрешить прерывания |
465 | |
466 | interval=millis()-oldTime; // Точное определение интервала ---------------------------- |
467 | oldTime= interval+oldTime; |
468 | if (interval<=0) interval=TimeMeasurement; // Через 50 дней millis() сбросится по этому после этого первая итерация расчетная |
469 |
470 | #ifdef DEMO // Демка |
471 | count1=random(190,240); |
472 | count2=random(160,200); |
473 | TCNT1=random(5,9); |
474 | emon1.realPower=random(1700,2700); |
475 | #endif |
476 |
477 | // Первый канал |
478 | HZ1=(count1*1000.0)/interval/2; // делить на 2 - это т.к. прерывания работает на оба фронта импульса CHANGE |
479 | flowRate1 = HZ1/calibrationFactor; // рассчитать поток в литрах за минуту |
480 | totalLitres1 = totalLitres1 + flowRate1*(interval/1000.0); |
481 | P1=(flowRate1/60) // литры/килограммы в секунду |
482 | *heat_capacity*(tOut1-tIn1); |
483 | totalPower1 = totalPower1 + P1*(interval/1000.0)/3600; |
484 | |
485 | // Второй канал |
486 | HZ2=(count2*1000.0)/interval/2; // делить на 2 - это т.к. прерывания работает на оба фронта импульса CHANGE |
487 | flowRate2 = HZ2/calibrationFactor; // рассчитать поток в литрах за минуту |
488 | totalLitres2 = totalLitres2 + flowRate2*(interval/1000.0); |
489 | P2=(flowRate2/60) // литры/килограммы в секунду |
490 | *heat_capacity*(tOut2-tIn2); |
491 | totalPower2 = totalPower2 + P2*(interval/1000.0)/3600; |
492 | |
493 | // Электросчетчик |
494 | eCount=eCount+TCNT1; // Общий счетчик |
495 | ePower=( float )TCNT1*3600.0/( float )eConst/(interval/1000.0); // Пиковый счетчик |
496 | eEnergy=( float )eCount/( float )eConst; |
497 | TCNT1 = 0; |
498 | |
499 | // Датчик напряжения и тока |
500 | pPower=emon1.realPower/1000.0; |
501 | pEnergy=pEnergy+emon1.realPower*(3600.0*interval/1000.0); |
502 | |
503 | } |
504 |
505 | // Сканирование клавиш ------------------------------------------ |
506 | void scanKey() |
507 | { |
508 | byte key; |
509 | key=digitalRead(sensorKey); |
510 | if ((key==1)&&(oldKey==1)&&(flagKey==1)) {fStart++;flagKey=0;} // Клавиша нажита |
511 | if ((key==0)&&(oldKey==1)) flagKey=1; // Начало (по заднему фронту) ожидания нового нажатия |
512 | oldKey=key; |
513 | if (fStart > NUM_SCREEN) fStart=1; |
514 | } |
515 |
516 | // Подготовка массива точек для графиков ---------------------------------------- |
517 | void Chart() |
518 | { |
519 | int i; |
520 | count++; |
521 | ChartInterval=millis()-ChartOldTime; // Точное определение интервала показа графика---------------------------- |
522 | ChartOldTime= ChartInterval+ChartOldTime; |
523 | if (ChartInterval<=0) ChartInterval=TimeMeasurement; // Через 50 дней millis() сбросится по этому после этого первая итерация расчетная |
524 | // Сдвиг графиков и запись новых данных |
525 | for (i=0;i<60;i++) |
526 | { |
527 | Chart1[i]=Chart1[i+1]; |
528 | Chart2[i]=Chart2[i+1]; |
529 | pChart[i]=pChart[i+1]; |
530 | ChartCOP[i]=ChartCOP[i+1]; |
531 | } |
532 | Chart1[59]=P1*2.5; |
533 | Chart2[59]=P2*2.5; |
534 | pChart[59]=9*emon1.realPower/1000; |
535 | if (emon1.realPower>500) ChartCOP[59]=(P1/(emon1.realPower/1000))*7.0; else ChartCOP[59]=0; |
536 | } |
537 | // Вызывается раз в час используется для сохранения показаний счетчиков в еепром------------------------------ |
538 | void Hour() |
539 | { |
540 | unsigned long dP,dG,dT; |
541 | // Электричество |
542 | dP= pEnergy-EnergyP; // Прирост за час |
543 | EnergyP=pEnergy; // запоминание для нового цикла |
544 | Eeprom.GlobalEnergyP =Eeprom.GlobalEnergyP+dP; |
545 | Eeprom.YearEnergyP=Eeprom.YearEnergyP+dP; |
546 | |
547 | // Тепло |
548 | dG= totalPower1-EnergyG; // Прирост за час |
549 | EnergyG=totalPower1; // запоминание для нового цикла |
550 | Eeprom.GlobalEnergyG =Eeprom.GlobalEnergyG+dG; |
551 | Eeprom.YearEnergyG=Eeprom.YearEnergyG+dG; |
552 | |
553 | // Мото часы |
554 | dT=millis()-TimeEeprom; |
555 | if (dT<=0) dT=0; |
556 | TimeEeprom=millis(); |
557 | Eeprom.GlobalHour=Eeprom.GlobalHour+TimeEeprom/1000/60/60; |
558 | Eeprom.YearHour=Eeprom.YearHour+TimeEeprom/1000/60/60; |
559 | //Eeprom.YearHour=Eeprom.YearHour+TimeEeprom; |
560 |
561 | // Запись во флеш |
562 | writeEeprom(); |
563 | } |
564 |
565 | // Старт преобразования одного датчика ----------------------------------------------- |
566 | void StartDS1820( byte *addr) |
567 | { |
568 | ds.reset(); |
569 | ds.select(addr); |
570 | ds.write(0x44,0); |
571 | } |
572 | // Чтение температуры одного датчика ----------------------------------------------- |
573 | float getTempDS1820(unsigned char *addr) |
574 | { |
575 | byte i; |
576 | byte type_s; |
577 | byte present = 0; |
578 | byte data[12]; |
579 | // Запрос уже послан ранее StartDS1820 |
580 | present = ds.reset(); |
581 | ds.select(addr); |
582 | ds.write(0xBE); // Команда на чтение регистра температуры |
583 | for ( i = 0; i < 9; i++) { data[i] = ds.read();} |
584 | int16_t raw = (data[1] << 8) | data[0]; |
585 | if (type_s) { |
586 | raw = raw << 3; // 9 bit resolution default |
587 | if (data[7] == 0x10) { |
588 | // "count remain" gives full 12 bit resolution |
589 | raw = (raw & 0xFFF0) + 12 - data[6]; |
590 | } |
591 | } else { |
592 | byte cfg = (data[4] & 0x60); |
593 | // at lower res, the low bits are undefined, so let's zero them |
594 | if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms |
595 | else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms |
596 | else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms |
597 | //// default is 12 bit resolution, 750 ms conversion time |
598 | } |
599 | return ( float )raw / 16.0; |
600 | } |
601 |
602 | // Чтение внутреннего датчика температуры --------------------------------------- |
603 | double GetTemp( void ) |
604 | { |
605 | unsigned int wADC; |
606 | double t; |
607 | ADMUX = (_BV(REFS1) | _BV(REFS0) | _BV(MUX3)); |
608 | ADCSRA |= _BV(ADEN); |
609 | delay(20); |
610 | ADCSRA |= _BV(ADSC); |
611 | while (bit_is_set(ADCSRA,ADSC)); |
612 | wADC = ADCW; |
613 | t = (wADC - 324.31 ) / 1.22; |
614 | return (t); |
615 | } |
616 |
617 | //----------------------------EEPROM FUNCTION-------------------------------------------------- |
618 |
619 | void writeEeprom() |
620 | { |
621 | // byte *x = (byte *)&Eeprom; |
622 | // for(int i = 0; i < 6*4; i++) EEPROM.write(i, x[i]); |
623 | |
624 | // eeprom_write_dword(0,32); |
625 | // eeprom_write_dword(4,33); |
626 |
627 | eeprom_write_dword((uint32_t *)(EE_SAVED_ADDRESS), *(uint32_t *)&Eeprom.GlobalEnergyP); |
628 | eeprom_write_dword((uint32_t *)(EE_SAVED_ADDRESS+4), *(uint32_t *)&Eeprom.GlobalEnergyG); |
629 | eeprom_write_dword((uint32_t *)(EE_SAVED_ADDRESS+8), *(uint32_t *)&Eeprom.YearEnergyP); |
630 | eeprom_write_dword((uint32_t *)(EE_SAVED_ADDRESS+12), *(uint32_t *)&Eeprom.YearEnergyG); |
631 | eeprom_write_dword((uint32_t *)(EE_SAVED_ADDRESS+16), *(uint32_t *)&Eeprom.GlobalHour); |
632 | eeprom_write_dword((uint32_t *)(EE_SAVED_ADDRESS+18), *(uint32_t *)&Eeprom.YearHour); |
633 |
634 |
635 | /*long a; |
636 | a=Eeprom.GlobalEnergyP; |
637 | eeprom_write_dword((uint32_t *)(EE_SAVED_ADDRESS), a); |
638 | a=Eeprom.GlobalEnergyG; |
639 | eeprom_write_dword((uint32_t *)(EE_SAVED_ADDRESS+4),a); |
640 | a=Eeprom.YearEnergyP; |
641 | eeprom_write_dword((uint32_t *)(EE_SAVED_ADDRESS+8),a); |
642 | a=Eeprom.YearEnergyG; |
643 | eeprom_write_dword((uint32_t *)(EE_SAVED_ADDRESS+12),a); |
644 | a=Eeprom.GlobalHour; |
645 | eeprom_write_dword((uint32_t *)(EE_SAVED_ADDRESS+16),a); |
646 | a=Eeprom.YearHour; |
647 | eeprom_write_dword((uint32_t *)(EE_SAVED_ADDRESS+18),a); |
648 | */ |
649 | } |
650 | // Полный сброс делается только один раз |
651 | void AllResetEeprom() |
652 | { |
653 | eeprom_write_dword((uint32_t *)EE_SAVED_ADDRESS, 0); |
654 | eeprom_write_dword((uint32_t *)EE_SAVED_ADDRESS+4, 0); |
655 | eeprom_write_dword((uint32_t *)EE_SAVED_ADDRESS+8, 0); |
656 | eeprom_write_dword((uint32_t *)EE_SAVED_ADDRESS+12, 0); |
657 | eeprom_write_dword((uint32_t *)EE_SAVED_ADDRESS+16, 0); |
658 | eeprom_write_dword((uint32_t *)EE_SAVED_ADDRESS+18, 0); |
659 | } |
660 | // Сброс только последнего сезона |
661 | void YearResetEeprom() |
662 | { |
663 | eeprom_write_dword((uint32_t *)EE_SAVED_ADDRESS, Eeprom.GlobalEnergyP); |
664 | eeprom_write_dword((uint32_t *)EE_SAVED_ADDRESS+4, Eeprom.GlobalEnergyG); |
665 | eeprom_write_dword((uint32_t *)EE_SAVED_ADDRESS+8, 0); |
666 | eeprom_write_dword((uint32_t *)EE_SAVED_ADDRESS+12, 0); |
667 | eeprom_write_dword((uint32_t *)EE_SAVED_ADDRESS+16, Eeprom.GlobalHour); |
668 | eeprom_write_dword((uint32_t *)EE_SAVED_ADDRESS+18, 0); |
669 | } |
670 |
671 | //read |
672 | void readEeprom() |
673 | { |
674 | Eeprom.GlobalEnergyP=eeprom_read_dword(( const uint32_t *)EE_SAVED_ADDRESS); |
675 | Eeprom.GlobalEnergyG=eeprom_read_dword(( const uint32_t *)EE_SAVED_ADDRESS+4); |
676 | Eeprom.YearEnergyP =eeprom_read_dword(( const uint32_t *)EE_SAVED_ADDRESS+8); |
677 | Eeprom.YearEnergyG =eeprom_read_dword(( const uint32_t *)EE_SAVED_ADDRESS+12); |
678 | Eeprom.GlobalHour =eeprom_read_dword(( const uint32_t *)EE_SAVED_ADDRESS+16); |
679 | Eeprom.YearHour =eeprom_read_dword(( const uint32_t *)EE_SAVED_ADDRESS+18); |
680 | } |
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 все стало работать. Да это не удобно но по другому никак. Да и в момент работы надо запрещать прерывания.
Сейчас все работает.