Is the problem in the code or in the OLED screen?

Thanks for the explanation. To be honest I am not fully convinced about this, let explain why. Imagine that instead of a rotary encoder I am using a set of 37 separate switches, each of them assigned to a different value. When I press switch 1-36, the code will go fetch the respective value from the array. When I press switch 37, however, I think we can agree that I can assign whatever value/command to it, because it's just another switch.
Now, if you think that the rotary encoder is simply another way to enter the value, which simply saves me the space and complication of having a dedicated switch for each of the possible option, then logic would want that every value within the 0-36 range can be attached to anything I want.
To make a very simple example, I could have a code that says that for:
value 0 = turn on red led
Value 1 = turn on green led
Value 2 = make a sound with the buzzer
Value 3 = activate a motor
Just because they are all activated by the rotary encoder when it's in a certain position, it doesn't mean that the actions that follow have to be related to each other or be part of a same array. In fact, I could use each value for anything I want.
Happy to hear your thoughts on this though in case I missed something or you think my logic is wrong.

I suggest you look at one of the examples provided in your OLED driver. Get the OLED working, then address the remainder of you project code.

Imagine that is NOT what your code does. You have an array of 36 elements, indexed 0-35. You assign an index (Fade2Value) using map to get a value between 0..36 INCLUSIVE. You then use this index to access the array - OUT OF BOUNDS. It doesn't matter what you do later, you have already broken the code
fadeValue2 = map(fadeValue1, 0, 1023, 0, 36);
charselect = Input[fadeValue2];

@blh64
Thank you for your clarification, now I understand! I went back and fixed a few things from the code according to your suggestions:

  1. To avoid selecting the inexistent 37th element from the chart, I added an IF statement that stops the code from searching for the 37th value in the array:
fadeValue2 = map(fadeValue1, 0, 1023, 0, 36);
  if (fadeValue2 != 36) charselect = Input[fadeValue2];
  1. I added some code to give an arbitrary value to the character '0' to '9'. As you correctly highlighted, the ASCII value would have not allowed for the calculation to be made ('0' = 48 and 48 - 96 = -48). To do this, I created another array, so I have two of them, one to store the input I want to show on the display (ASCII characters) and one array to store the correspondent value in the back-end, to use later in the code for the password calculation
char InputArrayCalc[100];

if (fadeValue2 < 26) InputArrayCalc[InputArrayPos] = charselect;
if (fadeValue2 >= 26) InputArrayCalc[InputArrayPos] = charselect+75;
  1. I also added the code to make sure the arrays are null terminated:
    InputArray[InputArrayPos] = charselect;
      if (fadeValue2 < 26) InputArrayCalc[InputArrayPos] = charselect;
      if (fadeValue2 >= 26) InputArrayCalc[InputArrayPos] = charselect+75;
    InputArrayPos = InputArrayPos + 1;
    InputArray[InputArrayPos] = '\0';
    InputArrayCalc[InputArrayPos] = '\0';
  1. and lastly, I also changed the calculation Dividing by 5 would have returned values that are not within the possible options available to use as coordinate to fetch the correspondent value in char AlphaNumChart[6][6]. Now it's dividing by 6 instead of 5, which will return values between 0-5, therefore usable to address a [6][6] matrix:
