Closed ferchinas closed 5 years ago
excellent!
don't you want to do a pull request? putting this at plugin
folder would be very nice even if specific to some setup (plugins can be specific). However, this one seems quite generic.
how to make this work on arduino? its not displaying properly for me on serial monitor of IDE.
are you using the floatlField above?
i am using everything as it is. and i tried to uploadit to a arduino UNO and evrithing coompiles smooth no erors but .. 11:50:30.219 -> Menu 4.x 11:50:30.219 -> Use keys + - * / 11:50:30.219 -> to control the menu navigation 11:50:30.219 -> ⸮⸮⸮⸮⸮⸮6⸮%⸮4⸮&⸮⸮⸮⸮%⸮4⸮⸮⸮⸮⸮⸮ߑϑ⸮
original using esp32, guess there is some discrepancies over memory allocation RAM vs FLASH
what IDE are you using?
1.8.12
arduino IDE wont let you specify compiling flags (at least last time i checked) otherwise we could force everything to RAM to make a quick check... I'm quite sure this example needs some review to work on flash memory, adding to my todo list
May 2017 Rui Azevedo - ruihfazevedo(@rrob@)gmail.com www.r-site.net unlike native objects, pluggins can be device specific, so some pluggins might not work on all devices. all sorts of plugins may be available in the future and if you customize a component and think it of interest of others please do pull request. contrubutions and contrubutors are welcome. decimalslField - To select the number of decimal places that are printed in float and double variables types. Feb 2019 ferchinas Tested on ESP32, Oled i2c display, u8g2 driver. It could work on other devices. ***/
this is on the beginning of the example
indeed, as a plugin it would work for all mcu's were menu uses ram by default, not the case of AVR's
ok as a possible improvement it is possible to make a normal expression (123.456...) of decimal number followed by a multiplier/denominator like Mega ,kilo, mili, nano.... ( 123.45 [kilo])
there is also an unit
text available for all numeric fields, however its not dynamic
as a note, improvements like this will probably be added as plugins because existing features are already tight on tiny mcu's like atmega328
thanks for the feed back, its really appreciated
for my case there should be no trouble because i intend to to use a ST7920 12864 display with a rotary encoder and Arduino mega as a HMI. the uno was used only for testing stuff that i intend to use.
meanwhile and if changing decimal places for all numeric fields is ok for you, you can change code at https://github.com/neu-rah/ArduinoMenu/blob/master/src/itemsTemplates.hpp#L37
to:
template<typename T>
idx_t menuField<T>::printReflex(menuOut& o) const {return o.print(reflex,3);}
here using 3 decimal places
Hi!
added a decimal places format field, not with a fancy unit scale print (like Mega ,kilo, mili, nano....) but allowing only specification of decimal places, was so simple that no plugin added, now its part of the lib
usage example here https://github.com/neu-rah/ArduinoMenu/blob/master/examples/handlers/handlers/handlers.ino#L140
altFIELD(decPlaces<3>::menuField,test,"Test","%",0,100,1,0.001,showEvent,anyEvent,wrapStyle)
hope it works ok, let me know if not
P.S. for now you have to download latest version 4.19.x manually, I will make a release if this works ok
17:27:01.853 -> [-] Alert test
17:27:01.853 -> [-] Name
17:27:01.853 -> [-] Hex 0x11
17:27:03.978 -> ========
17:27:03.978 -> Event for target: 0x55A
17:27:03.978 -> nav level:0 path:[3]
17:27:03.978 -> 128 selBlurEvent
17:27:03.978 ->
17:27:03.978 -> ========
17:27:03.978 -> Event for target: 0x55A
17:27:03.978 -> nav level:0 path:[3]
17:27:03.978 -> 32 blurEvent
17:27:03.978 ->
17:27:03.978 -> ========
17:27:03.978 -> Event for target: 0x55A
17:27:03.978 -> nav level:0 path:[2]
17:27:03.978 -> 16 focusEvent
17:27:03.978 ->
17:27:03.978 -> ========
17:27:03.978 -> Event for target: 0x55A
17:27:03.978 -> nav level:0 path:[2]
17:27:03.978 -> 64 selFocusEvent
17:27:04.013 ->
17:27:04.013 ->
17:27:04.013 -> Main menu
17:27:04.013 -> [3]>Test 55.000%
17:27:04.013 -> [4] Sub-Menu
17:27:04.013 -> [5] Led: Off
17:27:04.013 -> [6] LED On
17:27:04.013 -> [7] LED Off
17:27:04.013 -> [8] Select Zero
17:27:04.013 -> [9] Choose Last
17:27:04.013 -> [-] Alert test
17:27:04.013 -> [-] Name
17:27:08.029 -> ========
17:27:08.029 -> Event for target: 0x55A
17:27:08.029 -> nav level:0 path:[2]
17:27:08.029 -> 4 exitEvent
17:27:08.029 ->
17:27:08.029 -> suspending menu!
17:27:08.029 -> suspended...
ok i testedit on my device Mega +encoder+12864 and its wierd
it differs from the example i used were first i set the decade and then the units this example setts everithing before the "," by counting with the encoder then everyting the same after the ",".
#include <Arduino.h>
/********************
Arduino generic menu system
U8G2 menu example
U8G2: https://github.com/olikraus/u8g2
Oct. 2016 Stephen Denne https://github.com/datacute
Based on example from Rui Azevedo - ruihfazevedo(@rrob@)gmail.com
Original from: https://github.com/christophepersoz
menu on U8G2 device
output: Wemos D1 mini OLED Shield (SSD1306 64x48 I2C) + Serial
input: Serial + encoder
mcu: nano328p
*/
#include <menu.h> //menu macros and objects
#include <menuIO/u8g2Out.h>
#include <TimerOne.h>
#include <ClickEncoder.h>
#include <menuIO/clickEncoderIn.h>
#include <menuIO/keyIn.h>
#include <menuIO/chainStream.h> // concatenate multiple input streams (this allows adding a button to the encoder)
#include <menuIO/serialOut.h>
#include <menuIO/serialIn.h>
using namespace Menu;
#define LEDPIN LED_BUILTIN
// #define USE_PCD8544
//#define USE_SSD1306
//#define(USE_PCD8544)
// rotary encoder pins
#define encA A0
#define encB A1
#define encBtn A2
#define encSteps 2
ClickEncoder clickEncoder = ClickEncoder(encA, encB, encBtn, encSteps);
ClickEncoderStream encStream(clickEncoder, 1);
//ClickEncoder clickEncoder(encA,encB,encBtn,2);
//ClickEncoderStream encStream(clickEncoder,1);
//MENU_INPUTS(in,&encStream);
void timerIsr() {clickEncoder.service();}
result doAlert(eventMask e, prompt &item);
result showEvent(eventMask e,navNode& nav,prompt& item) {
Serial.print("event: ");
Serial.println(e);
return proceed;
}
//#define U8G2_16BIT///////////
#include <SPI.h>
#define USE_HWSPI
// #define U8_DC 9
// #define U8_CS 10
// #define U8_RST 8
#define fontName u8g2_font_6x10_tr
//#define fontName u8g2_font_chikita_tr
#define fontX 6
#define fontY 12
#define offsetX 0
#define offsetY 0
#define U8_Width 128
#define U8_Height 64
//U8G2_ST7920_128X64_1_HW_SPI u8g2(U8G2_R0, /* CS=*/ 10, /* reset=*/ 8);
U8G2_ST7920_128X64_1_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* CS=*/ 10, /* reset=*/ 8); /////not working// working for arduino mega
//U8G2_ST7920_128X64_1_HW_SPI u8g2(U8G2_R0, /* CS=*/ 10, /* reset=*/ 8);
// define menu colors --------------------------------------------------------
//each color is in the format:
// {{disabled normal,disabled selected},{enabled normal,enabled selected, enabled editing}}
// this is a monochromatic color table
const colorDef<uint8_t> colors[6] MEMMODE={
//{{0,0},{0,1,1}},//bgColor
//{{1,1},{1,0,0}},//fgColor
//{{1,1},{1,0,0}},//valColor
//{{1,1},{1,0,0}},//unitColor
//{{0,1},{0,0,1}},//cursorColor
//{{1,1},{1,0,0}},//titleColor
{{0,0},{0,1,1}},//bgColor
{{1,1},{1,0,0}},//fgColor
{{1,1},{1,0,0}},//valColor
{{1,1},{1,0,0}},//unitColor
{{0,1},{0,0,1}},//cursorColor
{{1,1},{1,0,0}},//titleColor
};
float test=55;
int ledCtrl=HIGH;
result myLedOn() {
ledCtrl=HIGH;
return proceed;
}
result myLedOff() {
ledCtrl=LOW;
return proceed;
}
TOGGLE(ledCtrl,setLed,"Led: ",doNothing,noEvent,noStyle//,doExit,enterEvent,noStyle
,VALUE("On",HIGH,doNothing,noEvent)
,VALUE("Off",LOW,doNothing,noEvent)
);
int selTest=0;
SELECT(selTest,selMenu,"Select",doNothing,noEvent,noStyle
,VALUE("Zero",0,doNothing,noEvent)
,VALUE("One",1,doNothing,noEvent)
,VALUE("Two",2,doNothing,noEvent)
);
int chooseTest=-1;
CHOOSE(chooseTest,chooseMenu,"Choose",doNothing,noEvent,noStyle
,VALUE("First",1,doNothing,noEvent)
,VALUE("Second",2,doNothing,noEvent)
,VALUE("Third",3,doNothing,noEvent)
,VALUE("Last",-1,doNothing,noEvent)
);
// //customizing a prompt look!
// //by extending the prompt class
// class altPrompt:public prompt {
// public:
// altPrompt(constMEM promptShadow& p):prompt(p) {}
// Used printTo(navRoot &root,bool sel,menuOut& out, idx_t idx,idx_t len,idx_t panelNr) override {
// return out.printRaw(F("special prompt!"),len);;
// }
// };
MENU(subMenu,"Sub-Menu",doNothing,noEvent,noStyle
,OP("Sub1",doNothing,noEvent)
// ,altOP(altPrompt,"",doNothing,noEvent)
,EXIT("<Back")
);
uint16_t hrs=0;
uint16_t mins=0;
//define a pad style menu (single line menu)
//here with a set of fields to enter a date in YYYY/MM/DD format
altMENU(menu,timeMenu,"Time",doNothing,noEvent,noStyle,(systemStyles)(_asPad|Menu::_menuData|Menu::_canNav|_parentDraw)
,FIELD(hrs,"",":",0,11,1,0,doNothing,noEvent,noStyle)
,FIELD(mins,"","",0,59,10,1,doNothing,noEvent,wrapStyle)
);
char* constMEM hexDigit MEMMODE="0123456789ABCDEF";
char* constMEM hexNr[] MEMMODE={"0","x",hexDigit,hexDigit};
char buf1[]="0x11";
MENU(mainMenu,"Main menu",doNothing,noEvent,wrapStyle //
,OP("Op1",doNothing,noEvent)
,OP("Op2",doNothing,noEvent)
,OP("Op3",doNothing,noEvent)
// ,FIELD(test,"Test","%",0,100,10,1,doNothing,noEvent,wrapStyle)//seteaza o val in procente decimale si dupaia unitati ////////////////////////////////////////////////////////////////////
,altFIELD(decPlaces<3>::menuField,test,"Test","%",0,100,1,0.001,showEvent,anyEvent,wrapStyle) //works ok//////////////////////////////////////////////////////////////////////////////////
,SUBMENU(timeMenu)
,SUBMENU(subMenu)
,SUBMENU(setLed)
,OP("LED On",myLedOn,enterEvent)
,OP("LED Off",myLedOff,enterEvent)
,SUBMENU(selMenu)
,SUBMENU(chooseMenu)
,OP("Alert test",doAlert,enterEvent)
,EDIT("Hex",buf1,hexNr,doNothing,noEvent,noStyle)
,EXIT("<Exit")
);
#define MAX_DEPTH 2
//encoderIn<encA,encB> encoder;//simple quad encoder driver
// encoderInStream<encA,encB> encStream(encoder,4);// simple quad encoder fake Stream
//encoder<encA,encB> encoder;//simple quad encoder driver
//encoderInStream<encA,encB> encStream(encoder,4);// simple quad encoder fake Stream
//a keyboard with only one key as the encoder button
keyMap encBtn_map[]={{-encBtn,defaultNavCodes[enterCmd].ch}};//negative pin numbers use internal pull-up, this is on when low
keyIn<1> encButton(encBtn_map);//1 is the number of keys
//menuIn* inputsList[]={&encBuitton,&Serial};
//chainStream<2> in(inputsList);//1 is the number of inputs
//serialIn serial(Serial);
//MENU_INPUTS(in,&serial);
MENU_INPUTS(in,&encStream,&encButton);//,&serial);//////////////////////// //// ///
MENU_OUTPUTS(out,MAX_DEPTH
,U8G2_OUT(u8g2,colors,fontX,fontY,offsetX,offsetY,{0,0,U8_Width/fontX,U8_Height/fontY})
,SERIAL_OUT(Serial)
);
NAVROOT(nav,mainMenu,MAX_DEPTH,in,out);
////
result alert(menuOut& o,idleEvent e) {
if (e==idling) {
o.setCursor(0,0);
o.print("alert test");
o.setCursor(0,1);
o.print("[select] to continue...");
}
return proceed;
}
result doAlert(eventMask e, prompt &item) {
nav.idleOn(alert);
return proceed;
}
result idle(menuOut& o,idleEvent e) {
switch(e) {
case idleStart:o.setCursor(0,0);o.print("suspending menu!");break;
case idling:o.setCursor(0,1);o.print("suspended...");break;
case idleEnd:o.setCursor(0,2);o.print("resuming menu.");break;
}
return proceed;
}
////
//result alert(menuOut& o,idleEvent e) {
// if (e==idling) {
// o.setCursor(0,0);
// o.print("alert test");
// o.setCursor(0,1);
// o.print("press [select]");
// o.setCursor(0,2);
// o.print("to continue...");
// }
// return proceed;
//}
//result doAlert(eventMask e, prompt &item) {
// nav.idleOn(alert);
// return proceed;
//}
//when menu is suspended
//result idle(menuOut& o,idleEvent e) {
// o.clear();
// switch(e) {
// case idleStart:o.println("suspending menu!");break;
// case idling:o.println("suspended...");break;
// case idleEnd:o.println("resuming menu.");break;
// }
// return proceed;
//}
void setup() {
Serial.begin(115200);
while(!Serial);
Serial.println("menu 4.x test");Serial.flush();
clickEncoder.setAccelerationEnabled(true);
clickEncoder.setDoubleClickEnabled(false); // Disable doubleclicks makes the response faster. See: https://github.com/soligen2010/encoder/issues/6
encButton.begin();/////////////////////////////////////////////////////////y dont konoo
// encoder.begin();
// pinMode(LEDPIN,OUTPUT);//cant use pin 13 when using hw spi
// and on esp12 i2c can be on pin 2, and that is also led pin
// so check first if this is adequate for your board
// #if defined(USE_HWSPI)
SPI.begin();
u8g2.begin();
// #elif defined(USE_HWI2C)
// Wire.begin();
// u8g2.begin();
//#else
//#error "please choose your interface (I2c,SPI)"
// #endif
u8g2.setFont(fontName);
// u8g2.setBitmapMode(0);
// disable second option
//mainMenu[1].enabled=disabledStatus; //it makes second line Op2/mainMenu[1] or first line Op1/mainMenu[0]... of main menu unselectable if //uncommented
// nav.idleTask=idleON();//point a function to be used when menu is suspended
nav.idleOn();////sets menu to Idle at powerup.
Serial.println("setup done.");Serial.flush();
Timer1.initialize(1000);
Timer1.attachInterrupt(timerIsr);
}
void loop() {
nav.doInput();
// digitalWrite(LEDPIN, ledCtrl);
if (nav.changed(0)) {//only draw if menu changed for gfx device
//change checking leaves more time for other tasks
u8g2.firstPage();
do nav.doOutput(); while(u8g2.nextPage());
}
nav.doInput();
if (nav.sleepTask) {
u8g2.firstPage();
do {
u8g2.setFont(u8g2_font_4x6_tn);
//u8g2.setFont(u8g2_font_inb16_mr); // draw the current pixel width
u8g2.drawBox(0,55,1+test,2);
u8g2.setCursor(2+test , 58);
u8g2.print(test); // this value must be lesser than 128 unless U8G2_16BIT is set
//u8g2.setFont(u8g2_font_unifont_t_symbols);
//u8g2.setCursor(2+test, 32);
u8g2.setFont(u8g2_font_4x6_tr);
u8g2.drawStr(test-1, 64,"^"); ///this should become setpoint
u8g2.setCursor(2+test , 64);
u8g2.print(test,3);
u8g2.setFont(u8g2_font_6x10_tr);
} while ( u8g2.nextPage() );
} else {
if (nav.changed(0)) {
u8g2.firstPage();
do nav.doOutput(); while(u8g2.nextPage());
}
}
nav.timeOut=300; //menu goes idle after 300seconds of not useage
delay(25);//simulate other tasks delay
}
//}
//}
ok its very nice actually and it works great (my mistake forgot to change from int test to float test) but.... i have no control of the amount of zeroes after ",". or do I? or somthing like i write(1234567) and then move the "," where i need it like (1,234567),(12,34567),(123,4567) as means of inputing a value, or just something like 1.2345*10^3 scientific calculator format.
yes you do, on this part decPlaces<3>
change the number to desired places
the implementation is quite trivial, it took me some time to find the better way
template<uint8_t dps>//here a template parameter for the number of places
struct decPlaces {
template<typename T>
struct menuField:Menu::menuField<T> {//and here we are reusing the old menuField class
using Menu::menuField<T>::menuField;//even reusing the constructor as extra parameter are on outside template
idx_t printReflex(menuOut& o) const override;//only to change the way it prints out
};
};
and the we can implement the printing to whatever we want
template<uint8_t dps>
template<typename T>
idx_t decPlaces<dps>::menuField<T>::printReflex(menuOut& o) const {
return o.print(Menu::menuField<T>::reflex,dps);//just by changing here what its printed
}
,altFIELD(decPlaces<3>::menuField,test,"Test","%",0,100,1,0.001,showEvent,anyEvent,wrapStyle)//works ok
,altFIELD(decPlaces<4>::menuField,test,"Test","%",0,100,1,0.0001,showEvent,anyEvent,wrapStyle)//works ok
it works
but... still... lets say in my case i can only change value by selecting befor or after "'," and incrementing (counting by encoder ) to the desired value if i have 55.0000 and want to change it to 55.4321 it is a lot of counting by manual encoder so ... i was thinking of something like this
55.4000 55.4300 .. 55.4321 {confirm by pressing ... stuff... encButton}.
if you are using serial input you can type in the value for the field (nor checked with floats)...
clickencoder can use acceleration, rotating to same direction increases the stepping
something like
,FIELD(test,"Test","%",0,100,10,1,doNothing,noEvent,wrapStyle
off coures here are only 2 digits
you're welcome to join us at https://gitter.im/ArduinoMenu/Lobby
if you are using serial input you can type in the value for the field (nor checked with floats)...
clickencoder can use acceleration, rotating to same direction increases the stepping
it seems i cant get acceleration working at first i thought my hardware debouncer is overkill . but.. i changed it and the same whatever speed i turn the encoder it does not accelerate (change rate)
are you using the clickencoder (https://github.com/0xPIT/encoder)?
if not working please open a new issue, we are getting off topic here
Hi Rui: I made the custom menuField to work, at least for my setup ESP32 "core:1.0.0" HW Oled i2C 0.96 u8g2 driver
The number of places for decimals is defined by the user, you can change it at any time of the execution. Each field can have a different number of decimal places.
I share an example for those who may need it