Скетч Arduino + W5100 обсуждаем, пишем, тестируем

Подключение исполнительных устройств, датчиков, контроллеров.

Модератор: immortal

flair
Сообщения: 198
Зарегистрирован: Сб янв 16, 2016 12:18 am
Откуда: Минск
Благодарил (а): 16 раз
Поблагодарили: 15 раз

Re: Скетч Arduino + W5100 обсуждаем, пишем, тестируем

Сообщение flair » Чт фев 18, 2016 10:44 am

Ну в общем суть таже) ибо в самом начале своего вникания.... Очень долго искал нужное
DAP
Сообщения: 118
Зарегистрирован: Пн апр 06, 2015 10:25 pm
Благодарил (а): 6 раз
Поблагодарили: 16 раз

Re: Скетч Arduino + W5100 обсуждаем, пишем, тестируем

Сообщение DAP » Вс фев 21, 2016 2:34 pm

Взял один из предидущих примеров и добавил к нему многоканальный диммер
(код для меги) блок обработки выключателей закомментил т.к. шлет запросы на сервер при отключенных входных контактах на плате и дико лагает из-за этого. управляется командой http://xx.xx.xx.xx/command?100=DIM№ где № - номер диммера начиная с 0 и значением от 0 до 200
СпойлерПоказать

Код: Выделить всё


/**

  Общение с шилдом происходит по шине SPI (как с W5100 так и с microSD), занимая выводы 11, 12, 13 для плат на Atmega8/168/328
  или 50, 51, 52 для плат серии Mega (на Atmega1280/2560) т.е. их нельзя будет использовать в своём скетче.
  На платах серии Mega (на Atmega1280/2560) для корректной работы модуля SPI, также необходимо перевести в режим выхода пин 53.
  Для совместимости  со всеми вариантами плат соединение с шиной SPI осуществляется только через  разъём ICSP (ISP).

  Работать с W5100 и с microSD можно только по очереди (так как сидят на одной шине), выбор W5100 осуществляется пином 10,  microSD - пином 4 (эти пины так же нельзя будет использовать в своём скетче )


  Контроллер-исполнительное устройство (к проекту http://smartliving.ru/)
  Platform: Arduino UNO R3 + EthernetShield W5100
  IDE: Arduino 1.0.1

  исполнительные устройства (реле) подключены к Digital 3 - 9
  управляющие кнопки  14 - 18
  обращение по http://xx.xx.xx.xx/ выдаст справочную информацию по этому устройству (нужно для того, чтобы когда обращаешься
  по IP к устройству понять что это за контроллер и пр.)

  /state - состояние всех портов
  /command - выполнение команды
          команды можно вызывать серией в 1 запросе. Например http://xx.xx.xx.xx/command?3=CLICK&4=CLICK&5=ON&6=OFF
          только длинна строки запроса не должна привышать maxLength
  /getdev - получить список всех устройст на 1-wire
          формат вывода:
                 T<номер устройства на шине>:<HEX адрес устройства>:<текущая температура в градусах цельсия>;[...]
                 (пример T0:1060CF59010800E3:24.06;T1:109ABE59010800FE:24.56;)

**/

#include <Ethernet.h>
#include <SPI.h>
#include <Arduino.h>
#include "WebServer.h" // Webduino (https://github.com/sirleech/Webduino)
#include <OneWire.h>
#include <DallasTemperature.h>
#include <math.h>
#include <TimerOne.h>

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xE4, 0xDE, 0x34 }; // MAC-адрес нашего устройства
byte ip[] = { 192, 168, 95, 120 };
byte subnet[] = { 255, 255, 255, 0 };
byte gateway[] = { 192, 168, 95, 254 };
byte dns_server[] = { 192, 168, 95, 254 };
// ip-адрес удалённого сервера
byte server[] = { 192, 168, 95, 38 }; //Адрес сервера MAJORDOMO
char buf[80];
char ipbuff[16];

EthernetClient rclient;
// Функция отправки HTTP-запроса на сервер
void sendHTTPRequest() {
  Serial.println(buf);
  if (rclient.connect(server, 80)) {
    rclient.print(buf);
    rclient.println(" HTTP/1.0");
    Serial.println("Send http get request");
    Serial.println(buf);
    rclient.print("Host: ");
    sprintf(ipbuff, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
    rclient.println(ipbuff); // ip адрес нашего контроллера в текстовом виде
    rclient.print("Content-Type: text/html\n");
    rclient.println("Connection: close\n");
    delay(1000);
    rclient.stop();
  } else {
    Serial.println("FAILED");
  }
}

void sendAPin(int a) {
  int DPin = a - 11;
  if (digitalRead(a) == LOW) { //если кнопка нажата и перемення flag равна 0 , то ...
    digitalWrite(DPin, !digitalRead(DPin)); //Инвертируем выход
    Serial.print("Button: ");
    Serial.print(a);
    Serial.print(" Pin: ");
    Serial.print(DPin);
    Serial.print(" = ");
    Serial.println(digitalRead(DPin));
    sprintf(buf, "GET /objects/?object=sensor222%i&op=m&m=st&status=%i", DPin, digitalRead(DPin));//Готовим запрос на сервер
    sendHTTPRequest();

  }
}


// Настройки выходов реле
int startPin = 26;
int endPin = 49;

// Настройки входов
int startAPin = 11;
int endAPin = 14;

// Настройки выходов диммеров
volatile uint8_t tic ; //счётчик времени
uint8_t data;
int startDimPin = 14; //пин к которому присоединен первый диммер
int endDimPin = 21; //пин к которому присоединен последний диммер
int Dimmer[7]; //количество диммеров минус 1


// 1-wie
#define ONE_WIRE_BUS 5 // Digital Pin данных (куда подключен выход с шины датчиков DS18X20
#define TEMPERATURE_PRECISION 9 //уровень точности

#define VERSION_STRING "DAP_0.2"
#define COMPILE_DATE_STRING "2016-02-21"

P(Page_info) = "<html><head><title>" COMPILE_DATE_STRING" " VERSION_STRING "</title></head><body>\n";
P(location_info) = "NA";
P(pin_info) = "D5 - 1-wire";
P(version_info) = VERSION_STRING " " COMPILE_DATE_STRING;

String url = String(25);
int maxLength = 25; // Максимальная длинна строки запроса

#define delayClick 1000 // задержка при обычном CLICK
#define delayLClick 3000 // задержка при длинном LCLICK
#define MAX_COMMAND_LEN             (10)
#define MAX_PARAMETER_LEN           (10)
#define COMMAND_TABLE_SIZE          (18)
#define PREFIX ""

WebServer webserver(PREFIX, 80);
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

// Для поиска
DeviceAddress Termometers;
float tempC;

#define NAMELEN 32
#define VALUELEN 32

char gCommandBuffer[MAX_COMMAND_LEN + 1];
char gParamBuffer[MAX_PARAMETER_LEN + 1];
long gParamValue;

typedef struct {
  char const    *name;
  void          (*function)(WebServer &server);
} command_t;

command_t const gCommandTable[COMMAND_TABLE_SIZE] = {
  //  {"LED",     commandsLed, },
  {"HELP",     commandsHelp, }, // Выводит список комманд (вызов http://xx.xx.xx.xx/command?8=HELP )
  {"ON",     commandsOn, }, // Устанавливает "1" на заданном цифровом порту (вызов http://xx.xx.xx.xx/command?8=ON )
  {"OFF",     commandsOff, }, // Устанавливает "0" на заданном цифровом порту (вызов http://xx.xx.xx.xx/command?8=OFF )
  {"STATUS",     commandsStatus, }, // Получить состояние цифрового порта (1 или 0) (вызов http://xx.xx.xx.xx/command?8=STATUS ),
  // если вместо номера порта передать ALL (вызов http://xx.xx.xx.xx/command?ALL=STATUS ), то получим состояние всех портов (Пример вывода P3=0;P4=0;P5=0;P6=0;P7=0;P8=1;P9=1;)
  {"CLICK",     commandsClick, }, // Кратковременная "1" на порту 1сек (время настраивается) (вызов http://xx.xx.xx.xx/command?8=CLICK )
  {"LCLICK",     commandsLClick, }, // Кратковременная "1" на порту 3сек (время настраивается) (вызов http://xx.xx.xx.xx/command?8=LCLICK )
  {"DIM0",      commandsDim0 }, // диммер
  {"DIM1",      commandsDim1 }, // диммер
  {"DIM2",      commandsDim2 }, // диммер
  {"DIM3",      commandsDim3 }, // диммер
  {"DIM4",      commandsDim4 }, // диммер
  {"DIM5",      commandsDim5 }, // диммер
  {"DIM6",      commandsDim6 }, // диммер
  {"DIM7",      commandsDim7 }, // диммер
  {"DIM8",      commandsDim8 }, // диммер
  {"DIM9",      commandsDim9 }, // диммер
  {NULL,      NULL }
};

/**********************************************************************************************************************

   Function:    cliProcessCommand

   Description: Look up the command in the command table. If the
                command is found, call the command's function. If the
                command is not found, output an error message.

   Notes:

   Returns:     None.

 **********************************************************************/
void cliProcessCommand(WebServer &server)
{
  int bCommandFound = false;
  int idx;

  gParamValue = strtol(gParamBuffer, NULL, 0);  // Convert the parameter to an integer value. If the parameter is empty, gParamValue becomes 0.
  for (idx = 0; gCommandTable[idx].name != NULL; idx++) {  // Search for the command in the command table until it is found or the end of the table is reached. If the command is found, break out of the loop.
    if (strcmp(gCommandTable[idx].name, gCommandBuffer) == 0) {
      bCommandFound = true;
      break;
    }
  }

  if (bCommandFound == true) {  // Если команда найдена (в массиве команд), то выполняем ее. Если нет - игнорируем
    (*gCommandTable[idx].function)(server);
  }
  else { // Command not found
    server.print("Command not found");
  }
}


/**********************************************************************************************************************/
/* Обработчики команд */

void commandsOn(WebServer &server) {
  if (gParamValue >= startPin && gParamValue <= endPin) {
    digitalWrite(gParamValue, HIGH);
  } else ErrorMessage(server);
}

void commandsOff(WebServer &server) {
  if (gParamValue >= startPin && gParamValue <= endPin) {
    digitalWrite(gParamValue, LOW);
  } else ErrorMessage(server);
}

void commandsClick(WebServer &server) {
  if (gParamValue >= startPin && gParamValue <= endPin) {
    digitalWrite(gParamValue, LOW);
    delay(delayClick);
    digitalWrite(gParamValue, HIGH);
  } else ErrorMessage(server);
}

void commandsLClick(WebServer &server) {
  if (gParamValue >= startPin && gParamValue <= endPin) {
    digitalWrite(gParamValue, LOW);
    delay(delayLClick);
    digitalWrite(gParamValue, HIGH);
  } else ErrorMessage(server);
}

void commandsStatus(WebServer &server) {
  if  (strcmp(gParamBuffer,  "ALL") == 0) { // выдать состояние всех пинов
    for (int i = startPin; i <= endPin; i++) {
      int st = digitalRead(i);
      char my_st[5];
      itoa(st, my_st, 10);
      server.print("P");
      server.print(i);
      server.print("=");
      server.print(my_st);
      server.print(";");
    }
  } else { // выдать состояние только 1 пина
    if (gParamValue >= startPin && gParamValue <= endPin) {
      server.print("P");
      server.print(gParamValue);
      server.print("=");
      server.print(digitalRead(gParamValue));
    } else ErrorMessage(server);
  }
}

void commandsHelp(WebServer &server) {
  int idx;
  for (idx = 0; gCommandTable[idx].name != NULL; idx++) {
    server.print(gCommandTable[idx].name);
    server.print("<br>");
  }
}
//**диммер**
void commandsDim0 (WebServer &server)
{
  if (gParamValue >= 0 && gParamValue <= 200) {
    Dimmer[0] = gParamValue;
  } else ErrorMessage(server);
}
void commandsDim1 (WebServer &server)
{
  if (gParamValue >= 0 && gParamValue <= 200) {
    Dimmer[1] = gParamValue;
  } else ErrorMessage(server);
}
void commandsDim2 (WebServer &server)
{
  if (gParamValue >= 0 && gParamValue <= 200) {
    Dimmer[2] = gParamValue;
  } else ErrorMessage(server);
}
void commandsDim3 (WebServer &server)
{
  if (gParamValue >= 0 && gParamValue <= 200) {
    Dimmer[3] = gParamValue;
  } else ErrorMessage(server);
}
void commandsDim4 (WebServer &server)
{
  if (gParamValue >= 0 && gParamValue <= 200) {
    Dimmer[4] = gParamValue;
  } else ErrorMessage(server);
}
void commandsDim5 (WebServer &server)
{
  if (gParamValue >= 0 && gParamValue <= 200) {
    Dimmer[5] = gParamValue;
  } else ErrorMessage(server);
}
void commandsDim6 (WebServer &server)
{
  if (gParamValue >= 0 && gParamValue <= 200) {
    Dimmer[06] = gParamValue;
  } else ErrorMessage(server);
}
void commandsDim7 (WebServer &server)
{
  if (gParamValue >= 0 && gParamValue <= 200) {
    Dimmer[7] = gParamValue;
  } else ErrorMessage(server);
}
void commandsDim8 (WebServer &server)
{
  if (gParamValue >= 0 && gParamValue <= 200) {
    Dimmer[8] = gParamValue;
  } else ErrorMessage(server);
}
void commandsDim9 (WebServer &server)
{
  if (gParamValue >= 0 && gParamValue <= 200) {
    Dimmer[9] = gParamValue;
  } else ErrorMessage(server);
}

/**********************************************************************************************************************/

void ErrorMessage(WebServer &server) {
  server.print("This Pin is not I/O");
}

/**********************************************************************************************************************
  Разбор запроса
**/
void parsedRequest(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete)
{
  URLPARAM_RESULT rc;
  char name[NAMELEN];
  int  name_len;
  char value[VALUELEN];
  int value_len;

  server.httpSuccess();  // this line sends the standard "we're all OK" headers back to the browser

  /* if we're handling a GET or POST, we can output our data here.
     For a HEAD request, we just stop after outputting headers. */
  if (type == WebServer::HEAD)
    return;

  if (strlen(url_tail))
  {
    while (strlen(url_tail)) // Разбор URI на составные части (выборка параметров)
    {
      rc = server.nextURLparam(&url_tail, name, NAMELEN, value, VALUELEN);
      if (rc == URLPARAM_EOS) {
        //      server.printP(Params_end);
      }
      else // Получили параметр (name) и его значение (value)
      {
        // Выполняем команды
        strcpy (gCommandBuffer, value); // параметры (значение)
        strcpy (gParamBuffer, name); // команда
        cliProcessCommand(server);
      }
    }
  }
  /*
    if (type == WebServer::POST)
    {
      server.printP(Post_params_begin);
      while (server.readPOSTparam(name, NAMELEN, value, VALUELEN))
      {
        server.print(name);
        server.printP(Parsed_item_separator);
        server.print(value);
        server.printP(Tail_end);
      }
    }
  */

}

void get1wireDevices(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete)
{
  //TODO получить все устройства на шине и выдать на страницу
  int numberOfDevices = sensors.getDeviceCount();
  sensors.begin();
  sensors.requestTemperatures();
  for (int i = 0; i < numberOfDevices; i++) {
    if (sensors.getAddress(Termometers, i))
    {
      server.print("T");
      server.print(i);
      server.print(":");
      for (uint8_t i = 0; i < 8; i++) {
        if (Termometers[i] < 16) server.print("0");
        server.print(Termometers[i], HEX);
      }
      float tempC = sensors.getTempC(Termometers);
      server.print(":");
      server.print(tempC);
      server.print(";");
    } else {
      // not found
      server.print("NOT FOUND");
    }
  }
}


void stateRequest(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete)
{
  strcpy (gParamBuffer, "ALL");
  commandsStatus(server);
}

/**********************************************************************************************************************
  Генерация и вывод информации об устройстве
**/
void infoRequest(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete)
{
  server.printP(Page_info);
  server.print("IP:");
  server.print(Ethernet.localIP());
  server.print("<br>State: ");
  strcpy (gParamBuffer, "ALL");
  commandsStatus(server);
  server.print("<br><a href='/getdev'>getdev</a>");
  server.print("<hr>Commands:<br>");
  commandsHelp(server);
  server.print("<hr>Version: ");
  server.printP(version_info);

}


/**********************************************************************************************************************
  Поиск устройств (датчиков температуры на шине 1-wire)
**/
void searchDevices() {
  Serial.println("Search on 1-wire");
  int numberOfDevices = sensors.getDeviceCount();
  sensors.begin();

  for (int i = 0; i < numberOfDevices; i++) {
    if (sensors.getAddress(Termometers, i))
    {
      Serial.print("Device ");
      Serial.print(i, DEC);
      Serial.print(" address: ");
      for (uint8_t i = 0; i < 8; i++) {
        if (Termometers[i] < 16) Serial.print("0");
        Serial.print(Termometers[i], HEX);
      }

      //          Serial.print(" Resolution actually set to: ");
      Serial.print(" Set to: ");
      Serial.print(sensors.getResolution(Termometers), DEC);
      Serial.println();
      float tempC = sensors.getTempC(Termometers);
      Serial.print(tempC);
      Serial.println("C");

    } else {
      // not found
    }
  }
}


/**********************************************************************************************************************/


void setup() {
  // Для дебага будем выводить отладочные сообщения в консоль
  //TODO Убрать вывод в консоль "за дабаг" (т.е. вывод только если скимпилированно с поддержкой дебага)
  Serial.begin(9600);
  Serial.println("Start");
  Ethernet.begin(mac, ip, dns_server, gateway, subnet); // Инициализируем Ethernet Shield
  sprintf(buf, "GET /objects/?script=controller_widget&dev=%u.%u.%u.%u&code=start", ip[0], ip[1], ip[2], ip[3]); //Готовим запрос на сервер
  sendHTTPRequest();

  webserver.setDefaultCommand(&infoRequest); // дефолтная страница вывода (информация о контроллере)
  webserver.addCommand("command", &parsedRequest); // команды
  webserver.addCommand("state", &stateRequest); // выдать состояния всех устройств
  webserver.addCommand("getdev", &get1wireDevices); // получить список устройств на 1-wire
  webserver.begin();

  Serial.print("IP ");
  Serial.println(Ethernet.localIP());

  // Настройка портов
  for (int thisAPin = startAPin; thisAPin <= endAPin; thisAPin++)  {
    pinMode(thisAPin, INPUT);
  }
  // Настройка портов
  for (int thisPin = startPin; thisPin <= endPin; thisPin++)  {
    pinMode(thisPin, OUTPUT);
  }
  // Настройки 1-wire
  sensors.begin(); // Инициализация шины 1-wire (для датчиков температуры)
  sensors.requestTemperatures(); // Перед каждым получением температуры надо ее запросить

  searchDevices();

  //*****диммер****
  //*********************Настраиваем порты на выход**********************

  for ( int i = startDimPin; i <= endDimPin; i++) //пройдемся циклом по портам
  {
    pinMode (i, OUTPUT);
    digitalWrite(i, LOW); // гасим cответствующий пин

    Dimmer[i - startDimPin] = 0; //выставим яркость соответствующего диммера в 0
  }
  //CHANGE – прерывание вызывается при любом изменении значения на входе;
  //RISING – вызов прерывания при изменении уровня напряжения с низкого (Low) на высокий(HIGH)
  //FALLING – вызов прерывания при изменении уровня напряжения с высокого (HIGH) на низкий (Low)
  attachInterrupt(0, detect_up, LOW);  // настроить срабатывание прерывания interrupt0 на pin 2 на низкий уровень
  Timer1.initialize(40);              // Интервал срабатывания таймера в мкс
  Timer1.attachInterrupt(halfcycle);   //будет вызыватся каждый раз при отсчете заданого времени
  Timer1.stop();
  Serial.begin(115200); //инициализация порта
  //randomSeed(analogRead(0)); //псевдогенератор случайных чисел будет использовать шумы на аналог пин 0


}
//***************************Диммер****************************************


//********************обработчики прерываний*******************************
void halfcycle()  //прерывания таймера
{
  tic--;  //счетчик
  for ( int i = startDimPin; i <= endDimPin; i++)
  {
    if (Dimmer[i - startDimPin] > tic )
      digitalWrite(i, HIGH); //управляем выходом (откроем семистор)
  }
}

void  detect_up()  // обработка внешнего прерывания. Сработает по переднему фронту
{
  tic = 200;           //обнулить счетчик
  Timer1.resume();   //запустить таймер
  attachInterrupt(0, detect_down, HIGH);  //перепрограммировать прерывание на другой обработчик
}

void  detect_down()  // обработка внешнего прерывания. Сработает по заднему фронту
{
  Timer1.stop(); //остановить таймер
  for ( int i = startDimPin; i <= endDimPin; i++)
  {

    digitalWrite(i, LOW);
  }
  tic = 200;     //обнулить счетчик
  attachInterrupt(0, detect_up, LOW); //перепрограммировать прерывание на другой обработчик

}

//***************************Диммер**************************************


/**********************************************************************************************************************/
void loop() {
 char buff[64];
  int len = 64;

  /**********************************************************************************************************************

    /* Работа с выключателями
     *  отключено т.к. шлет запросы на сервер при отключенных входных контактах на плате
     *
  for (int i = startAPin; i <= endAPin; i++) {

    int st = digitalRead(i);
    char my_st[5];
    itoa(st, my_st, 10);
    if (st == 1)
    {
      sendAPin(i);
    }
  }
*/
  webserver.processConnection(buff, &len);  // process incoming connections one at a time forever
  
} 
Последний раз редактировалось DAP Вс фев 21, 2016 2:49 pm, всего редактировалось 1 раз.
За это сообщение автора DAP поблагодарил:
masf (Сб апр 11, 2020 6:34 am)
Рейтинг: 1.16%
VGor
Сообщения: 32
Зарегистрирован: Сб янв 23, 2016 12:08 pm
Благодарил (а): 1 раз
Поблагодарили: 1 раз

Re: Скетч Arduino + W5100 обсуждаем, пишем, тестируем

Сообщение VGor » Вс фев 21, 2016 2:40 pm

DAP писал(а):помогите с добавлением в код прошивки многоканального диммера отсюда: http://www.cyber-place.ru/showthread.ph ... 1#post3371 у меня не хватает опыта совместить все функции в одно устройство, не хочется городить 2 платы в щитке.
Использую такой диммер. Объединять в один скетч не советую, т.к. там прерывания каждые 40 мс (если не ошибаюсь) и основной скетч не будет нормально работать. Я под диммер выделил нано, а ему по uart пересылают значение диммирования в зависимости от продолжительности нажатия кнопки.
DAP
Сообщения: 118
Зарегистрирован: Пн апр 06, 2015 10:25 pm
Благодарил (а): 6 раз
Поблагодарили: 16 раз

Re: Скетч Arduino + W5100 обсуждаем, пишем, тестируем

Сообщение DAP » Вс фев 21, 2016 2:50 pm

VGor
всё прекрасно работает =) в том посте я видимо себя недооценил :lol:
VGor
Сообщения: 32
Зарегистрирован: Сб янв 23, 2016 12:08 pm
Благодарил (а): 1 раз
Поблагодарили: 1 раз

Re: Скетч Arduino + W5100 обсуждаем, пишем, тестируем

Сообщение VGor » Вс фев 21, 2016 2:54 pm

Я подумал, что вы хотите в этот скетч добавить сам скетч диммера.
flair
Сообщения: 198
Зарегистрирован: Сб янв 16, 2016 12:18 am
Откуда: Минск
Благодарил (а): 16 раз
Поблагодарили: 15 раз

Re: Скетч Arduino + W5100 обсуждаем, пишем, тестируем

Сообщение flair » Вс фев 21, 2016 4:09 pm

VGor писал(а):
DAP писал(а):помогите с добавлением в код прошивки многоканального диммера отсюда: http://www.cyber-place.ru/showthread.ph ... 1#post3371 у меня не хватает опыта совместить все функции в одно устройство, не хочется городить 2 платы в щитке.
Использую такой диммер. Объединять в один скетч не советую, т.к. там прерывания каждые 40 мс (если не ошибаюсь) и основной скетч не будет нормально работать. Я под диммер выделил нано, а ему по uart пересылают значение диммирования в зависимости от продолжительности нажатия кнопки.
а можно оба скетча глянуть? наны и меги?
Мазур
Сообщения: 133
Зарегистрирован: Чт ноя 26, 2015 3:52 pm
Благодарил (а): 32 раза
Поблагодарили: 1 раз

