Arduino Mega 2560 зависание!!

Samodelkin
Offline
Зарегистрирован: 07.06.2012

Здравствуйте пользователи форума! Нужна Ваша помощь!!

Аппаратная часть:

1.Arduino Mega 2560

2.Ethernet шилд WIZnet W5100

3. Два датчика DS18B20

4. LCD дисплей

5. Питание ардуины  от стабилизированного БП 7,5В. 2А.

Реализовал (пока) не большой проект. Ардуина считывает показания двух датчиков температуры, по 1-ware, один находится на улице, другой в комнате. Показания выводятся на LCD дисплей и на веб-страницу работающую на самой ардуине. Веб страница настроена на обновление каждые 5 секунд. И все вроде бы работает замечательно, НО если у пользователя продолжительное время открыта страница с показаниями датчиков, ардуина вешается напрочь, пока не нажать кнопку RESET. Например, если не открывать страницу вообще, и считывать показания только с дисплея, то все работает относительно стабильно (иногда, через сутки работы или больше на дисплее вместе с показаниями в неиспользуемой обласити дисплея появляется "мусор"), если начать просмотр показаний со страницы, то через минуту или две - ардуина вешается. Я новичек и только осваиваю эту тематику. Нужен Ваш совет, может в самом коде ошибка или можно придумать программный ресет, если ардуина зависла.

Читал, что есть функции программного сброса

void(* resetFunc) (void) = 0; // Reset MC function
resetFunc(); //вызов

или даже использывание библиотеки #include <avr/wdt.h>

Но как их грамотно пристроить к своему коду, не могу пока понять.

Вот мой код:

// Подключаем библиотеки
#include <SPI.h>
#include <Ethernet.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <LiquidCrystal.h>

// Задаем mac адрес и ip
byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x55, 0xE93 };
IPAddress ip(192,168,0, 107);

// Датчик температуры DS18B20 подключен на 7 пин Arduino
#define ONE_WIRE_BUS 7
// Инициализация 1-ware
OneWire oneWire(ONE_WIRE_BUS);

// Инициализация Ethernet server library
EthernetServer server(80);
DallasTemperature sensors(&oneWire);

// Инициализация библиотеки LiquidCrystal с перечнем задействованных выводов
LiquidCrystal lcd(9, 8, 6, 5, 4, 3); 

void setup(){
// Инициализируем дисплей: 2 строки по 16 символов
lcd.begin(8, 2);

  // Инициализация the sensor library
  sensors.begin();
  
  // Запуск Ethernet connection and the server:
  Ethernet.begin(mac, ip);
  server.begin();
}

void loop()
{
  char b = 176;
  sensors.requestTemperatures(); // Send the command to get temperatures
  lcd.print(sensors.getTempCByIndex(1));
  lcd.setCursor(0, 1);
  lcd.print(sensors.getTempCByIndex(0));
  lcd.home();
  // listen for incoming clients
  EthernetClient client = server.available();
  if (client) {
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        if (c == '\n' && currentLineIsBlank) {
          
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connnection: close");
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");
          client.println("<meta http-equiv=\"refresh\" content=\"5\">");
          client.println("<title>Pogoda v ...</title></head>");
          client.println("<body>\n");
          client.println("<h3>Arduino Web Server</h3>");
          client.println("<h3>*Pogoda v ....*</h3>");
          client.print("Temperatura v komnate: "); 
          client.print("<FONT color=red>");
          client.print(sensors.getTempCByIndex(1));
          client.print(" ");
          client.print(b);
          client.print("C");
          client.println("</FONT>");
          client.print("<br />");
          client.println("Temperatura na ulice: "); 
          client.print("<FONT color=red>");
          client.print(sensors.getTempCByIndex(0));
          client.print(" ");
          client.print(b);
          client.print("C");
          client.println("</FONT>");
          client.print("<br />");
          client.println("<a href= http://www.gismeteo.ru/> Prognoz na Gismeteo.ru </a>");
          client.println("</html>");
          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        } 
        else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    } 
    // give the web browser time to receive the data
    delay(1);
    // close the connection:
    client.stop();
  }
}

 

 

