Зависание Arduino
- Войдите на сайт для отправки комментариев
Втр, 08/04/2014 - 16:39
#include <SPI.h> #include <Wire.h> #include "DHT.h" #include "Adafruit_BMP085.h" //#include <ETHER_28J60.h> #include <EtherShield.h> #define DHT_S1_PIN A0 // пин для датчика DHT22 int humidity = 0, temp_dht = 0, temp_bmp = 0, temp = 0; int32_t pressure_pa = 0, pressure_mm = 0; int mode = 0; dht dht_s1; Adafruit_BMP085 bmp; static uint8_t mymac[6] = { 0x54,0x55,0x55,0x10,0x00,0x25}; static uint8_t myip[4] = { 192,168,1,88}; #define MYWWWPORT 80 #define BUFFER_SIZE 500 static uint8_t buf[BUFFER_SIZE+1]; // The ethernet shield EtherShield es=EtherShield(); uint16_t http200ok(void) { return(es.ES_fill_tcp_data_p(buf,0,PSTR("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nPragma: no-cache\r\n\r\n"))); } int add_string(char* str, uint16_t &plen) { int i = 0; //Loop through each char while (str[i]) { // Add each char one by one to the buffer buf[TCP_CHECKSUM_L_P + 3 + plen] = str[i]; i++; plen++; } } // prepare the webpage by writing the data to the tcp send buffer uint16_t print_webpage(uint8_t *buf) { Z1_sensors_update(); Z1_SerialOutput(); uint16_t plen; plen=http200ok(); plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<html><head><title>Weather Station</title></head><body>")); plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<center><h2><font color=\"blue\">-- ARDUINO OnLine -- </font></h2></center><hr>")); plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("<center><table border=1 align=center>")); char mystr[400]; sprintf(mystr,"<tr><td> Humidity DHT </td><td> %d %% </td></tr>",humidity); add_string(mystr, plen); sprintf(mystr,"<tr><td> Pressure BMP </td><td> %d mm </td></tr>",pressure_mm); add_string(mystr, plen); sprintf(mystr,"<tr><td> Temp DHT </td><td> %d *C </td></tr>",temp_dht); add_string(mystr, plen); sprintf(mystr,"<tr><td> Temp BMP </td><td> %d *C </td></tr>",temp_bmp); add_string(mystr, plen); plen=es.ES_fill_tcp_data_p(buf,plen,PSTR("</table></center></body></html>")); return(plen); } void setup(){ SPI.begin(); // Initialise SPI interface es.ES_enc28j60SpiInit(); // initialize enc28j60 es.ES_enc28j60Init(mymac); // init the ethernet/ip layer: es.ES_init_ip_arp_udp_tcp(mymac,myip, MYWWWPORT); if (!bmp.begin()) { Serial.println("ERROR: BMP085 sensor failed"); } Serial.begin(9600); Serial.println("\n ...---===[ Weather Station ]===---...\n"); // Тестовые строки для отображения в мониторе порта } void loop(){ char buff[64]; int len = 64; mode = (mode + 1) % 100; uint16_t plen, dat_p; while(1) { // read packet, handle ping and wait for a tcp packet: dat_p=es.ES_packetloop_icmp_tcp(buf,es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf)); if(dat_p==0){ // no http request continue; } // tcp port 80 begin if (strncmp("GET ",(char *)&(buf[dat_p]),4)!=0){ // head, post and other methods: dat_p=http200ok(); dat_p=es.ES_fill_tcp_data_p(buf,dat_p,PSTR("<h1>200 OK</h1>")); goto SENDTCP; } // just one web page in the "root directory" of the web server if (strncmp("/ ",(char *)&(buf[dat_p+4]),2)==0){ dat_p=print_webpage(buf); goto SENDTCP; } else{ dat_p=es.ES_fill_tcp_data_p(buf,0,PSTR("HTTP/1.0 401 Unauthorized\r\nContent-Type: text/html\r\n\r\n<h1>401 Unauthorized</h1>")); goto SENDTCP; } SENDTCP: es.ES_www_server_reply(buf,dat_p); // send web page data // tcp port 80 end } } void Z1_sensors_update() { // if (mode%30==0) { // BMP085 (Temp and Pressure) temp_bmp = bmp.readTemperature(); pressure_pa = bmp.readPressure(); pressure_mm = pressure_pa/133.3; // DHT22 (Temp) if (dht_s1.read22(DHT_S1_PIN) == DHTLIB_OK) { humidity = dht_s1.humidity; temp_dht = dht_s1.temperature; temp = temp_dht; } else { temp = temp_bmp; } // } } void Z1_SerialOutput() { Serial.print("T1 = "); Serial.print(temp_dht); Serial.print(" *C | "); Serial.print("T2 = "); Serial.print(temp_bmp); Serial.print(" *C | "); Serial.print("Pressure = "); Serial.print(pressure_mm); Serial.print(" mm | "); Serial.print("Humidity = "); Serial.print(humidity); Serial.print(" %"); Serial.print("\n\n"); }
Собственно вот. Дело значит обстоит так:
Включаем arduino и в терминале появится надпись инита
Заходим браузером на 192.168.1.88 и видим табличку нужную. Одновременно в уарт вылетит та же информация, что и на страничку
Нажимаем в браузере F5 и... всё. Ардуина зависает и не откликается ни на какие действия. После ресета ситуация повторяется.
В чем может быть проблема?
1. какая у вас ардуина?
2. если не мега, то, наверняка, у вас проблема с нехваткой оперативки
3. закомментируйте большую часть метода print_webpage и добейтесь стабильной работы.
4. помните, что все браузеры дополнительно отправляют запрос на адрес /favicon.ico
1. pro mini atmega328
2. как посчитать сколько будет заюзано памяти?
3. урезал вывод - помогло. спасибо.
4. а это имеет значение? ардуинка же не отвечает и не обрабатывает такой запрос...
>3. урезал вывод - помогло. спасибо.
Еще про экономию:
Каждая текстовая строка в коде вида "some string" - забирает у вас оперативки "длина строки+1"
Вот поэтому код вида
Предпочтительнее чем
В первом случае у вас строка "выжрала оперативу", а во втором она осталась во Flash-памяти и не грузанулась автоматом в RAM при старте скетча.
Флеша у вас есть 32 KB (-2kb на бутлоадер), а SRAM 2KB на все про все. Хотя с SRAM и проще работать, но....
А два КБ - это не так уж и много. Как делаете строку длинной 2023 и больше ни на что оперативки вообще не осталось.
Далее:
Осторожней с размером массивов. Одной этой строкой вы забрали под этот массив 400 байт из 2048. 20% памяти. И это не считаю того что само использование spintf тоже заставляет компилятор "добавить еще одну библиотеку в итоговый скетч".
А еще, раз у вас Enc28j60, то значит весь TCP/IP стек реализован програмно, а не аппаратно. И сама библиотека не маленькая, и на ее нужды, буфер вы выделили 500 байт.
А еще библиотеки датчиков, а еще буфферок
Повезло что оно вообще "взлетело". Прямо как в анекдоте
Вообщем если есть возможность - лучше переходите на wiznet (а него аппаратный TCP/IP, и стабильней, и быстрее и меньше ресурсов жрет). Блоаго в цене, спасибо китайцам, они упали. Плюс у него часто уже бывает встроенная SD-карта. Можно на ней хранить "странички, картинки, CSS-ски" (хотя писать на ардуино полноценное WebUI - тот еще гимор).
Осваивайте PROGMEM и PSTR http://scott.dd.com.au/wiki/Arduino_Static_Strings
Под лупой рассмативайте каждый массив. Думайте можно ли кого-то из них "заюзать два раза". Внимательно смотрите за размерами массивов, типов переменных.
Скажем
Судя по ее названию ей бы за глаза хватило и одного байта, вместо двух. Или у вас действительно может быть разных режимов больше 255-ти?
P.S. А если еще вниматеьленй посмотреть, то вообще не очень ясно зачем эта mode там присутсвует.
Обалденно. Вот если бы так отвечали... Спасибо за развернутый ответ.
Изначальный код был нерабочим. Там стер - тут закомментировал - здесь поменял... и остался mode :)
Этот сетевой модуль брался как самый дешевый для чисто посмотреть. Bтоговый вариант девайса это почти то, что надо, но громоздко - будем уменьшать. SD-карты и прочие модули у меня есть самопаянные. но нне требуются.
sprintf был использован как первый попавшийся вариант передачи в вывод значения переменных.
И этот момент объяснений не совсем понятен: разве оптимизируя использование рам, не логичнее хранить во флеш-памяти (sprintf), нежели грузить в рам (PSTR)?
sprintf - ничего не хранит. это функция форматирования строки. Причем в RAM.
PSTR - ничего не грузит (скорее даже наоборот: указание "не грузить").
кто-то моё сообщение стёр ~19:10. id=63735.
:(
>3. урезал вывод - помогло. спасибо.
Еще про экономию:
Каждая текстовая строка в коде вида "some string" - забирает у вас оперативки "длина строки+1"
Вот поэтому код вида
Предпочтительнее чем
В первом случае у вас строка "выжрала оперативу", а во втором она осталась во Flash-памяти и не грузанулась автоматом в RAM при старте скетча.
Вот блин, насоветовал. Предпочтительность - правильно. Причина - все с точностью наоборот. PSTR оставила строку во flash. А просто "bla-bla" - выжрала память. Поэтому PSTR - предпочтительней (или PROGMEM если объявляем переменную) Отсюда и у вас пошла путаница кто хранит в памяти, а кто во флеше.