I am in the process of updating my 1.44in Display menu with button debouncing, Code was initially posted to Arduino forums but I was quickly running out of memory so Converted to Teensy to continue working on it.
Here is my Current Code for the main file(named colors is included in the attachments to keep post less than 10,000 chars):
The problem I am encountering is my use of boolean operators in the code regarding Bounce2. I've defined 3 buttons, btnLeft, btnRight, and btnSelect. When I use boolean operators to detect the button presses I am trying to ensure only one button is pressed while also leaving options to detect multiple button presses. Currently it doesn't care if another button is being held when I specifiacly am trying to detect exclusivly 1 button press in the following code.
EDIT: For clarity, the "if" section of "void processButtons(){}" is still alowing multiple button presses instead of exclusivly just one at a time as I would assume the multiple boolean && operators depict. I am trying to perform an Exclusive && not somehow. Also, the code I posted to the arduino forum is at https://forum.arduino.cc/t/128x128-display-menu-template/614162 . My setup is exactly the same as pictured there except using a Teensy because the memory is greater.



END EDIT
It still works just not how I want it to, any clue as to what I am doing wrong? Thanks in advance for any help, as usual it is always appreciated!
Jorge
Here is my Current Code for the main file(named colors is included in the attachments to keep post less than 10,000 chars):
C++:
/* Copyright 2018-2022 Jorge Joaquin Pareja
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software without restriction, including without
limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
Software, and to permit persons to whom the Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
/* 128x128-Menu-Template.ino - Impliment a UTFT 128x128 SPI display menu template
This code is for the 1.44" TFT LCD Module using Adafruit's current libraries pulled fresh from github,
ignore the products linked video since the links included in the video, from the amazon seller, have
some older code that causes errors on this screen.
* 1.44" TFT LCD https://www.amazon.com/gp/product/B07B4BDWCL
* Adafruit GFX library https://github.com/adafruit/Adafruit-GFX-Library
* Adafruit HW Specific Library https://github.com/adafruit/Adafruit-ST7735-Library
Pinout Display:
These budget displays have what seem to be a misprinted silkscreen text that, at first sight, one
will think these are I2C. They are not! They are in fact SPI. Wire them as follows:
Display | Arduino
* 5V to +5V
* GND to GND
* GND to GND
* NC
* NC
* LED to 5V
* SCL to Digital 13
* SDA to Digital 11
* RS to Digital 7
* RST to Digital 6
* CS to Digital 5
Pinout Buttons (Active Low With Internal PU Resistors enabled, see setup().)
* Left to pin 4
* Right to pin 3
* Select to pin 2
*/
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <SPI.h>
#include <Bounce2.h>
#include "jjp-NamedColors.h" // pulled from wikipedia list of named colors and added some conversion notes using regex to convert between RGB565 and PC
Bounce2::Button btnLeft = Bounce2::Button();
Bounce2::Button btnRight = Bounce2::Button();
Bounce2::Button btnSelect = Bounce2::Button();
#define BTNLEFT_PIN 4
#define BTNRIGHT_PIN 3
#define BTNSELECT_PIN 2
#define DEBOUNCE2_INTERVAL_MS 25
const byte TFT_CS = 5; // Silkscreen label CS
const byte TFT_RST = 6; // Silkscreen label RST
const byte TFT_DC = 7; // Silkscreen label RS
//const byte TFT_SCLK = 13; // Silkscreen label SCL (Needs to be Connected even if this line is commented)
//const byte TFT_MOSI = 11; // Silkscreen label SDA (Needs to be Connected even if this line is commented)
// For 1.44" TFT with ST7735 use
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
///// Display, Font, and Padding constants, may need to be changed to int instead of byte values for larger
// screens when the values will excede 255
// Display Properties
const byte screenWidth = 128; // in pixels
const byte screenHeight = 128; // in pixels
// font properties
const byte fntWidth = 6; // in pixels
const byte fntHeight = 8; // in pixels
const byte screenMaxCharsPerLine = screenWidth/fntWidth;
const byte screenMaxLines = screenHeight/fntHeight;
// Padding in pixels, incase font is slightly off screen
const byte cpadding = 0; // column padding
const byte rpadding = 0; // row/line padding
// 21 Columns on a 1.44 (128x128) display. I use this for calculating the
// columns for text placement using setCursor, default font 6x8!
// DONE!! This can be populated in a for loop and account for alternate screen
// and font sizes, and also to possibly save memory, see setup().
int tft144Col[screenMaxCharsPerLine];
int tft144Row[screenMaxLines];
void cls(int color = c_Black, byte rotation = 1);
// Buttons
const byte bSelect = 2; // not yet implimented
const byte bLeft = 3;
const byte bRight = 4;
//pages
byte pageStartup = 0;
byte pageDRO = 1;
byte pageSettings_A = 2;
byte pageSettings_B = 3;
// Menu Settings and variables
byte mIndex = 5; // menu index
byte pIndex = 5; // previous page
byte cIndex = 5; // current page
const String sVersion = "V1.0";
void setup() {
// Use this for a 1.44" TFT
tft.initR(INITR_144GREENTAB);
// setup easy access for text positions
for (byte i = 0; i < screenMaxCharsPerLine; i++){
tft144Col[i] = (cpadding+(i*fntWidth));
}
for (byte i = 0; i < screenMaxLines; i++){
tft144Row[i] = (rpadding+(i*fntHeight));
}
// set the text color, and the background color so that new text will cover over any old text
// without having to blank the entire screen
setTextWhiteBlack(); // white text on black background, prevents having to redraw the entire screen
tft.setTextWrap(false); // disable wrapping of text
cls(c_Black, 1);
// configure buttons
btnLeft.attach( BTNLEFT_PIN, INPUT_PULLUP);
btnRight.attach( BTNRIGHT_PIN, INPUT_PULLUP);
btnSelect.attach(BTNSELECT_PIN, INPUT_PULLUP);
//Debonce intervals
btnLeft.interval( DEBOUNCE2_INTERVAL_MS);
btnRight.interval( DEBOUNCE2_INTERVAL_MS);
btnSelect.interval(DEBOUNCE2_INTERVAL_MS);
//
btnLeft.setPressedState( LOW);
btnRight.setPressedState( LOW);
btnSelect.setPressedState(LOW);
//
}
void loop() {
layoutScreen();
delay(50);
}
void layoutScreen(){
processButtons();
drawMenu(mIndex);
switch(mIndex){
case 1:
Page1();
break;
case 2:
Page2();
break;
case 3:
Page3();
break;
case 4:
Page4();
break;
case 5:
Page5();
break;
default:
Page5();
break;
}
}
void processButtons(){
btnLeft.update();
btnRight.update();
btnSelect.update();
// check if the pushbutton is pressed. If it is, the buttonState is HIGH:
if ((btnLeft.pressed() == true) && (btnRight.pressed() == false) && (btnSelect.pressed() == false)){
pIndex = mIndex;
mIndex -= 1;
}
if ((btnLeft.pressed() == false) && (btnRight.pressed() == true) && (btnSelect.pressed() == false)){
pIndex = mIndex;
mIndex += 1;
}
if( mIndex <= 0){ // loop around to the end page
mIndex = 5;
}
else if (mIndex > 5){ // loop around to the beginning page
mIndex = 1;
}
}
void Page1(){ // display Page 1
// "0123456789012345678901" // max 22 chars per line referance
setTextWhiteBlack();
pl("Page 1", 2,4);
}
void Page2(){ // display Page 2
// "0123456789012345678901" // max 22 chars per line referance
pl("Page 2", 2,4);
}
void Page3(){ // display Page 3
// "0123456789012345678901" // max 22 chars per line referance
pl("Page 3", 2,4);
}
void Page4(){ // display Page 4
// "0123456789012345678901" // max 22 chars per line referance
pl("Page 4", 2,4);
}
void Page5(){// Main Screen Page
// "0123456789012345678901" // max 22 chars per line referance
pl("Menu Template", 2,4);
pl(sVersion, 3, 8);
pl("using a",6,7);
pl("1.44\" TFT LCD", 7,4);
pl("By", 8,10);
pl("Jorge Pareja", 9, 5);
tft.setTextColor(c_Red, c_Black);
pl("Press Left Or Right", 13, 1);
pl("buttons To Begin", 14, 3);
}
void drawMenu(byte index) {// calling this will clear the screen and draw the menu on line 0, similar to tabbed pages. No need to modify, add code to Page#() functions instead
String page0 = "DRO ";
String page1 = " SA ";
String page2 = " SB ";
String page3 = " NA ";
cIndex = index;
setTextWhiteBlue();
if(pIndex != cIndex){
cls();
pIndex = cIndex;
}
if(index == 1){
setTextBlackRed();
pl(page0, 0, 1);
setTextWhiteBlue();
pl(page1, 0, 6);
pl(page2, 0, 11);
pl(page3, 0, 16);
}
else if(index == 2){
pl(page0, 0, 1);
setTextBlackRed();
pl(page1, 0, 6);
setTextWhiteBlue();
pl(page2, 0, 11);
pl(page3, 0, 16);
}
else if(index == 3){
pl(page0, 0, 1);
pl(page1, 0, 6);
setTextBlackRed();
pl(page2, 0, 11);
setTextWhiteBlue();
pl(page3, 0, 16);
}
else if(index == 4){
// Page 4
pl(page0, 0, 1);
pl(page1, 0, 6);
pl(page2, 0, 11);
setTextBlackRed();
pl(page3, 0, 16);
}
else if(index == 5){
// menu item not selected
pl(page0, 0, 1);
pl(page1, 0, 6);
pl(page2, 0, 11);
pl(page3, 0, 16);
}
setTextWhiteBlack();
}
void setTextWhiteBlue() {tft.setTextColor(c_White, c_Blue);}
void setTextWhiteBlack(){tft.setTextColor(c_White, c_Black);}
void setTextBlackRed() {tft.setTextColor(c_Black, c_Red);}
void uprint(String txt, int fg_color, int bg_color, byte lineNumber, byte columnNumber){
tft.setTextColor(fg_color, bg_color);
tft.setCursor(tft144Col[columnNumber], tft144Row[lineNumber]);
tft.print(txt);
}
void pl(String txt, byte lineNumber, byte columnNumber) { // print string based on the line and column numbers, calculated in the arrays
tft.setCursor(tft144Col[columnNumber], tft144Row[lineNumber]);
tft.print(txt);
}
void cls(int color = c_Black, byte rotation = 1){ // Clear the Screen w/ screen rotation
tft.setRotation(rotation);
tft.fillScreen(color);
}
The problem I am encountering is my use of boolean operators in the code regarding Bounce2. I've defined 3 buttons, btnLeft, btnRight, and btnSelect. When I use boolean operators to detect the button presses I am trying to ensure only one button is pressed while also leaving options to detect multiple button presses. Currently it doesn't care if another button is being held when I specifiacly am trying to detect exclusivly 1 button press in the following code.
C++:
void processButtons(){
btnLeft.update();
btnRight.update();
btnSelect.update();
// check if the pushbutton is pressed. If it is, the buttonState is HIGH:
if ((btnLeft.pressed() == true) && (btnRight.pressed() == false) && (btnSelect.pressed() == false)){
pIndex = mIndex;
mIndex -= 1;
}
if ((btnLeft.pressed() == false) && (btnRight.pressed() == true) && (btnSelect.pressed() == false)){
pIndex = mIndex;
mIndex += 1;
}
if( mIndex <= 0){ // loop around to the end page
mIndex = 5;
}
else if (mIndex > 5){ // loop around to the beginning page
mIndex = 1;
}
}
EDIT: For clarity, the "if" section of "void processButtons(){}" is still alowing multiple button presses instead of exclusivly just one at a time as I would assume the multiple boolean && operators depict. I am trying to perform an Exclusive && not somehow. Also, the code I posted to the arduino forum is at https://forum.arduino.cc/t/128x128-display-menu-template/614162 . My setup is exactly the same as pictured there except using a Teensy because the memory is greater.



END EDIT
It still works just not how I want it to, any clue as to what I am doing wrong? Thanks in advance for any help, as usual it is always appreciated!
Jorge
Attachments
Last edited: