neu-rah / ArduinoMenu

Arduino generic menu/interactivity system
GNU Lesser General Public License v2.1
933 stars 189 forks source link

Compatability with Adafruit 1.8" TFT V2 ? #290

Closed PeteMoog closed 4 years ago

PeteMoog commented 4 years ago

hi I am using a a mega 2560 with the Adafruit 1.8" TFT + joystick and 3 button shield (it's the V2 Shield) here https://www.adafruit.com/product/802

Is it possible to use ArduinoMenu with this shield? the shield uses i2c seesaw chip to communicate and I am struggling to get anything running (or even to compile) to use this board and ArduinoMeno, If there is any sample code that someone could direct me to it would be very helpful. even some ideas to the most suitable libraries or includes would be very helpful.

Do I use

include

include

from the shield example... OR

include

that rui uses in his example "menu_tft_test.ino"

This is my Arduio and first project, I fear I have bitten off more than I can chew!

FYI the board and shield are wired up correctly and the following example runs fine... https://learn.adafruit.com/1-8-tft-display/testing-the-shield

thanks in advance....

Pete

neu-rah commented 4 years ago

Hi Pete!

It should work...

feel free to add error messages or code to this issue :+1:

rui

PeteMoog commented 4 years ago

many thanks for the quick reply, i am on child care duties in the morning but will try as soon as i can get to my desk, 👍

PeteMoog commented 4 years ago

Hi again I have been working on this frequently since we last spoke but have been reluctant to ask for help as my C++ and arduino knowledge is so basic I thought I had better RTFM first, which I now have, my understanding is slightly greater but much of it is still a mystery.

I now have an example compiling and the screen displaying the default menu, I also know the buttons on the shield are being read via the SPI as I have put some code in the Void loop() to read the buttons using the shield's seesaw/SPI and when I press a button or move the joystick I see these being printed in the serial monitor view (i am using eclipse/sloeber).

#include <Arduino.h>

/********************
Sept. 2014 ~ Oct 2016 Rui Azevedo - ruihfazevedo(@rrob@)gmail.com

menu with adafruit GFX
output: 1.8" TFT 128*160 (ST7735 HW SPI)
input: Serial + encoder
www.r-site.net

alternative encoder (clickEncoder) uses:
https://github.com/0xPIT/encoder
https://github.com/PaulStoffregen/TimerOne
***/

//removed as extra libs are not included into travis
// #define USE_CLICK_ENCODER

#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <menu.h>
#include <menuIO/adafruitGfxOut.h>
#ifdef USE_CLICK_ENCODER
  #include <TimerOne.h>
  #include <ClickEncoder.h>
  #include <menuIO/clickEncoderIn.h>
#else
  #include <menuIO/encoderIn.h>
#endif
#include <menuIO/keyIn.h>
#include <menuIO/chainStream.h>
#include <menuIO/serialOut.h>
#include <menuIO/serialIn.h>
#include <Adafruit_seesaw.h>
#include <Adafruit_TFTShield18.h>

Adafruit_TFTShield18 ss;

using namespace Menu;

//ST7735 1.8TFT 128x160 This was original by RUI - replaced below by example from seesaw_shield18_test
// #define TFT_CS   A1
// #define TFT_DC   A0
// #define TFT_RST  A2

// #define SD_CS    4  // Chip select line for SD card on Shield            //from seesaw_shield18_test
#define TFT_CS  10  // Chip select line for TFT display on Shield       //from seesaw_shield18_test
#define TFT_DC   8  // Data/command line for TFT on Shield              //from seesaw_shield18_test
#define TFT_RST  -1  // Reset line for TFT is handled by seesaw!        //from seesaw_shield18_test

Adafruit_ST7735 gfx(TFT_CS, TFT_DC, TFT_RST);

#define LEDPIN A3

// rotary encoder pins
#define encA    2
#define encB    3
#define encBtn  4

result doAlert(eventMask e, prompt &item);

int test=55;

int ledCtrl=LOW;

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) override {
    return out.printRaw(F("special prompt!"),len);;
  }
};

MENU(subMenu,"Sub-Menu",doNothing,noEvent,noStyle
  ,altOP(altPrompt,"",doNothing,noEvent)
  ,OP("Op",doNothing,noEvent)
  ,EXIT("<Back")
);

char* constMEM hexDigit MEMMODE="0123456789ABCDEF";
char* constMEM hexNr[] MEMMODE={"0","x",hexDigit,hexDigit};
char buf1[]="0x11";

MENU(mainMenu,"Main test menu",doNothing,noEvent,wrapStyle
  ,OP("Speed",doNothing,noEvent)
  ,OP("Distance",doNothing,noEvent)
 // ,FIELD(test,"Test","%",0,100,10,1,doNothing,noEvent,wrapStyle)
  ,FIELD(test,"Pause int","%",0,100,10,1,doNothing,noEvent,wrapStyle)
  ,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("<Back")
);

// define menu colors --------------------------------------------------------
//  {{disabled normal,disabled selected},{enabled normal,enabled selected, enabled editing}}
//monochromatic color table

#define ST7735_GRAY RGB565(128,128,128)

const colorDef<uint16_t> colors[6] MEMMODE={
  {{(uint16_t)ST7735_BLACK,(uint16_t)ST7735_BLACK}, {(uint16_t)ST7735_BLACK, (uint16_t)ST7735_BLUE,  (uint16_t)ST7735_BLUE}},//bgColor
  {{(uint16_t)ST7735_GRAY, (uint16_t)ST7735_GRAY},  {(uint16_t)ST7735_WHITE, (uint16_t)ST7735_WHITE, (uint16_t)ST7735_WHITE}},//fgColor
  {{(uint16_t)ST7735_WHITE,(uint16_t)ST7735_BLACK}, {(uint16_t)ST7735_YELLOW,(uint16_t)ST7735_YELLOW,(uint16_t)ST7735_RED}},//valColor
  {{(uint16_t)ST7735_WHITE,(uint16_t)ST7735_BLACK}, {(uint16_t)ST7735_WHITE, (uint16_t)ST7735_YELLOW,(uint16_t)ST7735_YELLOW}},//unitColor
  {{(uint16_t)ST7735_WHITE,(uint16_t)ST7735_GRAY},  {(uint16_t)ST7735_BLACK, (uint16_t)ST7735_BLUE,  (uint16_t)ST7735_WHITE}},//cursorColor
  {{(uint16_t)ST7735_WHITE,(uint16_t)ST7735_YELLOW},{(uint16_t)ST7735_BLUE,  (uint16_t)ST7735_RED,   (uint16_t)ST7735_RED}},//titleColor
};

serialIn serial(Serial);

#ifdef USE_CLICK_ENCODER
  ClickEncoder clickEncoder(encA,encB,encBtn);
  ClickEncoderStream encStream(clickEncoder,1);
  MENU_INPUTS(in,&encStream,&serial);
  void timerIsr() {clickEncoder.service();}
#else
  encoderIn<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
  MENU_INPUTS(in,&encStream,&encButton,&serial);
#endif

#define MAX_DEPTH 4
#define textScale 1
MENU_OUTPUTS(out,MAX_DEPTH
  ,ADAGFX_OUT(gfx,colors,6*textScale,9*textScale,{0,0,14,8},{14,0,14,8})
  ,SERIAL_OUT(Serial)
);

NAVROOT(nav,mainMenu,MAX_DEPTH,in,out);

//when menu is suspended
result idle(menuOut& o,idleEvent e) {
  if (e==idling) {
    o.println(F("suspended..."));
    o.println(F("press [select]"));
    o.println(F("to continue"));
  }
  return proceed;
}

//config myOptions('*','-',defaultNavCodes,false);

void setup() {
  //options=&myOptions;//can customize options
  pinMode(TFT_CS, OUTPUT);
  digitalWrite(TFT_CS, LOW);
  pinMode(LEDPIN,OUTPUT);
  Serial.begin(9600);
  while(!Serial);
  Serial.println("menu 4.x V2 test");
  Serial.flush();
  nav.idleTask=idle;//point a function to be used when menu is suspended
  mainMenu[1].disable();
//outGfx.usePreview=true;//reserve one panel for preview?
//nav.showTitle=false;//show menu title?

// Start seesaw helper chip
   if (!ss.begin()){
     Serial.println("seesaw could not be initialized!");
     while(1);
   }
   Serial.println("seesaw started");
   Serial.print("Version: "); Serial.println(ss.getVersion(), HEX);

// Start set the backlight off
//ss.setBacklight(TFTSHIELD_BACKLIGHT_OFF);

// Reset the TFT
  ss.tftReset();

// Initialize 1.8" TFT
  gfx.initR(INITR_BLACKTAB);   // initialize a ST7735S chip, black tab

//Serial.println("TFT OK!");

  ss.setBacklight(64000);

  //pinMode(encBtn, INPUT_PULLUP);
  #ifdef USE_CLICK_ENCODER
    Timer1.initialize(1000);
    Timer1.attachInterrupt(timerIsr);
  #else
    encButton.begin();
    encoder.begin();
  #endif

  SPI.begin();
  gfx.initR(INITR_BLACKTAB);
  gfx.setRotation(3);
  gfx.setTextSize(textScale);//test scalling
  gfx.setTextWrap(false);
  gfx.fillScreen(ST7735_BLACK);
  gfx.setTextColor(ST7735_RED,ST7735_BLACK);
  gfx.println("Menu 4.x test GFX");
  delay(1000);
}

uint8_t buttonhistory = 0;
uint8_t oldbuttonhistory =0;

