Trying to work with MIDI Shield on SerialPort 2 (pins 16/17) #317
-
I am working on an escape room puzzle, based on Pay It Again Sam, from Playful Tech. My biggest problem is the MIDI Shield I have is hard wired to Pins 0/1 so this creates issues when trying to debug or run with an ethernet shield, etc. I am trying to move the MIDI Shield to pins 16/17 Serial2 on the Mega 2560 that I have pins on. At present the MIDI Shield,(https://tinkersphere.com/shields/3187-midi-shield-for-arduino.html), I am using doesn't have an easy method to do this, so at present the 5V side of the shield is plugged into the ethernet shield, the pins on the other side have been slightly bent and the shield is NOT in the headers. For the hardware serial, I have jumper wires going from 0/1 to the 17/16 pins for Serial2. I have tried denoting the change in code, but no matter what I do, it will not respond in the program. How do I use an alternative Serial interface? Coding examples are VERY much appreciated. |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 3 replies
-
You could use SoftwareSerial on any two pins, check out the examples. |
Beta Was this translation helpful? Give feedback.
-
@franky47, I am trying that. But it is not wanting to fire up. Here is my code: #include <FastLED.h>
#include <MIDI.h>
// This library defines a simple list structure to keep track of multiple notes played simultaneously by the player
#include "noteList.h"
// Lookup table to define tone frequency of musical notes. e.g. Concert A = 440Hz
#include "pitches.h"
// Standard Epicenter Libraries
#include <SPI.h>
#include <Ethernet.h>
#include <Wire.h>
#include <aREST.h>
#include <avr/wdt.h>
#include <SoftwareSerial.h>
#define debug
int rxPin = 17;
int txPin = 16;
SoftwareSerial mySerial = SoftwareSerial(rxPin, txPin);
// CONSTANTS
// Define the number of steps in the sequence that the player must follow
const byte numSteps = 48;
// The correct melody required to solve the puzzle.
// Defined using MIDI note numbers - see http://www.inspiredacoustics.com/en/MIDI_note_numbers_and_center_frequencies
const int RELAY_PIN = 40;
String nextGameCode = "";
bool gameCodeSent = false;
int gameStatus = 0; // 0=default, 1=startup. 2=start, 3=solved, 4=done, 5=shutdown
// Keyboard Numbers:
// 5th Symphony: 20(G-67), 20(G-67), 20(G-67), 16(Eb-63), 18(F-65), 18(F-65), 18(F-65), 15(D-62)
// Ode To Joy: 22(A-69), 22(A-69), 23(Bb-70), 25(C-72), 25(C-72), 23(Bb-70), 22(A-69), 20(G-67), 18(F-65), 18(F-65), 20(G-67), 22(A-69), 22(A-69), 20(G-67), 20(G-67)
// Fur Elise: 17(E-64), 16(Eb-63), 17(E-64), 16(Eb-63), 17(E-64), 12(B-59), 15(D-62), 13(C-60). 10(A-57)
// Rick Roll: 10(A-57),12(B-59), 15(D-62), 12(B-59), 19(F#-66), 19(F#-66), 17(E-64), 10(A-57), 12(B-59), 14(C#-61), 10(A-57), 17(E-64), 17(E-64), 15(D-62), 14(C#-61), 12(B-59)
const byte melody[numSteps] = {67, 67, 67, 63, 65, 65, 65, 62, 69, 69, 70, 72, 72, 70, 69, 67, 65, 65, 67, 69, 69, 67, 67, 64, 63, 64, 63, 64, 59, 62, 60, 57, 57, 59, 62, 59, 66, 66, 64, 57, 59, 61, 57, 64, 64, 62, 61, 59 };
// The MIDI note of the key which will reset the puzzle when pressed. 49 = C#3
const byte resetPitch = 49;
// This pin will have a piezo buzzer connected to it to produce crude audio output
const byte audioOutPin = 9;
// The maximum number of notes that we'll keep track of being pressed at once
const unsigned int maxHeldNotes = 16;
// GLOBALS
// This macro creates an instance of the MIDI interface using the hardware serial ports (0 and 1)
MIDI_CREATE_INSTANCE(SoftwareSerial, mySerial, MIDI);
// Create a list structure to keep track of the notes currently being held
MidiNoteList<maxHeldNotes> midiNotes;
// What step of the melody is the player currently on?
int currentStep = 0;
// Create an array to hold the RGB values of each LED in the strip
CRGB leds[numSteps];
CRGB overhead[8];
// Track the overall state of the puzzle
enum PuzzleState {Initialising, Running, Solved};
PuzzleState puzzleState = Initialising;
// aREST to NodeRed
int HTTP_PORT = 1880;
String HTTP_METHOD = "GET";
char HOST_NAME[] = "172.16.40.100";
String PATH_NAME = "/api";
String queryString = "";
// Create aREST instance
aREST rest = aREST();
// The MAC Address and IP for the game
byte mac[] = {
0xDE, 0xAD, 0x02, 0x00, 0x00, 0x08
};
IPAddress ip(172, 16, 40, 108);
EthernetServer server(80);
EthernetClient client;
EthernetClient client2;
// Create Reset function
void(* resetFunc) (void) = 0; //declare reset function @ address 0
/**
Called when the program first starts, or each time it is reset
*/
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(115200);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
Serial.println(__FILE__);
Serial.println("Compiled: " __DATE__ ", " __TIME__);
while (Ethernet.linkStatus() == LinkOFF) {
Serial.println(F("Ethernet cable is not connected."));
delay(500);
}
// start the Ethernet connection:
Serial.println(F("Attempting to obtain IP from DHCP, stand by..."));
Ethernet.begin(mac);
delay(1000);
if (Ethernet.begin(mac) == 0) {
// Failed to configure ethernet using DHCP, reverting to static IP
Serial.print(F("Failed to obtain DHCP address, reverting to "));
Serial.println(ip);
Ethernet.begin(mac, ip);
} else {
// Obtained DHCP address
Serial.print(F("Received IP: "));
Serial.println(Ethernet.localIP());
}
if (client.connect(HOST_NAME, HTTP_PORT)) {
NodeRedUpdate("?game=beethoven&action=startup");
gameStatus = 1;
} else {
Serial.println(F("Failed connecting to NodeRed Server"));
}
rest.function("favicon.ico", favIcon);
rest.function("gameState", setGameState);
rest.function("gameReset", setGameReset);
rest.function("api", returnAPI);
rest.set_id("011");
rest.set_name("Epicenter_Beethoven");
// The handleNoteOn callback function will be triggered on receipt of a MIDI NoteOn msg
MIDI.setHandleNoteOn(handleNoteOn);
// The handleNoteOff callback function will be triggered on receipt of a MIDI NoteOff msg
MIDI.setHandleNoteOff(handleNoteOff);
// Initiate MIDI communications - my keyboard input uses MIDI channel 1
MIDI.begin(1);
Serial.println(F("MIDI Interface Initialized."));
// Initialise the LED strip on pin A0. WS2812B strip uses GRB byte-ordering.
FastLED.addLeds<WS2812B, A15, GRB>(leds, numSteps);
FastLED.clear();
FastLED.addLeds<WS2812B, A12, GRB> (overhead, A0);
FastLED.setBrightness(175);
FastLED.show();
//Initialize the power to the keyboard
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, LOW);
Serial.println(F("Relay initialized and pulled low."));
//Puzzle initialized, ready to run.
gameStatus = 2; // <=== TEMPORARY during testing
puzzleState = Running;
Serial.println(F("Temporarily added. Power cycling the keyboard:"));
digitalWrite(RELAY_PIN, HIGH);
delay(6000);
digitalWrite(RELAY_PIN, LOW);
Serial.println(F("Relay has been cycled."));
Serial.println(F("Ready for REST API."));
}
/**
Callback function to handle a new note being pressed
*/
void handleNoteOn(byte channel, byte pitch, byte velocity) {
Serial.print(F("MIDI Note ON: "));
Serial.print(String(pitch));
Serial.print(F(" | "));
Serial.print(String(velocity));
Serial.println(F(""));
// Add the note value to our list of notes being played
midiNotes.add(MidiNote(pitch, velocity));
// Play the note on the buzzer
tone(audioOutPin, sNotePitches[pitch]);
// If the puzzle is in progress..
if (puzzleState == Running) {
// Has the correct note been pressed?
if (pitch == melody[currentStep]) {
// Move on to the next note in the melody
currentStep++;
// Have we reached the last note in the melody?
if (currentStep == numSteps) {
// Puzzle has been solved!
onSolve();
}
}
// Has an incorrect note been pressed?
else {
// Flash the LEDs red
for (int x = 0; x < 2; x++) {
for (int i = currentStep; i < numSteps; i++) {
leds[i] = CRGB::Red;
}
FastLED.show();
delay(100);
for (int i = currentStep; i < numSteps; i++) {
leds[i] = CRGB::Black;
}
FastLED.show();
delay(100);
}
// Start from the beginning of the sequence again
currentStep = 0;
}
}
// If the puzzle is solved, has the reset key being pressed?
else if (puzzleState == Solved && pitch == resetPitch) {
onReset();
}
}
/**
Callback function to handle a note being released
*/
void handleNoteOff(byte channel, byte pitch, byte velocity) {
Serial.print(F("MIDI Note OFF: "));
Serial.print(String(pitch));
Serial.print(F(" | "));
Serial.print(String(velocity));
Serial.println(F(""));
// Remove this note from the list of notes being held
midiNotes.remove(pitch);
// If no other notes are being held
if (midiNotes.empty()) {
// Turn off the audio
noTone(audioOutPin);
}
// If there are other notes still being held down
else {
// Get the last note to be added (i.e. the most recently played one)
byte currentNote = 0;
if (midiNotes.getLast(currentNote)) {
// And play that note instead
tone(audioOutPin, sNotePitches[currentNote]);
}
}
}
/**
Updates the LED strip based on the current game state
*/
void updateDisplay() {
switch (puzzleState) {
Serial.print(F("updateDisplay called - "));
Serial.println(puzzleState);
// If the game is in progress
case Running:
// Turn on the number of LEDs corresponding to the current step
for (int i = 0; i < numSteps; i++) {
if (i < 8) {
leds[i] = (i < currentStep ? CRGB::Green : CRGB::Black);
} else if (i < 23) {
leds[i] = (i < currentStep ? CRGB::Blue : CRGB::Black);
} else if (i < 32) {
leds[i] = (i < currentStep ? CRGB::Yellow : CRGB::Black);
} else {
leds[i] = (i < currentStep ? CRGB::Purple : CRGB::Black);
}
}
break;
// If the game has been completed
case Solved:
// Show a chase sequence of blue LEDs
fadeToBlackBy(leds, numSteps, 20);
int pos = beatsin16(12, 0, numSteps - 1);
leds[pos] = CRGB::Blue;
FastLED.delay(30);
break;
}
// Update the display
FastLED.show();
}
/**
This function is called when the puzzle is reset
*/
void onReset() {
// Stop the audio
noTone(audioOutPin);
// Light the LEDs up yellow
for (int i = 0; i < numSteps; i++) {
leds[i] = CRGB::Yellow;
FastLED.show();
FastLED.delay(20);
leds[i] = CRGB::Black;
}
// Then clear the LED display
for (int i = 0; i < numSteps; i++) {
leds[i] = CRGB::Black;
}
FastLED.show();
// And update the puzzle state
puzzleState = Running;
}
/**
This function gets called when the puzzle is solved
*/
void onSolve() {
// Set the puzzle state
puzzleState = Solved;
gameStatus = 3;
NodeRedUpdate("?game=beethoven&action=solved");
}
/**
Main program loop
*/
void loop() {
EthernetClient client = server.available();
rest.handle(client);
if (gameStatus == 2) {
// The read() function checks for incoming MIDI messages and automatically calls the assigned NoteOn or NoteOff callback
// if a matching input has been received - no further action required!
MIDI.read();
// Updates the LED strip based on the current state of the puzzle
updateDisplay();
}
if (gameStatus == 3) {
// game is solved
onSolve();
}
}
//----------------------------------------------------------
// REST COMMANDS
int setGameState(String gameState) {
Serial.println(F("Game State called for."));
if (gameState == "start") {
digitalWrite(RELAY_PIN, HIGH);
Serial.println(F("Remotely Triggered: Game Begin."));
NodeRedUpdate("?game=beethoven&action=start");
delay(6000);
digitalWrite(RELAY_PIN, LOW);
// Start Game
gameStatus = 2;
// Set the puzzle state to running
puzzleState = Running;
for (int x = 0; x < 8; x++) {
overhead[x] = CRGB::White;
}
FastLED.show();
} else if (gameState == "solved") {
Serial.println(F("Remotely Triggered: Game Reset."));
NodeRedUpdate("?game=beethoven&action=solved");
onSolve();
} else if (gameState == "done") {
Serial.println(F("Remote Triggered: Game Done."));
for (int i = 0; i < numSteps; i++) {
leds[i] = (CRGB::Black);
FastLED.show();
delay(10);
}
for (int x = 0; x < 8; x++) {
overhead[x] = CRGB::Black;
}
FastLED.show();
NodeRedUpdate("?game=beethoven&action=done");
gameStatus = 4;
// Game done
} else if (gameState == "override") {
Serial.println(F("Remotely Triggered: Game Overridden, solved."));
setGameOverride();
}
return 001;
}
int setGameReset() {
for (int i = 0; i < numSteps; i++) {
leds[i] = (CRGB::Black);
FastLED.show();
delay(10);
}
delay(350);
resetFunc();
}
void setGameOverride() {
// api call to override and show game as solved.
for (int i = 0; i < numSteps; i++) {
if (i < 8) {
leds[i] = (CRGB::Green);
} else if (i < 23) {
leds[i] = (CRGB::Blue);
} else if (i < 32) {
leds[i] = (CRGB::Yellow);
} else {
leds[i] = (CRGB::Purple);
}
FastLED.show();
delay(50);
}
delay(1500);
// The game has been forced solved, show a chase sequence of blue LEDs
fadeToBlackBy(leds, 55, 20);
int pos = beatsin16(12, 0, numSteps - 1);
leds[pos] = CRGB::Blue;
// Update the display
FastLED.show();
//run onSolve
onSolve();
}
int returnAPI(String apiString) {
#ifdef debug
Serial.println(F("API received."));
#endif
}
int favIcon() { // fixes browser double call of functions
}
int NodeRedUpdate(String query) {
if (client.connect(HOST_NAME, HTTP_PORT)) {
client.println(HTTP_METHOD + " " + PATH_NAME + query + " HTTP/1.1");
client.println("Host: " + String(HOST_NAME));
client.println(F("Connection: close"));
client.println();
while (client.connected()) {
if (client.available()) {
char c = client.read();
//Serial.print(c);
}
}
client.stop();
//Serial.println(F("disconnected"));
} else {
//Serial.println(F("connection failed"));
}
} |
Beta Was this translation helpful? Give feedback.
@franky47, I am trying that. But it is not wanting to fire up. Here is my code: