How to set all digital pins to HIGH by default

Hello,
I'm using an Arduino UNO R3 to run a modified version of code that reads MIDI files from an SD card and sends it as a digital output as mentioned here. The code I have right now works all right, it plays the MIDI file and moves to the next one using an IR remote. But whenever it first starts to play, all the digital pins (which I have connected to an eight-channel relay) are set to LOW by default. That is to say that power is allowed to flow through all the relays. And since the actuators that I have connected to the NC of the relay are wired in parallel, they can only play one note at a time due to amp constraints, meaning that until every note is read at least once, no note can be played by the actuators. So, I just want to find a way to set all the pins to HIGH before the notes are read.

*I also want to specify that most of the code that I included was written by eijifrey, not me.

#include "SdFat.h"
#include <MD_MIDIFile.h>
#include <IRremote.h>

#define SERIAL_RATE 57600

#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))

const uint8_t NOTE_SIZE = 1; // Number of items in each note listing

// Define a structure to contain all the related data for executing a note
typedef struct
{
  const int pin;              // Motor output relay pin
  const int note[NOTE_SIZE];  // MIDI pitch value for each "note"
} noteData_t;

noteData_t noteData[] =
{
    {2, {84}},  // Note C5
    {3, {86}},   // Note D5
    {4, {88}},   // Note E5
    {5, {89}},   // Note F5
    {6, {91}},   // Note G5
    {7, {93}},   // Note A5
    {8, {95}},   // Note B5
    {9, {96}}    // Note C6
};

// SD chip select pin for SPI comms.
const uint8_t SD_SELECT = 10;

// The files in the tune list should be located on the SD card
// or an error will occur opening the file and the next in the
// list will be opened (skips errors).
const char *tuneList[] =
{
    "6.mid", // Most complex and fast file
    "7.mid", // Another example tune
    "8.mid"  // Another example tune
};

SdFat SD;
MD_MIDIFile SMF;

IRrecv irrecv(14); // Define the IR receiver pin
decode_results results;

#define NOTE_DELAY_MS 50  // 50 ms delay between notes

void midiCallback(midi_event *pev)
{
    if (pev->size > 0 && (pev->data[0] == 0x80 || pev->data[0] == 0x90))
    {
        playNote(pev->data[1], pev->data[2]);
        delay(NOTE_DELAY_MS);  // Delay after each note to create separation
    }
}


void playNote(int pitch, int velocity)
{
    int state = (velocity > 10) ? LOW : HIGH;
    bool found = false;

    for (uint8_t n = 0; n < ARRAY_SIZE(noteData) && !found; n++)
    {
        for (uint8_t m = 0; m < NOTE_SIZE && !found; m++)
        {
            if (pitch == noteData[n].note[m])
            {
                found = true;
                digitalWrite(noteData[n].pin, state);
            }
        }
    }
}

void sysexCallback(sysex_event *pev)
{
    // Ignored as sysex events are not handled in this setup
}

void midiSilence()
{
    // Turn everything off on every channel.
    midi_event ev;

    // All sound off
    ev.size = 0;
    ev.data[ev.size++] = 0xb0;
    ev.data[ev.size++] = 120;
    ev.data[ev.size++] = 0;

    for (ev.channel = 0; ev.channel < 16; ev.channel++)
        midiCallback(&ev);
}

// Function to set all relay pins to LOW
void resetRelayPins()
{
    for (uint8_t i = 0; i < ARRAY_SIZE(noteData); i++)
    {
        digitalWrite(noteData[i].pin, LOW);
    }
}

void setup()
{
    // Set up motor pins
    for (uint8_t i = 0; i < ARRAY_SIZE(noteData); i++)
    {
        pinMode(noteData[i].pin, OUTPUT);
    }

    // Initialize Serial, SD, and IR
    Serial.begin(SERIAL_RATE);

    if (!SD.begin(SD_SELECT, SPI_FULL_SPEED))
    {
        while (true);  // Halt if SD initialization fails
    }

    SMF.begin(&SD);
    SMF.setMidiHandler(midiCallback);
    SMF.setSysexHandler(sysexCallback);
    irrecv.enableIRIn();  // Initialize IR receiver
}

void loop()
{
    static enum { S_IDLE, S_PLAYING, S_END, S_WAIT_BETWEEN } state = S_IDLE;
    static uint16_t currTune = 0;  // Start with the first song
    static uint32_t timeStart;

    // Check for IR remote input
    if (irrecv.decode(&results))
    {
        long int decCode = results.value;
        irrecv.resume();  // Receive the next value

        // Check if the up or down buttons are pressed
        if (decCode == 0xFF10EF)  // Up button (replace with actual code)
        {
            // Go back to the previous song
            if (currTune == 0)
                currTune = ARRAY_SIZE(tuneList) - 1; // Loop to the last song
            else
                currTune--;
        }
        else if (decCode == 0xFF5AA5)  // Down button (replace with actual code)
        {
            // Go forward to the next song
            currTune++;
            if (currTune >= ARRAY_SIZE(tuneList))
                currTune = 0; // Loop back to the first song
        }

        // Stop the current song before starting a new one
        if (state == S_PLAYING || state == S_END)
        {
            SMF.close();  // Close the current MIDI file
            midiSilence();  // Turn off all notes
        }

        // Reset relay pins before starting the new song
        resetRelayPins();

        // Restart the song
        state = S_IDLE;
    }

    switch (state)
    {
    case S_IDLE:    // Now idle, set up the next tune
    {
        int err;

        // Use the next file name and play it
        err = SMF.load(tuneList[currTune]);
        if (err != MD_MIDIFile::E_OK)
        {
            timeStart = millis();
            state = S_WAIT_BETWEEN;
        }
        else
        {
            state = S_PLAYING;
        }
    }
    break;

    case S_PLAYING: // Play the file
        if (!SMF.isEOF())
        {
            if (SMF.getNextEvent());
        }
        else
            state = S_END;
        break;

    case S_END:   // Done with this one
        SMF.close();
        midiSilence();
        timeStart = millis();
        state = S_WAIT_BETWEEN;
        break;

    case S_WAIT_BETWEEN:    // Signal finished with a pause
        if (millis() - timeStart >= 2000)
            state = S_IDLE;
        break;

    default:
        state = S_IDLE;
        break;
    }
}

If I understand what you're asking for, it's very simple:

    // Set up motor pins
    for (uint8_t i = 0; i < ARRAY_SIZE(noteData); i++)
    {
        digitalWrite(noteDate[i].pin, HIGH); // <--- add this
        pinMode(noteData[i].pin, OUTPUT);
    }

In the interest of completeness, I should mention that writing to a pin before it's set to OUTPUT doesn't work on the Uno R4 (you have to do pinMode(pin, OUTPUT) then digitalWrite(pin, HIGH). It works fine on the Uno R3 though. The advantage of doing it this way is you don't get a few microseconds of LOW on the output before it's written HIGH.

1 Like

Thank you so much! I'm kind of new to this and your help is greatly appreciated!

@van_der_decken
This is AFAIK the recommended way to set a pin HIGH before setting it to OUTPUT.

pinMode(pin, INPUT_PULLUP); // first enable internal pull up
pinMode(pin, OUTPUT); // then set the pin to output

Maybe that works on an R4 (don't have one).
Leo..

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.