void loop() {

// Following block reads switch inputs from SPI interface (seesaw) copied from seesaw_shield18
    uint32_t buttons = ss.readButtons();
      if(! (buttons & TFTSHIELD_BUTTON_DOWN)){      // DOWN
          buttonhistory |= 1;
      }
      if(! (buttons & TFTSHIELD_BUTTON_LEFT)){      // LEFT
        buttonhistory |= 2;
      }
      if(! (buttons & TFTSHIELD_BUTTON_UP)){        // UP
        buttonhistory |= 4;
      }
      if(! (buttons & TFTSHIELD_BUTTON_RIGHT)){     // RIGHT
        buttonhistory |= 8;
      }
      if(! (buttons & TFTSHIELD_BUTTON_1)){         // Button 1
        buttonhistory |= 16;
      }
      if(! (buttons & TFTSHIELD_BUTTON_2)){         // Button 2
        buttonhistory |= 32;
      }
      if(! (buttons & TFTSHIELD_BUTTON_3)){         // Button 3
        buttonhistory |= 64;
      }
      if (! (buttons & TFTSHIELD_BUTTON_IN)) {      // Button IN
          buttonhistory |= 128;
      }
      if (oldbuttonhistory != buttonhistory) {
          serial.println(buttonhistory);
      }
      oldbuttonhistory = buttonhistory;
//    Serial.println(TFTSHIELD_BUTTON_1);
//    Serial.println(buttons);
  nav.poll();//this device only draws when needed
  digitalWrite(LEDPIN, ledCtrl);
  delay(1000);//simulate a delay when other tasks are done
  buttonhistory = 0;
}

What I am completely stuck on is how to I transfer the button presses on the shield into Serial input to control ArduinoMenu?

Any example code or examples would be greatly appreciated.

Thanks in advance

P

PeteMoog commented 4 years ago

Hi Rui I have found an example called "codeCtrl.ino" and noticed the "nav.donav(upCmd)" statements, I added these to my loop section as follows and I now have a working screen and the joystick almost works. I cant seem to enter any submenus, or change the 55% in the example, why could that be?

As you can see I started trying to write commands to serialIn so I could concatenate this stream using Chainstream and subsequently after a bit more reading I would have used MENU_INPUTS after realising this does the same thing as chainstream. Would any of the previous methods I mention been better that method I am posting now?

I want to use ArduinoMenu to control a few stepper motors, they must run uninterrupted and run at a defined speed and defined number of steps, I will use the menu so I can set these parameters. The duration of this may be as much as 30 minutes and the steppers should run uninterrupted with the exception of a possible ABORT command driven from a dedicated hardware button on the shield should things go wrong in the physical world.

void loop() {

// Following block reads switch inputs from SPI interface (seesaw) copied from seesaw_shield18
    uint32_t buttons = ss.readButtons();
      if(! (buttons & TFTSHIELD_BUTTON_DOWN)){      // DOWN
          buttonhistory |= 1;
//        strIn.write(downCmd);
          nav.doNav(downCmd);
      }
      if(! (buttons & TFTSHIELD_BUTTON_LEFT)){      // LEFT
        buttonhistory |= 2;
//      strIn.write(leftCmd);
        nav.doNav(leftCmd);
      }
      if(! (buttons & TFTSHIELD_BUTTON_UP)){        // UP
        buttonhistory |= 4;
//      strIn.write(upCmd);
        nav.doNav(upCmd);
      }
      if(! (buttons & TFTSHIELD_BUTTON_RIGHT)){     // RIGHT
        buttonhistory |= 8;
//      strIn.write(rightCmd);
        nav.doNav(rightCmd);
      }
      if(! (buttons & TFTSHIELD_BUTTON_1)){         // Button 1
        buttonhistory |= 16;
//      strIn.write(Button1=1);
      }
      if(! (buttons & TFTSHIELD_BUTTON_2)){         // Button 2
        buttonhistory |= 32;
//      strIn.write(Button2=1);
      }
      if(! (buttons & TFTSHIELD_BUTTON_3)){         // Button 3
        buttonhistory |= 64;
//      strIn.write(Button3=1);
      }
      if (! (buttons & TFTSHIELD_BUTTON_IN)) {      // Button IN
          buttonhistory |= 128;
//        strIn.write(idxCmd);
          nav.doNav(upCmd);
      }
      if (oldbuttonhistory != buttonhistory) {
          serial.println(buttonhistory);

      }
      oldbuttonhistory = buttonhistory;
//    Serial.println(TFTSHIELD_BUTTON_1);
//    Serial.println(buttons);
  nav.poll();//this device only draws when needed
  digitalWrite(LEDPIN, ledCtrl);
  delay(1000);//simulate a delay when other tasks are done
  buttonhistory = 0;
}
PeteMoog commented 4 years ago

PS. I also joined the Gitter bbut I think people are away on bank holidays...

neu-rah commented 4 years ago

Hi Pete

Thanks for sharing the code... yes, gitter was a bit abandoned but text stays there, I'm on a kindo of holiday cabling my home made CNC.

PeteMoog commented 4 years ago

Stay on holiday, please dont talk to me again until it's Finished 👍

When you are back from holiday tell me how big your CNC is.

PS. fixed the select menu thing, it was a typo.

PeteMoog commented 4 years ago

All almost work, as few small glitches with secondary panel having blank lines when scrolling down the main panel but sure its something I have done. Will close this issue and open a fresh one if I can resolve it. Thanks for your help Rui.