SSD1306 OLED Blinking display Cursor

Hi all,

I have a beginner-to-hobbyist level of programming proficiency with Arduino boards (get that out of the way first lol) I am building this project Waveform Generator but I am porting the display code over to use the SSD1306 graphic display instead of a 16x2 character display, which is mostly done so far aside from placing data where I want it.

The only part I am stuck on is that the LiquidCrystal_I2C library code has a blink function for when you wish to interact with menu selections. The SSD1306/Arduino_GFX library does not have this as far as I can tell. I have read a possible way about it is to invert the pixels in the character block back and forth but I do not know how to do this in a way that will not interfere with the process of selecting things. Like I know the delay(); function stops everything, so I am not sure how to go about it. I am also open to other ideas if you think some other cursor idea would be better.

Here are some links to the libraries I am using:
Arduino_GFX
Adafruit_SSD1306

I can post my code if needed, its kinda long for a forum post though, I might need to attach it somewhere if that's allowed or cloud host it.

Thanks!

Welcome to the forum

Use millis() for timing instead of delay()

See Using millis() for timing. A beginners guide, Several things at the same time and the BlinkWithoutDelay example in the IDE

1 Like

Welcome to the forum.
Posting your code is the only way to get advice on modifying said code, right?
Do the following:

  • In the Arduino IDE, press ctrl-T. That will format your code.
  • press Ctrl-shft-C to copy the code for the forum. (or, select menu item "copy for Forum").
  • in a new message in this thread, press Ctrl-V. That will insert your entire code, properly formatted. That way, we can copy it to our IDE for inspection, or read it onscreen in order to comment on it.

Thanks

1 Like

Ok here you go, the menu starts shortly after the main loop() starts:

//#include "LiquidCrystal_I2C.h"
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "AD9833.h"
#include "Rotary.h"
#include <SPI.h>
#include <Wire.h>

#define SCREEN_WIDTH   128  // OLED display width, in pixels
#define SCREEN_HEIGHT  64   // OLED display height, in pixels
#define OLED_RESET     -1   // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define LOGO_HEIGHT    32
#define LOGO_WIDTH     32

static const unsigned char PROGMEM Sine_bmp[] =
{ B00000111,B11100000,B00000000,B00000000,
  B00001000,B00010000,B00000000,B00000000,
  B00010000,B00001000,B00000000,B00000000,
  B00100000,B00000100,B00000000,B00000000,
  B00100000,B00000100,B00000000,B00000000,
  B01000000,B00000010,B00000000,B00000000,
  B01000000,B00000010,B00000000,B00000000,
  B10000000,B00000001,B00000000,B00000000,
  B10000000,B00000001,B00000000,B00000000,
  B10000000,B00000001,B00000000,B00000000,
  B10000000,B00000001,B00000000,B00000000,
  B10000000,B00000001,B00000000,B00000000,
  B10000000,B00000001,B00000000,B00000000,
  B10000000,B00000001,B00000000,B00000000,
  B10000000,B00000001,B00000000,B00000000,
  B10000000,B00000001,B00000000,B00000000,
  B01000100,B01000101,B01000100,B01000110,
  B00000000,B00000001,B00000000,B00000010,
  B00000000,B00000001,B00000000,B00000010,
  B00000000,B00000001,B00000000,B00000010,
  B00000000,B00000001,B00000000,B00000010,
  B00000000,B00000001,B00000000,B00000010,
  B00000000,B00000001,B00000000,B00000010,
  B00000000,B00000001,B00000000,B00000010,
  B00000000,B00000001,B00000000,B00000010,
  B00000000,B00000000,B10000000,B00000100,
  B00000000,B00000000,B10000000,B00000100,
  B00000000,B00000000,B01000000,B00001000,
  B00000000,B00000000,B01000000,B00001000,
  B00000000,B00000000,B00100000,B00010000,
  B00000000,B00000000,B00010000,B00100000,
  B00000000,B00000000,B00001111,B11000000};

static const unsigned char PROGMEM Tri_bmp[] =
{ B00000000,B00000000,B00000000,B00000000,
  B00000001,B10000000,B00000000,B00000000,
  B00000001,B10000000,B00000000,B00000000,
  B00000010,B01000000,B00000000,B00000000,
  B00000010,B01000000,B00000000,B00000000,
  B00000100,B00100000,B00000000,B00000000,
  B00000100,B00100000,B00000000,B00000000,
  B00001000,B00010000,B00000000,B00000000,
  B00001000,B00010000,B00000000,B00000000,
  B00010000,B00001000,B00000000,B00000000,
  B00010000,B00001000,B00000000,B00000000,
  B00100000,B00000100,B00000000,B00000000,
  B00100000,B00000100,B00000000,B00000000,
  B01000000,B00000010,B00000000,B00000000,
  B01000000,B00000010,B00000000,B00000000,
  B10000000,B00000001,B00000000,B00000000,
  B01000100,B01000101,B11000100,B01000110,
  B00000000,B00000000,B10000000,B00000100,
  B00000000,B00000000,B10000000,B00000100,
  B00000000,B00000000,B01000000,B00001000,
  B00000000,B00000000,B01000000,B00001000,
  B00000000,B00000000,B00100000,B00010000,
  B00000000,B00000000,B00100000,B00010000,
  B00000000,B00000000,B00010000,B00100000,
  B00000000,B00000000,B00010000,B00100000,
  B00000000,B00000000,B00001000,B01000000,
  B00000000,B00000000,B00001000,B01000000,
  B00000000,B00000000,B00000100,B10000000,
  B00000000,B00000000,B00000100,B10000000,
  B00000000,B00000000,B00000011,B00000000,
  B00000000,B00000000,B00000011,B00000000,
  B00000000,B00000000,B00000000,B00000000};

static const unsigned char PROGMEM Square_bmp[] =
{ B00000000,B00000000,B00000000,B00000000,
  B11111111,B11111111,B00000000,B00000000,
  B10000000,B00000001,B00000000,B00000000,
  B10000000,B00000001,B00000000,B00000000,
  B10000000,B00000001,B00000000,B00000000,
  B10000000,B00000001,B00000000,B00000000,
  B10000000,B00000001,B00000000,B00000000,
  B10000000,B00000001,B00000000,B00000000,
  B10000000,B00000001,B00000000,B00000000,
  B10000000,B00000001,B00000000,B00000000,
  B10000000,B00000001,B00000000,B00000000,
  B10000000,B00000001,B00000000,B00000000,
  B10000000,B00000001,B00000000,B00000000,
  B10000000,B00000001,B00000000,B00000000,
  B10000000,B00000001,B00000000,B00000000,
  B10000000,B00000001,B00000000,B00000000,
  B01000100,B01000101,B11000100,B01000110,
  B00000000,B00000001,B00000000,B00000010,
  B00000000,B00000001,B00000000,B00000010,
  B00000000,B00000001,B00000000,B00000010,
  B00000000,B00000001,B00000000,B00000010,
  B00000000,B00000001,B00000000,B00000010,
  B00000000,B00000001,B00000000,B00000010,
  B00000000,B00000001,B00000000,B00000010,
  B00000000,B00000001,B00000000,B00000010,
  B00000000,B00000001,B00000000,B00000010,
  B00000000,B00000001,B00000000,B00000010,
  B00000000,B00000001,B00000000,B00000010,
  B00000000,B00000001,B00000000,B00000010,
  B00000000,B00000001,B00000000,B00000010,
  B00000000,B00000001,B11111111,B11111110,
  B00000000,B00000000,B00000000,B00000000};

//Uncomment the line below if you want to change the Phase instead of the FREQ register
//#define usePhase

AD9833 sigGen(10, 24000000); // Initialise our AD9833 with FSYNC pin = 10 and a master clock frequency of 24MHz
//LiquidCrystal_I2C lcd(0x27, 16, 2); // LCD Initialise

Rotary encoder(2, 3);// Initialise the encoder on pins 2 and 3 (interrupt pins)

// Variables used to input data and walk through menu
unsigned long encValue;        // Value used by encoder
unsigned long lastButtonPress; // Value used by button debounce
unsigned char lastButtonState;
unsigned char settingsPos[] = {0, 14, 20, 29};
unsigned char button;
volatile unsigned char cursorPos = 0;
unsigned char lastCursorPos = 0;
unsigned char menuState = 0;
const int buttonPin = 1;
int digitPos = 0;
const unsigned long maxFrequency = 14000000;
const unsigned int maxPhase = 4095; // Only used if you enable PHASE setting instead of FREQ register
unsigned long newFrequency = 1000;
volatile bool updateDisplay = false;
unsigned long depressionTime;
int freqRegister = 0; // Default FREQ register is 0
// LCD constants
const String powerState[] = {" ON", "OFF"};
const String mode[] = {"SIN", "TRI", "CLK"};
// Variables used to store phase, frequency, mode and power
unsigned char currentMode = 0;
unsigned long frequency0 = 1000;
unsigned long frequency1 = 1000;
unsigned long frequency = frequency0;
unsigned long currFrequency; // Current frequency used, either 0 or 1
unsigned long phase = 0; // Only used if you enable PHASE setting instead of FREQ register
unsigned char currentPowerState = 0;
// Greek PHI symbol for phase shift
// Only used if you enable PHASE setting instead of FREQ register
uint8_t phi[8] = {0b01110, 0b00100, 0b01110, 0b10101,
                  0b10101, 0b01110, 0b00100, 0b01110
                 };

void setup() {
  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }
  // Initialise the LCD, start the backlight and print a "bootup" message for two seconds
  //lcd.begin();
  //lcd.backlight();
  //lcd.createChar(0, phi); // Custom PHI char for LCD
  //lcd.home();
  //lcd.print("AllAboutCircuits");
  //lcd.setCursor(0, 1);
  //lcd.print("Signal Generator");
  //delay(2000);
  // Display initial set values for freq, phase, mode and power
  //lcd.clear();

  //Boot screen  ---------------------------------------------------------
  display.setTextSize(1);      // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE); // Draw white text
  display.clearDisplay();
  display.setCursor(0,0);
  display.println(F("JN Signal Generator"));
  display.setCursor(0,12);
  display.println(F("Firmware v1.0.1"));
  display.setCursor(0,54);
  display.println(F("9/27/2023"));
  display.display();
  delay(2500); // Pause for 2ish seconds
  display.clearDisplay();
  //----------------------------------------------------------------------

  display.setCursor(0,10);
  displayFrequency();
  displayMode();
#ifdef usePhase
  displayPhase();
#endif
  displayPower();
#ifndef usePhase
  displayFreqRegister();
#endif
  // Initialise the AD9833 with 1KHz sine output, no phase shift for both
  // registers and remain on the FREQ0 register
  // sigGen.lcdDebugInit(&lcd);
  sigGen.reset(1);
  sigGen.setFreq(frequency0);
  sigGen.setPhase(phase);
  sigGen.setFPRegister(1);
  sigGen.setFreq(frequency1);
  sigGen.setPhase(phase);
  sigGen.setFPRegister(0);
  sigGen.mode(currentMode);
  sigGen.reset(0);

  // Set pins A and B from encoder as interrupts
  attachInterrupt(digitalPinToInterrupt(2), encChange, CHANGE);
  attachInterrupt(digitalPinToInterrupt(3), encChange, CHANGE);
  // Initialise pin as input with pull-up enabled and debounce variable for
  // encoder button
  pinMode(1, INPUT_PULLUP);
  lastButtonPress = millis();
  lastButtonState = 1;
  button = 1;
  // Set Cursor to initial possition
  display.setCursor(0, 0);
}

void loop() {
  // Check to see if the button has been pressed
  checkButton();
  // Update display if needed
  if (updateDisplay == true) {
    displayFrequency();
#ifdef usePhase
    displayPhase();
#endif
    displayPower();
#ifndef usePhase
    displayFreqRegister();
#endif
    displayMode();
    updateDisplay = false;
  }
  // We are using the variable menuState to know where we are in the menu and
  // what to do in case we press the button or increment/drecrement via the
  // encoder
  // Enter setting mode if the button has been pressed and display blinking
  // cursor over options (menuState 0)
  // Pick a setting (menuState 1)
  // Change that particular setting and save settings (menuState 2-5)

  switch (menuState) {
    // Default state
    case 0: {
        display.noBlink();   //Maybe use inverted text for this line?  Does GFX library have a blink?
        if (button == 0) {
          button = 1;
          display.setCursor(0, 0);
          display.blink();
          menuState = 1;
          cursorPos = 0;
        }
      } break;
    // Settings mode
    case 1: {
        if (button == 0) {
          button = 1;
          // If the setting in Power just toggle between on and off
          if (cursorPos == 1) {
            currentPowerState = abs(1 - currentPowerState);
            updateDisplay = true;
            menuState = 0;
            if (currentPowerState == 1)
              sigGen.sleep(3); // Both DAC and clock turned OFF
            else
              sigGen.sleep(0); // DAC and clock are turned ON
          }
          // If usePhase has not been set
#ifndef usePhase
          else if (cursorPos == 2) {
            updateDisplay = true;
            menuState = 0; // return to "main menu"
            if (freqRegister == 0) {
              freqRegister = 1;
              sigGen.setFPRegister(1);
              frequency = frequency1;
            } else {
              freqRegister = 0;
              sigGen.setFPRegister(0);
              frequency = frequency0;
            }
          }
#endif
          // Otherwise just set a new state
          else
            menuState = cursorPos + 2;
        }
        // Move the cursor position in case it changed
        if (lastCursorPos != cursorPos) {
          unsigned char realPosR = 0;
          unsigned char realPosC;
          if (settingsPos[cursorPos] < 16)
            realPosC = settingsPos[cursorPos];
          else {
            realPosC = settingsPos[cursorPos] - 16;
            realPosR = 1;
          }
          display.setCursor(realPosC, realPosR);
          lastCursorPos = cursorPos;
        }
      } break;
    // Frequency setting
    case 2: {
        // Each button press will either enable to change the value of another digit
        // or if all digits have been changed, to apply the setting
        if (button == 0) {
          button = 1;
          if (digitPos < 7)
            digitPos++;
          else {
            digitPos = 0;
            menuState = 0;
            sigGen.setFreq(frequency);
          }
        } else if (button == 2) {
          button = 1;
          digitPos = 0;
          menuState = 0;
        }
        // Set the blinking cursor on the digit you can currently modify
        display.setCursor(9 - digitPos, 0);
      } break;

    // Phase setting
    case 4: {
        if (button == 0) {
          button = 1;
          if (digitPos < 3)
            digitPos++;
          else {
            digitPos = 0;
            menuState = 0;
            sigGen.setPhase(phase);
          }
        }
        display.setCursor(5 - digitPos, 1);
      } break;
    // Change the mode (sine/triangle/clock)
    case 5: {
        if (button == 0) {
          button = 1;
          menuState = 0;
          sigGen.mode(currentMode);
        }
        display.setCursor(13 ,1);
      } break;
    // Just in case we messed something up
    default: {
        menuState = 0;
      }
  }
}
// Function to debounce the button
// 0 = pressed, 1 = depressed, 2 = long press
void checkButton() {
  if ((millis() - lastButtonPress) > 100) {
    if (digitalRead(buttonPin) != lastButtonState) {
      button = digitalRead(buttonPin);
      lastButtonState = button;
      lastButtonPress = millis();
    }
  }
}

