I have a Geniuno Micro board project where I would like to mount an LED on the outside of an enclosure that displays the Tx information (essentially just mimicing the small onboard LED).
I've tried connecting an LED to the Tx pin but I don't seem to be getting anything from it.
Should the connection be Tx pin to the LED - leg with the LED + leg going to +5v via a 1k resistor? Or should it be the Tx pin to the LED + leg via a 1k resistor with the LED - leg going off to GND? Either way there doesn't seem to be much happening with the external LED.
I'm sure this is covered somewhere but I couldn't find a board specific answer, would appreciate any links or tips.
But if you are instead using Serial, that is an interface directly between the ATmega32U4 microcontroller's USB interface and the computer, which is not broken out to the pin headers on the Micro.
The onboard LED is connected to Arduino pin 30 (which you can also reference in your code via the LED_BUILTIN_TX macro). Pin 30 is not broken out to the pin headers on the Micro, so there isn't a convenient way to make an electrical connection to that pin.
No. Serial1 doesn't have anything to do with the Tx LED. It is a completely separate communication interface from Serial. You would use it if you had a serial device connected to the RX and TX pins on the Micro.
You can add code to the sketch to blink your LED when it sends a MIDI message.
This would appear to be a good basic example of the kind of thing I'm after but is specifically for the MIDI.h library rather than the MIDIUSB.h library that I'm using for the rest of the code (for instance when I compile the code it doesn't understand the MIDI.begin command.)
Is there a straightforward way to alter this code for the MIDIUSB.h library?
#include <MIDI.h> // Or MIDIUSB.h for some boards
// Define the LED pin
int ledPin = 13;
// MIDI channel to listen on (0-15)
int midiChannel = 0;
void setup() {
pinMode(ledPin, OUTPUT); // Set the LED pin as output
MIDI.begin(midiChannel); // Start MIDI and listen on channel 0
}
void loop() {
// Check for MIDI messages
if (MIDI.read()) {
// Example: Blink the LED when a note on message is received
digitalWrite(ledPin, HIGH); // Turn LED ON
delay(500); // Wait for 500 milliseconds
digitalWrite(ledPin, LOW); // Turn LED OFF
delay(500); // Wait for 500 milliseconds
}
}
/*
Based on Sketch built by Gustavo Silveira (aka Music Nerd)
Modified by Dolce Wang
This code is only for Arduinos that use ATmega32u4 (like Micro, Pro Micro, Leonardo...)
Remember to also assign the correct board in the IDE (like Tools / Boards / Sparkfun AVR / Pro Micro...)
*/
// Change any fields with //**
// LIBRARY
#include "MIDIUSB.h"
// POTENTIOMETERS
const int NPots = 2; //*** total number of pots (knobs and faders)
const int potPin[NPots] = {A9, A10}; //*** define Analog Pins connected from Pots to Arduino; Leave nothing in the array if 0 pots {}
int potCState[NPots] = {0}; // Current state of the pot; delete 0 if 0 pots
int potPState[NPots] = {0}; // Previous state of the pot; delete 0 if 0 pots
int potVar = 0; // Difference between the current and previous state of the pot
int midiCState[NPots] = {0}; // Current state of the midi value; delete 0 if 0 pots
int midiPState[NPots] = {0}; // Previous state of the midi value; delete 0 if 0 pots
const int TIMEOUT = 300; //* Amount of time the potentiometer will be read after it exceeds the varThreshold
const int varThreshold = 10; //* Threshold for the potentiometer signal variation
boolean potMoving = true; // If the potentiometer is moving
unsigned long PTime[NPots] = {0}; // Previously stored time; delete 0 if 0 pots
unsigned long timer[NPots] = {0}; // Stores the time that has elapsed since the timer was reset; delete 0 if 0 pots
// MIDI Assignments
byte midiCh = 0; //* MIDI channel to be used
byte note = 36; //* Lowest note to be used; 36 = C2; 60 = Middle C
byte cc = 1; //* Lowest MIDI CC to be used
// SETUP
void setup() {
// Baud Rate
// 31250 for MIDI class compliant | 115200 for Hairless MIDI
}
// LOOP
void loop() {
potentiometers();
}
// POTENTIOMETERS
void potentiometers() {
for (int i = 0; i < NPots; i++) { // Loops through all the potentiometers
potCState[i] = analogRead(potPin[i]); // reads the pins from arduino
midiCState[i] = map(potCState[i], 0, 1023, 0, 127); // Maps the reading of the potCState to a value usable in midi
potVar = abs(potCState[i] - potPState[i]); // Calculates the absolute value between the difference between the current and previous state of the pot
if (potVar > varThreshold) { // Opens the gate if the potentiometer variation is greater than the threshold
PTime[i] = millis(); // Stores the previous time
}
timer[i] = millis() - PTime[i]; // Resets the timer 11000 - 11000 = 0ms
if (timer[i] < TIMEOUT) { // If the timer is less than the maximum allowed time it means that the potentiometer is still moving
potMoving = true;
}
else {
potMoving = false;
}
if (potMoving == true) { // If the potentiometer is still moving, send the change control
if (midiPState[i] != midiCState[i]) {
// Sends MIDI CC
// Use if using with ATmega32U4 (micro, pro micro, leonardo...)
controlChange(midiCh, cc + i, midiCState[i]); // (channel, CC number, CC value)
MidiUSB.flush();
potPState[i] = potCState[i]; // Stores the current reading of the potentiometer to compare with the next
midiPState[i] = midiCState[i];
}
}
}
}
// Arduino MIDI functions MIDIUSB Library
void noteOn(byte channel, byte pitch, byte velocity) {
midiEventPacket_t noteOn = {0x09, 0x90 | channel, pitch, velocity};
MidiUSB.sendMIDI(noteOn);
}
void noteOff(byte channel, byte pitch, byte velocity) {
midiEventPacket_t noteOff = {0x08, 0x80 | channel, pitch, velocity};
MidiUSB.sendMIDI(noteOff);
}
void controlChange(byte channel, byte control, byte value) {
midiEventPacket_t event = {0x0B, 0xB0 | channel, control, value};
MidiUSB.sendMIDI(event);
}
Very simple for creating a USB MIDI Joystick and can be fleshed out to include extra potentiometers etc
You can do something like what you found in that "MIDI.h" library example. However, this is what is known as "blocking" code, due to the use of delay:
The microcontroller can't do anything else for the 1000 ms (500 ms + 500 ms) during which this blocking code is running. That is a big problem when you want your program to react to external events (e.g., the user turns the potentiometer), or do multiple things simultaneously.
A better approach is to store a timestamp in a variable when some timed action (turning on the LED in this case) is initiated, then check the value returned by the millis() function in the loop function of your sketch and conclude the timed action when the value of millis() shows that sufficient time has elapsed since the timestamp.
You can see a simple example of that millis()-based approach in this tutorial:
Using that approach, if you wanted the LED to blink each time a MIDI message is sent, you could use digitalWrite to set the pin to which you have connected your LED LOW, and set the timestamp variable at this point in the sketch:
Then you would add code to the loop function that compares millis() against the timestamp and sets the pin HIGH when the difference is >= the duration you want for the blink.
So study that tutorial carefully and then have a go at adapting the sketch accordingly. If you get stuck, you can come back here with your updated sketch code and the forum helpers will provide assistance.
Thanks, I'm afraid marrying these two up us beyond what I understand how to do at the moment. I understand the original MIDI sketch to some extent and the tutorial code somewhat but I don't follow how set the timestamp at the position you highlighted.
I'm confident that you will be able to accomplish it with enough dedication and perseverance.
The forum helpers are here to assist you in your learning journey, but most of us aren't interested in doing the project for you. So if you make a strong effort at writing the code and get stuck, when you post the updated code it is likely the helpers will get you through that specific difficulty.
I recommend you begin by focusing all your attention on the "BlinkWithoutDelay" sketch for now. If you fully understand that sketch, you will have gained the foundation of knowledge for applying a similar technique to your MIDI project.
Start with the easy win of simply uploading the "BlinkWithoutDelay" sketch to your Micro board and verifying that the LED blinks as expected.
Next, adjust the "BlinkWithoutDelay" sketch code to make the LED blink faster. Upload it to the board again, and verify that the behavior is as you expect.
OK, if we can take this a little bit at a time it'd be helpful...
// MIDI Tx LED
const int ledPin = 2; // the number of the LED pin
int ledState = LOW; // ledState used to set the LED
unsigned long previousMillis = 0; // will store last time LED was updated
I've added this to my code where I have the LED on pin 2 and I want the initial state to be off. I've got the definition of previousMillis to be at 0 but this is then the first stumbling block for me... In the BlinkWithoutDelay example I can see this:
// constants won't change:
const long interval = 500; // interval at which to blink (milliseconds)
Which makes sense as a repeating flash every 500ms but how do I assign the interval to reference what's happening at controlChange(midiCh, cc + i, midiCState[i]); which is what I'm actually comparing to previousMillis = 0; in order to register a change with the LED?
As you noted, for your application, there won't be a fixed interval. Instead, the flash will be triggered at the point in the code where you call the controlChange function.
However, I think the reasonable approach will be to have a fixed blink duration. What I mean by this is that the LED will stay on for a fixed amount of time (e.g., 100 milliseconds) after each MIDI message is sent.
In the "BlinkWithoutDelay" sketch, the value of the interval variable actually determines the interval and the duration of the blink.
So you need write code that performs each of the following distinct operations:
Start Blink
When a MIDI message send is initiated, turn the LED on and save the timestamp in a global variable.
End Blink
On each execution of the loop function, check whether the blink duration has elapsed since the time of the timestamp, and if so turn the LED off.
This code will look similar to the following code in the "BlinkWithoutDelay" sketch:
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
// if the LED is off turn it on and vice-versa:
if (ledState == LOW) {
ledState = HIGH;
} else {
ledState = LOW;
}
// set the LED with the ledState of the variable:
digitalWrite(ledPin, ledState);
}
}
But your code will be more simple because the "BlinkWithoutDelay" sketch's code is toggling the state of the LED pin (If it is LOW, set it HIGH. If it is HIGH, set it LOW.) and your code only needs to turn the LED off.
That's great, this is helping a great deal and I now have the LED flashing where:
Start Blink
// MIDI Tx LED
const int ledPin = 2; // the number of the LED pin
int ledState = LOW; // ledState used to set the LED
unsigned long previousMillis = 0; // will store last time LED was updated
const long interval = 100; // interval at which to blink (milliseconds)
// SETUP
void setup() {
Serial.begin(32150);
pinMode(ledPin, OUTPUT); // set the digital pin as LED output
}
End Blink (within the loop function)
// Sends MIDI CC
// Use if using with ATmega32U4 (micro, pro micro, leonardo...)
controlChange(midiCh, cc + i, midiCState[i]); // (channel, CC number, CC value)
MidiUSB.flush();
// LED TIMESTAMPING
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
// if the LED is off turn it on and vice-versa:
if (ledState == LOW) {
ledState = HIGH;} else {
ledState = LOW;
}
// set the LED with the ledState of the variable:
digitalWrite(ledPin, ledState);
}
I wasn't sure what you were referring to here though?
If I declare the LED to be on with int ledState = LOW; don't I need to then include the "toggling" of on AND off within the loop function?
Otherwise, this is working well. The only downside of the approach is it is possible to end a pot turn with the LED remaining on as I guess it's not directly referencing the MIDI information being sent but actually the last-moved state the pot is in based on the timestamp?
As it stands it's not quite as accurate as the Tx LED on the board but it's certainly useful as visual feedback.
I have added "TODO" comments to the points in your sketch where I would add the code for each of those operations:
#include "MIDIUSB.h"
// POTENTIOMETERS
const int NPots = 2; //*** total number of pots (knobs and faders)
const int potPin[NPots] = { A9, A10 }; //*** define Analog Pins connected from Pots to Arduino; Leave nothing in the array if 0 pots {}
int potCState[NPots] = { 0 }; // Current state of the pot; delete 0 if 0 pots
int potPState[NPots] = { 0 }; // Previous state of the pot; delete 0 if 0 pots
int potVar = 0; // Difference between the current and previous state of the pot
int midiCState[NPots] = { 0 }; // Current state of the midi value; delete 0 if 0 pots
int midiPState[NPots] = { 0 }; // Previous state of the midi value; delete 0 if 0 pots
const int TIMEOUT = 300; //* Amount of time the potentiometer will be read after it exceeds the varThreshold
const int varThreshold = 10; //* Threshold for the potentiometer signal variation
boolean potMoving = true; // If the potentiometer is moving
unsigned long PTime[NPots] = { 0 }; // Previously stored time; delete 0 if 0 pots
unsigned long timer[NPots] = { 0 }; // Stores the time that has elapsed since the timer was reset; delete 0 if 0 pots
// MIDI Assignments
byte midiCh = 0; //* MIDI channel to be used
byte note = 36; //* Lowest note to be used; 36 = C2; 60 = Middle C
byte cc = 1; //* Lowest MIDI CC to be used
// SETUP
void setup() {
// Baud Rate
// 31250 for MIDI class compliant | 115200 for Hairless MIDI
}
// LOOP
void loop() {
// TODO: Add "End Blink" code here.
potentiometers();
}
// POTENTIOMETERS
void potentiometers() {
for (int i = 0; i < NPots; i++) { // Loops through all the potentiometers
potCState[i] = analogRead(potPin[i]); // reads the pins from arduino
midiCState[i] = map(potCState[i], 0, 1023, 0, 127); // Maps the reading of the potCState to a value usable in midi
potVar = abs(potCState[i] - potPState[i]); // Calculates the absolute value between the difference between the current and previous state of the pot
if (potVar > varThreshold) { // Opens the gate if the potentiometer variation is greater than the threshold
PTime[i] = millis(); // Stores the previous time
}
timer[i] = millis() - PTime[i]; // Resets the timer 11000 - 11000 = 0ms
if (timer[i] < TIMEOUT) { // If the timer is less than the maximum allowed time it means that the potentiometer is still moving
potMoving = true;
} else {
potMoving = false;
}
if (potMoving == true) { // If the potentiometer is still moving, send the change control
if (midiPState[i] != midiCState[i]) {
// Sends MIDI CC
// Use if using with ATmega32U4 (micro, pro micro, leonardo...)
controlChange(midiCh, cc + i, midiCState[i]); // (channel, CC number, CC value)
MidiUSB.flush();
// TODO: Add "Start Blink" code here.
potPState[i] = potCState[i]; // Stores the current reading of the potentiometer to compare with the next
midiPState[i] = midiCState[i];
}
}
}
}
// Arduino MIDI functions MIDIUSB Library
void noteOn(byte channel, byte pitch, byte velocity) {
midiEventPacket_t noteOn = { 0x09, 0x90 | channel, pitch, velocity };
MidiUSB.sendMIDI(noteOn);
}
void noteOff(byte channel, byte pitch, byte velocity) {
midiEventPacket_t noteOff = { 0x08, 0x80 | channel, pitch, velocity };
MidiUSB.sendMIDI(noteOff);
}
void controlChange(byte channel, byte control, byte value) {
midiEventPacket_t event = { 0x0B, 0xB0 | channel, control, value };
MidiUSB.sendMIDI(event);
}