#1 2016-07-11 15:25:56

electronhic
Учасник
Зареєстрований: 2016-03-23
Повідомлень: 7

Помогите сделать многоуровневое меню на енкодере.

Помогите сделать многоуровневое меню на енкодере.

Неактивний

#2 2016-07-11 17:40:10

NoName
Customer
З Київ
Зареєстрований: 2014-07-08
Повідомлень: 1,446

Re: Помогите сделать многоуровневое меню на енкодере.

привет,
RDA5807M освоили?  )

подскажите пожалуйста какой индикатор Вы используете.

Неактивний

#3 2016-07-11 22:09:24

vvr
Учасник
Зареєстрований: 2015-04-12
Повідомлень: 876

Re: Помогите сделать многоуровневое меню на енкодере.

electronhic пише:

Помогите сделать многоуровневое меню на енкодере.

это коммерческое предложение или просто так для вас поработать)))

Неактивний

#4 2016-07-12 17:00:26

Nefreemen
Учасник
З Киев
Зареєстрований: 2015-12-19
Повідомлень: 716

Re: Помогите сделать многоуровневое меню на енкодере.

Могу привести фрагмент кода своего меню (3 уровня) для энкодера если интересно.

Неактивний

#5 2016-07-12 17:46:26

NoName
Customer
З Київ
Зареєстрований: 2014-07-08
Повідомлень: 1,446

Re: Помогите сделать многоуровневое меню на енкодере.

Nefreemen, мне интересно как сделали меню для "сакральных" трех кнопок )

Неактивний

#6 2016-07-13 00:37:23

Nefreemen
Учасник
З Киев
Зареєстрований: 2015-12-19
Повідомлень: 716

Re: Помогите сделать многоуровневое меню на енкодере.

Фрагменты программы термостата инкубатура. Дисплей 128х64
/*****************************************************
*       21.04.16    13:25                          *
*****************************************************/

#include <ArduinoJson.h>
#include <DS1307.h>
#include <Encoder.h>
#include <DHT.h>
#include <DallasTemperature.h>
#include <OneWire.h>
#include <U8glib.h>
#include <EEPROM.h>
#include <avr/wdt.h>

/**************** Macro **********************/

#define ONE_WIRE_BUS       22           // DS18B20
#define DHTPIN             23             
#define DHTTYPE DHT22                   // DHT 22  (AM2302)
#define PIN_VENT1                       // резерв
#define PIN_VENT2                       // резерв
#define PIN_LIGHT          12           // подсветка дисплея
#define READ_ACTUATOR       3           // сенсор актуатора
#define TURN_ACTUATOR      48           // включение актуатра
#define DIRECT_ACTUATOR    46           // направление движения актуатора
#define BOOTOM_ACTUATOR    A2           // кнопка управления актуатором
#define PIN_ENCODER1        2           // энкодер
#define PIN_ENCODER2       24           // энкодер
#define PIN_ENCODER_BOOTOM 25           // кнопка энкодера
#define SENSETIVE_ENC       2           // чувств. энкодера
#define HITER_UP1          11           // нагреватель 1  вверх
#define HITER_UP2          10           // нагреватель 2  вверх
#define HITER_DOWN1        9            // нагреватель 1  низ
#define HITER_DOWN2        8            // нагреватель 2  низ
#define HITER_VENT         A14          // вентилятор нагревателей
#define HITER_WATER        A15          // ТЭН вода 
#define VENT_WATER         A8           // вентилятор вода
#define VENT_BOX           A9           // вентилятор камеры


/********************** Proto *************************/

DHT dht( DHTPIN , DHTTYPE );
OneWire oneWire( ONE_WIRE_BUS );
DallasTemperature sensors(&oneWire);
DeviceAddress thermometer_low; //, thermometer_high;
DeviceAddress thermometer_high;

//U8GLIB_ST7920_128X64_1X u8g(50, 51, 53);  // SPI Com: SCK = en = 18, MOSI = rw = 16, CS = di = 17
U8GLIB_ST7920_128X64_4X u8g(50, 51, 53);  // SPI Com: SCK = en = 18, MOSI = rw = 16, CS = di = 17

//U8GLIB_ST7920_128X64_1X u8g(12, 11, 10);  // SPI Com: SCK = en = 18, MOSI = rw = 16, CS = di = 17
//U8GLIB_ST7920_128X64_4X u8g(12, 11, 10);    // SPI Com: SCK = en = 18, MOSI = rw = 16, CS = di = 17

Encoder myEnc(PIN_ENCODER1, PIN_ENCODER2);

//DS1307 rtc(A4, A5);
DS1307 rtc(20, 21);

Time date_time;

/***************** Переменные *************************/

int menu_current = 0;
int menu_level = 0;
int item_current = 0;
int i = 0;
int n = 2;

int rotor  = 0;
int lastHour = 0;
int lastMinute = 0;
int rotorMinute = 0;
int lastrotorHour = 0;

float P, dhtt, dhth, dst, dht_t, dht_h;

long lastTime = 0;
long lastTime_light = 0;

String Items = "";
String Exit = "No Save";
long oldPosition  = 0;

float Value = 0;

String StatusSinhro = "";
String StatusInfo = "";
String HitUp = "";
String HitDown = "";
String HitWat = "";
String Vent = "";
String Actuator = "";
String TimeSinhro = "";
String ConstSinhro = "";
String SendSinhro = "";

boolean getsinhro = false;
boolean constSinhro = false;
// Переменные актуатора
int directActuator = 0;     //false - вниз, true - вверх
//boolean initActuator = false;
//long lastTime_Actuator = 0;
int old_actPosition = 0;
volatile int actPosition = 0;

/******************** Array ********************/

const char *menu_strings[ ] = { "Main", "Termostat", "Amendment", "Info", "Elapsed time", "Network" };
int l = 6;

char* FloatTopic [ ] = { "type", "tmp1", "tmp2", "tmpdht", "hmdr", "tmp3", "rotor", "alarm", "hitUp", "hitDown" };
float FloatValue [ ] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
int work = 10;

char* ConstTopic [ ] = { "type", "tmp1", "tmp2", "hmdr", "tmp3", "rotor", "dltmp1",
                         "dltmp2", "dltmp3", "dlthmdr", "amt1", "amt2", "amt3"
                       };
float ConstValue [ ] = { 1, 37.81, 37.81, 60, 37.81, 4, 0.06, 0.06, 0.06, 1.0, 0.0, 0.0, 0.0 };
float ConstUp [ ] = { 1, 40.0, 40.0, 90, 40.0, 6, 0.24, 0.24, 0.24, 2.5, 1.0, 1.0, 1.0 };
float ConstDown [ ] = { 1, 35.0, 35.0, 60, 35.0, 0, 0.0, 0.0, 0.0, 0.0, -1.0, -1.0, -1.0 };
float ConstStep [ ] = { 1, 0.01, 0.01, 0.5, 0.01, 1, 0.06, 0.06, 0.06, 0.5, 0.06, 0.06, 0.06 };
int cons = 13;

char* ItemConst [ ] = { "Exit", "TempUp", "TempDown", "Humidity", "TempHiter", "Rotor",
                        "DltTempUp", "DltTempDown", "DltTempHiter", "DltHumidity", "AmdTempUp",
                        "AmdTempDown", "AmdTempHiter"
                      };
int item = 13;

char* InfDtTopic [ ] = { "type", "dt1", "dt2", "dt3", "dt4", "dt5" };
long InfDtValue [ ] = { 3, 30212, 30209, 22810, 21522, 21923 };

char* ItemInf [ ] = {"Exit", "Date" };
int iteminf = 2;

char* InfGoTopic [ ] = { "type", "go1", "go2", "go3", "go4", "go5" };
float InfGoValue [ ] = { 4, 11.8, 13.11, 14.15, 19.20, 20.23 };
int inf = 6;

char* NetTopic [ ] = { "type", "ip", "ssid", "passw", "mqttip" };
String NetValue [ ] = { "ip", "192.168.1.180", "***", "*****", "192.168.1.20" };
int net = 5;

...........................

/**************************************************
*             Энкодер                            *
* ************************************************/

void EncoderRead( void )
{
  if (menu_level == 0) {
    EncoderReadL0();
  }
  if (menu_level == 1) {
    EncoderReadL1();
  }
  if (menu_level == 2) {
    EncoderReadL2();
  }
}