leshak
Offline
Зарегистрирован: 29.09.2011

 Как минимум в строке 45 вы пытетесь сделать что-то очень непонятное.

Samodelkin
Offline
Зарегистрирован: 07.06.2012

Нашел для себя, один из вариантов решения.. что то типа

void(* resetFunc) (void) = 0; // Reset MC function
unsigned long time;

void loop() {

time = millis();

if (time > 120000)
{resetFunc();}

}

 Делаю сброс каждые 2 минуты, это помогает. Однако хотелось бы решать не следствие, а причину зависания..

Samodelkin
Offline
Зарегистрирован: 07.06.2012

leshak пишет:

 Как минимум в строке 45 вы пытетесь сделать что-то очень непонятное.

Спасибо за ответ. Пример взят где-то на просторах интернета, возможно с "ошибками", буду анализировать, разбираться, но надеюсь и на вашу помощь.

Сейчас посмотрел, такое решение с 45 строки во всех примерах для веб сервера на ардуине..

Samodelkin
Offline
Зарегистрирован: 07.06.2012

Продолжаю тестировать свой проект, не стабильно работает... Пришлось уменьшить время для resetFunc() до 30 секунд. Никак не могу уловить закономерность зависаний. Например если на страницу зайти одновременно с двух разных компьютеров, то может сразу повиснуть, а может прекрасно работать. Но если повисает то resetFunc() уже не помогает, вешается капитально.

leshak
Offline
Зарегистрирован: 29.09.2011

 >Сейчас посмотрел, такое решение с 45 строки во всех примерах для веб сервера на ардуине..

Вы правы (действительно есть такое на официальном сайте). Но не во всех примерах. 

Как на меня это не есть правильно.

Моя логика такова: avaliable() возвращает число байт доступных для чтения. Мы, почему-то, присваем его переменной с типом EthernetClient. Более строгий, по сравнению с С, компилятор вообще должен сразу нафиг послать за такую попытку, даже не дать скомпилирватся.

Предположим что avaliable(), вернул число 100. Потом мы пыатеся у этого числа 100 вызвать метод read(). Что значит вызывать метод у числа? Нет же смысла. Вообщем IMHO это приведет к передаче управления на какой-то случаный адресс. Ну и "завис".

IMHO вот тут http://arduino.cc/en/Reference/IfEthernetClient и http://arduino.cc/en/Reference/ClientConstructor более корректные примеры.

Вообщем я бы, строчку 45 выкинул :) 

Далее. Как-то страно детектится пустая строка после хедера.

Что в коде? Поймали первы попавшийся символ \n, выставили флаг  currentLineIsBlank = true (причем совершенно непонятно почему, мы же нигде не проверяли что до \n в этой строке небыло символов). И дальше ждем еще пока еще какие-то данные не прийдут. Если после \n никаких данных больше не поступит - мы будем ждать бесконечно.

Вообщем похоже происходит вот так:

1. Браузер послал header, в его конце вы поймали первый \n

2. Браузер пустую строку, завершающуюся \n - вы и ее поймали

3. Все браузер считает что выполнил работу ждет от вас  данных, а вы ждете от него "ну дай еще хоть один байтик" :)

 

 

 

 

