This may be a stupid question, but since I am quite new to programming anything outside of 1980's BASIC, I am having trouble locating what I need to know.
Basically, I am building a simple LED scrolling text display using an MAX7219 4-in-1 matrix and a Nano. That part is easy, and there is a ton of such projects out there to help you with the code needed for displaying a single message.
My problem is, I want to know how I would code the ability to select the message being displayed, with the messages being pulled from a preset bank, each time a momentary switch is pressed. So, it goes high, move to next message in the list. Reach the end of the list, go back to the first message. Repeat.
You can enter custom messages via serial, Bluetooth, etc. in many examples, but I do not want this, I want to simply have selectable messages contained within the code. No outside connections.
I know it's possible, but have no idea how, I really want to understand how to do this so I can learn as I go. Sadly, with my limited time, it's turning out to be a slower process than I had wished.
Please provide more information on your setup. What Arduino?
MAX7219 4-in-1 matrix.
What matrix modules (data sheet, link to where you got them)? What Bluetooth (classic, BLE)? Serial from where, a PC?
What have you done so far? Post your code (in code tags), describe what it does and what it should be doing.
I have code for a setup of 8 FC16 matrix module that can be controlled by classic Bluetooth and using the Parola libray that may be adapted to do what you want. I will look for it.
I have their code example up and running, reading through it so I understand whats going on. Messing with parameters. Testing.
// Include the required Arduino libraries:
#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
// Define hardware type, size, and output pins:
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4
#define CS_PIN 3
// Create a new instance of the MD_Parola class with hardware SPI connection:
// MD_Parola myDisplay = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
// Setup for software SPI:
#define DATA_PIN 4
#define CLK_PIN 5
MD_Parola myDisplay = MD_Parola(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);
void setup() {
// Intialize the object:
myDisplay.begin();
// Set the intensity (brightness) of the display (0-15):
myDisplay.setIntensity(0);
// Clear the display:
myDisplay.displayClear();
myDisplay.displayText("TEST MESSAGE - It works. !! @@ $$", PA_CENTER, 100, 0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
}
void loop() {
if (myDisplay.displayAnimate()) {
myDisplay.displayReset();
}
}
I am testing on a Mega 2560, but will move to a Nano on the final version.
I am not using any serial or BT connection for entering the messages. I edited my main post to be more clear, my bad. I am not wanting to use any external connection, just selectable messaged contained in the code that you cycle through using a momentary switch.
I think I already gave the right links and some explanation.
The button bouncing is turned of this Wokwi project, to make it work. Perhaps you need to add a debounce library.
When the button is pressed, increment a global variable. Then have a series of if statements that check it and send a message to the display. Or use an array.
Here is a quick example that shows, I think, the points that @ Koepel talked of in reply #2. Using pointer to a string in a array of pointers to select a message to display and the state change detection method for detecting and counting button presses.
// Program to demonstrate the MD_Parola library
// button select canned messages
// MD_MAX72XX library can be found at https://github.com/MajicDesigns/MD_MAX72XX
// by groundFungus AKA c. goulding
#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
const byte buttonPin = 7; // the pin that the pushbutton is attached to
// Define the number of devices we have in the chain and the hardware interface
// NOTE: These pin numbers will probably not work with your hardware and may
// need to be adapted
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 8
#define CLK_PIN 13
#define DATA_PIN 11
#define CS_PIN 10
MD_Parola P = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
// individual messages in strings
const char msg_1[] = "it is time";
const char msg_2[] = "all good men";
const char msg_3[] = "to come to";
const char msg_4[] = "the aid of";
const char msg_5[] = "their";
const char msg_6[] = "country";
// an array of pointers to the strings
char *messages[] = {msg_1, msg_2, msg_3, msg_4, msg_5, msg_6};
byte messageNum = sizeof(messages) / sizeof(messages[0]);
int buttonPushCounter = 0; // counter for the number of button presses
int buttonState = 0; // current state of the button
int lastButtonState = 0; // previous state of the button
void setup(void)
{
Serial.begin(115200);
Serial.println("\nParola pick a message program\n");
P.begin();
pinMode(buttonPin, INPUT_PULLUP);
}
void loop(void)
{
if (P.displayAnimate()) // time to show next frame?
{
P.displayText(messages[buttonPushCounter], PA_CENTER, 200, 3000, PA_SCROLL_DOWN, PA_SCROLL_UP);
}
checkButton();
}
void checkButton()
{
static unsigned long timer = 0;
unsigned long interval = 50;
if (millis() - timer >= interval)
{
timer = millis();
buttonState = digitalRead(buttonPin);
// compare the buttonState to its previous state
if (buttonState != lastButtonState)
{
if (buttonState == LOW)
{
// if the current state is LOW then the button
// went from off to on:
buttonPushCounter++; // add one to counter
// if counter over number of messages, reset the counter to message 0
if (buttonPushCounter >= messageNum)
{
buttonPushCounter = 0;
}
//Serial.println(buttonPushCounter);
}
}
lastButtonState = buttonState;
}
}
You may need to add button debounce. This is tested and works OK with my Uno and 8 FC16 8x8 matrix modules.
I can't thank you enough. This is perfect since it allows me to see different ways of getting to the same end result. It also allows me to see what's easier for me. I am one of those people who prefer code that's "readable", easier to understand and follow what it's doing. Using remarks is fine, and they help out immensely, but being able to read the code is better in my opinion.
@groundFungus uses byte messageNum = sizeof(messages) / sizeof(messages[0]); and I use #define NUM_MESSAGES 2.
Those are the same things. It is the total number of messages. The one that groundFungus uses asks the compiler how many elements there are in the array.
We both use the State Change Detection, that I linked to earlier.
There are a few minor differences. I have never used a MAX7219 display so I don't know what I'm doing, and it seems that groundFungus has it laying on his table.
I had to change yours a little to work with my setup, but it works great as well!
Would work better if I had more than one 4 unit display. I do plan on picking up a few more, but I wanted to make sure I have a grasp of what I am doing first. lol
// Program to demonstrate the MD_Parola library
// button select canned messages
// MD_MAX72XX library can be found at https://github.com/MajicDesigns/MD_MAX72XX
// by groundFungus AKA c. goulding
#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
const byte buttonPin = 2; // the pin that the pushbutton is attached to
// Define the number of devices we have in the chain and the hardware interface
// NOTE: These pin numbers will probably not work with your hardware and may
// need to be adapted
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4
#define CLK_PIN 5
#define DATA_PIN 4
#define CS_PIN 3
MD_Parola P = MD_Parola(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);
// individual messages in strings
const char msg_1[] = "it is time";
const char msg_2[] = "all good men";
const char msg_3[] = "to come to";
const char msg_4[] = "the aid of";
const char msg_5[] = "their";
const char msg_6[] = "country";
// an array of pointers to the strings
char *messages[] = {msg_1, msg_2, msg_3, msg_4, msg_5, msg_6};
byte messageNum = sizeof(messages) / sizeof(messages[0]);
int buttonPushCounter = 0; // counter for the number of button presses
int buttonState = 0; // current state of the button
int lastButtonState = 0; // previous state of the button
void setup(void)
{
Serial.begin(115200);
Serial.println("\nParola pick a message program\n");
P.begin();
pinMode(buttonPin, INPUT_PULLUP);
}
void loop(void)
{
if (P.displayAnimate()) // time to show next frame?
{
P.displayText(messages[buttonPushCounter], PA_CENTER, 30, 0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
}
checkButton();
}
void checkButton()
{
static unsigned long timer = 0;
unsigned long interval = 50;
if (millis() - timer >= interval)
{
timer = millis();
buttonState = digitalRead(buttonPin);
// compare the buttonState to its previous state
if (buttonState != lastButtonState)
{
if (buttonState == LOW)
{
// if the current state is LOW then the button
// went from off to on:
buttonPushCounter++; // add one to counter
// if counter over number of messages, reset the counter to message 0
if (buttonPushCounter >= messageNum)
{
buttonPushCounter = 0;
}
//Serial.println(buttonPushCounter);
}
}
lastButtonState = buttonState;
}
}
I had planned on, eventually, working on a larger similar array that I could use to display basic pixel art. That will of course, require it's own separate power. For now though, I want to understand the basics before I try and dive too far into coding something like that. There are some good examples out there to work with, I will likely follow one of those, but I want to know what I'm doing first.
Electronics, not a problem, I built more projects than I can remember, back when I had the time, about 20 years ago. I am picking it back up now as a hobby. I find it relaxing. I just wish we had Arduino 20 years ago. lol
Again, thank you so much for the assistance! My wife thinks I am crazy, but this is my idea of fun.