помогите уменьшить размер скетча
- Войдите на сайт для отправки комментариев
Втр, 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():
unsigned long millis() { unsigned long m; uint8_t oldSREG = SREG; // disable interrupts while we read timer0_millis or we might get an // inconsistent value (e.g. in the middle of a write to timer0_millis) cli(); m = timer0_millis; SREG = oldSREG; return m; }где видим переменную, которая нам нужна, а так же читаем, что при доступе к ней нужно запрещать прерывания. Короче, делаем "обнулятель"
void zero_millis() { uint8_t oldSREG = SREG; // disable interrupts while we read timer0_millis or we might get an // inconsistent value (e.g. in the middle of a write to timer0_millis) cli(); timer0_millis=0L; SREG = oldSREG; }О... я еще и опоздал с ответом :)
Проверил - работает. Только функцию нужно расположить там же, где и 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, что-бы выполнить привязку к реальному времени.