Re: Скетч Arduino + W5100 обсуждаем, пишем, тестируем

Сообщение Мазур » Вт июн 14, 2016 2:46 pm

m-malva писал(а):скеч для Контроллер-исполнительное устройство с добавленными выключателями и отправкой
переключения на сервер.
СпойлерПоказать

Код: Выделить всё

/**
* Контроллер-исполнительное устройство (к проекту http://smartliving.ru/)
* Platform: Arduino UNO R3 + EthernetShield W5100
* IDE: Arduino 1.0.1
*
* исполнительные устройства (реле) подключены к Digital 3 - 9
* управляющие кнопки  14 - 18 
* обращение по http://xx.xx.xx.xx/ выдаст справочную информацию по этому устройству (нужно для того, чтобы когда обращаешься
* по IP к устройству понять что это за контроллер и пр.)
*
* /state - состояние всех портов
* /command - выполнение команды
*         команды можно вызывать серией в 1 запросе. Например http://xx.xx.xx.xx/command?3=CLICK&4=CLICK&5=ON&6=OFF
*         только длинна строки запроса не должна привышать maxLength
* /getdev - получить список всех устройст на 1-wire
*         формат вывода: 
*                T<номер устройства на шине>:<HEX адрес устройства>:<текущая температура в градусах цельсия>;[...]
*                (пример T0:1060CF59010800E3:24.06;T1:109ABE59010800FE:24.56;)
*
**/

