Не ведись квон! Это провокация, там классов нет! И даже без шаблонов. Такой код недопустим, работать будет не стабильно, он не масштабируется и его поддержка невозможна. Ему здесь не место!
Не ведись квон! Это провокация, там классов нет! И даже без шаблонов. Такой код недопустим, работать будет не стабильно, он не масштабируется и его поддержка невозможна. Ему здесь не место!
И ты, Брут. А он тебя жалел, говорил, флудерасты выгнали, на форум не пущают.
/**/
void saveStringToEeprom(int adr, String obj) {
unsigned int len = obj.length() + 1;
for (unsigned int i = 0; i < len; i++, adr++)
eeprom_write_byte((uint8_t*)adr, obj[i]);
}
void loadStringFromEeprom(int adr, String &obj) {
obj = "";
uint8_t tmp;
do {
tmp = eeprom_read_byte((uint8_t*)adr);
adr++;
obj += String((char)tmp);
}
while (tmp != 0);
}
String StringFromEeprom(int adr) {
String obj("");
uint8_t tmp;
do {
tmp = eeprom_read_byte((uint8_t*)adr);
adr++;
obj += String((char)tmp);
}
while (tmp != 0);
return obj;
}
//---------------------------------------------
const int adr1 =/*адресс eeprom*/10;
const int adr2 =/*адресс eeprom*/20;
//-----------------------------------------------------
void setup() {
Serial.begin(9600);
String aaa("qwerty");
Serial.println(aaa);
saveStringToEeprom(adr1, F("qwone"));
saveStringToEeprom(adr2, F("Winnie the Pooh"));
loadStringFromEeprom(adr1, aaa);
Serial.println(aaa);
String bbb(StringFromEeprom(adr2));
Serial.println(bbb);
}
void loop() {
}
Строка номер 2 - надо по ссылке передавать параметр типа String, чтобы не было копирования, со всеми вытекающими, типа жёсткой работы с памятью.
Писать/читаться строки в EEPROM лучше с префиксом - сколько байт сохранено. У String есть чудесный метод reserve, который избавит тебя от дичайшей переаллокации каждый раз, когда ты плюсуешь к строке один байт. Представь, что у тебя сохранена строка в 50 байт - в твоём случае это целых 50 выделений/освобождений памяти, зачем ты так не любишь микроконтроллеры?
Квон, я понимаю, что сказать нам - дуракам хоть слово, с высоты твое величия - западло. А потому я не знаю, зачем ты выложил этот вариант. Но, если в смысле, что в нём нету фрагемнтации памяти, то мимо - никуда она не делась, смотри
#include <MemoryExplorer.h>
/**/
void saveStringToEeprom(int adr, String obj) {
unsigned int len = obj.length() + 1;
for (unsigned int i = 0; i < len; i++, adr++)
eeprom_write_byte((uint8_t*)adr, obj[i]);
}
void loadStringFromEeprom(int adr, String &obj) {
obj = "";
uint8_t tmp;
do {
tmp = eeprom_read_byte((uint8_t*)adr);
adr++;
obj += String((char)tmp);
}
while (tmp != 0);
}
String StringFromEeprom(int adr) {
String obj("");
uint8_t tmp;
do {
tmp = eeprom_read_byte((uint8_t*)adr);
adr++;
obj += String((char)tmp);
}
while (tmp != 0);
return obj;
}
//---------------------------------------------
const int adr1 =/*адресс eeprom*/10;
const int adr2 =/*адресс eeprom*/20;
//-----------------------------------------------------
void setup() {
Serial.begin(115200);
memoryReport("At Start");
String aaa("qwerty");
Serial.println(aaa);
saveStringToEeprom(adr1, F("qwone"));
saveStringToEeprom(adr2, F("Winnie the Pooh"));
loadStringFromEeprom(adr1, aaa);
Serial.println(aaa);
String bbb(StringFromEeprom(adr2));
Serial.println(bbb);
memoryReport("Freed p1");
}
void loop() {
}
Ну с точками т тире каждый может. А ты с буквами покажи :)
Да там всего лишь это еще раз обернуть. Передавать побуквенно заменив буквы на точки и все. Долго таблицу составлять для всех букв русских английских больших и маленьких и спец знаков.
ua6em, я не стрелюсь к простым скетчам или компактным. Я стремлюсь к таким что бы и опыт подчерпнуть и потом в процессе совместить с другими компонентами, причем по возможности не блокирую их работу.
Пух, стандартное поведение древнего Виндовс АПИ, когда отдаваемый буфер может быть разного размера, это вызов функции с пустым указателем, тогда она реально ничо никуда не пишет, а отдает длину необходимого буфера. После этого ты отгрызаешь памяти скока надо и вызываешь ф-ю повторно, уже с правильным указателем на буфер нужного размера, и отец Вындоуз его наполняет.
Я сделал так (строка в ROM храница вместе с нулем)
// читает строку из адреса ASrcAddr в буфер AStrBuf вместе с завершающим нулем
// отдает длину в байтах прочитанной строки (вместе с нулём)
// если вызвать с NULL вместо адреса буфера куда читать, можно невозбранно поиметь длину строки
//
// Пример:
//
// size_t len = EEPROM.ReadString(0x100, NULL); сначала узнаем, скока байт надо (вместе с нулём)
// char *str = new char[len]; потом выделим память
// EEPROM.ReadString(0x100, str); потом прочитаем строку
// Serial << str << '\n'; чонить с ней сделаем
// delete[] str; и удалим, када станет не надо
size_t ReadString(addr_t ASrcAddr, char *AStrBuf) {
char c;
size_t len = 0;
do {
c = readByte(ASrcAddr++);
if (AStrBuf != NULL) AStrBuf[len] = c;
} while (len++, (c > '\0'));
return len;
}
Ну вот, квон - осталось дооптимизировать, сохраняя байт длины строки перед самой строкой, и при чтении - вычитывать сначала один байт, потом резервировать память, потом - читать данные. Не помешает ещё заголовок в пару байт, чтобы убедиться, что данные таки сохранены.
По итогу что это всё даёт:
1. Есть заголовок - проверка записи на валидность;
2. Есть длина данных - не надо её высчитывать мееедленным чтением из EEPROM.
На примере строки в 1 байт длиной: твой вариант (с хранением нулевого завершающего байта) - даст чтений 2 + 2 = 4. Мой вариант, с заголовком из двух байт, байтом длины и данными, даст чтений 2 + 1 + 1 = 4. При этом мой вариант бьёт твой, начиная с длины строки > 1.
Скетч использует 3088 байт (10%) памяти устройства. Всего доступно 30720 байт.
Глобальные переменные используют 198 байт
Виш! 112 байт на ровном месте! И притом что "pustozvon" еще и длинней чем "qwone" ;)
Как избавится от стринга при переменной длине строки в loadFromEeprom, а заодно от использывания кучи и следовательно фрагментации - думай квон, думай ;) Меня ж тошнить начинает когда я вижу два прохода в loadFromEeprom и return obj.
Да. В WAVGAT по другому. Но не суть важно, важно другое - указатель (или адрес) всегда эффективней будет.
Еще один забавный пример, давно хотел глянуть на эти цифры.
void setup() {
int t;
// put your setup code here, to run once:
Serial.begin(9600);
for(char c='1';c<'z';c++)
{
t=micros();
Serial.print(c);
Serial.print(':');
Serial.println((int)micros()-t);
}
}
void loop() {
// put your main code here, to run repeatedly:
}
Все просто, меряем время вывода в сириал. Имеем
1:12
2:16
3:16
4:12
5:12
6:16
7:16
8:12
9:16
::12
;:12
<:1728
=:2076
>:2076
?:2076
@:2076
На 2 порядка!!!
Все просто, пока в буфер помещается - быстро. Потом сильно медлено.
На первый взгляд это к примерам выше вобще не относится. Но только на первый. Т.к. на второй позволяет понять есть ли разница между выводом всей строки сразу и выводом её по символьно. Ну и когда как стоит делать. Кстати 2076мксек - время на реальную, физическую отправку 2 байт на скорости 9600бод.
Воспользуйтесь этим драйвером I2C, ....
Не ведись квон! Это провокация, там классов нет! И даже без шаблонов. Такой код недопустим, работать будет не стабильно, он не масштабируется и его поддержка невозможна. Ему здесь не место!
Воспользуйтесь этим драйвером I2C, ....
Не ведись квон! Это провокация, там классов нет! И даже без шаблонов. Такой код недопустим, работать будет не стабильно, он не масштабируется и его поддержка невозможна. Ему здесь не место!
И ты, Брут. А он тебя жалел, говорил, флудерасты выгнали, на форум не пущают.
DetSimen,точно херня с буфером на 30 вылезла.
/*cluster*/ template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; } #include <Wire.h> #define SIZE_CLUSTER 32 // размер кластера #define MAX_CLUSTER 128 // кол-во кластеров class buffer_t { public: byte buffer[SIZE_CLUSTER]; buffer_t(); buffer_t(const __FlashStringHelper* txt); }; buffer_t::buffer_t(void) { for (int i = 0; i < SIZE_CLUSTER; i++)buffer[i] = '!'; } buffer_t::buffer_t(const __FlashStringHelper* txt) { int len = strlen_P((const char*)txt); if (len > SIZE_CLUSTER)len = SIZE_CLUSTER; for (int i = 0; i < SIZE_CLUSTER; i++)buffer[i] = pgm_read_byte_near((const char*)txt + i); } class e24c32 { protected: byte adr_i2c; public: byte buffer[SIZE_CLUSTER]; byte cluster; void save_cluster(); void load_cluster(); void viev_byffer(); void save_byffer(buffer_t obj); e24c32(byte adr): adr_i2c(adr) {} void init(); }; void e24c32::init() { Wire.begin(); } void e24c32::save_cluster() { Wire.beginTransmission(adr_i2c); uint16_t address = cluster * SIZE_CLUSTER; Wire.write(address >> 8); Wire.write(address & 0xFF); for (byte i = 0; i < SIZE_CLUSTER; i++) Wire.write(buffer[i]); Wire.endTransmission(); delay(10); } void e24c32::load_cluster() { Wire.beginTransmission(adr_i2c); uint16_t address = cluster * SIZE_CLUSTER; Wire.write(address >> 8); Wire.write(address & 0xFF); Wire.endTransmission(); Wire.requestFrom(adr_i2c, (byte)SIZE_CLUSTER ); for (byte i = 0; i < SIZE_CLUSTER; i++) if (Wire.available()) buffer[i] = Wire.read(); } void e24c32::viev_byffer() { for (int i = 0; i < SIZE_CLUSTER; i++) { char tmp = buffer[i]; if (tmp == 0) break; Serial << tmp; } Serial << F("\n"); } void e24c32::save_byffer(buffer_t obj = buffer_t()) { for (int i = 0; i < SIZE_CLUSTER; i++)buffer[i] = obj.buffer[i]; } e24c32 cluster(/* адр i2c*/0x57); void setup() { Serial.begin(9600); cluster.init(); cluster.save_byffer();//< cluster.save_cluster(); Serial << F("1\n"); cluster.viev_byffer(); cluster.save_byffer(F("qwertyuiop")); Serial << F("2\n"); cluster.viev_byffer(); cluster.load_cluster(); Serial << F("3\n"); cluster.viev_byffer(); } void loop() { } /* Выведено 1 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 2 qwertyuiop 3 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!Hб */ПС: и да когда кому-нибудь захочется проверить этот код не забудьте подключить модуль
Примитив но просто не интересовался этим.
void setup() { Serial.begin(9600); String AAA(F("1234567890")); Serial.println(AAA.begin()); } void loop() { }Примитив но просто не интересовался этим.
void setup() { Serial.begin(9600); String AAA(F("1234567890")); Serial.println(AAA.begin()); } void loop() { }и так тоже отрабатывает
void setup() { Serial.begin(9600); String AAA(("1234567890")); Serial.println(AAA.begin()); } void loop() {Да и ваша версия отъедает ОЗУ.
А Ваша? Точно так же отъёдает, ни на байт не меньше. Только не статикой, а запросом памяти при работе конструктора.
/**/ #include <EEPROM.h> void saveStringToEeprom(int adr, String obj); void loadStringFromEeprom(int adr, String &obj); void saveStringToEeprom(int adr, String obj) { unsigned int len = obj.length() + 1; for (unsigned int i = 0; i < len; i++) EEPROM.write(adr + i, obj[i]); } void loadStringFromEeprom(int adr, String &obj) { obj = ""; uint8_t tmp; do { tmp = EEPROM.read(adr); adr++; obj += String((char)tmp); } while (tmp != 0); } //--------------------------------------------- const int adr1 =/*адресс eeprom*/10; const int adr2 =/*адресс eeprom*/20; //----------------------------------------------------- void setup() { Serial.begin(9600); String aaa("qwerty"); Serial.println(aaa); saveStringToEeprom(adr1, F("qwone")); saveStringToEeprom(adr2, F("Winnie the Pooh")); loadStringFromEeprom(adr1, aaa); Serial.println(aaa); loadStringFromEeprom(adr2, aaa); Serial.println(aaa); } void loop() { }Пух, ты лучше на выборы сходи.
DetSimen, вы тоже сходите. Напишите на бумажке свой выбор и бростьте ближайшую урну.Результат будет такой же.
Пух, за что так с памятью-то? Совсем не жалко? Чё она тебе плохого сделала, что ты её так?
#include <MemoryExplorer.h> /**/ #include <EEPROM.h> void saveStringToEeprom(int adr, String obj); void loadStringFromEeprom(int adr, String &obj); void saveStringToEeprom(int adr, String obj) { unsigned int len = obj.length() + 1; for (unsigned int i = 0; i < len; i++) EEPROM.write(adr + i, obj[i]); } void loadStringFromEeprom(int adr, String &obj) { unsigned int len = 0; while (EEPROM.read(adr + len) != 0) { len++; } char *buf = new char[len + 1]; for (unsigned int i = 0; i <= len; i++) buf[i] = EEPROM.read(adr + i); obj = String(buf); delete[] buf; } //--------------------------------------------- const int adr1 =/*адресс eeprom*/10; const int adr2 =/*адресс eeprom*/20; //----------------------------------------------------- void setup() { Serial.begin(115200); memoryReport("At Start"); String aaa("qwerty"); Serial.println(aaa); saveStringToEeprom(adr1, F("qwone")); saveStringToEeprom(adr2, F("Winnie the Pooh")); loadStringFromEeprom(adr1, aaa); Serial.println(aaa); loadStringFromEeprom(adr2, aaa); Serial.println(aaa); memoryReport("At End"); } void loop() { }вот чего печатает
Это тока фрагментация, а сколько там по ходу дела нафик не нужных запросов - жуть, сам посмотри.
/**/ void saveStringToEeprom(int adr, String obj) { unsigned int len = obj.length() + 1; for (unsigned int i = 0; i < len; i++, adr++) eeprom_write_byte((uint8_t*)adr, obj[i]); } void loadStringFromEeprom(int adr, String &obj) { obj = ""; uint8_t tmp; do { tmp = eeprom_read_byte((uint8_t*)adr); adr++; obj += String((char)tmp); } while (tmp != 0); } String StringFromEeprom(int adr) { String obj(""); uint8_t tmp; do { tmp = eeprom_read_byte((uint8_t*)adr); adr++; obj += String((char)tmp); } while (tmp != 0); return obj; } //--------------------------------------------- const int adr1 =/*адресс eeprom*/10; const int adr2 =/*адресс eeprom*/20; //----------------------------------------------------- void setup() { Serial.begin(9600); String aaa("qwerty"); Serial.println(aaa); saveStringToEeprom(adr1, F("qwone")); saveStringToEeprom(adr2, F("Winnie the Pooh")); loadStringFromEeprom(adr1, aaa); Serial.println(aaa); String bbb(StringFromEeprom(adr2)); Serial.println(bbb); } void loop() { }/**/ void saveStringToEeprom(int adr, String obj) { unsigned int len = obj.length() + 1; for (unsigned int i = 0; i < len; i++, adr++) eeprom_write_byte((uint8_t*)adr, obj[i]); } void loadStringFromEeprom(int adr, String &obj) { obj = ""; uint8_t tmp; do { tmp = eeprom_read_byte((uint8_t*)adr); adr++; obj += String((char)tmp); } while (tmp != 0); } String StringFromEeprom(int adr) { String obj(""); uint8_t tmp; do { tmp = eeprom_read_byte((uint8_t*)adr); adr++; obj += String((char)tmp); } while (tmp != 0); return obj; } //--------------------------------------------- const int adr1 =/*адресс eeprom*/10; const int adr2 =/*адресс eeprom*/20; //----------------------------------------------------- void setup() { Serial.begin(9600); String aaa("qwerty"); Serial.println(aaa); saveStringToEeprom(adr1, F("qwone")); saveStringToEeprom(adr2, F("Winnie the Pooh")); loadStringFromEeprom(adr1, aaa); Serial.println(aaa); String bbb(StringFromEeprom(adr2)); Serial.println(bbb); } void loop() { }Строка номер 2 - надо по ссылке передавать параметр типа String, чтобы не было копирования, со всеми вытекающими, типа жёсткой работы с памятью.
Писать/читаться строки в EEPROM лучше с префиксом - сколько байт сохранено. У String есть чудесный метод reserve, который избавит тебя от дичайшей переаллокации каждый раз, когда ты плюсуешь к строке один байт. Представь, что у тебя сохранена строка в 50 байт - в твоём случае это целых 50 выделений/освобождений памяти, зачем ты так не любишь микроконтроллеры?
... У String есть чудесный метод ...
Вот если меня спросить, что мне более всего нравится в стрингах, то я отвечу, что в "стрингах" мне более всего нравятся барышни... лет 25ти. ;))))
Ответ на #163.
Квон, я понимаю, что сказать нам - дуракам хоть слово, с высоты твое величия - западло. А потому я не знаю, зачем ты выложил этот вариант. Но, если в смысле, что в нём нету фрагемнтации памяти, то мимо - никуда она не делась, смотри
#include <MemoryExplorer.h> /**/ void saveStringToEeprom(int adr, String obj) { unsigned int len = obj.length() + 1; for (unsigned int i = 0; i < len; i++, adr++) eeprom_write_byte((uint8_t*)adr, obj[i]); } void loadStringFromEeprom(int adr, String &obj) { obj = ""; uint8_t tmp; do { tmp = eeprom_read_byte((uint8_t*)adr); adr++; obj += String((char)tmp); } while (tmp != 0); } String StringFromEeprom(int adr) { String obj(""); uint8_t tmp; do { tmp = eeprom_read_byte((uint8_t*)adr); adr++; obj += String((char)tmp); } while (tmp != 0); return obj; } //--------------------------------------------- const int adr1 =/*адресс eeprom*/10; const int adr2 =/*адресс eeprom*/20; //----------------------------------------------------- void setup() { Serial.begin(115200); memoryReport("At Start"); String aaa("qwerty"); Serial.println(aaa); saveStringToEeprom(adr1, F("qwone")); saveStringToEeprom(adr2, F("Winnie the Pooh")); loadStringFromEeprom(adr1, aaa); Serial.println(aaa); String bbb(StringFromEeprom(adr2)); Serial.println(bbb); memoryReport("Freed p1"); } void loop() { }Печатаить
Ну и зарисовки по Морзе
/**/ //------------------------------------------------- const byte st_none = 0; const byte st_next = 1; const byte st_dot = 2; const byte st_dush = 3; const byte st_pause_dot = 4; const byte st_pause_dush = 5; class cMorse { protected: String buffer; unsigned int ii; byte pin; unsigned long past; unsigned long time; unsigned long dot_time; byte state, next_state; void set( byte s); public: cMorse(byte p); void init(unsigned long t = 300); void run(); void play(String msg); }; void cMorse::set(byte s) { state = s; past = millis(); while (state == st_next) { char tmp = buffer[ii++]; switch (tmp) { case '.': state = st_dot; break; case '-': state = st_dush; break; case ' ': state = st_pause_dush; break; case '\0': state = st_none; break; } } switch (state) { case st_none: Serial.print(F("OK")); break; case st_next: break; case st_dot: Serial.print(F(".")); digitalWrite(pin, HIGH); time = dot_time; next_state = st_pause_dot; break; case st_dush: Serial.print(F("-")); digitalWrite(pin, HIGH); time = dot_time * 3; next_state = st_pause_dot; break; case st_pause_dot: digitalWrite(pin, LOW); time = dot_time; next_state = st_next; break; case st_pause_dush: Serial.print(F(" ")); digitalWrite(pin, LOW); time = dot_time * 3; next_state = st_next; break; } } cMorse::cMorse(byte p) : pin(p) {} void cMorse::init(unsigned long t) { dot_time = t; ii = 0; set(st_none); pinMode(pin, OUTPUT); } void cMorse::run() { if (state != st_none && millis() - past >= time) set(next_state); } void cMorse::play(String msg) { buffer = msg; ii = 0; set(st_next); } cMorse Morse(/*пин*/13); //----------- кнопка ------------------------ typedef void (*pDo)(); class Cl_Btn { protected: byte pin; unsigned long past; bool state; void set(bool s) { past = millis(); state = s; if (s == true)Do(); } public: pDo Do = [] {}; Cl_Btn(byte p): pin(p) {} void init() { pinMode(pin, INPUT_PULLUP); set(false); } void run() { if (millis() - past >= 100) { switch (state) { case false : if (!digitalRead(pin)) set(true); break; case true : if (digitalRead(pin)) set(false); break; } } } }; Cl_Btn Btn(/*пин*/2);// кнопка void setup() { Serial.begin(9600); Morse.init(100);//0.1 секунды длит точки Btn.init(); Btn.Do = [] { Serial.println(); Morse.play(F("... --- ... "));// сообщение SOS }; } void loop() { Morse.run(); Btn.run(); }Ну с точками и тире каждый может. А ты с буквами покажи :)
А почему для статусов какой нибудь enum, ну или #define не используешь ? Какая у тебя на сей счет религия ?
Ну с точками т тире каждый может. А ты с буквами покажи :)
Не, не экономно... Не красиво получится :(
Квон - какой такой душ?
st_dush
Тире - это dash.
с точками, тире и генерацией частоты на пине самый простой скетч у Максима Клименко, занимает менее 1600 байт, озу 445 байт )))
с точками, тире и генерацией частоты на пине самый простой скетч у Максима Клименко, занимает менее 1600 байт, озу 445 байт )))
Расход ОЗУ в приведённом скетче можно сократить раз в 10 ;) Переместив кое-чего во флеш ;)
const char CODE[] = { B0000000, B01110011, B0000000, B0000000, B0000000, B0000000, B0000000, B0000000,// !"# $%&' B0000000, B0000000, B0000000, B0000000, B01010101, B01010101, B0000000, B0110010,//()*+ -,./ B0111111, B0101111, B0100111, B0100011, B0100001, B0100000, B0110000, B0111000,//0123 4567 B0111100, B0111110, B0000000, B0000000, B0000000, B0000000, B0000000, B01001100,//89:; <=>? B01011010, B0101, B011000, B011010, B01100, B010, B010010, B01110,//@ABC DEFG B01000, B0100, B010111, B01101, B010100, B0111, B0110, B01111,//HIJK LMNO B010110, B011101, B01010, B01000, B011, B01001, B010001, B01011,//PQRS TUVW B011001, B011011, B011100, B0000000, B0000000, B0000000, B0000000, B0000000,//XYZ[ \]^_ B0000000, B0101, B011000, B011010, B01100, B010, B010010, B01110,//`abc defg B01000, B0100, B010111, B01101, B010100, B0111, B0110, B01111,//hijk lmno B010110, B011101, B01010, B01000, B011, B01001, B010001, B01011,//pgrs tuvw B011001, B011011, B011100, B0000000, B0000000, B0000000, B0000000, B0000000 //xyz{ |}~ }; String msg(".,/?!@0123456789 abcdef"); void setup() { Serial.begin(9600); for (unsigned int i = 0; i < msg.length(); i++) { String aaa; byte tmp = CODE[msg[i] - ' ']; if (tmp == 0) aaa = " "; else { bool f = 0; aaa = ""; for (int i = 0; i < 8; ++i) { if (f) { if (tmp & 0x80) aaa += "-"; else aaa += "."; } else if (tmp & 0x80) f = 1; tmp = tmp << 1; } } Serial.println(); Serial.print(msg[i]); Serial.print(" "); Serial.print(aaa); } } void loop() { }ua6em, я не стрелюсь к простым скетчам или компактным. Я стремлюсь к таким что бы и опыт подчерпнуть и потом в процессе совместить с другими компонентами, причем по возможности не блокирую их работу.
с точками, тире и генерацией частоты на пине самый простой скетч у Максима Клименко, занимает менее 1600 байт, озу 445 байт )))
Расход ОЗУ в приведённом скетче можно сократить раз в 10 ;) Переместив кое-чего во флеш ;)
со строкой понятно, а массив как?
с точками, тире и генерацией частоты на пине самый простой скетч у Максима Клименко, занимает менее 1600 байт, озу 445 байт )))
Расход ОЗУ в приведённом скетче можно сократить раз в 10 ;) Переместив кое-чего во флеш ;)
со строкой понятно, а массив как?
А чем массив отличается от строки таким, что его нельзя во флеш поместить? Правильно - ничем.
Пух, стандартное поведение древнего Виндовс АПИ, когда отдаваемый буфер может быть разного размера, это вызов функции с пустым указателем, тогда она реально ничо никуда не пишет, а отдает длину необходимого буфера. После этого ты отгрызаешь памяти скока надо и вызываешь ф-ю повторно, уже с правильным указателем на буфер нужного размера, и отец Вындоуз его наполняет.
Я сделал так (строка в ROM храница вместе с нулем)
// читает строку из адреса ASrcAddr в буфер AStrBuf вместе с завершающим нулем // отдает длину в байтах прочитанной строки (вместе с нулём) // если вызвать с NULL вместо адреса буфера куда читать, можно невозбранно поиметь длину строки // // Пример: // // size_t len = EEPROM.ReadString(0x100, NULL); сначала узнаем, скока байт надо (вместе с нулём) // char *str = new char[len]; потом выделим память // EEPROM.ReadString(0x100, str); потом прочитаем строку // Serial << str << '\n'; чонить с ней сделаем // delete[] str; и удалим, када станет не надо size_t ReadString(addr_t ASrcAddr, char *AStrBuf) { char c; size_t len = 0; do { c = readByte(ASrcAddr++); if (AStrBuf != NULL) AStrBuf[len] = c; } while (len++, (c > '\0')); return len; }с точками, тире и генерацией частоты на пине самый простой скетч у Максима Клименко, занимает менее 1600 байт, озу 445 байт )))
Расход ОЗУ в приведённом скетче можно сократить раз в 10 ;) Переместив кое-чего во флеш ;)
со строкой понятно, а массив как?
А чем массив отличается от строки таким, что его нельзя во флеш поместить? Правильно - ничем.
у меня не получилось, компилируется но не работает )))
/**/ void saveToEeprom(int adr, String obj) { unsigned int len = obj.length() + 1; for (unsigned int i = 0; i < len; i++, adr++) eeprom_write_byte((uint8_t*)adr, obj[i]); } String loadFromEeprom(int adr) { unsigned int a = adr; for (; eeprom_read_byte((uint8_t*)a) != 0; a++); String obj; obj.reserve(a - adr + 1); uint8_t tmp; do { tmp = eeprom_read_byte((uint8_t*)adr++); obj += String((char)tmp); } while (tmp != 0); return obj; } //--------------------------------------------- const int adr1 =/*адресс eeprom*/10; const int adr2 =/*адресс eeprom*/20; //----------------------------------------------------- void setup() { Serial.begin(9600); String aaa("qwerty"); Serial.println(aaa); saveToEeprom(adr1, F("qwone")); saveToEeprom(adr2, F("Winnie the Pooh")); Serial.println(loadFromEeprom(adr1)); Serial.println(loadFromEeprom(adr2)); } void loop() { }Ну вот, квон - осталось дооптимизировать, сохраняя байт длины строки перед самой строкой, и при чтении - вычитывать сначала один байт, потом резервировать память, потом - читать данные. Не помешает ещё заголовок в пару байт, чтобы убедиться, что данные таки сохранены.
По итогу что это всё даёт:
1. Есть заголовок - проверка записи на валидность;
2. Есть длина данных - не надо её высчитывать мееедленным чтением из EEPROM.
На примере строки в 1 байт длиной: твой вариант (с хранением нулевого завершающего байта) - даст чтений 2 + 2 = 4. Мой вариант, с заголовком из двух байт, байтом длины и данными, даст чтений 2 + 1 + 1 = 4. При этом мой вариант бьёт твой, начиная с длины строки > 1.
Напишешь ещё вариант? Думаю, пригодится ;)
мой вариант бьёт твой, начиная с длины строки > 1.
Пожалуй, я с тобой соглашуся. Хоть чтение и не так тормозит, как запись, но сётаки переделаю.
Ой квон, безнадежен ты. Абсолютно безнадежен.
Твое:
void saveToEeprom(int adr, String obj) { unsigned int len = obj.length() + 1; for (unsigned int i = 0; i < len; i++, adr++) eeprom_write_byte((uint8_t*)adr, obj[i]); } String loadFromEeprom(int adr) { unsigned int a = adr; for (; eeprom_read_byte((uint8_t*)a) != 0; a++); String obj; obj.reserve(a - adr + 1); uint8_t tmp; do { tmp = eeprom_read_byte((uint8_t*)adr++); obj += String((char)tmp); } while (tmp != 0); return obj; } const int adr1 =/*адресс eeprom*/10; void setup() { Serial.begin(9600); saveToEeprom(adr1, F("qwone")); Serial.println(loadFromEeprom(adr1)); } void loop() { }Скетч использует 3200 байт (10%) памяти устройства. Всего доступно 30720 байт.
Правильное:
void saveToEeprom(int adr, const char * p) { uint8_t a; do { a= pgm_read_byte(p++); eeprom_write_byte((uint8_t*)adr++,a); } while (a); } String loadFromEeprom(int adr) { unsigned int a = adr; for (; eeprom_read_byte((uint8_t*)a) != 0; a++); String obj; obj.reserve(a - adr + 1); uint8_t tmp; do { tmp = eeprom_read_byte((uint8_t*)adr++); obj += String((char)tmp); } while (tmp != 0); return obj; } const int adr1 =/*адресс eeprom*/10; const char Sub[] PROGMEM ="pustozvon"; void setup() { Serial.begin(9600); saveToEeprom(adr1, Sub); Serial.println(loadFromEeprom(adr1)); } void loop() { }Мда. В какую битву титанов я влес... А ведь даже писАть не умею. :)
Но я, кста, не уверен, что он тут хотел из EEPROMa в EEPROM писать
void saveToEeprom(int adr, const char * p) { uint8_t a; do { a= pgm_read_byte(p++); eeprom_write_byte((uint8_t*)adr++,a); } while (a); }мне кажеца, *p это указатель на ОЗУ.
кажется - проверь! Не сцо! В боях крепчают! Оба кода рабочие. А PROGMEM и EEPROM - точно разные штуковины.
АААААА там же из флэша в EEPROM, точно. Звиняйте.
кажется - проверь! Не сцо! В боях крепчают! Оба кода рабочие. А PROGMEM и EEPROM - точно разные штуковины.
в WAVGAT это одно и тоже вроде как, только адреса разные
Да. В WAVGAT по другому. Но не суть важно, важно другое - указатель (или адрес) всегда эффективней будет.
Еще один забавный пример, давно хотел глянуть на эти цифры.
void setup() { int t; // put your setup code here, to run once: Serial.begin(9600); for(char c='1';c<'z';c++) { t=micros(); Serial.print(c); Serial.print(':'); Serial.println((int)micros()-t); } } void loop() { // put your main code here, to run repeatedly: }Все просто, меряем время вывода в сириал. Имеем
Кстати 2076мксек - время на реальную, физическую отправку 2 байт на скорости 9600бод.
так буфер у сериала вроде как должен быть 16 байт, куда остальные делись?
Я слышал что 64байта по умолчанию. И по примеру тоже похоже. Первые 11 быстро прошли. Имеют строк по 6 байт в строке. Итого 66.
Кстати 2076мксек - время на реальную, физическую отправку 2 байт на скорости 9600бод.
так буфер у сериала вроде как должен быть 16 байт, куда остальные делись?
изучи нимательно
и доложи, у какой ATMeg-и Serial буфер 16 байт.
Кстати 2076мксек - время на реальную, физическую отправку 2 байт на скорости 9600бод.
так буфер у сериала вроде как должен быть 16 байт, куда остальные делись?
изучи нимательно
и доложи, у какой ATMeg-и Serial буфер 16 байт.
это тлетворное влияние PC-XT
Выдернутый отсюда код как писать большими буквами в lcd2004 https://github.com/voltnik/SmokeClock/blob/master/SmokeClock/SmokeClock.ino
#include <LiquidCrystal_I2C.h> LiquidCrystal_I2C lcd(0x3F, 20, 4); byte custom[8][8] = { // символы большого шрифта { B11111, B11111, B11111, B00000, B00000, B00000, B00000, B00000 }, { B11100, B11110, B11111, B11111, B11111, B11111, B11111, B11111 }, { B11111, B11111, B11111, B11111, B11111, B11111, B01111, B00111 }, { B00000, B00000, B00000, B00000, B00000, B11111, B11111, B11111 }, { B11111, B11111, B11111, B11111, B11111, B11111, B11110, B11100 }, { B11111, B11111, B11111, B00000, B00000, B00000, B11111, B11111 }, { B11111, B00000, B00000, B00000, B00000, B11111, B11111, B11111 }, { B00111, B01111, B11111, B11111, B11111, B11111, B11111, B11111 } }; const char *bigChars[][2] = { // символы из новых букв {"\024\024\024", "\024\024\024"}, // Space {"\377", "\007"}, // ! {"\005\005", "\024\024"}, // " {"\004\377\004\377\004", "\001\377\001\377\001"}, // # {"\010\377\006", "\007\377\005"}, // $ {"\001\024\004\001", "\004\001\024\004"}, // % {"\010\006\002\024", "\003\007\002\004"}, // & {"\005", "\024"}, // ' {"\010\001", "\003\004"}, // ( {"\001\002", "\004\005"}, // ) {"\001\004\004\001", "\004\001\001\004"}, // * {"\004\377\004", "\001\377\001"}, // + {"\024", "\005"}, // , {"\004\004\004", "\024\024\024"}, // - {"\024", "\004"}, // . {"\024\024\004\001", "\004\001\024\024"}, // / {"\010\001\002", "\003\004\005"}, // 0 {"\001\002\024", "\024\377\024"}, // 1 {"\006\006\002", "\003\007\007"}, // 2 {"\006\006\002", "\007\007\005"}, // 3 {"\003\004\002", "\024\024\377"}, // 4 {"\377\006\006", "\007\007\005"}, // 5 {"\010\006\006", "\003\007\005"}, // 6 {"\001\001\002", "\024\010\024"}, // 7 {"\010\006\002", "\003\007\005"}, // 8 {"\010\006\002", "\024\024\377"}, // 9 {"\004", "\001"}, // : {"\004", "\005"}, // ; {"\024\004\001", "\001\001\004"}, // < {"\004\004\004", "\001\001\001"}, // = {"\001\004\024", "\004\001\001"}, // > {"\001\006\002", "\024\007\024"}, // ? {"\010\006\002", "\003\004\004"}, // @ {"\010\006\002", "\377\024\377"}, // A {"\377\006\005", "\377\007\002"}, // B {"\010\001\001", "\003\004\004"}, // C {"\377\001\002", "\377\004\005"}, // D {"\377\006\006", "\377\007\007"}, // E {"\377\006\006", "\377\024\024"}, // F {"\010\001\001", "\003\004\002"}, // G {"\377\004\377", "\377\024\377"}, // H {"\001\377\001", "\004\377\004"}, // I {"\024\024\377", "\004\004\005"}, // J {"\377\004\005", "\377\024\002"}, // K {"\377\024\024", "\377\004\004"}, // L {"\010\003\005\002", "\377\024\024\377"}, // M {"\010\002\024\377", "\377\024\003\005"}, // N {"\010\001\002", "\003\004\005"}, // 0/0 {"\377\006\002", "\377\024\024"}, // P {"\010\001\002\024", "\003\004\377\004"}, // Q {"\377\006\002", "\377\024\002"}, // R {"\010\006\006", "\007\007\005"}, // S {"\001\377\001", "\024\377\024"}, // T {"\377\024\377", "\003\004\005"}, // U {"\003\024\024\005", "\024\002\010\024"}, // V {"\377\024\024\377", "\003\010\002\005"}, // W {"\003\004\005", "\010\024\002"}, // X {"\003\004\005", "\024\377\024"}, // Y {"\001\006\005", "\010\007\004"}, // Z {"\377\001", "\377\004"}, // [ {"\001\004\024\024", "\024\024\001\004"}, // Backslash {"\001\377", "\004\377"}, // ] {"\010\002", "\024\024"}, // ^ {"\024\024\024", "\004\004\004"}, // _ }; int writeBigChar(char ch, int x, int y) { const char *(*blocks)[2] = NULL; // Pointer to an array of two strings (character pointers) if (ch < ' ' || ch > '_') // If outside our table range, do nothing return 0; blocks = &bigChars[ch - ' ']; // Look up the definition for (int half = 0; half <= 1; half++) { int t = x; // Write out top or bottom string, byte at a time for (const char *cp = (*blocks)[half]; *cp; cp++) { lcd.setCursor(t, y + half); lcd.write(*cp); t = (t + 1) % 40; // Circular scroll buffer of 40 characters, loop back at 40 } lcd.setCursor(t, y + half); lcd.write(' '); // Make space between letters, in case overwriting } return strlen((*blocks)[0]); // Return char width } void writeBigString(const char *str, int x, int y) { // пишем большие буквы char c; while ((c = *str++)) x += writeBigChar(c, x, y) + 1; } //----------------------------------------------- void setup() { lcd.init(); lcd.backlight(); lcd.clear(); for (int i = 0; i < 8; i++) lcd.createChar(i + 1, custom[i]); writeBigString("GAS", 0, 0); writeBigString("1.2", 0, 2); lcd.setCursor(10, 2); lcd.print("SmokeClock"); lcd.setCursor(13, 3); lcd.print("voltNik"); } void loop() { }Моя библиотека для работы с 2004
/**/ template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; } //------дисплей lcd2004_i2c----------------------------- // даташит <"https://www.sparkfun.com/datasheets/LCD/ADM1602K-NSW-FBS-3.3v.pdf">https://www.sparkfun.com/datasheets/LCD/HD44780.pdf // на русском <"http://www.melt.aha.ru/pdf/mt-16s2h.pdf"> #include <Wire.h> // команды #define LCD_CLEARDISPLAY 0x01 #define LCD_RETURNHOME 0x02 #define LCD_ENTRYMODESET 0x04 #define LCD_DISPLAYCONTROL 0x08 #define LCD_CURSORSHIFT 0x10 #define LCD_FUNCTIONSET 0x20 #define LCD_SETCGRAMADDR 0x40 #define LCD_SETDDRAMADDR 0x80 // флаги для режима ввода дисплея #define LCD_ENTRYRIGHT 0x00 #define LCD_ENTRYLEFT 0x02 #define LCD_ENTRYSHIFTINCREMENT 0x01 #define LCD_ENTRYSHIFTDECREMENT 0x00 // флаги для управления включением / выключением дисплея #define LCD_DISPLAYON 0x04 #define LCD_DISPLAYOFF 0x00 #define LCD_CURSORON 0x02 #define LCD_CURSOROFF 0x00 #define LCD_BLINKON 0x01 #define LCD_BLINKOFF 0x00 // флаги для отображения / сдвига курсора #define LCD_DISPLAYMOVE 0x08 #define LCD_CURSORMOVE 0x00 #define LCD_MOVERIGHT 0x04 #define LCD_MOVELEFT 0x00 // флаги для набора функций #define LCD_8BITMODE 0x10 #define LCD_4BITMODE 0x00 #define LCD_2LINE 0x08 #define LCD_1LINE 0x00 #define LCD_5x10DOTS 0x04 #define LCD_5x8DOTS 0x00 // флаги для управления подсветкой #define LCD_BACKLIGHT 0x08 #define LCD_NOBACKLIGHT 0x00 #define En B00000100 // Бит разрешения #define Rw B00000010 // Чтение / запись бит #define Rs B00000001 // Бит выбора регистра class Cl_lcd1602_i2c : public Print { protected: uint8_t adr, posX, posY; uint8_t _backlightval; uint8_t _displayfunction; uint8_t _displaycontrol; uint8_t _displaymode; byte buffer[80]; public: Cl_lcd1602_i2c(uint8_t a): adr(a) {} void init() { Wire.begin(); write4bits(0x03 << 4); delayMicroseconds(4500); // wait min 4.1ms write4bits(0x03 << 4); delayMicroseconds(4500); // wait min 4.1ms write4bits(0x03 << 4); delayMicroseconds(150); write4bits(0x02 << 4); delay(50); _backlightval = LCD_NOBACKLIGHT; expanderWrite(_backlightval); // сбросить расширение и выключить подсветку (бит 8 = 1) // режим работы дисплея 4-х битный интерфейс ,две строки,5х8 точек _displayfunction = LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS; command(LCD_FUNCTIONSET | _displayfunction); // режим контроля дисплей вкл, курсор не мигает,дисплей не мигает _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF; command(LCD_DISPLAYCONTROL | _displaycontrol); // режим ввода текста в память-начинать слева с движением в право _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT; command(LCD_ENTRYMODESET | _displaymode); clear(); } // подсветку вкл/выкл void backlight(void) { _backlightval = LCD_BACKLIGHT; expanderWrite(0); } void noBacklight(void) { _backlightval = LCD_NOBACKLIGHT; expanderWrite(0); } // очистить буфер void clear() { for (byte i = 0; i < 80; i++ )buffer[i] = 0x20; posX = 0; posY = 0; } // отправить информацию из буфера на экран void show() { line(0); for (byte i = 0; i < 20; i++ )out(buffer[i]); line(1); for (byte i = 20; i < 40; i++ )out(buffer[i]); line(2); for (byte i = 40; i < 60; i++ )out(buffer[i]); line(3); for (byte i = 60; i < 80; i++ )out(buffer[i]); } void setCursor(byte x, byte y) { if (x > 20) x = 20; else posX = x; if (y > 4) x = 4; else posY = y; } private: /*внутрение функции*/ void line(byte l) { switch (l) { case 0: command(LCD_SETDDRAMADDR + 0x00); break; case 1: command(LCD_SETDDRAMADDR + 0x40); break; case 2: command(LCD_SETDDRAMADDR + 0x14); break; case 3: command(LCD_SETDDRAMADDR + 0x54); break; } } inline void out(uint8_t value) { send(value, Rs); } inline size_t write(uint8_t value) { if (posX < 20 && posY < 4) { buffer[posY * 20 + posX] = value; posX++; } return 1; } /*команды низкоуровневого управления*/ inline void command(uint8_t value) { send(value, 0); } void send(uint8_t value, uint8_t mode) { uint8_t highnib = value & 0xf0; write4bits((highnib) | mode); uint8_t lownib = (value << 4) & 0xf0; write4bits((lownib) | mode); } void write4bits(uint8_t value) { expanderWrite(value); pulseEnable(value); } void expanderWrite(uint8_t _data) { Wire.beginTransmission(adr); Wire.write((int)(_data) | _backlightval); Wire.endTransmission(); } void pulseEnable(uint8_t _data) { expanderWrite(_data | En); // En high delayMicroseconds(1); // enable pulse must be >450ns expanderWrite(_data & ~En); // En low delayMicroseconds(50); // commands need > 37us to settle } }; Cl_lcd1602_i2c lcd(0x3F);//0x27 //-------------------------------------------------- void setup() { lcd.init(); lcd.backlight(); lcd.clear(); lcd.setCursor(0, 0); lcd << F("12345678901234567890"); lcd.setCursor(0, 1); lcd << F("12345678901234567890"); lcd.setCursor(0, 2); lcd << F("12345678901234567890"); lcd.setCursor(0, 3); lcd << F("12345678901234567890"); lcd.show(); } void loop() { } /**//**/ template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; } //------дисплей lcd2004_i2c----------------------------- #include <Wire.h> // команды #define LCD_CLEARDISPLAY 0x01 #define LCD_RETURNHOME 0x02 #define LCD_ENTRYMODESET 0x04 #define LCD_DISPLAYCONTROL 0x08 #define LCD_CURSORSHIFT 0x10 #define LCD_FUNCTIONSET 0x20 #define LCD_SETCGRAMADDR 0x40 #define LCD_SETDDRAMADDR 0x80 // флаги для режима ввода дисплея #define LCD_ENTRYRIGHT 0x00 #define LCD_ENTRYLEFT 0x02 #define LCD_ENTRYSHIFTINCREMENT 0x01 #define LCD_ENTRYSHIFTDECREMENT 0x00 // флаги для управления включением / выключением дисплея #define LCD_DISPLAYON 0x04 #define LCD_DISPLAYOFF 0x00 #define LCD_CURSORON 0x02 #define LCD_CURSOROFF 0x00 #define LCD_BLINKON 0x01 #define LCD_BLINKOFF 0x00 // флаги для отображения / сдвига курсора #define LCD_DISPLAYMOVE 0x08 #define LCD_CURSORMOVE 0x00 #define LCD_MOVERIGHT 0x04 #define LCD_MOVELEFT 0x00 // флаги для набора функций #define LCD_8BITMODE 0x10 #define LCD_4BITMODE 0x00 #define LCD_2LINE 0x08 #define LCD_1LINE 0x00 #define LCD_5x10DOTS 0x04 #define LCD_5x8DOTS 0x00 // флаги для управления подсветкой #define LCD_BACKLIGHT 0x08 #define LCD_NOBACKLIGHT 0x00 #define En B00000100 // Бит разрешения #define Rw B00000010 // Чтение / запись бит #define Rs B00000001 // Бит выбора регистра class Cl_lcd2004_i2c : public Print { protected: uint8_t adr, posX, posY; uint8_t _backlightval; uint8_t _displayfunction; uint8_t _displaycontrol; uint8_t _displaymode; byte buffer[80]; public: Cl_lcd2004_i2c(uint8_t a): adr(a) {} void init() { Wire.begin(); write4bits(0x03 << 4); delayMicroseconds(4500); // wait min 4.1ms write4bits(0x03 << 4); delayMicroseconds(4500); // wait min 4.1ms write4bits(0x03 << 4); delayMicroseconds(150); write4bits(0x02 << 4); delay(50); _backlightval = LCD_NOBACKLIGHT; expanderWrite(_backlightval); // сбросить расширение и выключить подсветку (бит 8 = 1) // режим работы дисплея 4-х битный интерфейс ,две строки,5х8 точек _displayfunction = LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS; command(LCD_FUNCTIONSET | _displayfunction); // режим контроля дисплей вкл, курсор не мигает,дисплей не мигает _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF; command(LCD_DISPLAYCONTROL | _displaycontrol); // режим ввода текста в память-начинать слева с движением в право _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT; command(LCD_ENTRYMODESET | _displaymode); clear(); } // подсветку вкл/выкл void backlight(void) { _backlightval = LCD_BACKLIGHT; expanderWrite(0); } void noBacklight(void) { _backlightval = LCD_NOBACKLIGHT; expanderWrite(0); } // очистить буфер void clear() { for (byte i = 0; i < 80; i++ )buffer[i] = 0x20; posX = 0; posY = 0; } // отправить информацию из буфера на экран void show() { line(0); for (byte i = 0; i < 20; i++ )out(buffer[i]); line(1); for (byte i = 20; i < 40; i++ )out(buffer[i]); line(2); for (byte i = 40; i < 60; i++ )out(buffer[i]); line(3); for (byte i = 60; i < 80; i++ )out(buffer[i]); } void setCursor(byte x, byte y) { if (x > 20) x = 20; else posX = x; if (y > 4) x = 4; else posY = y; } void createCharPROGMEM(uint8_t location, const uint8_t *charmap) { location &= 0x7; // we only have 8 locations 0-7 command(LCD_SETCGRAMADDR | (location << 3)); for (int i = 0; i < 8; i++) { out(pgm_read_byte_near(charmap + i)); } } void createChar(uint8_t location, uint8_t charmap[]) { location &= 0x7; // we only have 8 locations 0-7 command(LCD_SETCGRAMADDR | (location << 3)); for (int i = 0; i < 8; i++) { out(charmap[i]); } } private: /*внутрение функции*/ void line(byte l) { switch (l) { case 0: command(LCD_SETDDRAMADDR + 0x00); break; case 1: command(LCD_SETDDRAMADDR + 0x40); break; case 2: command(LCD_SETDDRAMADDR + 0x14); break; case 3: command(LCD_SETDDRAMADDR + 0x54); break; } } inline size_t write(uint8_t value) { if (posX < 20 && posY < 4) { buffer[posY * 20 + posX] = value; posX++; } return 1; } inline void out(uint8_t value) { send(value, Rs); } /*команды низкоуровневого управления*/ inline void command(uint8_t value) { send(value, 0); } void send(uint8_t value, uint8_t mode) { uint8_t highnib = value & 0xf0; write4bits((highnib) | mode); uint8_t lownib = (value << 4) & 0xf0; write4bits((lownib) | mode); } void write4bits(uint8_t value) { expanderWrite(value); pulseEnable(value); } void expanderWrite(uint8_t _data) { Wire.beginTransmission(adr); Wire.write((int)(_data) | _backlightval); Wire.endTransmission(); } void pulseEnable(uint8_t _data) { expanderWrite(_data | En); // En high delayMicroseconds(1); // enable pulse must be >450ns expanderWrite(_data & ~En); // En low delayMicroseconds(50); // commands need > 37us to settle } }; Cl_lcd2004_i2c lcd(0x3F);//0x27 //-------------------------------------------------- const byte custom[5][8] PROGMEM = { {0b00000, 0b01010, 0b11111, 0b11111, 0b11111, 0b01110, 0b00100, 0b00000},// \1 сердце {0b00000, 0b00000, 0b01010, 0b00000, 0b00000, 0b10001, 0b01110, 0b00000},// \2 улыбка {0b00000, 0b00000, 0b01010, 0b00000, 0b00000, 0b00000, 0b01110, 0b10001},// \3 грусть {0b00100, 0b01010, 0b00100, 0b00100, 0b01110, 0b10101, 0b00100, 0b0101}, // \4 руки вниз {0b00100, 0b01010, 0b00100, 0b10101, 0b01110, 0b00100, 0b00100, 0b01010} // \5 руки вверх }; void setup() { lcd.init(); lcd.backlight(); lcd.clear(); for (int i = 1; i < 6; i++) lcd.createCharPROGMEM(i, custom[i-1]); lcd.print("I \1 Arduino! \2\3\4\5"); lcd.show(); } void loop() { }/**/ template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; } //------дисплей lcd2004_i2c----------------------------- #include <Wire.h> // команды #define LCD_CLEARDISPLAY 0x01 #define LCD_RETURNHOME 0x02 #define LCD_ENTRYMODESET 0x04 #define LCD_DISPLAYCONTROL 0x08 #define LCD_CURSORSHIFT 0x10 #define LCD_FUNCTIONSET 0x20 #define LCD_SETCGRAMADDR 0x40 #define LCD_SETDDRAMADDR 0x80 // флаги для режима ввода дисплея #define LCD_ENTRYRIGHT 0x00 #define LCD_ENTRYLEFT 0x02 #define LCD_ENTRYSHIFTINCREMENT 0x01 #define LCD_ENTRYSHIFTDECREMENT 0x00 // флаги для управления включением / выключением дисплея #define LCD_DISPLAYON 0x04 #define LCD_DISPLAYOFF 0x00 #define LCD_CURSORON 0x02 #define LCD_CURSOROFF 0x00 #define LCD_BLINKON 0x01 #define LCD_BLINKOFF 0x00 // флаги для отображения / сдвига курсора #define LCD_DISPLAYMOVE 0x08 #define LCD_CURSORMOVE 0x00 #define LCD_MOVERIGHT 0x04 #define LCD_MOVELEFT 0x00 // флаги для набора функций #define LCD_8BITMODE 0x10 #define LCD_4BITMODE 0x00 #define LCD_2LINE 0x08 #define LCD_1LINE 0x00 #define LCD_5x10DOTS 0x04 #define LCD_5x8DOTS 0x00 // флаги для управления подсветкой #define LCD_BACKLIGHT 0x08 #define LCD_NOBACKLIGHT 0x00 #define En B00000100 // Бит разрешения #define Rw B00000010 // Чтение / запись бит #define Rs B00000001 // Бит выбора регистра class Cl_lcd1602_i2c : public Print { protected: uint8_t adr, posX, posY; uint8_t _backlightval; uint8_t _displayfunction; uint8_t _displaycontrol; uint8_t _displaymode; byte buffer[80]; public: Cl_lcd1602_i2c(uint8_t a): adr(a) {} void init() { Wire.begin(); write4bits(0x03 << 4); delayMicroseconds(4500); // wait min 4.1ms write4bits(0x03 << 4); delayMicroseconds(4500); // wait min 4.1ms write4bits(0x03 << 4); delayMicroseconds(150); write4bits(0x02 << 4); delay(50); _backlightval = LCD_NOBACKLIGHT; expanderWrite(_backlightval); // сбросить расширение и выключить подсветку (бит 8 = 1) // режим работы дисплея 4-х битный интерфейс ,две строки,5х8 точек _displayfunction = LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS; command(LCD_FUNCTIONSET | _displayfunction); // режим контроля дисплей вкл, курсор не мигает,дисплей не мигает _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF; command(LCD_DISPLAYCONTROL | _displaycontrol); // режим ввода текста в память-начинать слева с движением в право _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT; command(LCD_ENTRYMODESET | _displaymode); clear(); } // подсветку вкл/выкл void backlight(void) { _backlightval = LCD_BACKLIGHT; expanderWrite(0); } void noBacklight(void) { _backlightval = LCD_NOBACKLIGHT; expanderWrite(0); } // очистить буфер void clear() { for (byte i = 0; i < 80; i++ )buffer[i] = 0x20; posX = 0; posY = 0; } // отправить информацию из буфера на экран void show() { line(0); for (byte i = 0; i < 20; i++ )out(buffer[i]); line(1); for (byte i = 20; i < 40; i++ )out(buffer[i]); line(2); for (byte i = 40; i < 60; i++ )out(buffer[i]); line(3); for (byte i = 60; i < 80; i++ )out(buffer[i]); } void setCursor(byte x, byte y) { if (x > 20) x = 20; else posX = x; if (y > 4) x = 4; else posY = y; } void createChar(uint8_t location, uint8_t charmap[]) { location &= 0x7; // we only have 8 locations 0-7 command(LCD_SETCGRAMADDR | (location << 3)); for (int i = 0; i < 8; i++) { out(charmap[i]); } } inline size_t write(uint8_t value) { if (posX < 20 && posY < 4) { buffer[posY * 20 + posX] = value; posX++; } return 1; } private: /*внутрение функции*/ void line(byte l) { switch (l) { case 0: command(LCD_SETDDRAMADDR + 0x00); break; case 1: command(LCD_SETDDRAMADDR + 0x40); break; case 2: command(LCD_SETDDRAMADDR + 0x14); break; case 3: command(LCD_SETDDRAMADDR + 0x54); break; } } inline void out(uint8_t value) { send(value, Rs); } /*команды низкоуровневого управления*/ inline void command(uint8_t value) { send(value, 0); } void send(uint8_t value, uint8_t mode) { uint8_t highnib = value & 0xf0; write4bits((highnib) | mode); uint8_t lownib = (value << 4) & 0xf0; write4bits((lownib) | mode); } void write4bits(uint8_t value) { expanderWrite(value); pulseEnable(value); } void expanderWrite(uint8_t _data) { Wire.beginTransmission(adr); Wire.write((int)(_data) | _backlightval); Wire.endTransmission(); } void pulseEnable(uint8_t _data) { expanderWrite(_data | En); // En high delayMicroseconds(1); // enable pulse must be >450ns expanderWrite(_data & ~En); // En low delayMicroseconds(50); // commands need > 37us to settle } }; Cl_lcd1602_i2c lcd(0x3F);//0x27 byte custom[8][8] = { // символы большого шрифта { B11111, B11111, B11111, B00000, B00000, B00000, B00000, B00000 }, { B11100, B11110, B11111, B11111, B11111, B11111, B11111, B11111 }, { B11111, B11111, B11111, B11111, B11111, B11111, B01111, B00111 }, { B00000, B00000, B00000, B00000, B00000, B11111, B11111, B11111 }, { B11111, B11111, B11111, B11111, B11111, B11111, B11110, B11100 }, { B11111, B11111, B11111, B00000, B00000, B00000, B11111, B11111 }, { B11111, B00000, B00000, B00000, B00000, B11111, B11111, B11111 }, { B00111, B01111, B11111, B11111, B11111, B11111, B11111, B11111 } }; const char *bigChars[][2] = { // символы из новых букв {"\024\024\024", "\024\024\024"}, // Space {"\377", "\007"}, // ! {"\005\005", "\024\024"}, // " {"\004\377\004\377\004", "\001\377\001\377\001"}, // # {"\010\377\006", "\007\377\005"}, // $ {"\001\024\004\001", "\004\001\024\004"}, // % {"\010\006\002\024", "\003\007\002\004"}, // & {"\005", "\024"}, // ' {"\010\001", "\003\004"}, // ( {"\001\002", "\004\005"}, // ) {"\001\004\004\001", "\004\001\001\004"}, // * {"\004\377\004", "\001\377\001"}, // + {"\024", "\005"}, // , {"\004\004\004", "\024\024\024"}, // - {"\024", "\004"}, // . {"\024\024\004\001", "\004\001\024\024"}, // / {"\010\001\002", "\003\004\005"}, // 0 {"\001\002\024", "\024\377\024"}, // 1 {"\006\006\002", "\003\007\007"}, // 2 {"\006\006\002", "\007\007\005"}, // 3 {"\003\004\002", "\024\024\377"}, // 4 {"\377\006\006", "\007\007\005"}, // 5 {"\010\006\006", "\003\007\005"}, // 6 {"\001\001\002", "\024\010\024"}, // 7 {"\010\006\002", "\003\007\005"}, // 8 {"\010\006\002", "\024\024\377"}, // 9 {"\004", "\001"}, // : {"\004", "\005"}, // ; {"\024\004\001", "\001\001\004"}, // < {"\004\004\004", "\001\001\001"}, // = {"\001\004\024", "\004\001\001"}, // > {"\001\006\002", "\024\007\024"}, // ? {"\010\006\002", "\003\004\004"}, // @ {"\010\006\002", "\377\024\377"}, // A {"\377\006\005", "\377\007\002"}, // B {"\010\001\001", "\003\004\004"}, // C {"\377\001\002", "\377\004\005"}, // D {"\377\006\006", "\377\007\007"}, // E {"\377\006\006", "\377\024\024"}, // F {"\010\001\001", "\003\004\002"}, // G {"\377\004\377", "\377\024\377"}, // H {"\001\377\001", "\004\377\004"}, // I {"\024\024\377", "\004\004\005"}, // J {"\377\004\005", "\377\024\002"}, // K {"\377\024\024", "\377\004\004"}, // L {"\010\003\005\002", "\377\024\024\377"}, // M {"\010\002\024\377", "\377\024\003\005"}, // N {"\010\001\002", "\003\004\005"}, // 0/0 {"\377\006\002", "\377\024\024"}, // P {"\010\001\002\024", "\003\004\377\004"}, // Q {"\377\006\002", "\377\024\002"}, // R {"\010\006\006", "\007\007\005"}, // S {"\001\377\001", "\024\377\024"}, // T {"\377\024\377", "\003\004\005"}, // U {"\003\024\024\005", "\024\002\010\024"}, // V {"\377\024\024\377", "\003\010\002\005"}, // W {"\003\004\005", "\010\024\002"}, // X {"\003\004\005", "\024\377\024"}, // Y {"\001\006\005", "\010\007\004"}, // Z {"\377\001", "\377\004"}, // [ {"\001\004\024\024", "\024\024\001\004"}, // Backslash {"\001\377", "\004\377"}, // ] {"\010\002", "\024\024"}, // ^ {"\024\024\024", "\004\004\004"}, // _ }; int writeBigChar(char ch, int x, int y) { const char *(*blocks)[2] = NULL; // Pointer to an array of two strings (character pointers) if (ch < ' ' || ch > '_') // If outside our table range, do nothing return 0; blocks = &bigChars[ch - ' ']; // Look up the definition for (int half = 0; half <= 1; half++) { int t = x; // Write out top or bottom string, byte at a time for (const char *cp = (*blocks)[half]; *cp; cp++) { lcd.setCursor(t, y + half); lcd.write(*cp); t = (t + 1) % 40; // Circular scroll buffer of 40 characters, loop back at 40 } lcd.setCursor(t, y + half); lcd.write(' '); // Make space between letters, in case overwriting } return strlen((*blocks)[0]); // Return char width } void writeBigString(const char *str, int x, int y) { // пишем большие буквы char c; while ((c = *str++)) x += writeBigChar(c, x, y) + 1; } //----------------------------------------------- void setup() { lcd.init(); lcd.backlight(); lcd.clear(); for (int i = 0; i < 8; i++) lcd.createChar(i + 1, custom[i]); writeBigString("GAS", 0, 0); writeBigString("1.2", 0, 2); lcd.setCursor(10, 2); lcd.print("SmokeClock"); lcd.setCursor(13, 3); lcd.print("voltNik"); lcd.show(); } void loop() { }/**/ template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; } //------дисплей lcd2004_i2c----------------------------- #include <Wire.h> // команды #define LCD_CLEARDISPLAY 0x01 #define LCD_RETURNHOME 0x02 #define LCD_ENTRYMODESET 0x04 #define LCD_DISPLAYCONTROL 0x08 #define LCD_CURSORSHIFT 0x10 #define LCD_FUNCTIONSET 0x20 #define LCD_SETCGRAMADDR 0x40 #define LCD_SETDDRAMADDR 0x80 // флаги для режима ввода дисплея #define LCD_ENTRYRIGHT 0x00 #define LCD_ENTRYLEFT 0x02 #define LCD_ENTRYSHIFTINCREMENT 0x01 #define LCD_ENTRYSHIFTDECREMENT 0x00 // флаги для управления включением / выключением дисплея #define LCD_DISPLAYON 0x04 #define LCD_DISPLAYOFF 0x00 #define LCD_CURSORON 0x02 #define LCD_CURSOROFF 0x00 #define LCD_BLINKON 0x01 #define LCD_BLINKOFF 0x00 // флаги для отображения / сдвига курсора #define LCD_DISPLAYMOVE 0x08 #define LCD_CURSORMOVE 0x00 #define LCD_MOVERIGHT 0x04 #define LCD_MOVELEFT 0x00 // флаги для набора функций #define LCD_8BITMODE 0x10 #define LCD_4BITMODE 0x00 #define LCD_2LINE 0x08 #define LCD_1LINE 0x00 #define LCD_5x10DOTS 0x04 #define LCD_5x8DOTS 0x00 // флаги для управления подсветкой #define LCD_BACKLIGHT 0x08 #define LCD_NOBACKLIGHT 0x00 #define En B00000100 // Бит разрешения #define Rw B00000010 // Чтение / запись бит #define Rs B00000001 // Бит выбора регистра const byte custom[8][8] PROGMEM = { {0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000},// \0 {0b11111, 0b11111, 0b11111, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000},// \1 {0b00000, 0b00000, 0b00000, 0b11111, 0b11111, 0b11111, 0b00000, 0b00000},// \2 {0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b00000, 0b00000},// \3 {0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b11111, 0b11111},// \4 {0b11111, 0b11111, 0b11111, 0b00000, 0b00000, 0b00000, 0b11111, 0b11111},// \5 {0b00000, 0b00000, 0b00000, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111},// \6 {0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111} // \7 }; const byte fontChar[][6] PROGMEM = { {'\0', '\0', '\0', '\0', '\0', '\0'},// Space {'\0', '\7', '\0', '\0', '\6', '\0'},// ! {'"', ' ', ' ', ' ', ' ', ' '},// " {'#', ' ', ' ', ' ', ' ', ' '},// # {'$', ' ', ' ', ' ', ' ', ' '},// $ {'/', ' ', ' ', ' ', ' ', ' '},// % {'&', ' ', ' ', ' ', ' ', ' '},// & {',', ' ', ' ', ' ', ' ', ' '},// , {'\0', '\6', '\1', '\0', '\3', '\4'},// ( {'\1', '\6', '\0', '\4', '\3', '\0'},// ) {'\5', '\6', '\5', '\2', '\1', '\2'},// * {'\4', '\7', '\4', '\0', '\3', '\0'},// + {'\0', '\0', '\0', '\0', '\7', '\0'},// , {'\4', '\4', '\4', '\0', '\0', '\0'},// - {'\0', '\0', '\0', '\0', '\6', '\0'},// . {'\0', '\4', '\3', '\6', '\1', '\0'},// / {'\7', '\1', '\7', '\7', '\4', '\7'},// 0 {'\0', '\7', '\0', '\0', '\7', '\0'},// 1 {'\5', '\5', '\7', '\7', '\5', '\5'},// 2 {'\5', '\5', '\7', '\5', '\5', '\7'},// 3 {'\7', '\4', '\7', '\1', '\1', '\7'},// 4 {'\7', '\5', '\5', '\5', '\5', '\7'},// 5 {'\7', '\5', '\5', '\7', '\5', '\7'},// 6 {'\1', '\5', '\3', '\0', '\7', '\0'},// 7 {'\7', '\5', '\7', '\7', '\5', '\7'},// 8 {'\7', '\5', '\7', '\5', '\5', '\7'},// 9 {'\0', '\3', '\0', '\0', '\6', '\0'},// : {'\0', '\3', '\0', '\0', '\7', '\0'},// ; {'>', ' ', ' ', ' ', ' ', ' '},// < {'\2', '\2', '\2', '\2', '\2', '\2'},// = {'>', ' ', ' ', ' ', ' ', ' '},// > {'\1', '\5', '\3', '\0', '\6', '\0'},// ? {'\7', '\1', '\3', '\7', '\4', '\6'},// @ {'\6', '\1', '\6', '\7', '\1', '\7'},// A {'\7', '\5', '\3', '\7', '\4', '\3'},// B {'\7', '\1', '\3', '\7', '\4', '\6'},// C {'\7', '\1', '\6', '\7', '\4', '\3'},// D {'\7', '\5', '\1', '\7', '\5', '\4'},// E {'\7', '\5', '\1', '\7', '\0', '\0'},// F {'\7', '\1', '\1', '\7', '\4', '\7'},// G {'\7', '\4', '\7', '\7', '\0', '\7'},// H {'\0', '\7', '\0', '\0', '\7', '\0'},// I {'\0', '\7', '\0', '\4', '\7', '\0'},// J {'\7', '\4', '\3', '\7', '\1', '\6'},// K {'\7', '\0', '\0', '\7', '\3', '\3'},// L {'\7', '\4', '\7', '\7', '\0', '\7'},// M {'\7', '\4', '\7', '\7', '\0', '\7'},// N {'\7', '\1', '\7', '\7', '\4', '\7'},// O {'\7', '\1', '\6', '\7', '\1', '\0'},// P {'\7', '\1', '\7', '\7', '\4', '\3'},// Q {'R', ' ', ' ', ' ', ' ', ' '},// R {'S', ' ', ' ', ' ', ' ', ' '},// S {'T', ' ', ' ', ' ', ' ', ' '},// T {'U', ' ', ' ', ' ', ' ', ' '},// U {'V', ' ', ' ', ' ', ' ', ' '},// V {'W', ' ', ' ', ' ', ' ', ' '},// W {'X', ' ', ' ', ' ', ' ', ' '},// X {'Y', ' ', ' ', ' ', ' ', ' '},// Y {'Z', ' ', ' ', ' ', ' ', ' '},// Z {'\0', '\7', '\1', '\0', '\7', '\4'},// [ {'\3', '\4', '\0', '\0', '\1', '\6'},// Backslash {'\1', '\7', '\0', '\4', '\7', '\0'},// ] {'^', ' ', ' ', ' ', ' ', ' '},// ^ {'\4', '\4', '\4', '\4', '\4', '\4'}// _ }; class Cl_lcd2004_i2c : public Print { protected: uint8_t adr, posX, posY; uint8_t _backlightval; uint8_t _displayfunction; uint8_t _displaycontrol; uint8_t _displaymode; byte buffer[80]; static const byte smallChar = 0; static const byte bigChar = 1; byte sizeChar; public: Cl_lcd2004_i2c(uint8_t a): adr(a) {} void small() { sizeChar = smallChar; } void big() { sizeChar = bigChar; } void init() { Wire.begin(); write4bits(0x03 << 4); delayMicroseconds(4500); // wait min 4.1ms write4bits(0x03 << 4); delayMicroseconds(4500); // wait min 4.1ms write4bits(0x03 << 4); delayMicroseconds(150); write4bits(0x02 << 4); delay(50); _backlightval = LCD_NOBACKLIGHT; expanderWrite(_backlightval); // сбросить расширение и выключить подсветку (бит 8 = 1) // режим работы дисплея 4-х битный интерфейс ,две строки,5х8 точек _displayfunction = LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS; command(LCD_FUNCTIONSET | _displayfunction); // режим контроля дисплей вкл, курсор не мигает,дисплей не мигает _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF; command(LCD_DISPLAYCONTROL | _displaycontrol); // режим ввода текста в память-начинать слева с движением в право _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT; command(LCD_ENTRYMODESET | _displaymode); for (int i = 0; i < 8; i++) createCharPROGMEM(i, custom[i]); small(); clear(); } // подсветку вкл/выкл void backlight(void) { _backlightval = LCD_BACKLIGHT; expanderWrite(0); } void noBacklight(void) { _backlightval = LCD_NOBACKLIGHT; expanderWrite(0); } // очистить буфер void clear() { for (byte i = 0; i < 80; i++ )buffer[i] = 0x20; posX = 0; posY = 0; } // отправить информацию из буфера на экран void show() { line(0); for (byte i = 0; i < 20; i++ )out(buffer[i]); line(1); for (byte i = 20; i < 40; i++ )out(buffer[i]); line(2); for (byte i = 40; i < 60; i++ )out(buffer[i]); line(3); for (byte i = 60; i < 80; i++ )out(buffer[i]); } void setCursor(byte x, byte y) { if (x > 20) x = 20; else posX = x; if (y > 4) x = 4; else posY = y; } void createCharPROGMEM(uint8_t location, const uint8_t *charmap) { location &= 0x7; // we only have 8 locations 0-7 command(LCD_SETCGRAMADDR | (location << 3)); for (int i = 0; i < 8; i++) { out(pgm_read_byte_near(charmap + i)); } } void createChar(uint8_t location, uint8_t charmap[]) { location &= 0x7; // we only have 8 locations 0-7 command(LCD_SETCGRAMADDR | (location << 3)); for (int i = 0; i < 8; i++) { out(charmap[i]); } } private: /*внутрение функции*/ void line(byte l) { switch (l) { case 0: command(LCD_SETDDRAMADDR + 0x00); break; case 1: command(LCD_SETDDRAMADDR + 0x40); break; case 2: command(LCD_SETDDRAMADDR + 0x14); break; case 3: command(LCD_SETDDRAMADDR + 0x54); break; } } void writeToBuf(uint8_t value, uint8_t x, uint8_t y) { if (x < 20 && y < 4) buffer[y * 20 + x] = value; } inline size_t write(uint8_t value) { if (sizeChar == smallChar) { writeToBuf(value, posX, posY); posX++; } else { value -= ' '; writeToBuf(pgm_read_byte_near(&fontChar[value][0]), posX, posY); writeToBuf(pgm_read_byte_near(&fontChar[value][1]), posX + 1, posY); writeToBuf(pgm_read_byte_near(&fontChar[value][2]), posX + 2, posY); writeToBuf(' ' , posX + 3, posY); writeToBuf(pgm_read_byte_near(&fontChar[value][3]), posX , posY + 1); writeToBuf(pgm_read_byte_near(&fontChar[value][4]), posX + 1, posY + 1); writeToBuf(pgm_read_byte_near(&fontChar[value][5]), posX + 2, posY + 1); writeToBuf(' ' , posX + 3, posY + 1); posX += 4; } return 1; } inline void out(uint8_t value) { send(value, Rs); } /*команды низкоуровневого управления*/ inline void command(uint8_t value) { send(value, 0); } void send(uint8_t value, uint8_t mode) { uint8_t highnib = value & 0xf0; write4bits((highnib) | mode); uint8_t lownib = (value << 4) & 0xf0; write4bits((lownib) | mode); } void write4bits(uint8_t value) { expanderWrite(value); pulseEnable(value); } void expanderWrite(uint8_t _data) { Wire.beginTransmission(adr); Wire.write((int)(_data) | _backlightval); Wire.endTransmission(); } void pulseEnable(uint8_t _data) { expanderWrite(_data | En); // En high delayMicroseconds(1); // enable pulse must be >450ns expanderWrite(_data & ~En); // En low delayMicroseconds(50); // commands need > 37us to settle } }; Cl_lcd2004_i2c lcd(0x3F);//0x27 //-------------------------------------------------- unsigned long past; void view() { past = millis(); { lcd.clear(); lcd.big(); lcd << past / 1000; lcd.setCursor(0, 3); lcd.small(); lcd << past / 1000; lcd.show(); } } void setup() { lcd.init(); lcd.backlight(); view(); } void loop() { if (millis() - past >= 1000) view(); }Сброшу мои наметки для работы EEROMом
#include <EEPROM.h> typedef struct { uint16_t adr_txt1; uint16_t adr_txt2; uint16_t adr_txt3; uint16_t adr_txt4; } stData; stData Data EEMEM; uint8_t txt1[15] EEMEM = "uno"; uint8_t txt2[15] EEMEM = "due"; uint8_t txt3[15] EEMEM = "tre"; uint8_t txt4[15] EEMEM = "quattro"; void save() { // первая строка String aaa1(F("uno-1")); uint16_t i; for (i = 0; i < aaa1.length(); i++) { Serial.print(aaa1.charAt(i)); EEPROM.put((int)&txt1[i], aaa1.charAt(i)); // сохранить строку в EEROM } EEPROM.put((int)&txt1[i], 0);// занести конец строки EEPROM.put((int)&Data.adr_txt1, (int)txt1);// сохранить адрес строки EEROM в структуре // вторая строка String aaa2(F("due-2")); Serial.print('\n'); for (i = 0; i < aaa2.length(); i++) { Serial.print(aaa2.charAt(i)); EEPROM.put((int)&txt2[i], aaa2.charAt(i)); } EEPROM.put((int)&txt2[i], 0); EEPROM.put((int)&Data.adr_txt2, (int)txt2);// сохранить адрес строки EEROM в структуре // третья строка String aaa3(F("tre-3")); Serial.print('\n'); for (i = 0; i < aaa3.length(); i++) { Serial.print(aaa3.charAt(i)); EEPROM.put((int)&txt3[i], aaa3.charAt(i)); } EEPROM.put((int)&txt3[i], 0); EEPROM.put((int)&Data.adr_txt3, (int)txt3);// сохранить адрес строки EEROM в структуре // четвертая строка String aaa4(F("quattro-3")); Serial.print('\n'); for (i = 0; i < aaa4.length(); i++) { Serial.print(aaa4.charAt(i)); EEPROM.put((int)&txt4[i], aaa4.charAt(i)); } EEPROM.put((int)&txt4[i], 0); EEPROM.put((int)&Data.adr_txt4, (int)txt4);// сохранить адрес строки EEROM в структуре Serial.print('\n'); } void viev() { uint16_t adr; uint8_t c; EEPROM.get((int)&Data.adr_txt1, adr);// получить адресс 1 строки // adr = (uint16_t)&txt1[0]; while (1) { EEPROM.get(adr, c); if (c == 0) break; else { adr++; Serial.print((char)c); } } Serial.print('\n'); EEPROM.get((int)&Data.adr_txt2, adr);// получить адресс 2 строки // adr = (uint16_t)&txt2[0]; while (1) { EEPROM.get(adr, c); if (c == 0) break; else { adr++; Serial.print((char)c); } } Serial.print('\n'); EEPROM.get((int)&Data.adr_txt3, adr);// получить адресс 3 строки // adr = (uint16_t)&txt3[0]; while (1) { EEPROM.get(adr, c); if (c == 0) break; else { adr++; Serial.print((char)c); } } Serial.print('\n'); EEPROM.get((int)&Data.adr_txt4, adr);// получить адресс 4 строки // adr = (uint16_t)&txt4[0]; while (1) { EEPROM.get(adr, c); if (c == 0) break; else { adr++; Serial.print((char)c); } } Serial.print('\n'); } void setup() { Serial.begin(9600); save(); viev(); } void loop() { }/**/ template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; } //------дисплей lcd2004_i2c----------------------------- #include <Wire.h> // команды #define LCD_CLEARDISPLAY 0x01 #define LCD_RETURNHOME 0x02 #define LCD_ENTRYMODESET 0x04 #define LCD_DISPLAYCONTROL 0x08 #define LCD_CURSORSHIFT 0x10 #define LCD_FUNCTIONSET 0x20 #define LCD_SETCGRAMADDR 0x40 #define LCD_SETDDRAMADDR 0x80 // флаги для режима ввода дисплея #define LCD_ENTRYRIGHT 0x00 #define LCD_ENTRYLEFT 0x02 #define LCD_ENTRYSHIFTINCREMENT 0x01 #define LCD_ENTRYSHIFTDECREMENT 0x00 // флаги для управления включением / выключением дисплея #define LCD_DISPLAYON 0x04 #define LCD_DISPLAYOFF 0x00 #define LCD_CURSORON 0x02 #define LCD_CURSOROFF 0x00 #define LCD_BLINKON 0x01 #define LCD_BLINKOFF 0x00 // флаги для отображения / сдвига курсора #define LCD_DISPLAYMOVE 0x08 #define LCD_CURSORMOVE 0x00 #define LCD_MOVERIGHT 0x04 #define LCD_MOVELEFT 0x00 // флаги для набора функций #define LCD_8BITMODE 0x10 #define LCD_4BITMODE 0x00 #define LCD_2LINE 0x08 #define LCD_1LINE 0x00 #define LCD_5x10DOTS 0x04 #define LCD_5x8DOTS 0x00 // флаги для управления подсветкой #define LCD_BACKLIGHT 0x08 #define LCD_NOBACKLIGHT 0x00 #define En B00000100 // Бит разрешения #define Rw B00000010 // Чтение / запись бит #define Rs B00000001 // Бит выбора регистра const byte custom[8][8] PROGMEM = { {0, 0, 0, 0, 0, 0, 0, 0},// \0 {31, 31, 31, 0, 0, 0, 0, 0},// \1 {0, 0, 0, 31, 31, 31, 0, 0},// \2 {31, 31, 31, 31, 31, 31, 0, 0},// \3 {0, 0, 0, 0, 0, 0, 31, 31},// \4 {31, 31, 31, 0, 0, 0, 31, 31},// \5 {0, 0, 0, 31, 31, 31, 31, 31},// \6 {31, 31, 31, 31, 31, 31, 31, 31} // \7 }; const byte fontChar[][6] PROGMEM = { {'\0', '\0', '\0', '\0', '\0', '\0'},// Space {'\0', '\7', '\0', '\0', '\6', '\0'},// ! {'\3', '\0', '\3', '\0', '\0', '\0'},// " {'\7', '\2', '\7', '\3', '\1', '\3'}, // # {'\6', '\5', '\5', '\2', '\6', '\1'},// $ {'o' , '\4', '\3', '\6', '\1', 'o' },// % {'\3', '\7', '\4', '\3', '\4', '\4'},// & {',', '\0', '\0', '\0', '\0', '\0' },// , {'\0', '\6', '\1', '\0', '\3', '\4'},// ( {'\1', '\6', '\0', '\4', '\3', '\0'},// ) {'\5', '\6', '\5', '\2', '\1', '\2'},// * {'\4', '\7', '\4', '\0', '\3', '\0'},// + {'\0', '\0', '\0', '\0', '\7', '\0'},// , {'\4', '\4', '\4', '\0', '\0', '\0'},// - {'\0', '\0', '\0', '\0', '\6', '\0'},// . {'\0', '\4', '\3', '\6', '\1', '\0'},// / {'\7', '\1', '\7', '\7', '\4', '\7'},// 0 {'\2', '\7', '\0', '\0', '\7', '\0'},// 1 {'\5', '\5', '\7', '\7', '\5', '\5'},// 2 {'\5', '\5', '\7', '\5', '\5', '\7'},// 3 {'\7', '\4', '\7', '\1', '\1', '\7'},// 4 {'\7', '\5', '\5', '\5', '\5', '\7'},// 5 {'\7', '\5', '\5', '\7', '\5', '\7'},// 6 {'\1', '\5', '\3', '\0', '\7', '\0'},// 7 {'\7', '\5', '\7', '\7', '\5', '\7'},// 8 {'\7', '\5', '\7', '\5', '\5', '\7'},// 9 {'\0', '\3', '\0', '\0', '\6', '\0'},// : {'\0', '\3', '\0', '\0', '\7', '\0'},// ; {'\4', '\2', '\1', '\0', '\1', '\2'},// < {'\2', '\2', '\2', '\2', '\2', '\2'},// = {'\1', '\2', '\4', '\2', '\1', '\0'},// > {'\1', '\5', '\3', '\0', '\6', '\0'},// ? {'\7', '\1', '\3', '\7', '\4', '\6'},// @ {'\6', '\1', '\6', '\7', '\1', '\7'},// A {'\7', '\5', '\3', '\7', '\4', '\3'},// B {'\7', '\1', '\3', '\7', '\4', '\6'},// C {'\7', '\1', '\6', '\7', '\4', '\3'},// D {'\7', '\5', '\1', '\7', '\5', '\4'},// E {'\7', '\5', '\1', '\7', '\0', '\0'},// F {'\7', '\1', '\1', '\7', '\4', '\7'},// G {'\7', '\4', '\7', '\7', '\0', '\7'},// H {'\0', '\7', '\0', '\0', '\7', '\0'},// I {'\0', '\7', '\0', '\4', '\7', '\0'},// J {'\7', '\4', '\3', '\7', '\1', '\6'},// K {'\7', '\0', '\0', '\7', '\3', '\3'},// L {'\7', '\4', '\7', '\7', '\0', '\7'},// M {'\7', '\4', '\7', '\7', '\0', '\7'},// N {'\7', '\1', '\7', '\7', '\4', '\7'},// O {'\7', '\1', '\6', '\7', '\1', '\0'},// P {'\7', '\1', '\7', '\7', '\4', '\3'},// Q {'\7', '\1', '\6', '\7', '\1', '\6'},// R {'\7', '\5', '\5', '\5', '\5', '\7'},// S {'\1', '\7', '\1', '\0', '\7', '\0'},// T {'\7', '\0', '\7', '\3', '\6', '\3'},// U {'\7', '\0', '\7', '\0', '\7', '\0'},// V {'\7', '\0', '\7', '\0', '\7', '\0'},// W {'\3', '\4', '\3', '\6', '\1', '\6'},// X {'\3', '\4', '\3', '\0', '\7', '\0'},// Y {'\1', '\5', '\3', '\6', '\5', '\4'},// Z {'\0', '\7', '\1', '\0', '\7', '\4'},// [ {'\3', '\4', '\0', '\0', '\1', '\6'},// Backslash {'\1', '\7', '\0', '\4', '\7', '\0'},// ] {'\2', '\1', '\2', '\0', '\0', '\0'},// ^ {'\4', '\4', '\4', '\4', '\4', '\4'} // _ }; class Cl_lcd2004_i2c : public Print { protected: uint8_t adr, posX, posY; uint8_t _backlightval; uint8_t _displayfunction; uint8_t _displaycontrol; uint8_t _displaymode; byte buffer[80]; static const byte smallChar = 0; static const byte bigChar = 1; byte sizeChar; public: Cl_lcd2004_i2c(uint8_t a): adr(a) {} void small() { sizeChar = smallChar; } void big() { sizeChar = bigChar; } void printSec(uint8_t b) { if (b > 99) return; if (b <= 9)print('0'); print((int)b); } void init() { Wire.begin(); write4bits(0x03 << 4); delayMicroseconds(4500); // wait min 4.1ms write4bits(0x03 << 4); delayMicroseconds(4500); // wait min 4.1ms write4bits(0x03 << 4); delayMicroseconds(150); write4bits(0x02 << 4); delay(50); _backlightval = LCD_NOBACKLIGHT; expanderWrite(_backlightval); // сбросить расширение и выключить подсветку (бит 8 = 1) // режим работы дисплея 4-х битный интерфейс ,две строки,5х8 точек _displayfunction = LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS; command(LCD_FUNCTIONSET | _displayfunction); // режим контроля дисплей вкл, курсор не мигает,дисплей не мигает _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF; command(LCD_DISPLAYCONTROL | _displaycontrol); // режим ввода текста в память-начинать слева с движением в право _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT; command(LCD_ENTRYMODESET | _displaymode); for (int i = 0; i < 8; i++) createCharPROGMEM(i, custom[i]); small(); clear(); } // подсветку вкл/выкл void backlight(void) { _backlightval = LCD_BACKLIGHT; expanderWrite(0); } void noBacklight(void) { _backlightval = LCD_NOBACKLIGHT; expanderWrite(0); } // очистить буфер void clear() { for (byte i = 0; i < 80; i++ )buffer[i] = 0x20; posX = 0; posY = 0; } // отправить информацию из буфера на экран void show() { line(0); for (byte i = 0; i < 20; i++ )out(buffer[i]); line(1); for (byte i = 20; i < 40; i++ )out(buffer[i]); line(2); for (byte i = 40; i < 60; i++ )out(buffer[i]); line(3); for (byte i = 60; i < 80; i++ )out(buffer[i]); } void setCursor(byte x, byte y) { if (x > 20) x = 20; else posX = x; if (y > 4) x = 4; else posY = y; } void createCharPROGMEM(uint8_t location, const uint8_t *charmap) { location &= 0x7; // we only have 8 locations 0-7 command(LCD_SETCGRAMADDR | (location << 3)); for (int i = 0; i < 8; i++) { out(pgm_read_byte_near(charmap + i)); } } void createChar(uint8_t location, uint8_t charmap[]) { location &= 0x7; // we only have 8 locations 0-7 command(LCD_SETCGRAMADDR | (location << 3)); for (int i = 0; i < 8; i++) { out(charmap[i]); } } private: /*внутрение функции*/ void line(byte l) { switch (l) { case 0: command(LCD_SETDDRAMADDR + 0x00); break; case 1: command(LCD_SETDDRAMADDR + 0x40); break; case 2: command(LCD_SETDDRAMADDR + 0x14); break; case 3: command(LCD_SETDDRAMADDR + 0x54); break; } } void writeToBuf(uint8_t value, uint8_t x, uint8_t y) { if (x < 20 && y < 4) buffer[y * 20 + x] = value; } inline size_t write(uint8_t value) { if (sizeChar == smallChar) { writeToBuf(value, posX, posY); posX++; } else { value -= ' '; writeToBuf(pgm_read_byte_near(&fontChar[value][0]), posX, posY); writeToBuf(pgm_read_byte_near(&fontChar[value][1]), posX + 1, posY); writeToBuf(pgm_read_byte_near(&fontChar[value][2]), posX + 2, posY); writeToBuf(' ' , posX + 3, posY); writeToBuf(pgm_read_byte_near(&fontChar[value][3]), posX , posY + 1); writeToBuf(pgm_read_byte_near(&fontChar[value][4]), posX + 1, posY + 1); writeToBuf(pgm_read_byte_near(&fontChar[value][5]), posX + 2, posY + 1); writeToBuf(' ' , posX + 3, posY + 1); posX += 4; } return 1; } inline void out(uint8_t value) { send(value, Rs); } /*команды низкоуровневого управления*/ inline void command(uint8_t value) { send(value, 0); } void send(uint8_t value, uint8_t mode) { uint8_t highnib = value & 0xf0; write4bits((highnib) | mode); uint8_t lownib = (value << 4) & 0xf0; write4bits((lownib) | mode); } void write4bits(uint8_t value) { expanderWrite(value); pulseEnable(value); } void expanderWrite(uint8_t _data) { Wire.beginTransmission(adr); Wire.write((int)(_data) | _backlightval); Wire.endTransmission(); } void pulseEnable(uint8_t _data) { expanderWrite(_data | En); // En high delayMicroseconds(1); // enable pulse must be >450ns expanderWrite(_data & ~En); // En low delayMicroseconds(50); // commands need > 37us to settle } }; Cl_lcd2004_i2c lcd(0x3F);//0x27 //-------------------------------------------------- const byte page0 = 0; // главный экран const byte page1 = 1; // 1 страница byte page; unsigned long past; void goPage(byte p) { page = p; past = millis(); lcd.clear(); switch (page) { case page0: { int sec = past / 1000; int minut = (sec / 60) % 60; sec %= 60; lcd.big(); lcd.printSec(minut); lcd << ":"; lcd.printSec(sec); lcd.setCursor(0, 3); lcd.small(); lcd.printSec(minut); lcd << ":"; lcd.printSec(sec); } break; case page1: { lcd.small(); lcd << "page1"; } break; } lcd.show(); } void run() { if (page == page0 && millis() - past >= 1000) goPage(page0); } //----------------------- void setup() { lcd.init(); lcd.backlight(); goPage(page0); } void loop() { run(); }