void EncoderReadL0(void)
{
  long newPosition = myEnc.read();
  if (newPosition - oldPosition != 0 ) {
    digitalWrite( PIN_LIGHT, HIGH );   // подсветка дисплея
  }
  if (newPosition - oldPosition  < -2 ) {
    menu_current --;
    if ( menu_current < 0 ) {
      menu_current = l - 1;             //  l - коолл. элиментов
    }
  }
  if (newPosition - oldPosition > 2 ) {
    menu_current ++;
    if ( menu_current > l - 1 ) {
      menu_current = 0;
    }
  }
  oldPosition = newPosition;
}

void EncoderReadL1(void)
{
  long newPosition = myEnc.read();
  if (newPosition - oldPosition != 0 ) {
    digitalWrite( PIN_LIGHT, HIGH );
  }
  if (menu_current == 1) {
    if (newPosition - oldPosition  < -2 ) {
      item_current --;
      if ( item_current < 0 ) {
        item_current = item - 1 - 3;
      }
      if ( item_current == 0 ) {
        Exit = "Save";
      }
    }
    if (newPosition - oldPosition > 2 ) {
      item_current ++;
      if ( item_current > item - 1 - 3 ) {
        item_current = 0;
      }
      if ( item_current == 0 ) {
        Exit = "Save";
      }
    }
  }
  if (menu_current == 2) {
    if (newPosition - oldPosition  < -2 ) {
      item_current --;
      if (( item_current < 10 ) && ( item_current > 0 )) {
        item_current = 0;
      }
      if ( item_current == 0 ) {
        Exit = "Save";
      }
      if ( item_current < 0 ) {
        item_current = item - 1;
      }
    }
    if (newPosition - oldPosition > 2 ) {
      item_current ++;
      if ( item_current > item - 1 ) {
        item_current = 0;
      }
      if ( item_current == 0 ) {
        Exit = "Save";
      }
      if ( (item_current < item - 1 - 3) && (item_current > 0) ) {
        item_current = item - 1 - 2;
      }
    }
  }

  if (menu_current == 3) {
    if (newPosition - oldPosition  < -2 ) {
      if (Items == "Exit") {
        Items = (String) date_time.hour + "h " + (String) date_time.date + "d " +
                (String) date_time.mon + "m ";
        Value = 1;
        item_current = 1;
      }
      else {
        Items = "Exit";
        item_current = 0;
        Exit = "Save";
      }
    }
    if (newPosition - oldPosition > 2 ) {
      if (Items == "Exit") {
        Items = (String) date_time.hour + "h " + (String) date_time.date + "d " +
                (String) date_time.mon + "m ";
        Value = 1;
        item_current = 1;
      }
      else {
        Items = "Exit";
        Exit = "Save";
        item_current = 0;
      }
    }
    oldPosition = newPosition;
  }
  if ((menu_current == 1) || (menu_current == 2)) {
    Items = (String)ItemConst [ item_current ];
    Value = ConstValue [ item_current ];
    oldPosition = newPosition;
  }
}

void EncoderReadL2(void)
{
  long newPosition = myEnc.read();
  if (newPosition - oldPosition != 0 ) {
    digitalWrite( PIN_LIGHT, HIGH );
  }
  if (( menu_current == 1 ) || ( menu_current == 2 )) {
    if ( item_current != 0 ) {
      if (newPosition - oldPosition  < -2 ) {
        ConstValue [ item_current ] = ConstValue [ item_current ] - ConstStep [ item_current ];
        if ( ConstValue [ item_current ] < ConstDown [ item_current ] ) {
          ConstValue [ item_current ] = ConstUp [ item_current ];
        }
        Value = ConstValue [ item_current ];
      }
      if (newPosition - oldPosition > 2 ) {
        ConstValue [ item_current ] = ConstValue [ item_current ] + ConstStep [ item_current ];
        if ( ConstValue [ item_current ] > ConstUp [ item_current ] ) {
          ConstValue [ item_current ] = ConstDown [ item_current ];
        }
        Value = ConstValue [ item_current ];
      }
    }
    if ( item_current == 0 ) {
      if (newPosition - oldPosition  < -2 ) {
        if ( Exit == "Save" ) {
          Exit = "No Save";
        }
        else {
          Exit = "Save";
        }
      }
      if (newPosition - oldPosition > 2 ) {
        if ( Exit == "Save" ) {
          Exit = "No Save";
        }
        else {
          Exit = "Save";
        }
      }
    }
    oldPosition = newPosition;
  }
  if (menu_current == 3) {
    if ( item_current == 1) {
      if (newPosition - oldPosition  < -2 ) {
        Value--;
        if (Value < 1) {
          Value = inf - 1;
        }
      }
      if (newPosition - oldPosition > 2 ) {
        Value++;
        if ( Value > inf - 1) {
          Value = 0;
        }
      }
    }
    if ( item_current == 0 ) {
      if (newPosition - oldPosition  < -2 ) {
        if ( Exit == "Save" ) {
          Exit = "No Save";
        }
        else {
          Exit = "Save";
        }
      }
      if (newPosition - oldPosition > 2 ) {
        if ( Exit == "Save" ) {
          Exit = "No Save";
        }
        else {
          Exit = "Save";
        }
      }
    }
    oldPosition = newPosition;
  }
}