#include <Ethernet.h>
#include <SPI.h>
#include <Arduino.h>
#include "WebServer.h" // Webduino (https://github.com/sirleech/Webduino)
#include <OneWire.h>
#include <DallasTemperature.h>
#include <math.h>

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xE4, 0xDE, 0x33 }; // MAC-адрес нашего устройства
byte ip[] = { 192, 168, 0, 222 };
byte subnet[] = { 255, 255, 255, 0 };
byte gateway[] = { 192, 168, 0, 1 };
byte dns_server[] = { 192, 168, 0, 1 };
// ip-адрес удалённого сервера
byte server[] = { 192, 168, 0, 77 }; //Адрес сервера MAJORDOMO
char buf[80];
char ipbuff[16];

EthernetClient rclient;
// Функция отправки HTTP-запроса на сервер
void sendHTTPRequest() {
  Serial.println(buf); 
  if (rclient.connect(server, 80)) { 
   rclient.print(buf);
   rclient.println(" HTTP/1.0");
   Serial.println("Send http get request");
   Serial.println(buf);
   rclient.print("Host: ");
   sprintf(ipbuff, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
   rclient.println(ipbuff); // ip адрес нашего контроллера в текстовом виде
   rclient.print("Content-Type: text/html\n");
   rclient.println("Connection: close\n");
   delay(1000);
   rclient.stop();
  } else {
   Serial.println("FAILED");     
  }
}

void sendAPin(int a) {
   int DPin = a-11;
if (digitalRead(a)==LOW){//если кнопка нажата и перемення flag равна 0 , то ... 
    digitalWrite(DPin,!digitalRead(DPin)); //Инвертируем выход
    Serial.print("Button: ");
    Serial.print(a);
    Serial.print(" Pin: ");
    Serial.print(DPin);
    Serial.print(" = ");    
    Serial.println(digitalRead(DPin));
    sprintf(buf, "GET /objects/?object=sensor222%i&op=m&m=st&status=%i", DPin, digitalRead(DPin));//Готовим запрос на сервер
    sendHTTPRequest();

}    
}


// Настройки выходов
int startPin=3;
int endPin=9;

// Настройки входов
int startAPin=14;
int endAPin=18;


// Pin controller for connection data pin DS18S20
#define ONE_WIRE_BUS 2 // Digital 2 pin Arduino (куда подключен выход с шины датчиков DS18X20
#define TEMPERATURE_PRECISION 9

#define VERSION_STRING "0.2"
#define COMPILE_DATE_STRING "2015-11-14"

P(Page_info) = "<html><head><title>" COMPILE_DATE_STRING" " VERSION_STRING "</title></head><body>\n";
P(location_info) = "NA";
P(pin_info) = "D2 - 1-wire";
P(version_info) = VERSION_STRING " " COMPILE_DATE_STRING;

String url = String(25);
int maxLength=25; // Максимальная длинна строки запроса

#define delayClick 1000 // задержка при обычном CLICK
#define delayLClick 3000 // задержка при длинном LCLICK
#define MAX_COMMAND_LEN             (10)
#define MAX_PARAMETER_LEN           (10)
#define COMMAND_TABLE_SIZE          (8)
#define PREFIX ""

WebServer webserver(PREFIX, 80);
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

// Для поиска
DeviceAddress Termometers;
float tempC; 

#define NAMELEN 32
#define VALUELEN 32

char gCommandBuffer[MAX_COMMAND_LEN + 1];
char gParamBuffer[MAX_PARAMETER_LEN + 1];
long gParamValue;

typedef struct {
  char const    *name;
  void          (*function)(WebServer &server);
} command_t;

command_t const gCommandTable[COMMAND_TABLE_SIZE] = {
//  {"LED",     commandsLed, },
  {"HELP",     commandsHelp, }, // Выводит список комманд (вызов http://xx.xx.xx.xx/command?8=HELP )
  {"ON",     commandsOn, }, // Устанавливает "1" на заданном цифровом порту (вызов http://xx.xx.xx.xx/command?8=ON )
  {"OFF",     commandsOff, }, // Устанавливает "0" на заданном цифровом порту (вызов http://xx.xx.xx.xx/command?8=OFF )
  {"STATUS",     commandsStatus, }, // Получить состояние цифрового порта (1 или 0) (вызов http://xx.xx.xx.xx/command?8=STATUS ),
                                    // если вместо номера порта передать ALL (вызов http://xx.xx.xx.xx/command?ALL=STATUS ), то получим состояние всех портов (Пример вывода P3=0;P4=0;P5=0;P6=0;P7=0;P8=1;P9=1;)
  {"CLICK",     commandsClick, }, // Кратковременная "1" на порту 1сек (время настраивается) (вызов http://xx.xx.xx.xx/command?8=CLICK )
  {"LCLICK",     commandsLClick, }, // Кратковременная "1" на порту 3сек (время настраивается) (вызов http://xx.xx.xx.xx/command?8=LCLICK )
  {NULL,      NULL }
};

/**********************************************************************************************************************
 *
 * Function:    cliProcessCommand
 *
 * Description: Look up the command in the command table. If the
 *              command is found, call the command's function. If the
 *              command is not found, output an error message.
 *
 * Notes:       
 *
 * Returns:     None.
 *
 **********************************************************************/
void cliProcessCommand(WebServer &server)
{
  int bCommandFound = false;
  int idx;

  gParamValue = strtol(gParamBuffer, NULL, 0);  // Convert the parameter to an integer value. If the parameter is empty, gParamValue becomes 0.
  for (idx = 0; gCommandTable[idx].name != NULL; idx++) {  // Search for the command in the command table until it is found or the end of the table is reached. If the command is found, break out of the loop.
    if (strcmp(gCommandTable[idx].name, gCommandBuffer) == 0) {
      bCommandFound = true;
      break;
    }
  }

  if (bCommandFound == true) {  // Если команда найдена (в массиве команд), то выполняем ее. Если нет - игнорируем
    (*gCommandTable[idx].function)(server);
  }
  else { // Command not found
    server.print("Command not found");
  }
}


/**********************************************************************************************************************/
/* Обработчики команд */

void commandsOn(WebServer &server) {
  if (gParamValue>=startPin && gParamValue<=endPin) {
     digitalWrite(gParamValue,LOW);
  } else ErrorMessage(server);
}

void commandsOff(WebServer &server) {
  if (gParamValue>=startPin && gParamValue<=endPin) {
     digitalWrite(gParamValue,HIGH);
  } else ErrorMessage(server);
}

void commandsClick(WebServer &server) {
  if (gParamValue>=startPin && gParamValue<=endPin) {
     digitalWrite(gParamValue,LOW);     
     delay(delayClick);
     digitalWrite(gParamValue,HIGH);
  } else ErrorMessage(server);
}

void commandsLClick(WebServer &server) {
  if (gParamValue>=startPin && gParamValue<=endPin) {
     digitalWrite(gParamValue,LOW);     
     delay(delayLClick);
     digitalWrite(gParamValue,HIGH);
  } else ErrorMessage(server);
}

void commandsStatus(WebServer &server) {
   if  (strcmp(gParamBuffer,  "ALL") == 0) { // выдать состояние всех пинов
          for(int i=startPin;i<=endPin;i++) {
            int st=digitalRead(i);
            char my_st[5];
            itoa(st,my_st,10);
            server.print("P");
            server.print(i);
            server.print("=");
            server.print(my_st);
            server.print(";");
          }
   } else { // выдать состояние только 1 пина
          if (gParamValue>=startPin && gParamValue<=endPin) {
            server.print("P");
            server.print(gParamValue);
            server.print("=");
            server.print(digitalRead(gParamValue));
          } else ErrorMessage(server);
    }
}

void commandsHelp(WebServer &server) {
  int idx;
  for (idx = 0; gCommandTable[idx].name != NULL; idx++) {
    server.print(gCommandTable[idx].name);
    server.print("<br>");
  }
}

/**********************************************************************************************************************/

void ErrorMessage(WebServer &server) {
    server.print("This Pin is not I/O");
}

/**********************************************************************************************************************
* Разбор запроса
**/
void parsedRequest(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete)
{
  URLPARAM_RESULT rc;
  char name[NAMELEN];
  int  name_len;
  char value[VALUELEN];
  int value_len;

  server.httpSuccess();  // this line sends the standard "we're all OK" headers back to the browser

  /* if we're handling a GET or POST, we can output our data here.
     For a HEAD request, we just stop after outputting headers. */
  if (type == WebServer::HEAD)
    return;

  if (strlen(url_tail))
    {
    while (strlen(url_tail)) // Разбор URI на составные части (выборка параметров)
      {
      rc = server.nextURLparam(&url_tail, name, NAMELEN, value, VALUELEN);
      if (rc == URLPARAM_EOS) {
  //      server.printP(Params_end);
      }
       else // Получили параметр (name) и его значение (value)
        {
        // Выполняем команды
        strcpy (gCommandBuffer, value); // параметры (значение)
        strcpy (gParamBuffer, name); // команда
        cliProcessCommand(server);
        }
      }
    }
/*    
  if (type == WebServer::POST)
  {
    server.printP(Post_params_begin);
    while (server.readPOSTparam(name, NAMELEN, value, VALUELEN))
    {
      server.print(name);
      server.printP(Parsed_item_separator);
      server.print(value);
      server.printP(Tail_end);
    }
  }
*/

}

void get1wireDevices(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete)
{
  //TODO получить все устройства на шине и выдать на страницу
   int numberOfDevices = sensors.getDeviceCount();
   sensors.begin();
   sensors.requestTemperatures();
   for(int i=0;i<numberOfDevices; i++) {
      if(sensors.getAddress(Termometers, i))
      {
          server.print("T");
          server.print(i);
          server.print(":");
          for (uint8_t i = 0; i < 8; i++) {
            if (Termometers[i] < 16) server.print("0");
              server.print(Termometers[i], HEX);
          }
          float tempC = sensors.getTempC(Termometers);
          server.print(":");
          server.print(tempC);
          server.print(";");
      } else {
            // not found
            server.print("NOT FOUND");
      }
    }
}


void stateRequest(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete)
{
  strcpy (gParamBuffer, "ALL");
  commandsStatus(server);
}

/**********************************************************************************************************************
* Генерация и вывод информации об устройстве
**/
void infoRequest(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete)
{
  server.printP(Page_info);
  server.print("IP:");
  server.print(Ethernet.localIP());
  server.print("<br>State: ");
  strcpy (gParamBuffer, "ALL");
  commandsStatus(server);
  server.print("<br><a href='/getdev'>getdev</a>");
  server.print("<hr>Commands:<br>");
  commandsHelp(server);
  server.print("<hr>Version: ");
  server.printP(version_info);
  
}


/**********************************************************************************************************************
* Поиск устройств (датчиков температуры на шине 1-wire)
**/
void searchDevices() {
   Serial.println("Search on 1-wire");
   int numberOfDevices = sensors.getDeviceCount();
   sensors.begin();
   
   for(int i=0;i<numberOfDevices; i++) {
      if(sensors.getAddress(Termometers, i))
      {
          Serial.print("Device ");
            Serial.print(i, DEC);
          Serial.print(" address: ");
          for (uint8_t i = 0; i < 8; i++) {
            if (Termometers[i] < 16) Serial.print("0");
              Serial.print(Termometers[i], HEX);
          }

//          Serial.print(" Resolution actually set to: ");
          Serial.print(" Set to: ");
            Serial.print(sensors.getResolution(Termometers), DEC); 
          Serial.println();
          float tempC = sensors.getTempC(Termometers);
          Serial.print(tempC);
          Serial.println("C");
      
      } else {
            // not found
      }
    }
}


/**********************************************************************************************************************/

 
void setup() {
  // Для дебага будем выводить отладочные сообщения в консоль
  //TODO Убрать вывод в консоль "за дабаг" (т.е. вывод только если скимпилированно с поддержкой дебага)
  Serial.begin(9600);
  Serial.println("Start");
  Ethernet.begin(mac, ip, dns_server, gateway, subnet); // Инициализируем Ethernet Shield
  sprintf(buf, "GET /objects/?script=controller_widget&dev=%u.%u.%u.%u&code=start",ip[0], ip[1], ip[2], ip[3]);//Готовим запрос на сервер
  sendHTTPRequest();  

  webserver.setDefaultCommand(&infoRequest); // дефолтная страница вывода (информация о контроллере)
  webserver.addCommand("command", &parsedRequest); // команды
  webserver.addCommand("state", &stateRequest); // выдать состояния всех устройств
  webserver.addCommand("getdev", &get1wireDevices); // получить список устройств на 1-wire
  webserver.begin();
  
  Serial.print("IP ");
  Serial.println(Ethernet.localIP());
  
    // Настройка портов
  for (int thisAPin = startAPin; thisAPin <=endAPin; thisAPin++)  {
    pinMode(thisAPin, INPUT);      
  }
    // Настройка портов
  for (int thisPin = startPin; thisPin <=endPin; thisPin++)  {
    pinMode(thisPin, OUTPUT);      
  }
  // Настройки 1-wire 
  sensors.begin(); // Инициализация шины 1-wire (для датчиков температуры)
  sensors.requestTemperatures(); // Перед каждым получением температуры надо ее запросить
  
  searchDevices();
  
}


/**********************************************************************************************************************/
void loop() {
  char buff[64];
  int len = 64;

/**********************************************************************************************************************

/* Работа с выключателями
*/
          for(int i=startAPin;i<=endAPin;i++) {
 
            int st=digitalRead(i);
            char my_st[5];
            itoa(st,my_st,10);
             if (st==1)
             {
                sendAPin(i);
             }
          }

  webserver.processConnection(buff, &len);  // process incoming connections one at a time forever
}
 

Простите, Вы не поможете с скетчем для подключения Arduino по USB ?
denis
Сообщения: 284
Зарегистрирован: Сб ноя 24, 2012 11:47 am
Благодарил (а): 28 раз
Поблагодарили: 28 раз

Re: Скетч Arduino + W5100 обсуждаем, пишем, тестируем

Сообщение denis » Чт сен 01, 2016 9:03 pm

Anton_kulibin писал(а):Добрый день!!! Есть связка Mega+w5100. Скетч здешний, но немного доработанный,т.е. добавлены клиенты на NRF24l01. Проблема в то что зависает толи мега толи w5100, т.е. пинг идет, но web страничка не открывается, ресет не помогает. Бывает помогает отключение питания, после этого работает стабильно может день может неделю, потом опять зависает.
У меня та же проблема, но как я понял "лечения" этому нет, это проблема самого модуля w5100. Причем в код специально добавил watchdog, т.е. ардуина точно работает, а вот модуль подвис.
serghei
Сообщения: 2575
Зарегистрирован: Пт ноя 06, 2015 10:22 am
Откуда: Кишинёв
Благодарил (а): 303 раза
Поблагодарили: 282 раза

Re: Скетч Arduino + W5100 обсуждаем, пишем, тестируем

Сообщение serghei » Чт сен 01, 2016 9:11 pm

Как может быть проблема с W5100 если АМС 015 в такой же комплектации работает около месяца? Скорее всего проблема со скетчем или не пропаем в W5100.
AMS : ESP32 + NRF24 + 1Wire-I2C мост DS2482 + счетчик DS2423 + сеть MySensors + редактирование страниц в браузере + Upload по воздуху + SPIFFS
denis
Сообщения: 284
Зарегистрирован: Сб ноя 24, 2012 11:47 am
Благодарил (а): 28 раз
Поблагодарили: 28 раз

Re: Скетч Arduino + W5100 обсуждаем, пишем, тестируем

Сообщение denis » Чт сен 01, 2016 10:31 pm

serghei писал(а):Как может быть проблема с W5100 если АМС 015 в такой же комплектации работает около месяца? Скорее всего проблема со скетчем или не пропаем в W5100.
Но в AMS совершенно по другому переписали библиотеку для w5100. И я не знаю как АМС реагиурет на пропадание сети? У меня на w5100 пинг остается, веб-сервер (страничка) на ардуино недоступна! Т.е. ардуина работает, w5100 пингуется, а страница не открывается.

вот что нашел
http://gruntoff.ru/publ/ehlektronika/pe ... 12-1-0-114
Ответить