The attached .ino files send and receive SysEx messages that are coded and decoded to display numbers on 8-digit MAX7219 displays. One Arduino Micro clone is used to send the SysEx message to the DAW (VMPK app) and the DAW passes the SysEx message to a second Arduino Micro clone which displays the message as an 8 digit number on one or more MAX7219 displays. Each Micro is connected through USB to a Mac which hosts the DAW software. The attached code sends messages to two MAX7219 displays. I hope you find these examples useful.
/**
SysEx-Send_Max7219-Message.ino
Lowell Bahner
2020-02-14
Uses 2 Sparkfun Pro Micro boards, 1 to send MIDI message, 1 to receive MIDI message
Micro1 sends SysEx message with embedded text[8+] chars to
display on MAX7219 connected to Micro2, the receiving MIDI device.
SysEx[1] contains 0x77 (arbitrary) and SysEx[2] contains arbitrary
device code which is checked by the receiving MIDI device, so it
displays on the desired device. Each SPI device uses a different CS
pin, similar in concept to a MIDI channel.
Serial monitor will display out going characters as integers.
Midi Monitor app will display SysEx as multiple bytes in hex format.
Example shows how to send MIDI System Exclusive messages.
*/
#include <Control_Surface.h>
// Instantiate the MIDI over USB interface
USBMIDI_Interface midi;
// Push button connected between pin 2 and ground.
// SysEx message is sent when pressed.
Button pushbutton = {2};
void setup() {
Serial.begin(115200);
pushbutton.begin(); // enables internal pull-up
midi.begin();
}
void loop() {
// Send a SysEx message when the push button is pressed
// convert double value to char string.
double value = 1234.567890;
char txt[16]; // Buffer big enough for 8-character float decimal point plus null
dtostrf(value, 6, 2, txt); // 6 total digits plus decimal plus 2 decimal digits --> txt[]
// insert txt[0...7] into sysex[3...10+]. Decimal points require an additional byte each.
// sysex[0] is start code, sysex[15] is end code
// sysex[1] is arbitrary manufacturer code
// sysex[2] is arbitrary device code for desired SPI output device on cs pin 10
//
uint8_t len = strlen(txt);
uint8_t sysex[] = {0xF0, 0x77, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xF7};
for (int i = 0; i < len; i++)
{
sysex[i + 3] = int8_t(txt[i]); // convert int8_t char to uint8_t sysex
}
// second display using cs=pin 9
char txt1[16]; // Buffer big enough for 8-character float decimal point plus null
dtostrf(value, 8, 4, txt1); // 8 total digits, decimal pt, with 4 decimal digits --> txt[]
len = strlen(txt1);
uint8_t sysex1[] = {0xF0, 0x77, 0x09, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xF7};
for (int i = 0; i < len; i++)
{
sysex1[i + 3] = int8_t(txt1[i]); // convert int8_t char to uint8_t sysex
}
if (pushbutton.update() == Button::Falling) {
Serial.println("SysEx from Device 10:");
Serial.println(txt);
for (int i = 0; i < 16; i++)
{
Serial.print(sysex[i]);
Serial.print(" ");
}
Serial.println(); // send line feed <cr>
Serial.println("SysEx from Device 9:");
Serial.println(txt1);
for (int i = 0; i < 16; i++)
{
Serial.print(sysex1[i]);
Serial.print(" ");
}
Serial.println(); // send line feed <cr>
// Serial output after buttonpush
/*
20:32:28.794 -> SysEx from Device 10:
20:32:28.794 -> 1234.57
20:32:28.794 -> 240 119 16 49 50 51 52 46 53 55 0 0 0 0 0 247
20:32:28.794 -> SysEx from Device 9:
20:32:28.794 -> 1234.5679
20:32:28.794 -> 240 119 9 49 50 51 52 46 53 54 55 57 0 0 0 247
*/
// send the SysEx message out the USB port
midi.send(sysex);
midi.send(sysex1);
}
// SysEx messages were sent.
// Midi Monitor:
// 03:32:48.132 From ProMicro musinou SysEx Unknown Manufacturer 16 bytes F0 77 10 31 32 33 34 2E 35 37 00 00 00 00 00 F7
// 03:32:48.132 From ProMicro musinou SysEx Unknown Manufacturer 16 bytes F0 77 09 31 32 33 34 2E 35 36 37 39 00 00 00 F7
}
/**
SysEx-Read-MAX7219-Message.ino
Modified MIDI-Input-Callback.ino by PieterP
Lowell Bahner 2020-02-15
This code reads incoming SysEx message on a SparkFun Pro Micro with 32U4 USB
attached to a Mac host USB port. The SysEx message is read and passes the
8 digits (bytes) to one or more MAX7219 displays.
Debug Serial was enabled in the Arduino Micro board.txt definition.
A SysEx message originates from another ProMicro with 32U4 USB, attached to the
Mac host through USB. The SysEx message includes 9+ bytes (8 digits plus a decimal point)
to populate a MAX7219 display, plus a manufacturer code and device code. Set those
to match the codes used by the sender code. By using different device codes, multiple
MAX7219 displays can be driven by the reader Arduino using different cs pins.
Arduinos on different USB ports with MAX7219 displays can also be run from one
sender Arduino.
The SysEx-Send_MAX7219-Message.ino sender code runs on a ProMicro using a
ProMicro musinou board definition which is just a renamed copy of the Micro definition
used to differentiate the boards by name (Micro and ProMicro musinou).
The SysEx message is logged on the Mac MIDI Monitor app.
The VMPK DAW app on Mac is used to route the MIDI messages using USB between the
two Arduinos. (vmpk:Edit:MIDI Connections:{Input:CoreMIDI:ProMicro musinou},
{Output:CoreMIDI:Arduino Micro})
The SysEx message includes 8+ bytes to display up to 8 digits on a MAX7219 display.
==============================
MIDI-Input-Callback Written by PieterP, 2019-08-07
https://github.com/tttapa/Control-Surface
*/
#include <Control_Surface.h> // Include the Control Surface library
USBMIDI_Interface midi;
//int led17 = 17; // on board blue LED, usually pin 13 for most Arduinos.
// ProMicro SPI pins used by Control_Surface MAX7219
uint8_t cs10 = 10; // pin 10 as first Max7219 CS
uint8_t cs09 = 9; // pin 9 as second Max7219 CS
// uint8_t mosi = 16; // pin 16 is ProMicro MOSI
// uint8_t sck = 15; // pin 15 is ProMicro SCK
// uint8_t miso = 14; // pin 14 is ProMicro MISO
MAX7219SevenSegmentDisplay max72_10 = {cs10}; // display # 1
MAX7219SevenSegmentDisplay max72_09 = {cs09}; // display # 2
// function to display the SysEx message on each MAX7219 display
void display_max7219(uint8_t msg[]) {
// the sysex message starts with "f0 77 XX ...", start byte, manufacturer code, device code
if (msg[1] != 0x77) return; // check for desired manufacturer code
if (msg[2] == 0x10) Serial.println("SysEx from Device 10:"); // device code 10
if (msg[2] == 0x09) Serial.println("SysEx from Device 09:"); // device code 09
char txt[16]; // array for the number as char array
for (int i = 0; i < strlen(msg); i++)
{
txt[i] = int8_t(msg[i + 3]); // convert uint8_t sysex to int8_t char
Serial.print(txt[i]);
Serial.print(" ");
}
Serial.println(" ");
// if the device code is accepted, display the txt on the device code display
if (msg[2] == 0x10) max72_10.display(txt, 0); // device code 10
if (msg[2] == 0x09) max72_09.display(txt, 0); // device code 09
}
// function to capture the incoming SysEx message
bool sysExMessageCallback(SysExMessage se) {
// send the se.data to the display function
// size_t len = se.length;
// uint8_t cn = se.CN; // port is not implemented, just = 0
display_max7219(se.data); // pass the data to MAX7219 function
// send debug info to Serial Log
Serial << F("System Exclusive message: ") << hex;
for (size_t i = 0; i < se.length; ++i)
Serial << se.data[i] << ' ';
Serial << dec << F("on cable ") << se.CN << endl;
return true; // Return true to indicate that handling is done,
// and Control_Surface shouldn't handle it anymore.
// If you want Control_Surface to handle it as well,
// return false;
}
/*
Serial output from Message Callback
19:51:36.857 -> SysEx from Device 10:
19:51:36.857 -> 1 2 3 4 . 5 7
19:51:36.857 -> System Exclusive message: f0 77 10 31 32 33 34 2e 35 37 00 00 00 00 00 f7 on cable 0
19:51:36.857 -> f0 77 09 31 32 33 34 2e 35 36 37 39 00 00 00 f7
19:51:36.857 -> SysEx from Device 09:
19:51:36.857 -> 1 2 3 4 . 5 6 7 9
19:51:36.857 -> System Exclusive message: f0 77 09 31 32 33 34 2e 35 36 37 39 00 00 00 f7 on cable 0
*/
/*
MIDI Monitor log:
02:55:54.343 From ProMicro musinou SysEx Unknown Manufacturer 16 bytes F0 77 10 31 32 33 34 2E 35 37 00 00 00 00 00 F7
02:55:54.343 From ProMicro musinou SysEx Unknown Manufacturer 16 bytes F0 77 09 31 32 33 34 2E 35 36 37 39 00 00 00 F7
02:55:54.349 From VMPK Output SysEx Unknown Manufacturer 16 bytes F0 77 10 31 32 33 34 2E 35 37 00 00 00 00 00 F7
02:55:54.349 To Arduino Micro SysEx Unknown Manufacturer 16 bytes F0 77 10 31 32 33 34 2E 35 37 00 00 00 00 00 F7
02:55:54.349 From VMPK Output SysEx Unknown Manufacturer 16 bytes F0 77 09 31 32 33 34 2E 35 36 37 39 00 00 00 F7
02:55:54.349 To Arduino Micro SysEx Unknown Manufacturer 16 bytes F0 77 09 31 32 33 34 2E 35 36 37 39 00 00 00 F7
*/
void setup() {
Serial.begin(115200);
max72_10.begin();
max72_10.clear();
max72_09.begin();
max72_09.clear();
Control_Surface.begin();
Control_Surface.setMIDIInputCallbacks(nullptr, //
sysExMessageCallback, //
nullptr); //
}
void loop() {
Control_Surface.loop();
}
The attached .ino files send and receive SysEx messages that are coded and decoded to display numbers on 8-digit MAX7219 displays. One Arduino Micro clone is used to send the SysEx message to the DAW (VMPK app) and the DAW passes the SysEx message to a second Arduino Micro clone which displays the message as an 8 digit number on one or more MAX7219 displays. Each Micro is connected through USB to a Mac which hosts the DAW software. The attached code sends messages to two MAX7219 displays. I hope you find these examples useful.