void EncoderBootom(void)
{
  if (menu_level == 0) {
    if (( menu_current == 1 ) || ( menu_current == 2 )) {
      delay(20);
      Items = (String)ItemConst [ item_current ];
      Value = ConstValue [ item_current ];
      menu_level = 1;
      return;
    }
    if ( menu_current == 3 ) {
      delay(20);
      Items = "Exit";
      Exit = "Save";
      menu_level = 1;
      return;
    }
  }

  if (menu_level == 1) {
    if (( menu_current == 1 ) || ( menu_current == 2 )) {
      delay(20);
      Items = (String)ItemConst [ item_current ];
      Value = ConstValue [ item_current ];
      menu_level = 2;
      return;
    }
    if (menu_current == 3) {
      menu_level = 2;
      return;
    }
  }

  if (menu_level == 2) {
    if (( menu_current == 1 ) || ( menu_current == 2 )) {
      if (item_current != 0) {
        delay(20);
        Items = (String)ItemConst [ item_current ];
        Value = ConstValue [ item_current ];
        menu_level = 1;
      }
      if (item_current == 0) {
        if (Exit == "Save") {
          JsonSerial(1);
          SaveValue1EEPROM();
          menu_level = 0;
          return;
        }
        else {
          ReadValue2EEPROM();
          JsonSerial(1);
          menu_level = 0;
        }
      }
      return;
    }
    if (menu_current == 3) {
      if ((item_current == 0) && ( Exit == "Save")) {
        //Написать сохранение
        InfDtValue [ (int)Value ] = date_time.mon * 10000L + date_time.date * 100L + date_time.hour;
        GoInf();
        SaveValue2EEPROM();
        menu_level = 0;
        JsonSerial(3);
        //delay(1000);
        JsonSerial(4);
        return;
      }
      if ((item_current == 0) && ( Exit == "No Save")) {
        menu_level = 0;
        return;
      }
      if (item_current == 1) {
        menu_level = 1;
      }
    }
  }
}
Писалось все в "лоб" переписывалось фиг знает сколько раз поэтому ни о какой оптимизации речи не может быть. Комментариев тоже нет  sad .

Неактивний

#7 2016-07-13 09:12:55

NoName
Customer
З Київ
Зареєстрований: 2014-07-08
Повідомлень: 1,446

Re: Помогите сделать многоуровневое меню на енкодере.

"нащадки" не будут Вам благодарны )  я бы не рискнул использовать ваш пример )))))
НО! работает, в нашем деле, это пожалуй, один из важнейших факторов )

я  предпочитаю такое оформление, если предусматривается работа со строкой  ( 4 подменю на экране )
код избыточен, но как обычно через пару лет понимаю что куда  идет

const SMenu_TICxxx xxx[] = {
 ///  STR            E L R EXE L:R ( Local )
// --- pos 00  ----  // 
 { "Manual control       ",1,0,0, 0, 1,1, // переходим на старт
   "Setting              ",2,0,0, SelectLine0, 0,0,
   "X                    ",0,0,0, SelectLine0, 0,0,
   "Y                    ",0,0,0,SelectLine0, 0,0,},
// --- pos 01  ----  // 
{  "max xxxx             ",1,1,1, SelectLine0, 255,255,
   "min xxxx             ",0,0,0, SelectLine0, 0,0,
   "pos                  ",0,0,0, 0, 0,0,
   "% xxx.xx R           ",0,0,0, SelectLine0, 0,0 },
};