void calculateOutput() {
  for (int i = 0; i < (InputLen - 1); i++) {
    num[0][i] = (InputArrayCalc[i] - 97) / 6;
    num[1][i] = (InputArrayCalc[i] - 97) % 6;

After doing all this, I wish I could say that the code finally started working, however unfortunately that was not the case :sob: :sob:

Is there something else that I am missing in the rest of the code that is causing it not to run? Just in case, I am pasting the entire code again below after the modification

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128  // OLED display width, in pixels
#define SCREEN_HEIGHT 64  // OLED display height, in pixels

// On an arduino UNO:       A4(SDA), A5(SCL)
#define OLED_RESET 4         // 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);


char InputArray[100]; // stores the selected value from char Input
char InputArrayCalc[100]; // stores the selected value to run calculation
char Output[100]; // stores the final result to show on screen
char Input[36] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; // shows value on screen and allows selection to store in char InputArray
char AlphaNumChart[6][6] = { { 'a', 'b', 'c', 'd', 'e', 'f' },
                             { 'g', 'h', 'i', 'j', 'k', 'l' },
                             { 'm', 'n', 'o', 'p', 'q', 'r' },
                             { 's', 't', 'u', 'v', 'w', 'x' },
                             { 'y', 'z', '0', '1', '2', '3' },
                             { '4', '5', '6', '7', '8', '9' } }; // based on coordinates calculated by the formula, will select characters from this matrix to store in char Output

int num[2][100];  //first row to store reminder, second row to store quotients
int InputLen;
int i;
int Key = 2; // key to allow selection of the value to store in char InputArray
int fadeValue1; // raw potentiometer value
int fadeValue2; // potentiometer value adjusted to select one of the 36 options from char Input
char charselect; // to show and store selected value from char Input
int InputArrayPos = 0; //this is just for word positioning on the display
int cursor; // this is just for word positioning on the display
int CursorStart; // this is just for word positioning on the display
int CursorRef;  // this is just for word positioning on the display
int CursorEnd;  // this is just for word positioning on the display

void setup() {
  pinMode(Key, INPUT);
  Serial.begin(9600);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.setTextWrap(false);
  display.clearDisplay();
}

void loop() {

  fadeValue1 = analogRead(A0);
  fadeValue2 = map(fadeValue1, 0, 1023, 0, 36);
  if (fadeValue2 != 36) charselect = Input[fadeValue2];

  display.clearDisplay();
  displayPrint(0, 0, WHITE, 1);
  display.println("Your selection:");

  displayPrint(55, 15, WHITE, 4);
  display.println(charselect);

  if (fadeValue2 == 36) {
    display.clearDisplay();
    displayPrint(0, 22, WHITE, 2);
    display.println("SHOW Output");
  }

  displayPrint(cursor, 47, WHITE, 2);
  display.println(InputArray);

  display.display();

  if ((digitalRead(Key) == 1) && (fadeValue2 != 36)) {

    InputArray[InputArrayPos] = charselect;
      if (fadeValue2 < 26) InputArrayCalc[InputArrayPos] = charselect;
      if (fadeValue2 >= 26) InputArrayCalc[InputArrayPos] = charselect+75;
    InputArrayPos = InputArrayPos + 1;
    InputArray[InputArrayPos] = '\0';
    InputArrayCalc[InputArrayPos] = '\0';

    display.clearDisplay();
    displayPrint(0, 0, WHITE, 1);
    display.println("Your selection:");
    displayPrint(50, 22, WHITE, 2);
    display.println("OK!");

    InputLen = (strlen(InputArray));
    if (InputLen > 10) {
      cursor = (10 - InputLen) * 12;
    } else
      cursor = 0;

    displayPrint(cursor, 47, WHITE, 2);
    display.println(InputArray);
    display.display();

    delay(500);
  }


  while ((digitalRead(Key) == 1) && (fadeValue2 == 36)) {

   calculateOutput(); 
   displayOutput();
  }
}

void calculateOutput() {

  for (int i = 0; i < (InputLen - 1); i++) {
    num[0][i] = (InputArrayCalc[i] - 97) / 6;
    num[1][i] = (InputArrayCalc[i] - 97) % 6;
  }
 
 for (int i = 0; i < (InputLen - 1); i++) {
     Output[i] = AlphaNumChart[num[0][i]][num[1][InputLen - 1 - i]];
  }

}

void displayOutput() {

  CursorEnd = (-12 * InputLen) + display.width();
  CursorStart = 0;

  while (digitalRead(Key) == 1) {

    if (InputLen <= 10) {
      display.clearDisplay();
      displayPrint(0, 0, WHITE, 1);
      display.println("Your Output:");

      displayPrint(0, 27, WHITE, 2);
      display.println(Output);
      display.display();
    }

    if (InputLen > 10) {
      display.clearDisplay();
      displayPrint(0, 0, WHITE, 1);
      display.println("Your Output:");
      displayPrint(CursorStart, 27, WHITE, 2);
      display.println(Output);
      display.display();
      if (CursorStart == 0) {CursorStart = CursorStart - 2; CursorRef = 0; delay(1000);}
      if ((CursorStart < 0) && (CursorRef == 0)) CursorStart = CursorStart - 2;
      if (CursorStart == CursorEnd) {CursorStart = CursorStart + 2; CursorRef = 1; delay(1000);}
      if ((CursorStart < 0) && (CursorRef == 1)) CursorStart = CursorStart + 2;
    }
  }
}

void displayPrint(int x, int y, int color, int size) {
  display.setCursor(x, y);
  display.setTextColor(color);
  display.setTextSize(size);
}

How about you describe what it is doing vs. what you want it to do? "Not working" never a helpful description of a problem.

so what happens to charselect is fadeValue2 is 36 ?

if 36 is not a valid index, then why don't you do

fadeValue2 = map(fadeValue1, 0, 1023, 0, 35);

Another thing to ask: How is your KEY wired up? You have it declared as an INPUT so it requires either a pull-up or pull-down resistor. Did you install one? An easier and more typical arrangement is to connect one end of a button to ground and the other to the arduino pin and then declare that pin as INPUT_PULLUP. It will read HIGH when not pressed and LOW when pressed.

Here's an attempt to tidy up your code and make it only react when things change... It takes up quite a bit less memory. The OLED library takes quite a bit so you could be running out with all those large arrays...

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128  // OLED display width, in pixels
#define SCREEN_HEIGHT 64  // OLED display height, in pixels

// On an arduino UNO:       A4(SDA), A5(SCL)
#define OLED_RESET 4         // 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);

const int maxInput = 100;

char InputArray[maxInput]; // stores the selected value from char Input
char Output[maxInput]; // stores the final result to show on screen
char Input[36] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; // shows value on screen and allows selection to store in char InputArray
char AlphaNumChart[6][6] = { { 'a', 'b', 'c', 'd', 'e', 'f' },
  { 'g', 'h', 'i', 'j', 'k', 'l' },
  { 'm', 'n', 'o', 'p', 'q', 'r' },
  { 's', 't', 'u', 'v', 'w', 'x' },
  { 'y', 'z', '0', '1', '2', '3' },
  { '4', '5', '6', '7', '8', '9' }
}; // based on coordinates calculated by the formula, will select characters from this matrix to store in char Output

uint8_t num[maxInput];  //indicies of InputArray

const int keyPin = 2; // key to allow selection of the value to store in char InputArray
const int selectionPin = A0;  // rotary pot
int prevKeyState;
int prevSelectionState;
int prevSelectionIdx;

int InputArrayPos = 0; //this is just for word positioning on the display

void setup() {
  pinMode(keyPin, INPUT);
  Serial.begin(9600);
  display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS);
  display.setTextWrap(false);
  display.clearDisplay();
}

void loop() {

  int selectionIdx = map(analogRead(selectionPin), 0, 1023, 0, 36);
  int keyState = digitalRead(keyPin);

  if ( selectionIdx == prevSelectionIdx && keyState == prevKeyState ) {
    // nothing has changed, so nothing to do, exit loop at try again
    return;
  }

  // something has changed, either the character selected or the state of the key

  if ( selectionIdx != prevSelectionIdx ) {
    updateCharSelection(selectionIdx);
    prevSelectionIdx = selectionIdx;
  }

  if ( keyState != prevKeyState ) {
    prevKeyState = keyState;
    if ( selectionIdx < 36 ) {
      // process a key selection
      if (keyState == HIGH) {
        // key was pressed, add it to input
        addCharInput(selectionIdx);
      }
      else {
        // key was released, do nothing
      }
    }
    else {
      // deal with final "Show output" selection
      if (keyState == HIGH) {
        // key was pressed, show output
        calculateOutput();
        displayOutput();
      }
      else {
        // key was released, do nothing
      }
    }
    delay(20);  // debounce key
  }
}

void calculateOutput() {

  for (int i = 0; i < InputArrayPos; i++) {
    int row = num[i] / 6;
    int col = num[InputArrayPos - 1 - i] % 6;
    Output[i] = AlphaNumChart[row][col];
  }
  Output[InputArrayPos] = '\0';
}

void displayOutput() {

  int CursorEnd = (-12 * InputArrayPos) + display.width();
  int CursorStart = 0;
  int CursorRef = 0;
  
  while (digitalRead(keyPin) == HIGH) {

    if (InputArrayPos <= 10) {
      displayPrint(0, 27, WHITE, 2);
      display.println(Output);
      display.display();
    }
    else {
      display.clearDisplay();
      displayPrint(0, 0, WHITE, 1);
      display.println("Your Output:");
      displayPrint(CursorStart, 27, WHITE, 2);
      display.println(Output);
      display.display();
      if (CursorStart == 0) {
        CursorStart = CursorStart - 2;
        CursorRef = 0;
        delay(1000);
      }
      if ((CursorStart < 0) && (CursorRef == 0)) CursorStart = CursorStart - 2;
      if (CursorStart == CursorEnd) {
        CursorStart = CursorStart + 2;
        CursorRef = 1;
        delay(1000);
      }
      if ((CursorStart < 0) && (CursorRef == 1)) CursorStart = CursorStart + 2;
    }
  }
}

void displayPrint(int x, int y, int color, int size) {
  display.setCursor(x, y);
  display.setTextColor(color);
  display.setTextSize(size);
}

void updateCharSelection(int idx) {
  char ch;
  bool onChar;    // true when selection is on a char, false if "Show Output"

  if (idx < 36) {
    ch = Input[idx];
    onChar = true;
  }
  else {
    onChar = false;
  }

  display.clearDisplay();
  if ( onChar ) {
    displayPrint(0, 0, WHITE, 1);
    display.println("Your selection:");
    displayPrint(55, 15, WHITE, 4);
    display.print(ch);
  }
  else {
    displayPrint(0, 22, WHITE, 2);
    display.println("SHOW Output");
  }
  displayInput();
}

void addCharInput(int idx) {

  num[InputArrayPos] = idx; // store index for later computation
  InputArray[InputArrayPos++] = Input[idx];
  InputArray[InputArrayPos] = '\0';
  if ( InputArrayPos >= maxInput - 1 ) {
    InputArrayPos = maxInput - 2;
  }
  display.clearDisplay();
  displayPrint(0, 0, WHITE, 1);
  display.println("Your selection:");
  displayPrint(50, 22, WHITE, 2);
  display.println("OK!");

  displayInput();
}

void displayInput() {
  int cursor = 0;

  if (InputArrayPos > 10) {
    cursor = (10 - InputArrayPos) * 12;
  }
    displayPrint(cursor, 47, WHITE, 2);
    display.println(InputArray);
    display.display();
}

if fadeValue2 is 36, then this happens (it's later in the code):

 if (fadeValue2 == 36) {
    displayPrint(18, 22, WHITE, 2);
    display.println("SHOW Output");
  }

And this, if the switch is pressed:

 while ((digitalRead(Key) == 1) && (fadeValue2 == 36)) {
    calculateOutput(); 
    displayOutput();
  }

Thank you very much for providing an alternative code, I have to be honest I don't understand most of it due to me being an ignorant beginner, but I tried to run it and nothing is showing on the screen.

And apologies for not providing an explanation about what I am trying to achieve with the code. I have provided some info about it inside the code after //, however it was probably not enough so let me explain.

This is the flow:

  1. I input an arbitrary word (which can include digits as well) by turning the dial of the rotary encoder, which shows a letter or digit on the screen according to its value. Once the chosen letter or digit appears on the screen, I press the button (Key 2) and the letter/digit gets stored and I move onto the next one

  2. I keep doing this until I have finished selecting all letters/digits, at which point I go to fadeValue2 ==36, which shows on the screen "show output" and press Key. This basically serves the function of a keyboard's "ctrl+enter" key if I were using serial monitor to input the word

  3. once I press the key on fadeValue2=36, the program performs a calculation based on the ASCII value of each letter and the arbitrary value assigned to the digits that are stored in InputArrayCalc[100] (the arbitrary value of the digits is given by using the code
    if (fadeValue2 >= 26) InputArrayCalc[InputArrayPos] = charselect+75).

  4. the calculation divides these values by 6 and stores the quotients and remainder in int num[2][100] (num[0][100] stores the quotients, num[1][100] stores the remainders). Based on how the calculation is set up, it should return values between 0-5 for both quotients and remainders

  5. finally, these values are used as coordinates to go fetch the correspondent ASCII character in the matrix AlphaNumChart[6][6]

to give you an example, in case the initial input word is "az"
a=97, z=122
num[0][0] = (97 - 97) / 6=0; num[0][1] = (122- 97) / 6=4;
num[1][0] = (97 - 97) % 6=0; num[1][1] = (122 - 97) % 6=1;

this code then re-arranges the remainders in the opposite order and use the combination of quotients and remainders values as "coordinates" for the AlphaNumChart matrix

Output[i] = AlphaNumChart[num[0][i]][num[1][InputLen - 1 - i]]

so, the final result uses coordinates num[0][0]=0, num[1][1]=1 to find the first value 'g' and num[0][1]=4, num[1][0]=0 coordinates to find the second value 'e'.

The code should output the word "ge" on the screen as a final result.

I hope this is clear enough, It's a bit complex to explain, but I hope it can help understand the matter better.

Regarding your comment about the pull-up resistor, I have wired the components according to the tutorial that came with the Arduino when I bought it, therefore I believe it should all be wired up correctly... I am attaching here another photo where it's maybe easier to see how they are all connected (from left to right OLED, encoder, switch).

Please note, the first part of the code (the word inputting part) and the screen work perfectly as long as I remove the line calculateOutput(); from void calculateOutput(). I am able to see the letters/digits appearing, able to store them and have them appear as one word on the screen. It's when I add the "calculation" part of the code that everything freezes...

I get your explanation. A couple of things to note

  1. the OLED display takes up a LOT of memory and it looks like you are using an UNO so you may be running out of memory.

  2. You calculations on the input reduce to simply the index into the original array. a..z = 0..25 and '0'..'9' go to 26..35. That is why my code just stores the index along with the char when you press the KEY.

  3. your two indices into your matrix are just counting from each end of your array.

  4. What comes out on the Serial Monitor? Adding some debug statements during the calculation may help.

  5. what part of the code I provided don't you understand? I simply renamed a few variables, moved a few global variables to local versions and put some code inside functions. Nothing too fancy.

Thank you very much for the additional comments.

  1. the OLED display takes up a LOT of memory and it looks like you are using an UNO so you may be running out of memory.

when I compile the code, it is well within the limit (50% or so), although I don't know if that's a reliable value or if things change when running for real

  1. You calculations on the input reduce to simply the index into the original array. a..z = 0..25 and '0'..'9' go to 26..35. That is why my code just stores the index along with the char when you press the KEY.

This is genius, and at the same time I feel stupid for not having thought of that before... :sweat_smile:

  1. your two indices into your matrix are just counting from each end of your array.

Correct, the one for the quotients is ascendant, while the one for the remainder is descendent order

  1. What comes out on the Serial Monitor? Adding some debug statements during the calculation may help.

If you are talking about the code you provided, nothing comes out of the serial monitor (I don't think your code included any serial.print, neither does mine). I want to add debug statements, however it's something I have never done before so I am planning to study about it and try to do it over the weekend. I only hope I'm gonna be able to figure out how to do it.

  1. what part of the code I provided don't you understand? I simply renamed a few variables, moved a few global variables to local versions and put some code inside functions. Nothing too fancy.

I do understand the general flow contained in void loop, however the logic that you used for some other parts of the code is too much for me to grasp :persevere:

For example, I am not sure where the value of "idx" comes from as I didn't see anywhere in the code where this is assigned, as well as I never saw "uint8_t" before or never used "bool" either. I also don't understand the logic of this code

  num[InputArrayPos] = idx; // store index for later computation
  InputArray[InputArrayPos++] = Input[idx];
  InputArray[InputArrayPos] = '\0';

I am sure it's probably the best possible way of writing this code, I just get lost in all these passages since everything I know about coding I have learnt in a span of only a couple of weeks, and only through the 20 lessons or so that came with the Arduino... That's about as much as I know when it comes to coding...

First off, 'idx' is a parameter passed into the addCharInput() function...
void addCharInput(int idx) {...

The above code just assigns the index into the num[] array and then puts the character into the InputArray[]. The shorthand of post-incrementing the index InputArrayPos save a line of code. It would be the same as

  num[InputArrayPos] = idx; // store index for later computation
  InputArray[InputArrayPos] = Input[idx];
  InputArrayPos++;  // or InputArrayPos = InputArrayPos + 1
  InputArray[InputArrayPos] = '\0';

'uint8_t is a standard C/C++ type. It means an 8 bit, unsigned value (aka byte or unsigned char) If you want a specific amount of storage, independent of which platform you are working on, you use uint8_t or uint16_t or uint32_t, etc. As an example, an Uno treats an int as 16 bits, but on an ESP32 an int is 32 bits. bool is a boolean variable that can be true or false

As for debugging, it is nothing more than inserting some Serial.print() statements into the code to inform you about what is happening...

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128  // OLED display width, in pixels
#define SCREEN_HEIGHT 64  // OLED display height, in pixels

// On an arduino UNO:       A4(SDA), A5(SCL)
#define OLED_RESET 4         // 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);

const int maxInput = 100;

char InputArray[maxInput]; // stores the selected value from char Input
char Output[maxInput]; // stores the final result to show on screen
char Input[36] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; // shows value on screen and allows selection to store in char InputArray
char AlphaNumChart[6][6] = { { 'a', 'b', 'c', 'd', 'e', 'f' },
  { 'g', 'h', 'i', 'j', 'k', 'l' },
  { 'm', 'n', 'o', 'p', 'q', 'r' },
  { 's', 't', 'u', 'v', 'w', 'x' },
  { 'y', 'z', '0', '1', '2', '3' },
  { '4', '5', '6', '7', '8', '9' }
}; // based on coordinates calculated by the formula, will select characters from this matrix to store in char Output

uint8_t num[maxInput];  //indicies of InputArray

const int keyPin = 2; // key to allow selection of the value to store in char InputArray
const int selectionPin = A0;  // rotary pot
int prevKeyState;
int prevSelectionState;
int prevSelectionIdx;

int InputArrayPos = 0; //this is just for word positioning on the display

void setup() {
  pinMode(keyPin, INPUT);
  Serial.begin(9600);
  display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS);
  display.setTextWrap(false);
  display.clearDisplay();

  Serial.println(F("Ready"));
}

void loop() {

  int selectionIdx = map(analogRead(selectionPin), 0, 1023, 0, 36);
  int keyState = digitalRead(keyPin);

  if ( selectionIdx == prevSelectionIdx && keyState == prevKeyState ) {
    // nothing has changed, so nothing to do, exit loop at try again
    return;
  }

  // something has changed, either the character selected or the state of the key

  if ( selectionIdx != prevSelectionIdx ) {
    updateCharSelection(selectionIdx);
    prevSelectionIdx = selectionIdx;
  }

  if ( keyState != prevKeyState ) {
    prevKeyState = keyState;
    if ( selectionIdx < 36 ) {
      // process a key selection
      if (keyState == HIGH) {
        // key was pressed, add it to input
        addCharInput(selectionIdx);
      }
      else {
        // key was released, do nothing
      }
    }
    else {
      // deal with final "Show output" selection
      if (keyState == HIGH) {
        // key was pressed, show output
        calculateOutput();
        displayOutput();
      }
      else {
        // key was released, do nothing
      }
    }
    delay(20);  // debounce key
  }
}

void calculateOutput() {

  Serial.print(F("calculating output. Char count= ")); Serial.println(InputArrayPos);

  for (int i = 0; i < InputArrayPos; i++) {
    int row = num[i] / 6;
    int col = num[InputArrayPos - 1 - i] % 6;
    Output[i] = AlphaNumChart[row][col];
    Serial.print(Input[num[i]]); Serial.print(F("->")); Serial.println(Output[i]);
  }
  Output[InputArrayPos] = '\0';
}

void displayOutput() {

  int CursorEnd = (-12 * InputArrayPos) + display.width();
  int CursorStart = 0;
  int CursorRef = 0;
  
  while (digitalRead(keyPin) == HIGH) {

    if (InputArrayPos <= 10) {
      displayPrint(0, 27, WHITE, 2);
      display.println(Output);
      display.display();
    }
    else {
      display.clearDisplay();
      displayPrint(0, 0, WHITE, 1);
      display.println("Your Output:");
      displayPrint(CursorStart, 27, WHITE, 2);
      display.println(Output);
      display.display();
      if (CursorStart == 0) {
        CursorStart = CursorStart - 2;
        CursorRef = 0;
        delay(1000);
      }
      if ((CursorStart < 0) && (CursorRef == 0)) CursorStart = CursorStart - 2;
      if (CursorStart == CursorEnd) {
        CursorStart = CursorStart + 2;
        CursorRef = 1;
        delay(1000);
      }
      if ((CursorStart < 0) && (CursorRef == 1)) CursorStart = CursorStart + 2;
    }
  }
}

void displayPrint(int x, int y, int color, int size) {
  display.setCursor(x, y);
  display.setTextColor(color);
  display.setTextSize(size);
}

void updateCharSelection(int idx) {
  char ch;
  bool onChar;    // true when selection is on a char, false if "Show Output"

  if (idx < 36) {
    ch = Input[idx];
    onChar = true;
  }
  else {
    onChar = false;
  }

  display.clearDisplay();
  if ( onChar ) {
    displayPrint(0, 0, WHITE, 1);
    display.println("Your selection:");
    displayPrint(55, 15, WHITE, 4);
    display.print(ch);
    Serial.print(F("Selection is ")); Serial.println(ch);
  }
  else {
    displayPrint(0, 22, WHITE, 2);
    display.println("SHOW Output");
    Serial.println(F("Selection is OUTPUT"));
  }
  displayInput();
}

void addCharInput(int idx) {

  Serial.print(F("Adding ")); Serial.println(Input[idx]);
  
  num[InputArrayPos] = idx; // store index for later computation
  InputArray[InputArrayPos++] = Input[idx];
  InputArray[InputArrayPos] = '\0';
  if ( InputArrayPos >= maxInput - 1 ) {
    InputArrayPos = maxInput - 2;
  }
  display.clearDisplay();
  displayPrint(0, 0, WHITE, 1);
  display.println("Your selection:");
  displayPrint(50, 22, WHITE, 2);
  display.println("OK!");

  displayInput();
}

void displayInput() {
  int cursor = 0;

  if (InputArrayPos > 10) {
    cursor = (10 - InputArrayPos) * 12;
  }
    displayPrint(cursor, 47, WHITE, 2);
    display.println(InputArray);
    display.display();
}
1 Like

Most OLED drivers allocate a (relatively) huge screen buffer at run time. That is not reported at compile time because it's dynamically allocated.

Thank you very much for your patient explanation and for the debug statements. When I run the code, this is what I can see from my serial monitor:

image

Basically it seems to make any sense only when the rotary encoder is on the initial value of 0, in which case is shows "ready" and adds "a" when I press the key. The moment I move the encoder, it starts printing gibberish. Just in case you think it might be a problem with the encoder, it does work in every other application that I have used it in and also with the original code for this project (when the calculation part is removed).

In the meantime, nothing is shown on the OLED screen...

EDIT:
after spending a little bit of time merging my original code with yours (in a way that I can easily understand :sweat_smile:), I found it pretty clear that the culprit is this part of the calculation:

image

line 92 this is the one line that freezes everything and, if removed, allows the program to run as it should. Is it possible that this is such a complicated operation that causes the Arduino to run out of memory?...

Below my newest version of the code after making modifications based on yours



#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128  // OLED display width, in pixels
#define SCREEN_HEIGHT 64  // OLED display height, in pixels

// On an arduino UNO:       A4(SDA), A5(SCL)
#define OLED_RESET 4         // 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);


char InputArray[100]; // stores the selected value from char Input
char Output[100]; // stores the final result to show on screen
char Input[36] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; // shows value on screen and allows selection to store in char InputArray
char AlphaNumChart[6][6] = { { 'a', 'b', 'c', 'd', 'e', 'f' },
                             { 'g', 'h', 'i', 'j', 'k', 'l' },
                             { 'm', 'n', 'o', 'p', 'q', 'r' },
                             { 's', 't', 'u', 'v', 'w', 'x' },
                             { 'y', 'z', '0', '1', '2', '3' },
                             { '4', '5', '6', '7', '8', '9' } }; // based on coordinates calculated by the formula, will select characters from this matrix to store in char Output

int num[100]={0};  //first row to store reminder, second row to store quotients
int InputLen;
int i;
int Key = 2; // key to allow selection of the value to store in char InputArray
int fadeValue1; // raw potentiometer value
int fadeValue2; // potentiometer value adjusted to select one of the 36 options from char Input
char charselect; // to show and store selected value from char Input
int InputArrayPos = 0; //this is just for word positioning on the display
int cursor; // this is just for word positioning on the display
int CursorStart; // this is just for word positioning on the display
int CursorRef;  // this is just for word positioning on the display
int CursorEnd;  // this is just for word positioning on the display

void setup() {
  pinMode(Key, INPUT);
  Serial.begin(9600);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.setTextWrap(false);
  display.clearDisplay();
}

void loop() {

  fadeValue1 = analogRead(A0);
  fadeValue2 = map(fadeValue1, 0, 1023, 0, 36);
  if (fadeValue2 != 36) charselect = Input[fadeValue2];

  display.clearDisplay();
  displayPrint(0, 0, WHITE, 1);
  display.println("Your selection:");

  displayPrint(55, 15, WHITE, 4);
  display.println(charselect);

  if (fadeValue2 == 36) {
    display.clearDisplay();
    displayPrint(0, 22, WHITE, 2);
    display.println("SHOW Output");
  }



  if ((digitalRead(Key) == 1) && (fadeValue2 != 36)) {

  addCharInput();

  delay(500);

  }


  while ((digitalRead(Key) == 1) && (fadeValue2 == 36)) {

   calculateOutput(); 
   displayOutput();
  }

displayInput();

}

void calculateOutput() {

  for (int i = 0; i < InputArrayPos; i++) {
    int row = num[i] / 6;
    int col = num[InputArrayPos - 1 - i] % 6;
   Output[i] = AlphaNumChart[row][col];
  }
  Output[InputArrayPos] = '\0';
}

void displayOutput() {

  CursorEnd = (-12 * InputLen) + display.width();
  CursorStart = 0;

  while (digitalRead(Key) == 1) {

    if (InputLen <= 10) {
      display.clearDisplay();
      displayPrint(0, 0, WHITE, 1);
      display.println("Your Output:");

      displayPrint(0, 27, WHITE, 2);
      display.println(Output);
      display.display();
    }

    if (InputLen > 10) {
      display.clearDisplay();
      displayPrint(0, 0, WHITE, 1);
      display.println("Your Output:");
      displayPrint(CursorStart, 27, WHITE, 2);
      display.println(Output);
      display.display();
      if (CursorStart == 0) {CursorStart = CursorStart - 2; CursorRef = 0; delay(1000);}
      if ((CursorStart < 0) && (CursorRef == 0)) CursorStart = CursorStart - 2;
      if (CursorStart == CursorEnd) {CursorStart = CursorStart + 2; CursorRef = 1; delay(1000);}
      if ((CursorStart < 0) && (CursorRef == 1)) CursorStart = CursorStart + 2;
    }
  }
}

void displayPrint(int x, int y, int color, int size) {
  display.setCursor(x, y);
  display.setTextColor(color);
  display.setTextSize(size);
}


void addCharInput() {

  num[InputArrayPos] = fadeValue2; // store index for later computation
  InputArray[InputArrayPos++] = Input[fadeValue2];
  InputArray[InputArrayPos] = '\0';
  if ( InputArrayPos >= 100 - 1 ) {
    InputArrayPos = 100 - 2;
  }
  display.clearDisplay();
  displayPrint(0, 0, WHITE, 1);
  display.println("Your selection:");
  displayPrint(50, 22, WHITE, 2);
  display.println("OK!");

  displayInput();
  Serial.print("added");
  Serial.print(fadeValue2);
}


void displayInput() {
  int cursor = 0;

  if (InputArrayPos > 10) {
    cursor = (10 - InputArrayPos) * 12;
  }
    displayPrint(cursor, 47, WHITE, 2);
    display.println(InputArray);
    display.display();
}

If you are getting multiple "Ready" messages, the arduino is resetting. This could be caused by either row and col being out of bounds. Why not insert another debug statement?

void calculateOutput() {
  for (int i = 0; i < InputArrayPos; i++) {
    int row = num[i] / 6;
    int col = num[InputArrayPos - 1 - i] % 6;
    Serial.print("row="); Serial.print(row);
    Serial.print("col="); Serial.println(col);
   Output[i] = AlphaNumChart[row][col];
  }
  Output[InputArrayPos] = '\0';
}

I would also seriously suggest that you reduce the size of your buffers from 100 down to something like 10, at least for testing. Your num array does not need to be of type 'int' which is 16 bits, make it type 'byte' since it never holds a value greater than 255. That cuts its size in half

#define BUFFER_SIZE 10
char InputArray[BUFFER_SIZE];
char Output[BUFFER_SIZE];
byte num[BUFFER_SIZE];
...

I would also recommend leaving in some of those debug statements, like the "ready" statement in setup() which tells you if the arduino has reset...

1 Like

@blh64 Tank you so very much, your suggestion to reduce the size of the arrays was the key, I lowered it to 10 and it finally started working!! Then I worked my way up to realize that 65 is the threshold at which the code stopped working (I will be keeping the size below that value to allow some room for the memory just in case).

I will do one more cleaning of the code tomorrow and share here as an FYI.

You have no idea how much I appreciate your help, I wish there was a way to repay the favor!! :smiley: :smiley: :smiley:

EDIT:
Here's the final code (at least for now) that I will be using for this project:

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128  // OLED display width, in pixels
#define SCREEN_HEIGHT 64  // OLED display height, in pixels

// On an arduino UNO:       A4(SDA), A5(SCL)
#define OLED_RESET 4         // 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);

const int maxInput = 65;

char InputArray[maxInput]; // stores the input word for displaying on the screen
char Output[maxInput]; // stores the final result to show on screen
char Input[36] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; // shows value on screen and allows selection to store in char InputArray
char AlphaNumChart[6][6] = { { 'a', 'b', 'c', 'd', 'e', 'f' },
                             { 'g', 'h', 'i', 'j', 'k', 'l' },
                             { 'm', 'n', 'o', 'p', 'q', 'r' },
                             { 's', 't', 'u', 'v', 'w', 'x' },
                             { 'y', 'z', '0', '1', '2', '3' },
                             { '4', '5', '6', '7', '8', '9' } }; // based on coordinates calculated by the formula, will select characters from this matrix to store in char Output

byte num[maxInput];  //stores the input values for computation
int Key=2; // key to allow selection of the value to store in char InputArray
int fadeValue1; // raw potentiometer value
int fadeValue2; // potentiometer value adjusted to select one of the 36 options from char Input
char charselect; // to show and store selected value from char Input
int InputArrayPos = 0; //this is just for word positioning on the display
int cursor; // this is just for word positioning on the display
int CursorStart; // this is just for word positioning on the display
int CursorRef;  // this is just for word positioning on the display
int CursorEnd;  // this is just for word positioning on the display

void setup() {
  pinMode(Key, INPUT);
  Serial.begin(9600);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.setTextWrap(false);
  display.clearDisplay();
}

void loop() {

  fadeValue1 = analogRead(A0);
  fadeValue2 = map(fadeValue1, 0, 1023, 0, 36);
  if (fadeValue2 != 36) charselect = Input[fadeValue2];

  display.clearDisplay();
  displayPrint(0, 0, WHITE, 1);
  display.println("Your selection:");

  displayPrint(55, 15, WHITE, 4);
  display.println(charselect);

  if (fadeValue2 == 36) {
    display.clearDisplay();
    displayPrint(0, 22, WHITE, 2);
    display.println("SHOW Output");
  }

  if ((digitalRead(Key) == 1) && (fadeValue2 != 36)) {

  addCharInput();

  delay(500);

  }


  while ((digitalRead(Key) == 1) && (fadeValue2 == 36)) {

   calculateOutput(); 
   displayOutput();
  }

displayInput();

}

void calculateOutput() {

  for (int i = 0; i < InputArrayPos; i++) {
    int X = num[i] / 6;
    int Y = num[InputArrayPos - 1 - i] % 6;
   Output[i] = AlphaNumChart[Y][X];
  }
  Output[InputArrayPos] = '\0';
}

void displayOutput() {

  CursorEnd = (-12 * (InputArrayPos)) + display.width();
  CursorStart = 0;

  while (digitalRead(Key) == 1) {

    if (InputArrayPos <= 10) {
      display.clearDisplay();
      displayPrint(0, 0, WHITE, 1);
      display.println("Your Output:");

      displayPrint(0, 27, WHITE, 2);
      display.println(Output);
      display.display();
    }

    if (InputArrayPos > 10) {
      display.clearDisplay();
      displayPrint(0, 0, WHITE, 1);
      display.println("Your Output:");
      displayPrint(CursorStart, 27, WHITE, 2);
      display.println(Output);
      display.display();
      if (CursorStart == 0) {CursorStart = CursorStart - 2; CursorRef = 0; delay(1000);}
      if ((CursorStart < 0) && (CursorRef == 0)) CursorStart = CursorStart - 2;
      if (CursorStart == CursorEnd) {CursorStart = CursorStart + 2; CursorRef = 1; delay(1000);}
      if ((CursorStart < 0) && (CursorRef == 1)) CursorStart = CursorStart + 2;
    }
  }
}


void displayPrint(int x, int y, int color, int size) {
  display.setCursor(x, y);
  display.setTextColor(color);
  display.setTextSize(size);
}


void addCharInput() {

  num[InputArrayPos] = fadeValue2; // store index for later computation
  Serial.print("added to num ");
  Serial.print(num[InputArrayPos]);
  InputArray[InputArrayPos++] = Input[fadeValue2];

  InputArray[InputArrayPos] = '\0';
  if ( InputArrayPos >= maxInput - 1 ) {
    InputArrayPos = maxInput - 2;
  }
  display.clearDisplay();
  displayPrint(0, 0, WHITE, 1);
  display.println("Your selection:");
  displayPrint(50, 22, WHITE, 2);
  display.println("OK!");

  displayInput();
  Serial.println("added ");
  Serial.print(fadeValue2);
}


void displayInput() {
  int cursor = 0;

  if (InputArrayPos > 10) {
    cursor = (10 - InputArrayPos) * 12;
  }
    displayPrint(cursor, 47, WHITE, 2);
    display.println(InputArray);
    display.display();
}

If you want a couple more bytes of memory, you can wrap all your string literals with the F() maco...

      ///display.println("Your Output:");
      display.println(F("Your Output:"));

You can also eliminate the entire Output array. Just move all the computation of the calculateOutput() inside of displayOutput() and then calculate and display 1 char at a time.

1 Like