объем EEPROM в китайском DS1307 real time clock module
- Войдите на сайт для отправки комментариев
Имеется китайский модуль I2C RTC DS1307 AT24C32 Real Time Clock Module.
Из названия следует, что в нем уставлена EEPROM AT24C32, объем которой 32 кбит = 8 кб. Но в моем экземпляре данный чип промаркирован как ATMLH134 320M. Через wire по стандартному адресу девайса 0x50 успешно записал и считал байт 222 в 10 ячейке, для примера. Возникает вопрос: как узнать объем моего конкретного чипа? даташит на него не нашел. А насиловать его многократной циклической записью с начала, что будет как я понял происходить при превышении конечного адреса, я не хочу. Да и придумывать, что же именно туда писать такое, что потом легко выдаст цикличность - как-то нет желания. Возможно придется это делать, но может кто-н сталкивался уже с подобным и имеет ответ на этот вопрос?
писать 1 2 3 4 5 6 7 8.. как наткнешься на 1 значит все, второй круг
мб там 320 мбит?)
Надо еще подумать над тем, как адресовать 8кб ячеек. Я когда-то пробовал с ней развлекаться, но дальше записать-прочитать дело не пошло...
/* * Use the I2C bus with EEPROM 24LC64 * Sketch: eeprom.pde * * Author: hkhijhe * Date: 01/10/2010 * * */ #include <Wire.h> //I2C library void i2c_eeprom_write_byte( int deviceaddress, unsigned int eeaddress, byte data ) { int rdata = data; Wire.beginTransmission(deviceaddress); Wire.write((int)(eeaddress >> 8)); // MSB Wire.write((int)(eeaddress & 0xFF)); // LSB Wire.write(rdata); Wire.endTransmission(); } // WARNING: address is a page address, 6-bit end will wrap around // also, data can be maximum of about 30 bytes, because the Wire library has a buffer of 32 bytes void i2c_eeprom_write_page( int deviceaddress, unsigned int eeaddresspage, byte* data, byte length ) { Wire.beginTransmission(deviceaddress); Wire.write((int)(eeaddresspage >> 8)); // MSB Wire.write((int)(eeaddresspage & 0xFF)); // LSB byte c; for ( c = 0; c < length; c++) Wire.write(data[c]); Wire.endTransmission(); } byte i2c_eeprom_read_byte( int deviceaddress, unsigned int eeaddress ) { byte rdata = 0xFF; Wire.beginTransmission(deviceaddress); Wire.write((int)(eeaddress >> 8)); // MSB Wire.write((int)(eeaddress & 0xFF)); // LSB Wire.endTransmission(); Wire.requestFrom(deviceaddress,1); if (Wire.available()) rdata = Wire.read(); return rdata; } // maybe let's not read more than 30 or 32 bytes at a time! void i2c_eeprom_read_buffer( int deviceaddress, unsigned int eeaddress, byte *buffer, int length ) { Wire.beginTransmission(deviceaddress); Wire.write((int)(eeaddress >> 8)); // MSB Wire.write((int)(eeaddress & 0xFF)); // LSB Wire.endTransmission(); Wire.requestFrom(deviceaddress,length); int c = 0; for ( c = 0; c < length; c++ ) if (Wire.available()) buffer[c] = Wire.read(); } void setup() { char somedata[] = "this is data from the eeprom: "; // data to write char somedata0[] = " "; char somedata1[] = "testing testing 2-nd string..\0"; Wire.begin(); // initialise the connection Serial.begin(9600); i2c_eeprom_write_page(0x50, 0, (byte *)somedata, sizeof(somedata)); // write to EEPROM delay(10); //add a small delay //i2c_eeprom_write_page(0x50, 16, (byte *)somedata0, sizeof(somedata0)); // write to EEPROM //delay(10); //add a small delay i2c_eeprom_write_page(0x50, 32, (byte *)somedata1, sizeof(somedata1)); // write to EEPROM delay(10); //add a small delay Serial.println("Memory written"); } void loop() { int addr=0; //first address byte b = i2c_eeprom_read_byte(0x50, 0); // access the first address from the memory while (b!=0) { Serial.print((char)b); //print content to serial port addr++; //increase address b = i2c_eeprom_read_byte(0x50, addr); //access an address from the memory } Serial.println(" "); delay(2000); }ошибся чуток, 32/8 =4, т.е. там 4кб должно быть, если этот чип аналог того что в описании.
а писать последовательно 0, 1, 2, 3.. так только до 255 можно. потом уже надо два байта писать.. и как-то все это учесть. По идее должно сработать, в начале хрень будет другая вместо 0, 1, 2.. после циклической перезаписи. Так-то eeprom вряд ли настолько мелкий по объему, что это дело его убьет.. но все ж хотелось бы наименее затратный и простой способ узнать. Китайцу-продавцу написал еще, вдруг ответит чего и правду)
насчет 320 мбит.. вряд ли, там эта надпись второй строкой идет, возможно и нет в ней смысла. но первая строка занимает все место, так что на всякий случай написал и вторую. На китайских сайтах что-то такое мне попадалось, но не скачать ничего оттуда было. и кругом одни иероглифы, и гугл не помогает))
ошибся чуток, 32/8 =4, т.е. там 4кб должно быть, если этот чип аналог того что в описании.
а писать последовательно 0, 1, 2, 3.. так только до 255 можно. потом уже надо два байта писать.. и как-то все это учесть. По идее должно сработать, в начале хрень будет другая вместо 0, 1, 2.. после циклической перезаписи. Так-то eeprom вряд ли настолько мелкий по объему, что это дело его убьет.. но все ж хотелось бы наименее затратный и простой способ узнать. Китайцу-продавцу написал еще, вдруг ответит чего и правду)
насчет 320 мбит.. вряд ли, там эта надпись второй строкой идет, возможно и нет в ней смысла. но первая строка занимает все место, так что на всякий случай написал и вторую. На китайских сайтах что-то такое мне попадалось, но не скачать ничего оттуда было. и кругом одни иероглифы, и гугл не помогает))
зачем до 255, если в дефолте они пустые пиши просто 1 пока 1 не найдешь
там ячейка на 100к перезаписей расчитана, то что ты 1 раз туда просто так запишешь 1 ей погоды не сделает
да и перебрать все не так уж и долго и затратно
о, дошло)) хотя может и не совсем то. что-то я тупанул совсем. можно ж просто записать 1 в начальную ячейку, а дальше читать все подряд, пока не наткнусь на свою единицу=) обнулив перед этим то что в примеред делал, да и вообще проверить надо на всякий случай сначала, пустые ли они все.
а в друг они мусором забиты?
можешь не ту 1 найти
только что закончил с проверкой, мусор был до 29 ячейки, в остальных - 255. почистил. ща пишу проверку на объем..
все проверил, единичка только в начале, и на всякий случай накинул +1 на предполагаемый размер 4кб - показало еще единицу после этого по адресу 4096.
Где-то обсуждалась память DS1307, так вот, если я не пропустил ничего - поздравляю всех обладателей подобных модулей: помимо часов у вас есть EEPROM на 4кбайта. AT24C32 по даташиту имеет миллион циклов перезаписи, что на порядок больше того что у нас в МК. Как с этим дела у моего видимо китайского аналога не знаю, но все равно круто. будет куда чего сохранять, не особо заботясь о ближайших 10-20 годах)) а заменить в случае чего модуль часов намного дешевле и проще, чем дуину со всем, к ней подключенным. Дату и время часы после моих манипуляций показывают как и раньше, с февраля примерно убежали на полторы минуты.
миллион на ячейку или всеко миллион раз записать?
и зачем всю ардуину?
если у тебя Uno то можно только чип заменить, стоит он рублей 400
скорее всего имеется в виду ячейка, остальные ведь не трогаются по идее. написано только это:
Endurance: 1 Million Write Cycles
насчет чипа да, можно в том случае если он достаточно крупный. а мелкие паять я лично не умею, если вообще возможно на меге например самому такое проделать.
Во всю использую AT24C32 - там 4 килобайта. В библиотеке функция блочной записи работает только с "ровными" блоками и при достижении конца блока начинает писать в него же с начала. После любой записи надо ждать 10-20 мс до следующей операци с AT24C32. А так отличный шустрый и надежный чип.
что то мне не верится что там надпись 320М. может таки 32СМ?
вроде, больше похоже на 32DM... а мне показалось что 320 ))) ну и ладно, главное что все уже стало ясно.
Во всю использую AT24C32 - там 4 килобайта. В библиотеке функция блочной записи работает только с "ровными" блоками и при достижении конца блока начинает писать в него же с начала.
Библиотека-то как называется?
Библиотека своя на основании примеров
i2ceeprom
i2ceeprom.h
#ifndef i2ceeprom_h #define i2ceeprom_h //#define i2ceeprom32_I2C_ADDRESS 0x50 //default address #if defined(ARDUINO) && ARDUINO >= 100 #include "Arduino.h" #else #include "WProgram.h" #endif class i2ceeprom { public: void i2c_eeprom_write_byte( byte deviceaddress, unsigned int eeaddress, byte data ); void i2c_eeprom_write_block( byte deviceaddress, unsigned int eeaddresspage, void* data, unsigned int length ); byte i2c_eeprom_read_byte( byte deviceaddress, unsigned int eeaddress ); void i2c_eeprom_read_buffer( byte deviceaddress, unsigned int eeaddress, void *buffer, byte length ); }; #endifi2ceeprom.cpp
#include <i2ceeprom.h> #include <Wire.h> //I2C library // A4,A5 // i2ceeprom32 provides 32,768 bits 0x50 void i2ceeprom::i2c_eeprom_write_byte( byte deviceaddress, unsigned int eeaddress, byte data ) { byte rdata = data; Wire.beginTransmission(deviceaddress); Wire.write((int)(eeaddress >> 8)); // MSB Wire.write((int)(eeaddress & 0xFF)); // LSB Wire.write(rdata); Wire.endTransmission(); } void i2ceeprom::i2c_eeprom_write_block( byte deviceaddress, unsigned int eeaddress, void* data, unsigned int length ) { const byte* current = reinterpret_cast<const byte*>(data); unsigned int c; for ( c = 0; c < length; c++) { Wire.beginTransmission(deviceaddress); Wire.write((int)(eeaddress >> 8)); // MSB Wire.write((int)(eeaddress & 0xFF)); // LSB Wire.write(*current++); Wire.endTransmission(); eeaddress++;delay(20); } } byte i2ceeprom::i2c_eeprom_read_byte( byte deviceaddress, unsigned int eeaddress ) { byte rdata = 0xFF; Wire.beginTransmission(deviceaddress); Wire.write((int)(eeaddress >> 8)); // MSB Wire.write((int)(eeaddress & 0xFF)); // LSB Wire.endTransmission(); Wire.requestFrom(deviceaddress,(byte)1); if (Wire.available()) rdata = Wire.read(); return rdata; } // maybe let's not read more than 30 or 32 bytes at a time! void i2ceeprom::i2c_eeprom_read_buffer( byte deviceaddress, unsigned int eeaddress, void *buffer, byte length ) { byte* current = reinterpret_cast<byte*>(buffer); Wire.beginTransmission(deviceaddress); Wire.write((int)(eeaddress >> 8)); // MSB Wire.write((int)(eeaddress & 0xFF)); // LSB Wire.endTransmission(); Wire.requestFrom(deviceaddress,(byte)length); int c = 0; for ( c = 0; c < length; c++ ) if (Wire.available()) *current++ = Wire.read(); }ales2k, а можно пример использования вашей билиотеки для работы с eeprom.
#include <Wire.h> //I2C library #include <i2ceeprom.h> void setup() { char somedata[] = "this is data from the eeprom"; // data to write ABCDEFGHIJKLMNOPQRSTUVWXYZ Wire.begin(); // initialise the connection Serial.begin(38400); i2c_eeprom_write_block(0x50, 0, (byte *)somedata, sizeof(somedata)); // write to EEPROM delay(10); //add a small delay Serial.println("Memory written"); } void loop() { int addr=0; //first address byte b = i2c_eeprom_read_byte(0x50, 0); // access the first address from the memory while (b!=0) { Serial.print((char)b); //print content to serial port addr++; //increase address b = i2c_eeprom_read_byte(0x50, addr); //access an address from the memory } Serial.println(" "); delay(200000); }Простой кусочек кода из какогото примера - не помню из какого.
Спасибо!!
Функция i2c_eeprom_write_block принимает аргумент
unsignedinteeaddress, для чего вы перед отпрвавкой eeaddress преобразовываете в int:Wire.write((int)(eeaddress >> 8));при условии что отправляется байт? Может преобразовать сразу в байт:Wire.write((byte)(eeaddress >> 8));Так же обратите внимание на аргументvoid* data,при передачи его в функцию вы преобразовываете в byte*:(byte*)somedata, а затем внутри функции делаете тоже самое еще раз:constbyte* current = reinterpret_cast<constbyte*>(data);так может тогда логичнее делать это один раз например только внутри:i2c_eeprom_write_block(0x50, 0,somedata,sizeof(somedata)).По первому пункту абсолютно согласен, не обратил внимания, по второму преобразование внутри функции сделано для совместимости, а пример давний, еще до этого изменения.
Спасибо за уточнения.
Интересно этот компилятор такие простые ошибки отлавливает при оптимизации выполнения и выкидывает не нужные действия?
Офтопик
Может на форуме завести раздел для библиотечек. Я бы поделился накопленными и написанными и подправили косяки заодно.
Скорее всего компилятор оптимизирует, так что если проверить хотябы по размеру скоплированного файла - размер будет одинаковый.
Добрый день!
Будьте любезны, подскажите как при помощи этого кода:
#include <Wire.h> //I2C library #include <i2ceeprom.h> void setup() { char somedata[] = "this is data from the eeprom"; // data to write ABCDEFGHIJKLMNOPQRSTUVWXYZ Wire.begin(); // initialise the connection Serial.begin(38400); i2c_eeprom_write_block(0x50, 0, (byte *)somedata, sizeof(somedata)); // write to EEPROM delay(10); //add a small delay Serial.println("Memory written"); } void loop() { int addr=0; //first address byte b = i2c_eeprom_read_byte(0x50, 0); // access the first address from the memory while (b!=0) { Serial.print((char)b); //print content to serial port addr++; //increase address b = i2c_eeprom_read_byte(0x50, addr); //access an address from the memory } Serial.println(" "); delay(200000); }сохранять несколько переменных, например: current_day=3; day_X=27; temp_min=18; temp_max=22; light_on=6; light_off=21; и т.д., а затем при необходимости считывать?
Проблема именно в организации сохранения значений при записи, а так же разнесении символов по переменным при считывании.
Будьте добры, посоветуйте.
Для меня это ОЧЕНЬ замечательная находка для сохранения небольших данных при отключении питания.
ОГРОМНОЕ спасибо ales2k за реализацию библиотеки.
Проблема именно в организации сохранения значений при записи, а так же разнесении символов по переменным при считывании.
Как выглядит код, который сохранит значения переменных в EEPROM, а затем считает их и присвоит переменным.
Может под каждую переменную выделить свои адреса и писать только в них, а значит и считывать в переменные из конкретных адресов?
Как выглядит код, который сохранит значения переменных в EEPROM, а затем считает их и присвоит переменным.
Может под каждую переменную выделить свои адреса и писать только в них, а значит и считывать в переменные из конкретных адресов?
Ну как вариант, может по аналогии с SD картой получится?
myFile = SD.open("CURRENT.TXT"); if (myFile) { while (myFile.available()) { // считываем байт входящего файла symbol2 = myFile.read(); array[h] = symbol2; h++; delay(1); } array[h]='\0'; myFile.close(); } char *p; byte t = 0; for( buffer = strtok_r(array, ",.", &p); buffer; buffer = strtok_r(NULL, ",.", &p) ) { Serial.print(t);Serial.print(" = ");Serial.println(atoi(buffer)); delay(1); outArray[t]=atoi(buffer); t++; } current_day = outArray[1]; day_X = outArray[2]; }ну только без myFile.close(); и тому подобного
Я бы сделал структуру и сохранял всю структуру целиком, затем читал всю структуру.
По примеру как это сделано с массивом char
somedata[] ="this is data from the eeprom";Никакой существенной разницы.
Только стоит помнить о ресурсе EEPROM примерно 10000 записей в одно место.
Ну как вариант, может по аналогии с SD картой получится?
Этот вариант к адекватным не относится.
Я бы сделал структуру и сохранял всю структуру целиком, затем читал всю структуру.
"Каждый сам творец своего счастья" так что
http://playground.arduino.cc/Code/Struct
Покажите, пожалуйста, пример с двумя переменными - послужит образцом.
Извините, опоздал с просьбой.
Спасибо, буду читать.
Как то так
#include <Wire.h> //I2C library #include <i2ceeprom.h> void setup() { Wire.begin(); struct DATA // Cтруктура { int current_day; int day_X; byte temp_min; byte temp_max; int light_on; int light_off; }; // Запись DATA data; // заполняем data.current_day = 3; data.day_X = 27; data.temp_min = 18; data.temp_max = 22; data.light_on = 6; data.light_off = 21; // Сохраняем i2c_eeprom_write_block(0x50, 0, &data, sizeof(data)); delay(10); // Чтение DATA data_2; // Заполняем data_2 из ЕЕПРОМ i2c_eeprom_read_buffer(0x50, 0, &data_2, sizeof(data_2)); // Присваиваем переменным int current_day = data_2.current_day; int day_X = data_2.day_X; byte temp_min = data_2.temp_min; byte temp_max = data_2.temp_max; int light_on = data_2.light_on; int light_off = data_2.light_off; } void loop(){}Обратите внимание на типы переменных, если у вас все типы переменных byte (char), то применять структуры бессысленно.
Поправь - ты 2 раза пишешь в EEPROM
И зачем данные структуры переменным присваивать - ими и так пользоваться можно и удобно
Поправил, ну так вы же не знаете как потом будут этим пользоваться. Может у AndyResh кода на 2 листа с этими переменными, что ему теперь весь код править...
Гениально! БЛАГОДАРЮ!
Я бы и поправил весь код если бы нужно было, а так - вообще замечтательно!
Как же ВЫ мне помогли, и последующим поколениям тоже.
На примере стало понятно откуда все берется и куда потом деётся.
Ctrl+F7 в редакторе FAR'а :)
Ctrl+F7 в редакторе FAR'а :)
В IDE Ctrl+F достаточно))
Тут вот какая загогулина получается. Понимаю рассудком, что чудес на свете не бывает, однако...
Создал папку \SOFT\ARDUINO\libraries\i2ceeprom , в нее положил файлы i2ceeprom.h и i2ceeprom.cpp
инклудил, собственно в шапку скетча #include <i2ceeprom.h> , а IDE 1.0.2 ругается:
sketch_LCD1602_RTC_Reley_DHT_31_10_2013.ino: In function 'void setup()':
sketch_LCD1602_RTC_Reley_DHT_31_10_2013:105: error: 'i2c_eeprom_read_buffer' was not declared in this scope
Как буд-то на видит библиотеку. От чего может так получится?
Ниже "портянка" целиком, версия на стадии написания/отладки/дописания
#include <Wire.h> #include <RTClib.h> #include <i2ceeprom.h> #include <LiquidCrystal.h> #include "DHT.h" RTC_DS1307 RTC; DateTime now; LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // define variables #define btnRIGHT 0 #define btnUP 1 #define btnDOWN 2 #define btnLEFT 3 #define btnSELECT 4 #define btnNONE 5 #define ON LOW // Реле включено #define OFF HIGH // Реле выключено int light_state = OFF; // этой переменной устанавливаем состояние освещения int current_day = 0; // сюда записываем текущий день int day_X = 24; // день на который приходится базовая длина дня с базовым времинем включения int lastDay = 0; int lastMonth = 0; int lastYear = 0; int lastHour = 0; int lastMinute = 0; int lcd_key = 0; int adc_key_in = 0; int menuOptions = 3; int menuOption = 0; int current_light_on_hours = 3; //Расчетное время включения освещения в часах int current_light_on_minutes = 20; //Расчетное время включения освещения в минутах int current_light_off_hours = 21; //Расчетное время выключения освещения в часах int current_light_off_minutes = 20; //Расчетное время выключения освещения в минутах bool resetClock = false; // define constants //const int hot1_Pin = 42; // номер выхода, подключенного к обогреву I //const int hot2_Pin = 43; // номер выхода, подключенного к оборгеву II //const int wind_Pin = 44; // номер выхода, подключенного к вентилятору ветра //const int jet_Pin = 45; // номер выхода, подключенного к вентилятору вытяжки #define PUMP1_Pin 46 // номер выхода, подключенного к помпе орашения //const int pump2_Pin = 47; // номер выхода, подключенного к помпе подкачки #define LAMP_Pin 48 // номер выхода, подключенного к освещению #define LOW_INTERVAL 20000 // время орашения #define HIGH_INTERVAL 120000 // время паузы между орашением, ДА-ДА, именно так! #define DHTPIN_1 22 #define DHTPIN_2 23 #define DHTTYPE DHT22 DHT DHT_1(DHTPIN_1, DHTTYPE); DHT DHT_2(DHTPIN_2, DHTTYPE); #define beeper A1 #define shortBeep 100 #define longBeep 500 void setup () { pinMode(beeper, OUTPUT); // режим PIN зумера digitalWrite(beeper, LOW); pinMode(LAMP_Pin, OUTPUT); // режим PIN освещения утро/вечер pinMode(PUMP1_Pin, OUTPUT); // режим PIN помпы орашения Wire.begin(); Serial.begin(9600); RTC.begin(); if (RTC.isrunning()) { Serial.println("RTC is running."); } else if (! RTC.isrunning()) { Serial.println("RTC is NOT running!"); } lcd.begin(16,2); //стартуем библиотеку экрана DHT_1.begin(); //стартуем библиотеку датчика температуры/влажности 1 DHT_2.begin(); //стартуем библиотеку датчика температуры/влажности 2 struct DATA // Cтруктура { int current_day; int day_X; byte temp_min; byte temp_max; int light_on; int light_off; }; // Чтение DATA data_R; // Заполняем data_2 из ЕЕПРОМ i2c_eeprom_read_buffer(0x50, 0, &data_R, sizeof(data_R)); // Присваиваем переменным int current_day = data_R.current_day; int day_X = data_R.day_X; } void loop () { now = RTC.now(); if (now.day() != lastDay) current_day++; // Текущий день + 1 button_loop(); // Функция слежения за нажатием кнопок pumping(); // Функция орашения lights(); // Функция освещения // temperatura(); // Функция считывания температуры с датчиков и адаптации к выводу } void pumping() { // Процедура цикличности орашения static unsigned long period= LOW_INTERVAL; // Текущий интервал орашения static unsigned long prevMillis=0; if( (millis()-prevMillis)>=period) { prevMillis=millis(); digitalWrite(PUMP1_Pin,!digitalRead(PUMP1_Pin)); // Меняем интервал через сколько нужно сработать в следующий раз period=(period==LOW_INTERVAL)?HIGH_INTERVAL: LOW_INTERVAL; // Чередуем LOW_INTERVAL / HIGH_INTERVAL } } void temperatura() { //Процедура считывания температуры и влажности с датчиков и адаптация данных для вывода float h_1 = DHT_1.readHumidity(); float t_1 = DHT_1.readTemperature(); float h_2 = DHT_2.readHumidity(); float t_2 = DHT_2.readTemperature(); /* lcd.setCursor(0,9); lcd.print(t_1, 0); lcd.print("C"); lcd.print("|"); lcd.print(h_1, 0); lcd.print("%"); //lcd.print("|"); //lcd.print(t_2, 0); //lcd.print(":"); //lcd.print(h_2, 0); */ } void printDigits(byte digits) { // utility function for digital clock display: prints preceding colon and leading 0 if(digits < 10) lcd.print('0'); lcd.print(digits,DEC); } void digitalClockDisplay() { if (now.minute() != lastMinute || resetClock == true) { lcd.setCursor(0,0); if(now.hour() < 10) lcd.print('0'); lcd.print(now.hour(), DEC); lcd.print( (now.second() % 2)?" ":":"); // разделитель моргает printDigits(now.minute()); lcd.setCursor(6,0); if(now.day() < 10) lcd.print('0'); lcd.print(now.day(), DEC); lcd.print("/"); if(now.month() < 10) lcd.print('0'); lcd.print(now.month(), DEC); lcd.print("/"); int thisYear = now.year(); lcd.print(thisYear, DEC); } lcd.setCursor(0,1); if(current_day < 10) lcd.print('0'); lcd.print(current_day); lcd.print("/"); lcd.print(day_X); /* if(current_light_on_hours < 10) lcd.print('0'); lcd.print(current_light_on_hours); lcd.print(":"); if(current_light_on_minutes < 10) lcd.print('0'); lcd.print(current_light_on_minutes); lcd.print("-"); lcd.print(current_light_off_hours); lcd.print(":"); if(current_light_off_minutes < 10) lcd.print('0'); lcd.print(current_light_off_minutes); lcd.print(" "); lcd.setCursor(14,1); if(current_day < 10) lcd.print('0'); lcd.print(current_day); */ resetClock = false; lastDay = now.day(); lastMonth = now.month(); lastYear = now.year(); lastHour = now.hour(); lastMinute = now.minute(); } void lights() { //Функция расчета включения освещения if (current_day > 0 && current_day <= day_X) { if (current_light_on_hours == lastHour && current_light_on_minutes <= lastMinute) light_state = ON; //включаем освещение light_state = HIGH; - выключаем освещение. else if (current_light_on_hours < lastHour && lastHour < current_light_off_hours) light_state = ON; else if (current_light_off_hours == lastHour && current_light_off_minutes > lastMinute) light_state = ON; else if (current_light_off_hours == lastHour && current_light_off_minutes <= lastMinute) light_state = OFF; else if (current_light_off_hours < lastHour) light_state = OFF; digitalWrite(LAMP_Pin, light_state); // Запись статуса освещения в пин } if (current_day > day_X) { if (current_light_on_hours + 3 == lastHour && current_light_on_minutes <= lastMinute) light_state = ON; //включаем освещение light_state = HIGH; - выключаем освещение. else if (current_light_on_hours + 3 < lastHour && lastHour < current_light_off_hours - 2) light_state = ON; else if (current_light_off_hours - 2 == lastHour && current_light_off_minutes > lastMinute) light_state = ON; else if (current_light_off_hours - 2 == lastHour && current_light_off_minutes <= lastMinute) light_state = OFF; else if (current_light_off_hours - 2 < lastHour) light_state = OFF; digitalWrite(LAMP_Pin, light_state); // Запись статуса освещения в пин } } void button_loop() { int button = read_LCD_buttons(); // digitalClockDisplay(); // Функция обновления часов if (button == btnSELECT) { timedBeep(shortBeep,1); selectMenu(); } } void selectScreen() { int button = 0; menuOption = 1; while (menuOption <= menuOptions) { digitalClockDisplay(); // Функция обновления часов pumping(); // Функция орашения - эксперимента ради пробую не останавливать полив на время выбора подменю lights(); // Функция освещения - эксперимента ради пробую не останавливать полив на время выбора подменю button = read_LCD_buttons(); if (button == btnRIGHT) { timedBeep(shortBeep,1); if (menuOption == 3) menuOption = 0; menuOption++; if (menuOption == 1) { lcdClear(); lcd.print("Current Day"); } if (menuOption == 2) { lcdClear(); lcd.print("Day X"); } if (menuOption == 3) { lcdClear(); lcd.print("Date/Time"); // menuOption = 0; } } if (button == btnLEFT) { timedBeep(shortBeep,1); menuOption--; if (menuOption < 1) menuOption = 3; if (menuOption == 1) { lcdClear(); lcd.print("Current Day"); } if (menuOption == 2) { lcdClear(); lcd.print("Day X"); } if (menuOption == 3) { lcdClear(); lcd.print("Date/Time"); } } } } void selectMenu() { int button = 0; menuOption = 1; lcdClear(); lcd.print("Current Day"); while (menuOption <= menuOptions) { pumping(); // Функция орашения - эксперимента ради пробую не останавливать полив на время выбора подменю lights(); // Функция освещения - эксперимента ради пробую не останавливать полив на время выбора подменю button = read_LCD_buttons(); if (button == btnRIGHT) { timedBeep(shortBeep,1); if (menuOption == 3) menuOption = 0; menuOption++; if (menuOption == 1) { lcdClear(); lcd.print("Current Day"); } if (menuOption == 2) { lcdClear(); lcd.print("Day X"); } if (menuOption == 3) { lcdClear(); lcd.print("Date/Time"); // menuOption = 0; } } if (button == btnLEFT) { timedBeep(shortBeep,1); menuOption--; if (menuOption < 1) menuOption = 3; if (menuOption == 1) { lcdClear(); lcd.print("Current Day"); } if (menuOption == 2) { lcdClear(); lcd.print("Day X"); } if (menuOption == 3) { lcdClear(); lcd.print("Date/Time"); } } if (button == btnSELECT) { if (menuOption == 1) { timedBeep(shortBeep,1); setCurrentDay(); return; } if (menuOption == 2) { timedBeep(shortBeep,1); setDay_X(); return; } if (menuOption == 3) { timedBeep(shortBeep,1); setDateTime(); return; } } } } void setCurrentDay() { //Установка текущего дня работы int button = 0; current_day = getTimerMinutes("Set Current Day", current_day, 366); if (current_day >= 0 && current_day < 367) { lcdClear(); lcd.setCursor(0,1); // if (current_day < 100) // lcd.print("0"); if (current_day < 10) lcd.print("0"); lcd.print(current_day); if (button == btnRIGHT) { timedBeep(shortBeep,1); lcd.setCursor(0,0); lcd.print("Current Day Set for"); delay(500); lcdClear(); return; } else { timerCancelled("Current Day"); lcdClear(); return; } } } void setDay_X() { //Установка деня на который приходится базовая длина дня с базовым времинем включения int button = 0; day_X = getTimerMinutes("Set Day X", day_X, 366); if (day_X >= 0 && day_X < 367) { lcdClear(); lcd.setCursor(0,1); // if (day_X < 100) // lcd.print("0"); if (day_X < 10) lcd.print("0"); lcd.print(day_X); if (button == btnRIGHT) { timedBeep(shortBeep,1); lcd.setCursor(0,0); lcd.print("Day X Set for"); delay(500); lcdClear(); return; } else { timerCancelled("Day X"); lcdClear(); return; } } } void setDateTime() { int button = 0; //get month int setMonth = getTimerMinutes("Set Month", lastMonth, 12); if (setMonth > 0 && setMonth < 13) { int setDay = getTimerMinutes("Set Day", lastDay, 31); if (setDay > 0 && setDay < 32) { //get year int setYear = getTimerMinutes("Set Year", lastYear, 2999); if (setYear > 2000 && setYear < 3000) { //get hour // int thisHour = lastHour; // int setHour = getTimerMinutes("Set Hour", thisHour, 23); int setHour = getTimerMinutes("Set Hour", lastHour, 23); if (setHour >= 0 && setHour < 24) { //get minutes int setMinute = getTimerMinutes("Set Minute", lastMinute, 59); if (setMinute < 60) { lcdClear(); lcd.setCursor(0,1); //display alarm time lcd.print(setHour); lcd.print(":"); if (setMinute < 10) lcd.print("0"); lcd.print(setMinute); if (button == btnRIGHT) { timedBeep(shortBeep,1); RTC.adjust(DateTime(setYear,setMonth,setDay,setHour,setMinute)); //прописываем дату и время в модуль реал-тайм //RTC.adjust(DateTime(2013,9,24,17,37)); //прописываем дату и время в модуль реал-тайм lcd.setCursor(0,0); lcd.print("Saving..."); delay(500); lcdClear(); return; } else { timerCancelled(""); return; } } else { timerCancelled(""); } } else { timerCancelled(""); } } else { timerCancelled(""); } } else { timerCancelled(""); } } else { timerCancelled(""); } } // read the buttons int read_LCD_buttons() { adc_key_in = analogRead(0); // read the value from the sensor // my buttons when read are centered at these valies: 0, 144, 329, 504, 741 // we add approx 50 to those values and check to see if we are close if (adc_key_in > 1000) return btnNONE; // We make this the 1st option for speed reasons since it will be the most likely result if (adc_key_in < 50) return btnRIGHT; if (adc_key_in < 195) return btnUP; if (adc_key_in < 380) return btnDOWN; if (adc_key_in < 555) return btnLEFT; if (adc_key_in < 790) return btnSELECT; return btnNONE; // when all others fail, return this... } int getTimerMinutes(char timerText[], int startNum, int maxCount) { int minutes = startNum; int button = 0; lcdClear(); lcd.print(timerText); lcd.setCursor(0,1); lcd.print(minutes); while (button != btnLEFT) { button = read_LCD_buttons(); Serial.println(button); /* if (button == btnLEFT) { if ((minutes + 10) <= maxCount) { timedBeep(shortBeep,1); minutes = minutes + 10; } else { timedBeep(shortBeep,2); } } */ if (button == btnUP) { if (minutes < maxCount) { timedBeep(shortBeep,1); minutes++; } else { timedBeep(shortBeep,2); } } if (button == btnDOWN) { if (minutes > 0) { timedBeep(shortBeep,1); minutes--; } else { timedBeep(shortBeep,2); } } if (button == btnSELECT) { timedBeep(shortBeep,1); return minutes; } lcd.setCursor(0,1); lcd.print(minutes); lcd.print(" "); } return 0; } void timedBeep(int beepTime, int beepCount) { for (int i = 0; i < beepCount; i ++) { digitalWrite(beeper, HIGH); delay(beepTime); digitalWrite(beeper, LOW); delay(beepTime); } } void lcdClear() { resetClock = true; lcd.clear(); lcd.begin(16,2); lcd.setCursor(0,0); } void timerCancelled(char message[]) { lcdClear(); lcd.print(message); lcd.print(" Cancelled"); timedBeep(shortBeep,3); }P.S. В листинге некоторые форумчане могут заметить части своих кодов)) За что им отдельная благодарность!
Нужно перезайти в среду разработки
...так ведь несколько раз это делал, пока переименовывал то в FAR'e, то показалось, что что-то с кодировкой внутри библиотек, то перебирал варианты с шапкой: #include <i2ceeprom.h> или #include 'i2ceeprom.h" (DHT у меня только так заработал), и каждый раз рестартил IDE.
Если какая-то банальность или моя невнимательность - придется застрелиться))
А так, может подскажете в каком направлении копать дальше, вроде и в более сложные вопросы приходилось вникать, а тут..?
//#include <i2ceeprom.h> void setup() { .... тыры пыры .... } void loop() { .... тыры пыры .... } void i2c_eeprom_write_block( byte deviceaddress, unsigned int eeaddress, void* data, unsigned int length ) { const byte* current = reinterpret_cast<const byte*>(data); unsigned int c; for ( c = 0; c < length; c++) { Wire.beginTransmission(deviceaddress); Wire.write((int)(eeaddress >> 8)); // MSB Wire.write((int)(eeaddress & 0xFF)); // LSB Wire.write(*current++); Wire.endTransmission(); eeaddress++; delay(20); } } // maybe let's not read more than 30 or 32 bytes at a time! void i2c_eeprom_read_buffer( byte deviceaddress, unsigned int eeaddress, void *buffer, byte length ) { byte* current = reinterpret_cast<byte*>(buffer); Wire.beginTransmission(deviceaddress); Wire.write((int)(eeaddress >> 8)); // MSB Wire.write((int)(eeaddress & 0xFF)); // LSB Wire.endTransmission(); Wire.requestFrom(deviceaddress,(byte)length); int c = 0; for ( c = 0; c < length; c++ ) if (Wire.available()) *current++ = Wire.read(); }О Боже! Что за волшебство?!
С конструкцией
//#include <i2ceeprom.h> int current_day = 0 // сюда записываем текущий день int day_X = 0 // день на который приходится базовая длина дня с базовым времинем включения struct DATA // Cтруктура { int curDay; int xDay; }; void setup() { .... // Чтение DATA data_R; // Заполняем data_R из ЕЕПРОМ i2c_eeprom_read_buffer(0x50, 0, &data_R, sizeof(data_R)); // Присваиваем переменным current_day = data_R.curDay; day_X = data_R.xDay; .... } void loop() { .... тыры пыры .... } void eerprom_write() { // Запись DATA data_W; // заполняем data_W.curDay = current_day; data_W.xDay = day_X; // Сохраняем i2c_eeprom_write_block(0x50, 0, &data_W, sizeof(data_W)); delay(10); } void eerprom_read() { // Чтение DATA data_R; // Заполняем data_R из ЕЕПРОМ i2c_eeprom_read_buffer(0x50, 0, &data_R, sizeof(data_R)); // Присваиваем переменным current_day = data_R.curDay; day_X = data_R.xDay; } void i2c_eeprom_write_block( byte deviceaddress, unsigned int eeaddress, void* data, unsigned int length ) { const byte* current = reinterpret_cast<const byte*>(data); unsigned int c; for ( c = 0; c < length; c++) { Wire.beginTransmission(deviceaddress); Wire.write((int)(eeaddress >> 8)); // MSB Wire.write((int)(eeaddress & 0xFF)); // LSB Wire.write(*current++); Wire.endTransmission(); eeaddress++; delay(20); } } // maybe let's not read more than 30 or 32 bytes at a time! void i2c_eeprom_read_buffer( byte deviceaddress, unsigned int eeaddress, void *buffer, byte length ) { byte* current = reinterpret_cast<byte*>(buffer); Wire.beginTransmission(deviceaddress); Wire.write((int)(eeaddress >> 8)); // MSB Wire.write((int)(eeaddress & 0xFF)); // LSB Wire.endTransmission(); Wire.requestFrom(deviceaddress,(byte)length); int c = 0; for ( c = 0; c < length; c++ ) if (Wire.available()) *current++ = Wire.read(); }все заработало, точнее - откомпелилось.
Проверить на железе нет возможности от RTC до МЕГИ нога отвалилась, а на работе паяльник непредусмотрен должностью))
Вечером отпишусь, как устраню железный баг.
Почитал даташит на еепром этот, там написано что можно писать страницами до 32 байт. глядя на реализацию этого дела, становится понятно, что оно будет пошустрее, чем если писать каждый байт по отдельности - как минимум, не надо передавать в еепром каждый раз адрес. да и отправка адреса устройства по i2c тоже время занимает. Функция записи блока, которая тут валяется вместе с остальными, записывает побайтно из этого блока в еепром. Можно модифицировать. Пока лишь сделал набросок проверочный, может сегодня доделаю и полностью готовый вариант. Как оказалось, можно записать так только 30 байт. Наверно 32 имелось в виду вместе с байтами адреса, которых 2. но в даташите это описали как 32 байта данных. ну и пох. После завершения этой функции надо обождать чуток, я ждал 50мс перед проверочным чтением. Может хватит и 20.
void i2c_eeprom_write_page(byte deviceaddress, unsigned int eeaddress, void* data, unsigned int length) { const byte* current = reinterpret_cast<const byte*>(data); unsigned int c; Wire.beginTransmission(deviceaddress); Wire.write((int)(eeaddress >> 8)); // MSB Wire.write((int)(eeaddress & 0xFF)); // LSB for ( c = 0; c < length; c++) { Wire.write(*current++); } Wire.endTransmission(); }Причем при записи 32 значений последние 2 не записываются, но и не происходит переполнения и записи с начала текущей страницы. Почему так - не знаю.
Если из функции записи блока для каждых 30 байт записывать постранично - будет намного быстрее. Тк помимо прочего еще и delay(20) или около того не нужен после записи каждого байта.
Сделал функцию, но почему-то хрень она записывает. Если размер блока 30 - еще норм. если больше - происходит ерунда. Даже с задержкой в секунду между записями страниц. Есть у кого идеи?
#define PAGE_SIZE 30 void i2c_eeprom_write_block_page(byte deviceaddress, unsigned int eeaddress, void* data, unsigned int length) { const byte* current = reinterpret_cast<const byte*>(data); unsigned int bytes_written, page_pos, addr; boolean f = true; bytes_written = 0; while(f) { if (length - bytes_written <= PAGE_SIZE) { page_pos = length - bytes_written; f=false; } else { page_pos = PAGE_SIZE; } addr = eeaddress + bytes_written; Wire.beginTransmission(deviceaddress); Wire.write((int)(addr >> 8)); // MSB Wire.write((int)(addr & 0xFF)); // LSB for (unsigned int c = 0; c < page_pos; c++) { Wire.write(*current++); } Wire.endTransmission(); delay(1000); bytes_written += page_pos; } }Здесь какой-то код есть, тоже со страничной записью, но возможно там просто ограничили длину записываемой последовательности, мне так показалось. Чето там немного мудреное для меня, кому интересно посмотрите. Так-то по уму надо заменить цикл с Wire.Write(*data) на Wire.Write(*data, count), но вряд ли это что-то исправит. ночью проверю
http://forum.arduino.cc/index.php?topic=90594.0
Баг железный устранил, однако работать, как планировалось, программа на стала. При запуске дисплей чистый, на кнопки реагирует, по меню ходит, но текущий день (current_day), день Икс (day_X), а так же дата с RTC выглядели ужастно. Так текущий день подгрузился 1501 (неадекватный параметр натолкнул на мысль, что ячейки на EEPROM RTC были заведомо не пусты); дата не отображалась, а при попытке забить ее вручную из меню, писала, что сохранилась, но по факту этого не происходило.
Курю код дальше.
Код по ссылке рабочий. Но каким образом работает там функция записи страницами - никак не пойму. может кто пояснить? там же адрес отправляется один и тот же..
все, дошло. там они этот аргумент функции меняют как переменную в теле функции.... я к такому как-то не привык, не заметил даже. ну примерно ясно теперь. кроме & ~ () вот этого.
так что обновите свой функционал! и задержку можно поискать вместо 50 какую поменьше можно поставить, наверно.
нашел, все-таки нужную тему..
Пробую добавить библиотеку:
Скачут ошибки:
Что не так?..
Помоему у тебя какието проблемы с библиотекой <Wire.h>, попробуй обновить...
Потому что IDE у него лохматой 0022 версии.
Потому что IDE у него лохматой 0022 версии.
Максим, а где взять свежее ? Что-то весь сайт перерыл, там только Arduino 1.0.5 и Arduino 1.5.6-r2...
с обозначениями у них беда, но 1.0.5 и есть более новая, чем 0022 :)