Неактивний

#8 2016-07-13 10:16:09

Nefreemen
Учасник
З Киев
Зареєстрований: 2015-12-19
Повідомлень: 716

Re: Помогите сделать многоуровневое меню на енкодере.

Да я рассматривал что то подобное. Согласен что структуры идеальный вариант построения многоуровневых меню. Но к большому моему огорчению они мне не подошли поскольку почти все элементы значений через сериал ( JSON ) шлются в ESP8266 и обратно. Да плюс ко всему этому  разные типы. Лепить что то типа структуры из структур не было времени, да опять тот же JSON, кроме этого не все так просто и однозначно с библиотекой Serial в Arduino (max 256 байт буфер). Собственно я привел пример что происходит если покрутить вправо влево или нажать кнопку. А построение многоуровневых меню это совершенно отдельная  тема. Ее то как раз можно рассматривать отдельно поскольку не важно как происходит выбор (кнопкой или энкодером). При построении меню на базе энкодера есть только один ньюанс, что в меню должен присутствовать пункт выхода (возврата) на предыдущий уровень .

Неактивний

#9 2016-07-13 10:25:39

NoName
Customer
З Київ
Зареєстрований: 2014-07-08
Повідомлень: 1,446

Re: Помогите сделать многоуровневое меню на енкодере.

а где потерялся ТС?  big_smile

Неактивний

#10 2016-07-13 11:49:34

Nefreemen
Учасник
З Киев
Зареєстрований: 2015-12-19
Повідомлень: 716

Re: Помогите сделать многоуровневое меню на енкодере.

Ушел курить и пить пиво  big_smile. Или уже написал сам big_smile .

Неактивний

#11 2016-07-17 11:53:34

qwone
Гість

Re: Помогите сделать многоуровневое меню на енкодере.

Это заговор какой-то.Народ в Ардуино тупо забывает о Классах.

#12 2016-07-17 20:51:11

NoName
Customer
З Київ
Зареєстрований: 2014-07-08
Повідомлень: 1,446

Re: Помогите сделать многоуровневое меню на енкодере.

qwone, без примера,  фраза очень остра )
мы все из ANSI C89 )

source  www.rosettacode.org/

 
#include <iostream>
#include <string>
#include <sstream>
 
namespace bottle_song
{
  // =================================================================
 
  // ***********************************
  // * Abstract base class for things. *
  // ***********************************
 
  class thing
  {
  public:
    // return the singular of the thing
    virtual std::string singular() const = 0;
 
    // return the plural of the thing
    virtual std::string plural() const = 0;
 
    // we need a virtual destructor, too
    virtual ~thing() {}
  };
 
  // =================================================================
 
  // ***************
  // * Containers. *
  // ***************
 
  // Containers are things which can contain other things. The
  // following class makes any thing into a container. The container
  // class is actually a decorator which makes any thing into a
  // container. Note that the contained thing is actually mutable,
  // even if the container is not. Note that the container can only
  // contain a single thing; if it shall contain several things, make
  // it contain a collection instead.
 
  class container: public thing
  {
  public:
    // The format gives the name. %self% is replaced by the containing
    // object's name (in proper pluralization), %contained% is
    // replaced by the contained object's name.
    container(std::string fmt, thing const& what, thing const& contained);
    std::string singular() const;
    std::string plural() const;
  private:
    std::string format;
    thing const& self;
    thing const& contained_thing;
    // helper function to replace strings
    static void replace(std::string& str, std::string from, std::string to);
  };
 
  container::container(std::string fmt,
                       thing const& what,
                       thing const& contained):
    format(fmt),
    self(what),
    contained_thing(contained)
  {
  }
 
  std::string container::singular() const
  {
    std::string result = format;
    replace(result, "%self%", self.singular());
    replace(result, "%contained%", contained_thing.singular());
    return result;
  }
 
