Ви не увійшли.
Помогите сделать многоуровневое меню на енкодере.
Неактивний
Фрагменты программы термостата инкубатура. Дисплей 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;
}
}
}
}
Писалось все в "лоб" переписывалось фиг знает сколько раз поэтому ни о какой оптимизации речи не может быть. Комментариев тоже нет .
Неактивний
"нащадки" не будут Вам благодарны ) я бы не рискнул использовать ваш пример )))))
НО! работает, в нашем деле, это пожалуй, один из важнейших факторов )
я предпочитаю такое оформление, если предусматривается работа со строкой ( 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 },
};
Неактивний
Да я рассматривал что то подобное. Согласен что структуры идеальный вариант построения многоуровневых меню. Но к большому моему огорчению они мне не подошли поскольку почти все элементы значений через сериал ( JSON ) шлются в ESP8266 и обратно. Да плюс ко всему этому разные типы. Лепить что то типа структуры из структур не было времени, да опять тот же JSON, кроме этого не все так просто и однозначно с библиотекой Serial в Arduino (max 256 байт буфер). Собственно я привел пример что происходит если покрутить вправо влево или нажать кнопку. А построение многоуровневых меню это совершенно отдельная тема. Ее то как раз можно рассматривать отдельно поскольку не важно как происходит выбор (кнопкой или энкодером). При построении меню на базе энкодера есть только один ньюанс, что в меню должен присутствовать пункт выхода (возврата) на предыдущий уровень .
Неактивний
Это заговор какой-то.Народ в Ардуино тупо забывает о Классах.
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;
}
Неактивний