Зависание 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"
Вот поэтому код вида
PSTR("<center><h2><font color=\"blue\">-- ARDUINO OnLine -- </font></h2></center><hr>")Предпочтительнее чем
В первом случае у вас строка "выжрала оперативу", а во втором она осталась во 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"
Вот поэтому код вида
PSTR("<center><h2><font color=\"blue\">-- ARDUINO OnLine -- </font></h2></center><hr>")Предпочтительнее чем
В первом случае у вас строка "выжрала оперативу", а во втором она осталась во Flash-памяти и не грузанулась автоматом в RAM при старте скетча.
Вот блин, насоветовал. Предпочтительность - правильно. Причина - все с точностью наоборот. PSTR оставила строку во flash. А просто "bla-bla" - выжрала память. Поэтому PSTR - предпочтительней (или PROGMEM если объявляем переменную) Отсюда и у вас пошла путаница кто хранит в памяти, а кто во флеше.