  std::string container::plural() const
  {
    std::string result = format;
    replace(result, "%self%", self.plural());
    replace(result, "%contained%", contained_thing.singular());
    return result;
  }
 
  void container::replace(std::string& str, std::string from, std::string to)
  {
    std::string::size_type pos = str.find(from);
    if (pos != std::string::npos)
      str.replace(pos, from.length(), to);
  }
  // =================================================================
 
  // *********************************
  // * A collection of equal things. *
  // *********************************
 
  // In the context of this program, a collection of things is again
  // considered a single thing.
  // This is a concrete class.
  class equal_collection: public thing
  {
  public:
    // constructor
    equal_collection(int count, thing const& what);
 
    // get singular
    std::string singular() const;
 
    // get plural. This has to be implemented, even if it isn't used,
    // because the inherited version is pure virtual, and not
    // implementing this would make the class abstract.
    std::string plural() const;
 
    // this just returns whether thwere are still things left to take away.
    bool there_is_some_left();
 
    // this takes one thing away from the collection. Taking a thing
    // away from an empty collection is undefined behaviour (i.e. not
    // explicitly checked).
    void take_one_away();
  private:
    int count_of_things;
    thing const& type_of_thing;
  };
 
  // equal_collection constructor
  equal_collection::equal_collection(int count, thing const& what):
    count_of_things(count),
    type_of_thing(what)
  {
  }
 
  // get singular. The singular of the collection is just the number
  // followed by the thing, proper pluralized. The fact that it's
  // grammatically still a plural form doesn't matter for the problem
  // at hand.
  std::string equal_collection::singular() const
  {
    std::ostringstream oss;
    oss << count_of_things << " ";
    if (count_of_things == 1)
      oss << type_of_thing.singular();
    else
      oss << type_of_thing.plural();
    return oss.str();
  }
 
  // get plural. For collections, the plural is just "times " followed
  // by the singular. That is 3 collections of 4 bottles each give 3
  // times 4 bottles.
  std::string equal_collection::plural() const
  {
    return "times " + singular();
  }
 
  // tell if there are still things to take away. There are things to
  // take away if there are more than 0 things.
  bool equal_collection::there_is_some_left()
  {
    return count_of_things > 0;
  }
 
  // take one thing away from the collection. That is, just decrement
  // the count of things.
  void equal_collection::take_one_away()
  {
    --count_of_things;
  }
 
  // =================================================================
 
  // ************
  // * The beer *
  // ************
 
  class beer: public thing
  {
  public:
    std::string singular() const { return "beer"; }
    std::string plural() const { return "beers"; }
  };
 
  // =================================================================
 
  // **************
  // * The bottle *
  // **************
 
  class bottle: public thing
  {
  public:
    std::string singular() const { return "bottle"; }
    std::string plural() const { return "bottles"; }
  };
 
  // =================================================================
 
  // ************
  // * The wall *
  // ************
 
  class wall: public thing
  {
  public:
    std::string singular() const { return "wall"; }
    std::string plural() const { return "walls"; }
  };
 
  // =================================================================
 
  // this is the class for the song.
  class song
  {
  public:
    song(int bottle_count);
    void sing(std::ostream& where); // note: singing the song modifies it!
  private:
    beer beverage;
    bottle drink_source;
    container bottle_of_beer;
    equal_collection collection_of_bottles;
    wall bottle_storage;
    container wall_of_bottles;
  };
 
  song::song(int bottle_count):
    bottle_of_beer("%self% of %contained%", drink_source, beverage),
    collection_of_bottles(bottle_count, bottle_of_beer),
    wall_of_bottles("%contained% on the %self%",
                    bottle_storage, collection_of_bottles)
  {
  }
 
  void song::sing(std::ostream& where)
  {
    while (collection_of_bottles.there_is_some_left())
    {
      where << wall_of_bottles.singular() << ".\n"
            << collection_of_bottles.singular() << ".\n"
            << "Take one down, pass it around.\n";
      collection_of_bottles.take_one_away();
      where << wall_of_bottles.singular() << ".\n\n";
    }
  }
}
 
int main()
{
  bottle_song::song song(100);
  song.sing(std::cout);
  return 0;
}

Неактивний

Швидке повідомлення

Введіть повідомлення і натисніть Надіслати

Підвал форуму