void encChange() {
  // Depending in which menu state you are
  // the encoder will either change the value of a setting:
  //-+ frequency, change between FREQ0 and FREQ1 register (or -+ phase), On/Off, mode
  // or it will change the cursor position
  unsigned char state = encoder.process();
  // Direction clockwise
  if (state == DIR_CW) {
    switch (menuState) {
      case 1: {
          if (cursorPos == 3)
            cursorPos = 0;
          else
            cursorPos++;
        } break;

      case 2: {
          // Here we initialise two variables.
          // newFrequency is the value of the frequency after we increment it
          // dispDigit is the digit that we are currently modifing, and we obtain it
          // by a neat little trick, using operator % in conjunction with division
          // We then compare these variables with the maximum value for our
          // frequency, if all is good, make the change
          unsigned long newFrequency = frequency + power(10, digitPos);
          unsigned char dispDigit =
            frequency % power(10, digitPos + 1) / power(10, digitPos);
          if (newFrequency <= maxFrequency && dispDigit < 9) {
            frequency += power(10, digitPos);
            updateDisplay = true;
          }

          if (freqRegister == 0) {
            frequency0 = frequency;
          } else if (freqRegister == 1) {
            frequency1 = frequency;
          }

        } break;

      case 4: {
          // if usePhase has been defined, changes in the encoder will vary the phase
          // value (upto 4096)
          // A better implementation would be to use increment of pi/4 or submultiples of
          // pi where 2pi = 4096
#ifdef usePhase
          unsigned long newPhase = phase + power(10, digitPos);
          unsigned char dispDigit =
            phase % power(10, digitPos + 1) / power(10, digitPos);
          if (newPhase < maxPhase && dispDigit < 9) {
            phase += power(10, digitPos);
            updateDisplay = true;
          }
#endif
        } break;

      case 5: {
          if (currentMode == 2)
            currentMode = 0;
          else
            currentMode++;
          updateDisplay = true;
        } break;
    }
  }
  // Direction counter clockwise
  else if (state == DIR_CCW) {
    switch (menuState) {
      case 1: {
          if (cursorPos == 0)
            cursorPos = 3;
          else
            cursorPos--;
        } break;

      case 2: {
          unsigned long newFrequency = frequency + power(10, digitPos);
          unsigned char dispDigit =
            frequency % power(10, digitPos + 1) / power(10, digitPos);
          if (newFrequency > 0 && dispDigit > 0) {
            frequency -= power(10, digitPos);
            updateDisplay = true;
          }

          if (freqRegister == 0) {
            frequency0 = frequency;
          } else if (freqRegister == 1) {
            frequency1 = frequency;
          }
        } break;

      case 4: {
          // if usePhase has been defined, changes in the encoder will vary the phase
          // value (upto 4096)
          // A better implementation would be to use increment of pi/4 or submultiples of
          // pi where 2pi = 4096
#ifdef usePhase
          unsigned long newPhase = phase + power(10, digitPos);
          unsigned char dispDigit =
            phase % power(10, digitPos + 1) / power(10, digitPos);
          if (newPhase > 0 && dispDigit > 0) {
            phase -= power(10, digitPos);
            updateDisplay = true;
          }
#endif
        } break;

      case 5: {
          if (currentMode == 0)
            currentMode = 2;
          else
            currentMode--;
          updateDisplay = true;
        } break;
    }
  }
}
// Function to display the current frequency in the top left corner
void displayFrequency() {
  unsigned long frequencyToDisplay = frequency;
  display.setCursor(0, 10);  //show on second "line"
  display.print("f=");
  for (int i = 7; i >= 0; i--) {
    unsigned char dispDigit = frequencyToDisplay / power(10, i);
    display.print(dispDigit);
    frequencyToDisplay -= dispDigit * power(10, i);
  }
  display.print("Hz");
}
// Function to display power state (ON/OFF) in the top right corner
void displayPower() {
  display.setCursor(13, 0);  //Need to find a new place for this, probably under the graphic
  display.print(powerState[currentPowerState]);
}
// Function to display the mode in the bottom right corner
void displayMode() {
  display.setCursor(34, 0);   //Move this to top line, centered to the left of the graphic.  How do i want to align?
  display.print(mode[currentMode]);
}
// Function to display the mode in the bottom left corner
// Only used if you enable PHASE setting instead of FREQ register
void displayPhase() {
  unsigned int phaseToDisplay = phase;
  display.setCursor(0, 1);
  //display.write(0);  //write a single character?  this needs to be modified for use with new library
  display.print("ph=");  //added ph I think the line above is a phase character.  Dont really need it
  for (int i = 3; i >= 0; i--) {
    unsigned int dispDigit = phaseToDisplay / power(10, i);
    display.print(dispDigit);
    phaseToDisplay -= dispDigit * power(10, i);
  }
}
// Function to display the FREQ register (either 0 or 1) in the bottom left
// corner
void displayFreqRegister() {
  display.setCursor(0, 1);  //Not sure where to put this
  display.print("FREQ");
  display.print(freqRegister);
}

unsigned long power(int a, int b) {
  unsigned long res;
  if (b == 0) {
    res = 1;
  } else {
    res = a;
    for (int i = 0; i < (b - 1); i++) {
      res *= a;
    }
  }
  return res;
}


/*

Need some way of creating a blinking cursor, I dont think the GFX/SSD1306 libraries have one.
--They do not, crap


*/

Excellent!
Okay. Not going to write it for you, but here's how I'd attack it.

  • call a blink() function from loop(). It needs three variables, as I see it
    -- blink location (other code sets this)
    -- blink enabled (other code sets/clears this)
    -- blink state (can be local static)

In the blink() function, just use a millis() timer, similar to the 100 ms use in the button routine, to determine whether it's time to toggle the cursor.
You may also need to track turning off the cursor, to avoid leaving a 'track' onscreen when it's disabled.

1 Like

Ok so as far as blink location goes, the old code uses a character location for positioning text. The Graphics one uses a pixel location, so (0,10) starts from top leftmost pixel, down 10 pixels and that's where it displays the first character (starting from the top leftmost pixel of the character I think). So I don't see how the display would know what character is already in that position in order to create an inverted block of it, so I guess I have to use a solid pixel block that is the same area as one character? Thanks for the help so far! The gears are turning I am still thinking of how to implement this. I have to read up on that millis() function too.

1 Like

Nope, that's up to the programmer!

1 Like

There are a few things in the Adafruit libraries that can help with this.

The Adafruit_GFX library has the functions getCursorX() and getCursorY() that return the current cursor X and Y coordinates.

The Adafruit_SSD1306 library function drawPixel() will invert the current pixel at a specific X Y coordinate if you give it SSD1306_INVERSE as the pixel color:

oled.drawPixel(<x coordinate>, <y coordinate>, SSD1306_INVERSE);

With a fixed-pitch font it is fairly straightforward to write a function that will invert all the pixels within a character-sized box around the current cursor position. This becomes more complex with a variable-pitch font, because you then have to know what character is being displayed, and get the bounds of that character from the library.

2 Likes

Here is a function I use on an Adafruit Clue OLED screen to allow two-button adjustment of an integer variable.

The function prints the variable value on the screen, underlines it, then blinks a digit that can be incremented by a button press. Another button selects the result and moves one digit to the right. A timeout ends and accepts data entry.

// adjustVariable
// interactively change value of input variable using A and B buttons
// two second timeout ends input and returns
// A selects digit
// B increases digit

unsigned int adjustVariable(unsigned int value) {
  uint32_t timeout = 2000; //millis
  uint8_t textsize = 3;
  uint16_t x0 = (((240 / (6 * textsize)) - 5) / 2) * (6 * textsize); //center the string
  uint16_t y0 = 8 * textsize;  //skip a line down
  arcada.display->fillScreen(ARCADA_BLACK);
  char buf[8] = {0}; //variable display buffer
  sprintf(buf, "%05u", value);
  arcada.display->setCursor(x0, y0);  //display the value to be changed.
  arcada.display->setTextSize(textsize);
  arcada.display->setTextColor(ARCADA_GREEN);
  arcada.display->println(buf);
  arcada.display->setCursor(x0, y0 + 8 * textsize);
  arcada.display->println("-----");  //underline the value
  int i = 0;
  int16_t invert = 1;  //state variable for blinking character
  uint32_t now1 = millis();
  uint32_t now2 = millis();

  while (1) {
    delay(10); //needed for button check
    arcada.readButtons();
    if (millis() - now1 > 250) { //blink the character to be modified at 2 Hz
      invert = !invert;
      now1 = millis();
    }
    if (invert)
      arcada.display->drawChar(x0 + 6 * textsize * i, y0, buf[i], ARCADA_BLACK, ARCADA_GREEN, textsize);
    else
      arcada.display->drawChar(x0 + 6 * textsize * i, y0, buf[i], ARCADA_GREEN, ARCADA_BLACK, textsize);

    uint32_t released = arcada.justReleasedButtons();

    if (released & ARCADA_BUTTONMASK_A) { //next digit
      if (invert) //make sure it is drawn in foreground color
        arcada.display->drawChar(x0 + 6 * textsize * i, y0, buf[i], ARCADA_GREEN, ARCADA_BLACK, textsize);
      i++; //next char
      if (i >= strlen(buf)) i = 0;
      now2 = millis(); //update timeout
    }
    if (released & ARCADA_BUTTONMASK_B) {
      buf[i]++; //inc value in ASCII
      if (buf[i] > '9') buf[i] = '0';
      now2 = millis(); //update timeout
    }
    if (millis() - now2 > timeout) {
      return atoi(buf); //timed out
    }
  }
}
1 Like

oooh interesting...So if I set the cursor to 10 pixels over and 5 pixels down with display.write(10,5) , print some text, and then getCursorX and getCursorY, will that give me the starting cursor value I set or does it return the cursor position AFTER the text characters? I will have to play with this function and see what I can do with it.

Again I think I just about passed the basics of arduino programming and I'm getting to more difficult things like this, so I apologize if I sound like a dummy approaching this in baby steps.

I am reading through the menu code and I am starting to think this is a bit over my head. I am not even entirely sure how it works so Idk how i'll be able to change it the way I want.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.