помогите уменьшить размер скетча
- Войдите на сайт для отправки комментариев
Втр, 07/08/2012 - 14:15
сделал скетч, читающий показания с датчиков bmp085 и dht11 и отсылающую на определенный адресс в сети, скетч не помещается на 306 байт большая просьба помочь с уменьшением размера
// // Ethernet shield attached to pins 10, 11, 12, 13 // // Connect VCC of the BMP085 sensor to 3.3V (NOT 5.0V!) // Connect GND to Ground // Connect SCL to i2c clock - on '168/'328 Arduino Uno/Duemilanove/etc thats Analog 5 // Connect SDA to i2c data - on '168/'328 Arduino Uno/Duemilanove/etc thats Analog 4 // EOC is not used, it signifies an end of conversion // XCLR is a reset pin, also not used here // // Connect pin 1 (on the left) of the DHT11 sensor to +5V // Connect pin 2 of the sensor to whatever your DHTPIN is // Connect pin 4 (on the right) of the sensor to GROUND // Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor // #include <SPI.h> #include <Ethernet.h> //#include <EthernetUdp.h> #include <SD.h> #include <Wire.h> #include <Adafruit_BMP085.h> #include <DHT.h> //#include <DallasTemperature.h> //#include <OneWire.h> #define DHTPIN 2 #define DHTTYPE DHT11 //#define ONE_WIRE_BUS 10 //#define TEMPERATURE_PRECISION 9 DHT dht(DHTPIN, DHTTYPE); Adafruit_BMP085 bmp; EthernetClient client; IPAddress server(192,168,1,1); //0neWire oneWire(ONE_WIRE_BUS); //DallasTemperature sensors(&oneWire); const int chipSelect = 4; // Enter a MAC address for your controller below. // Newer Ethernet shields have a MAC address printed on a sticker on the shield byte mac[] = { 0xDE, 0xAD, 0xBE, 0xFF, 0xFE, 0xED }; IPAddress ip(192,168,1,36); // Initialize the Ethernet client library // with the IP address and port of the server // that you want to connect to (port 80 is default for HTTP): unsigned int localPort = 8888; // local port to listen for UDP packets IPAddress timeServer(192, 43, 244, 18); // time.nist.gov NTP server const int NTP_PACKET_SIZE= 48; // NTP time stamp is in the first 48 bytes of the message byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets // A UDP instance to let us send and receive packets over UDP EthernetUDP Udp; void setup() { // Open serial communications and wait for port to open: Serial.begin(9600); // this check is only needed on the Leonardo: while (!Serial) { ; // wait for serial port to connect. Needed for Leonardo only } // start the Ethernet connection: if (Ethernet.begin(mac) == 0) { Serial.println("Failed to configure Ethernet using DHCP"); // DHCP failed, so use a fixed IP address: Ethernet.begin(mac, ip); } //конец инициализации сети Serial.print("Initializing SD card..."); // make sure that the default chip select pin is set to // output, even if you don't use it: pinMode(10, OUTPUT); // see if the card is present and can be initialized: if (!SD.begin(chipSelect)) { Serial.println("Card failed, or not present"); // don't do anything more: return; } Serial.println("card initialized."); dht.begin(); Udp.begin(localPort); } void loop() { unsigned long epoch = 0; //String data =""; int data_pos = 0; char data[100] = ""; sendNTPpacket(timeServer); // send an NTP packet to a time server // wait to see if a reply is available delay(1000); if ( Udp.parsePacket() ) { // We've received a packet, read the data from it Udp.read(packetBuffer,NTP_PACKET_SIZE); // read the packet into the buffer //the timestamp starts at byte 40 of the received packet and is four bytes, // or two words, long. First, esxtract the two words: unsigned long highWord = word(packetBuffer[40], packetBuffer[41]); unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]); // combine the four bytes (two words) into a long integer // this is NTP time (seconds since Jan 1 1900): unsigned long secsSince1900 = highWord << 16 | lowWord; const unsigned long seventyYears = 2208988800UL; // subtract seventy years: epoch = secsSince1900 - seventyYears; // print Unix time: //Serial.println(epoch); } File dataFile = SD.open("weather.txt", FILE_WRITE); if (dataFile) { dataFile.print(epoch); dataFile.print(","); dataFile.print(bmp.readTemperature()); dataFile.print(","); dataFile.print(dht.readHumidity()); dataFile.print(","); dataFile.println(bmp.readPressure()); dataFile.close(); } if (client.connect(server, 80)) { Serial.println("connected"); dataFile = SD.open("weather.txt"); if (dataFile) { //Serial.println("weather.txt:"); // read from the file until there's nothing else in it: while (dataFile.available()) { //data = char(dataFile.read()); data[data_pos] = char(dataFile.read()); data_pos++; } data_pos = 0; // close the file: dataFile.close(); } // Make a HTTP request: client.print("POST /getinfo.php?q="); client.print(data); client.println(" HTTP/1.1"); client.println(); } else { // kf you didn't get a connection to the server: Serial.println("connection failed"); } } unsigned long sendNTPpacket(IPAddress& address) { // set all bytes in the buffer to 0 memset(packetBuffer, 0, NTP_PACKET_SIZE); // Initialize values needed to form NTP request // (see URL above for details on the packets) packetBuffer[0] = 0b11100011; // LI, Version, Mode packetBuffer[1] = 0; // Stratum, or type of clock packetBuffer[2] = 6; // Polling Interval packetBuffer[3] = 0xEC; // Peer Clock Precision // 8 bytes of zero for Root Delay & Root Dispersion packetBuffer[12] = 49; packetBuffer[13] = 0x4E; packetBuffer[14] = 49; packetBuffer[15] = 52; // all NTP fields have been given values, now // you can send a packet requesting a timestamp: Udp.beginPacket(address, 123); //NTP requests are to port 123 Udp.write(packetBuffer,NTP_PACKET_SIZE); Udp.endPacket(); }
имхо, убрать все Serial.print
Вообще класс Serial убрать. вместе с сообщениями. Если все же нужны сообщения, то их по максимуму сократить, тексты разместить в eeprom (они сейчас прямо в програмной области валяются.
а можно подробнее про размещение текстов в eeprom? просто скетч еще не до конца закончен...
а можно подробнее про размещение текстов в eeprom? просто скетч еще не до конца закончен...
Гуглите слова PSTR, PROGMEM, prog_char,pgm_read_byte и т.п. в связке с ардуиной.
а можно подробнее про размещение текстов в eeprom? просто скетч еще не до конца закончен...
Гуглите слова PSTR, PROGMEM, prog_char,pgm_read_byte и т.п. в связке с ардуиной.
Человеку нужно в eeprom, а не в progmem
Вот только уж больно ущербная работа с епромом в ардуино. Я попробова, в принципе, может, вот только IDE почему-то не пишет eeprom :(
Или нужно сначала написать скетч, который зальет в еепром все, что надо, чтобы потом читать в основной программе, или воспользоваться программатором. Есть еще вариант "через дудку" - здесь описано у меня прочитать получилось не с первого раза. Вот такая строка прочитала:
Но, содержимое не очень похоже на правду... Надо будет при случае программатором проверить.
Человеку нужно в eeprom, а не в progmem
Да... на автомате ответил. Просто еще рядом еще пара подобных веток одновременно шла. Но тут еще возникает вопрос, а нужно ли человеку eeprom? У него скетч во флеш не влазит или оперативки не хватает? Если второе - то IMHO есть шанс отделатся "малой кровью". Просто не грузить строки в оперативку, не заморачиваясь с eeprom.
Человек ясно сказал - 306 байт у скетча лишние - то есть прога во флеш не лезет. До оперативки еще дело дойдет :) потом...
Человек ясно сказал - 306 байт у скетча лишние - то есть прога во флеш не лезет. До оперативки еще дело дойдет :) потом...
Ну проглядел, простите. Но как говорил Хаус - все врут ;)
2eldev:
В конце концов чудес не бывает и всегда можно наподключать либ столько что они не влезут в кристал никакими ухищрениями и выходом будет переход на более жирный кристал (или отказ от какой-то функциональности). Возможно вы уменьшите размер скетча за счет строк, но при этом увеличите за счет библиотек для EEPROM :(
Но тут "только пробовать" :(
Попробуте, для начала, как советовали выше, тупо повыкидвать все Serial.print которые можно. В тех которые "нельзя выкинуть никак" - сделать строки более короткими (какие-то абревиатуры использовать вместо целих слов, сокращения и т.п.)
Попробуте, для начала, как советовали выше, тупо повыкидвать все Serial.print которые можно. В тех которые "нельзя выкинуть никак" - сделать строки более короткими (какие-то абревиатуры использовать вместо целих слов, сокращения и т.п.)
serial.print'ы все поубирал - помогло, вот только скетч еще не дописан. нужно еще добавить удаление файла и задержку минут в 5. (добавил удаление файла - размер скетча опять выше нормы)
у меня вопрос именно в том что скетч по своим размерам не проходит в 30кБ
>(добавил удаление файла - размер скетча опять выше нормы)
Ну чудес не бывает. Если все подключеные вами библиотеки практически не оставляют места для вашего скетча - что ж с этим поделаешь? .zip -па тут нет :(
Варианты:
Ну еще, как вариант, забить на получение времени от TimeServer. А в место него купить микруху часов RTS. И надеяется что работа с ней будет занимать меньше памяти чем работа с сервером. Хотя, конечно, будет и не так точно на больших промежутках времени (но это уже зависит от того насколько точную микруху возьмете). Плюсом будет еще и то, что дуина сможет работать и запоминать погоду даже в отсуствие интернета. Тупо писать лог на карточку. И знать при этом время :)
да думал я об rts изначально, купил соответственно микросхему ds1307 с обвязкой встал вопрос об изготовлении платы, так что с ntp решение планировалось как бы временное... и еще хотелось использовать milis() вместо delay() с соответствующими изменениями...
теперь с новыми реалиями надо будет проверить целесообразность rts
как вариант убрать библиотеки bmp085 и dht и работать напрямую c i2c и 1-wire (dht заменить на sht11 тогда вообще 1-wire не нужна будет)
да думал я об rts изначально, купил соответственно микросхему ds1307 с обвязкой встал вопрос об изготовлении платы,
Можно и изготовить - опыт пригодится
А можно и купить готовую. Типа вот такой http://we.easyelectronics.ru/HomeTech/tqfp32---dip32-perehodnik-dlya-maketirovaniya.html
Видел на рынке такие под разные корпуса (только без прижима сверху, "под пайку" заточенные).
Либо панельку купить (но фиг найдешь и очень дорого).
Либо что-то такое намонстрячить
так что с ntp решение планировалось как бы временное...
Можно, в качестве "временного" - по сериал вермя читать. а на компе какую-то програмульку состряпать которая будет время сообщать.
В любом случае попробуйте выкинуть этот timeServer и посмотрите насколько уменьшится скетч (может быть и не уменьшится, может он сильно с клиентом "переплетен").
Потом можете попробовать добавить RTC либу и немного работы с ней (плевать, даже если микрухи нет - все равно размер скетча увидите).
Вообщем прикинте поможет вам переход на микруху или это "те же яйца только в профиль".
и еще хотелось использовать milis() вместо delay() с соответствующими изменениями...
http://arduino.ru/tutorials/BlinkWithoutDelay (и по форуму задачат типа "включить что-то на какой-то время без delay - масса была).
как вариант убрать библиотеки bmp085 и dht и работать напрямую c i2c и 1-wire
Ну "для работы" все равно код писать нужно будет. И не факт что он выйдет меньше чем у тех кто библиотеку писал :(
Да, именно про этот пример "мигание без delay()" я и имел ввиду, говоря про millis()
вопрос только в том что не на комп будет слаться информация, а на роутер zyxel keenetic с установленным на него lighttpd c php и sqlite, поэтому и идет запись на карту памяти с временными метками на случай отваливания сервера (после успешной передачи информации файл должен обнуляться)
Да, именно про этот пример "мигание без delay()" я и имел ввиду, говоря про millis()
Ну дык в чем проблема? :)
вопрос только в том что не на комп будет слаться информация, а на роутер zyxel keenetic с установленным на него lighttpd c php и sqlite,
А какая разница куда оно шлется? В том и суть http что про это можно не знать.
поэтому и идет запись на карту памяти с временными метками на случай отваливания сервера (после успешной передачи информации файл должен обнуляться)
А зачем вам тогда вообще, на стороне адруины знать точное время? Пишите в файл временные метки от millis(). И посылайте millis(). А уж когда запихиваете в базу - добавляйте текущие время роутера. Он-то время должен знать у большинства синхронизация времени "от рождения" имеется. А если нет - так запрос к timeServer на роутере сделать.
можно ли средствами самой ардуины обнулять millis()?
ардуину планирую связывать с миром только через LAN а millis() примерно через 50 дней переполнится (с обнулением)... смущает это неконтроллируемое примерно
Можете посмотреть на исходик миллис в файле hardware\arduino\cores\arduino\wiring.c
И попробовать обнулить timer0_millis, если она публична (только прерывания не забыть запретить при этом).
Но, imho бороться тут нужно не обнулением, а "засекать переполнение". Запоминать "предыдущие значение миллис". Если, вдруг, новое меньше старого - значит имело место переполнение. И "настоящие время" можно вычислить примерно так
НАСТОЯЩИЕ_ВРЕМЯ=millis()+МАКСИМАЛЬНОЕ_ЗНАЧЕНИЕ+ (МАКСИМАЛЬНОЕ_ЗНАЧЕНИЕ-old_millis)
Правда встает вопрос в какой тип влезет это "натоящие время" :(
Тут прийдется либо искать библиотеку которая имеет типы для работы с очень большими числами, либо писать свою. Можно еще попробовать поигратся с типом uint64_t, но очень вероятно что ардуина его не поймет. А если поймет - многие функции стандартные будет с ним глючить.
Так что, скорее всего, прийдется заводить отдельную переменнуюдля "счетчик переполнений". И держать отдельную переменную типа "поправка на ветер", куда добавлять каждый раз при "переходе через границу" МАКСИМАЛЬНОЕ_ЗНАЧЕНИЕ-old_millis
2eldev: и кстати, а какое отношение переполнение millis() имеет к изначальной теме "уменьшить размер скетча"? Лучше было отдельную тему завести.
Ну, если порыться в потрохах IDE (а это нужно делать, когда хочется изменить поведение чисто ардуинских функций) ;) ... то находим определение milles():
где видим переменную, которая нам нужна, а так же читаем, что при доступе к ней нужно запрещать прерывания. Короче, делаем "обнулятель"
О... я еще и опоздал с ответом :)
Проверил - работает. Только функцию нужно расположить там же, где и millis(), потому что только там доступна переменная timer0_millis, и добавить ее определение в arduino.h
>О... я еще и опоздал с ответом :)
В этом нет ничего страшного. Чай не на брейринге. А если два человека ответят "одно и тоже" - все равно не плохо. Чуть-чуть ответы будут отличатся в любом случае. Хотя-бы стилем. Одним людям один ответ понятней будет, другим - другой :) Даже при одинаковой сути.
2eldev: и кстати, а какое отношение переполнение millis() имеет к изначальной теме "уменьшить размер скетча"? Лучше было отдельную тему завести.
про millis() я начал спрашивать в контексте того чтобы попытаться исключить ntp и rts (в которую еще как-то нужно будет ввести текущее время без ntp и serial подключения) для уменьшения размера скетча и чтобы разобраться с учетом времени
я вот думаю что с тем же успехом можно попробовать писать в роутер счетчик переполнений и текущее значение и пусть он сам высчитывает от текущего времени (может даже переведенные в секунды)... и тогда наверное не понядобятся очень длинные переменные
>и тогда наверное не понядобятся очень длинные переменные
От них избавится можно еще переходом от "абсолютного времени" к "интервалам". То есть писать в лог, "сколько прошло времени с предыдущего события". Вряд ли интервалы будут больше 49 дней.
Хранить счетчик только на роутере - плохая идея. В этом случае зачем вам вообще время на ардуине? Пусть роутер на свои часы и смотрит.
Вам же millis() нужно, фактически, именно для ситуации когда "связь с роутером пропала", что-бы потом по логам с карты понять "что и когда происходило".
Я бы, наверное делал так: счетчик переполнений и текущие время (с поправкой на ветер) - писал-бы на карту и слал роутеру.
Он бы пихал это в базу+свое время.
Дополнительно к этим двум параметрам, при старте ардуины генерировал какое-то случайное числа и назвал-бы его sessionID (и тоже писал-бы в логи. на карту и в роутер).
Тогда, после обрыва связи, посмотрев на карту и найдя там записиь типа
sessionID=456, owerflowConuter=2, fixed_millis=5000
А потом найдя в логе роутера что-то типа
sessionID=456,owerflowConuter=0,fixed_millis=100,time=24.08.2012 10:31:15.1234
Я бы смог понять какое реальное время было у строчки с карты. Главное что-бы у роутера была хотя-бы одна запись с таким же sessionID, что-бы выполнить привязку к реальному времени.