I have an M5Stack CardKB wired to an Arduino Uno via SCL/SDA. The Serial Monitor is showing characters passing just fine. The Tab, Shift, Fn, Sym, and Space keys work fine. However, the Backspace, Enter, Esc, and Arrow keys only display a "square" in the serial monitor and do not work as intended.
I thoroughly reviewed the following two threads and had no success. I feel like I am so close to this working. What am I missing to read these particular keys via I2C (and not via UART)?
// Wire M5 CardKB to your Arduino:
// Use standard jumpers to connect like-named pins: Blk to GND, Red to VCC, Yel to SDA, Wht to SCL.
#include <Wire.h>
#define CARDKB_ADDR 0x5F // Define the I2C address of CardKB.
void setup() {
Serial.begin(9600);
Wire.begin();
}
void loop() {
Wire.requestFrom(CARDKB_ADDR, 1); // Request 1 byte from the CardKB.
while (
Wire.available()) { // If received data is detected,
char c = Wire.read(); // store the received data.
if (c != 0) {
Serial.print(c); // Print the received data.
}
}
}
Some of the characters on a keyboard are 'non-printing characters' therefore to make them visible you need to translate them into something that is visible.
For example Serial.print(c, HEX)
will turn an invisible character into a visible pair of hex characters. For example Esc is displayed as '1B'.
You may find a terminal program such as Realterm useful as it has the option to display the data in multiple formats.
So, I created an I2C bus and added a SSD1306 OLED in order to test the non-printing characters. I did an I2C Scan and found both addresses as expected: OLED at 0x3c and CardKB at 0x5f. So far so good, right?
I updated my sketch accordingly to use both components since the hardware appears wired and tests correct. However, the keyboard output does appear in the Serial Monitor but does not appear on the OLED.
Bad OLED? No, I tested the OLED by itself with several other sketches and it tests good when the CardKB is unplugged.
I suspect something is amiss in my sketch code for this particular testing setup. Can anyone find anything wrong that jumps out?
Thank you again as always!
#include <Wire.h>
#define CARDKB_ADDR 0x5F // Define the I2C address of CardKB.
#define SCREEN_ADDRESS 0x3C // Define the I2C address of the OLED.
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
void setup() {
Serial.begin(9600);
Wire.begin();
display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS);
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(0,0);
}
void loop() {
Wire.requestFrom(CARDKB_ADDR, 1); // Request 1 byte from the CardKB.
while (
Wire.available()) { // If received data is detected.
char c = Wire.read(); // Store the received data.
if (c != 0) {
Serial.print(c); // Print the received data to the Serial Monitor.
display.print(c); // Print the received data to the Screen.
}
}
}
...does not update the OLED screen. Take a look at some of the example sketches for that OLED library and you should see that you are missing something.
But even when you have figured that out, you will be no further forward. You don't seem to have understood that you are trying to print non-printable characters. The OLED will not be able to do it any more than Serial Monitor can.
Thank you, Paul! I'll go back and review that "display" command in some other OLED 1306
sketches.
For the non-printable characters, I hear what you are saying. But, for example, I would like to at least see the Enter key perform a carriage return. Does that make sense?
Per @PaulRB I had to add a line after my display.print(c) command. That command only writes the data to the OLED buffer. You have to add the line 'display.display()' after it in order to push the buffer data to the screen.
I looked up the keymapping codes in M5Stack's Git and was able to assign those codes directly to the Enter and Back keypresses. M5 CardKB raw values
I am able to use an 'if/else if' statement to push a Carriage Return to the screen using 'display.println()' if the hex for 'Enter' was input (0x0D).
I am able to capture the Back key input (0x08) using the same 'if/else if' method, but I have not figured out how to increment the cursor one space to the left no matter where it is onscreen. The 'display.setCursor' command wants exact X and Y coordinates. So, for now the workaround is for the Back/Del key to simply clear the whole screen.
// Wire OLED Display to your Arduino:
// Use standard jumpers to connect like-named pins: GND to GND bus, VCC to VCC bus, SCL to SCL bus, SDA to SDA bus.
// Wire M5 CardKB to your Arduino:
// Use standard jumpers to connect like-named pins: GND to GND bus, VCC to VCC bus, SCL to SCL bus, SDA to SDA bus.
#include <Wire.h>
#define CARDKB_ADDR 0x5F // Define the I2C address of CardKB.
#define SCREEN_ADDRESS 0x3C // Define the I2C address of the OLED.
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
void setup() {
Serial.begin(9600);
Wire.begin();
display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS);
display.clearDisplay();
display.setTextSize(2);
display.setCursor(0,0);
display.display();
}
void loop() {
Wire.requestFrom(CARDKB_ADDR, 1); // Request 1 byte from the CardKB.
while (
Wire.available()) { // If received data is detected.
char c = Wire.read(); // Store the received data.
if (c == 0x0D) { // If the data is an Enter keypress.
display.println(); // Write a Carriage Return to the OLED buffer.
display.display(); // Print the Carriage Return to the OLED screen.
}
else if (c == 0x08) { // If the data is a Back/Del keypress.
display.clearDisplay();
// display.setCursor(0,0); // Write a Backspace/Delete to the OLED buffer? How do I move the cursor 1 space to the left?
display.display(); // Print the Backspace/Delete to the OLED screen.
}
else if (c != 0) { // If the data is neither of the two above conditions nor is it blank.
display.print(c); // Write the received data to the OLED buffer.
display.display(); // Print the received data to the OLED screen.
}
}
}
Successful screen output with functional carriage returns.
I don't have Fritzing but here is the basic schematic of my CardKB and OLED setup. The only differences are the Arduino model (Uno) and the devices themselves.