leshak
Offline
Зарегистрирован: 29.09.2011

 Хотя, может быть строка 45-ть каким-то образом предназначенна для одновременной обработки нескольких подключений, именно для "одновременно с разных компов", но в таком случае логика ее работы - от меня, пока, ускользает :(

leshak
Offline
Зарегистрирован: 29.09.2011

 Блин, простите. Похоже я навел тень на плетень. Начал смотреть примеры EthernetClient-а, а у вас Server. Причем фактически "пример из документации" в чистом виде, без отсебятины. В таком случае особых проблемм в нем не видно :(

Можно попытася сделать какой-то таймаут, например если хедер начал передаватся, но почему-то не передался за 1 сек - обрывать соединение.

Следующие - проверить притание. У меня (правда на другом чипе и с другими либами) была очень похожая симптоматика. Оказалось что питание 3.3v плавало (у меня шилд питался от 3.3v пина дуины). Сделал отдельный регулятор - проблема исчезла.

И еще, недавно вышла свежая ArduinoIDE, у нее в release notes, довольно много упоминаний типа "пофиксан баг в EthernetShield". Попробуйте взять свежую версию, может какой-то из этих фиксов и отсветсвенен за вашу нестабильность.

 

 

step962
Offline
Зарегистрирован: 23.05.2011

leshak пишет:

Моя логика такова: avaliable() возвращает число байт доступных для чтения.

Если взглянуть в файл Server.h библиотеки Ethernet, то можно увидеть, что метод  available возвращает не число доступных байтов, а экземпляр класса Client (если удалось его создать):

class Server : 
public Print {
private:
  uint16_t _port;
  void accept();
public:
  Server(uint16_t);
  Client available(); // <===
  [...]
};

Цитата:

Вообщем я бы, строчку 45 выкинул :) 

а каким образом будет инициализирован клиент?

 

leshak
Offline
Зарегистрирован: 29.09.2011

step962 пишет:

leshak пишет:

Моя логика такова: avaliable() возвращает число байт доступных для чтения.

Если взглянуть в файл Server.h библиотеки Ethernet, то можно увидеть, что метод  available возвращает не число доступных байтов, а экземпляр класса Client (если удалось его создать):

[skip]

Вы правы. Как я уже говорил, я случайно посмотрел в доку к  EthernetClient, а не EthernetServer. Client - наследуется от Stream, у котого avaliable() возвращает число доступных для чтения байт. Ну и, в результате, развел неоправданную панику вокруг строки 45. Еще раз извиняюсь. Моя ошибка. Естественно, если он возвращает объект, то строка имеет смысл и жизненно необходима.

Samodelkin
Offline
Зарегистрирован: 07.06.2012

Кажется удалось решить проблему. Начал с того, что провери питание +5 В и +3,3 В, все в порядке, стоят как вкопаные. Дальше начал изучать сам эзернет шилд. Сделал поправки в своем скетче. Во-первых, дописал строки маски подсети и указал шлюз. В описании сказано, что это не обязательно и достаточно указать мас и ip, но лучше так. Во-вторых, как я понял, 4 пин шилда используется под работу SD, а на 4 пине у меня висела одна из ног LCD дисплея, перенес ее на другой пин. Низнаю что из этого помогло, но благодаря этим манипуляциям, все заработало так как надо, ардуина не зависает, как только я ее не мучал. 

Буду продолжать развивать свой проект, как только придут запчасти с ебая. Если форумчане не против, буду в дальнейшем выкладывать свои "успехи" в этой теме.

hugoboss317
hugoboss317 аватар
Offline
Зарегистрирован: 21.03.2013

Здрасте вам! Парни, нужна помощь. Вопрос в тему -зависание. Не знаю что важно а что нет, опишу всё в крации. Arduino mega2560, загружал скетч для ЖКИ 128х64 на контроллере ST7920, пару тройку скетчей залил, нормально всё, сначала забыл поменять плату с Atmega32 на дуину2560, потьом поменял. открын другой скетч, опять начал загружать, а было снова установлена атмега32, я переставил на дуину и не дождавшись окончания компеляции опять нажал на загрузку. Стал мигать светодиод (который к пину 13) как при загрузке и примерно раз в 4 -5 секунд помигивает другой, загружается минут 10 после чего пишет тайм аут, а диод так и продолжает мигать, визуально с частотой 6-7ь герц. снимаю питание, включаю - тоже самое. ничего загрузить не могу. В чём это дело?

и ещё вопрос, можно, подключить программатор прямо к Atmega2560 и как?

MaksMS
Offline
Зарегистрирован: 11.03.2013

скорее всего надо загрузчик перепрошить, ищите как прошить одну ардиуну другой ,или через программатор по SPI 

hugoboss317
hugoboss317 аватар
Offline
Зарегистрирован: 21.03.2013

Т.е. как я понял мне нужно подключится к Atmega2560 на arduino, и загрузить в неё бутлоудер? Если так, есть у кого-нибудь что загружать. Чё-то мне кажется не так всё просто. IDE как я понял не поможет? 

hugoboss317
hugoboss317 аватар
Offline
Зарегистрирован: 21.03.2013

Попытался загрузить через программатор скетч, перестал блинькать диод, написал "загрузка выполнена, но не загрузился

Через свой программатор так и пишет тайм аут, только не через 10 мин, а где то через пару. Как и что делать в сети не нашёл, для mega2560. Надежда на вас.

hugoboss317
hugoboss317 аватар
Offline
Зарегистрирован: 21.03.2013

Делаю всё как описывают, подключаю программатор USB asp к Atmega2560, открываю (предварительно обновив файл stk500v2 в папке booatloaders ) IDE, выбираю плату атмега2560, выбираю программатор USB asp, нажимаю "записать загрузчик" ...после примерно минуты  - ошибка при записи загрузчика и сообщение 

avrdude: verification error, first mismatch at byte 0x1e000
0xff != 0x0d
avrdude: verification error; content mismatch

Что делать? Без дуины края. на пару месяцев оказался в дали от цивилизации, взял с собой занятия, много что нужно сделать, а без платы ничего не смогу. Не проходите мимо.

MaksMS
Offline
Зарегистрирован: 11.03.2013

Я конечно таким спобом не прошивал загрузчик, в инете пишут http://forum.arduino.cc/index.php?topic=115531.0 про автосброс

и вот ещё http://www.cbxdragbike.com/arduino/bootloaderdocs/

Прошивал загрузчики только через LPT http://gokerze.blogspot.ru/2012/12/bootloader-atmega328p-pu-atmega-328-lpt.html (пример для атмеги 328) и через другую arduino..

Клапауций
Offline
Зарегистрирован: 10.02.2013

hugoboss317 пишет:
Что делать? Без дуины края. на пару месяцев оказался в дали от цивилизации, взял с собой занятия, много что нужно сделать, а без платы ничего не смогу. Не проходите мимо.

Сюда смотри: 

http://arduino.ru/Hardware/ArduinoBoardMega2560

или сюда http://arduino.cc/en/Main/arduinoBoardMega2560

ключевое слово  Atmel's FLIP software.

пример восстановления http://arduino.ru/forum/obshchii/arduino-ne-opredelyaetsya-kompyuterom-i-kak-eto-ispravit#comment-663

hugoboss317
hugoboss317 аватар
Offline
Зарегистрирован: 21.03.2013

Отлично, всё получилось. Спасибо.

Клапауций
Offline
Зарегистрирован: 10.02.2013

hugoboss317 пишет:

Отлично, всё получилось. Спасибо.

Так, расскажи, чего было и что делал.

axill
Offline
Зарегистрирован: 05.09.2011

leshak пишет:

Моя логика такова: avaliable() возвращает число байт доступных для чтения. Мы, почему-то, присваем его переменной с типом EthernetClient. Более строгий, по сравнению с С, компилятор вообще должен сразу нафиг послать за такую попытку, даже не дать скомпилирватся.

это фишка С++ :) Си конечно же такую конструкцию не переварил бы.

в описании сказано, что если нет данных для чтения, то такая конструкция будет интерпретировано как логическое:

Цитата:

Returns

a Client object; if no Client has data available for reading, this object will evaluate to false in an if-statement (see the example below)

hugoboss317
hugoboss317 аватар
Offline
Зарегистрирован: 21.03.2013

Клапауций пишет:

hugoboss317 пишет:

Отлично, всё получилось. Спасибо.

Так, расскажи, чего было и что делал.

Открыл IDE, выбрал "плату" Atmega8 (не Atmega2560),  в меню "сервис" выбрал, записать загрузчик. Менее чем через минуту написало что то вроде "запись загрузчика не удалась НО, загрузил тестовый скетч и всё пошло.

Подобное повторилось после того, как я стал загружать скетч для ЖКИ128х64 (ST7920) с подключённым RESET от дуины к ЖКИ. Снова заглючила, выличил таким же способом.