Go Down

Topic: Setting pin to input breaks program (Read 459 times) previous topic - next topic

jrmymllr

Normally I design my own custom microcontroller-based solutions, but I was in a time pinch so I obtained my first (off-brand) Arduino boards.  It's a Mega 2560 clone and Ethernet shield with a W1500. 

I programmed the "WebServer" example to the board and it worked the first time, which was awesome.  I used this example as a starting point for a project where it listens for commands over my LAN and will play a tune using the tone() function, a LAN-based doorbell/alarm of sorts.  This worked fine so far.

Here's where I ran into problems: I want to use tone() to output to either of two pins for the purpose of having two different volume levels.  I'm using a BJT to drive a speaker and one Arduino pin goes to the base of the BJT through a resistor, and the other Arduino pin goes through a different value resistor to the same BJT.

This works as it should, IF both Arduino pins are not connected at the same time.  It's clear the inactive pin is set as an output and, let's say, exerting its influence on the BJT.  No problem, set the inactive pin to an input with pinMode(pin, INPUT) so it's high impedance, right? 

This causes some totally unexpected behavior.  I'm using pins 53 and 22 as tone() outputs, but have also tried others.  This is on a header that the Ethernet shield is not using, and from what I can tell, should be completely free to use.  When I use the pinMode() function to set the inactive pin to an input, the program is getting stuck in EthernetClient client = server.available();, as I'm checking for incoming connections while playing the tune in a loop.  If I do not use pinMode(pin, INPUT), program execution runs just fine, except the inactive pin is causing problems.  This makes no sense!  Normally it would be easy to track down the cause, but so much of what is happening is abstracted away with Arduino. 



Anybody have any idea what is happening?  The suspect section of code is below.  It's crude but generally seems to do the job.


Code: [Select]
    else if (strstr(&req[0], "GET /TRIGGER/") > 0)
    {
pinMode(53, INPUT)
      while (digitalRead(49) == LOW)
      {
        int thisNote;
        thisNote = 0;
   
        while ((thisNote < 56))
        {
          int noteDuration = 1000 / underworld_tempo[thisNote];
          tone(22, underworld_melody[thisNote], noteDuration);
          int pauseBetweenNotes = noteDuration * 1.30;
          delay(pauseBetweenNotes);
          noTone(22);
          thisNote++;
          EthernetClient client = server.available();
          if (client)
          {
            client.stop();
          }
        }

      }
    }





econjack

It would be better to see all of the code, since we can't tell completely what's going on. Also, you can simplify some of the code. Example:

Code: [Select]

        //  int pauseBetweenNotes = noteDuration * 1.30;
        //  delay(pauseBetweenNotes);

          delay(noteDuration * 1.30);   // This will get truncated

jrmymllr

Here's the complete code.  Pins 43 and 45 are used for a switch and status LED, but that works.  It's hacked together but this isn't very refined yet.

Code: [Select]
#include <SPI.h>
#include <Ethernet.h>
#include "pitches.h"

int melody[] = {
  NOTE_E7, NOTE_E7, 0, NOTE_E7,
  0, NOTE_C7, NOTE_E7, 0,
  NOTE_G7, 0, 0,  0,
  NOTE_G6, 0, 0, 0,
  NOTE_C7, 0, 0, NOTE_G6,
  0, 0, NOTE_E6, 0,
  0, NOTE_A6, 0, NOTE_B6,
  0, NOTE_AS6, NOTE_A6, 0,
  NOTE_G6, NOTE_E7, NOTE_G7,
  NOTE_A7, 0, NOTE_F7, NOTE_G7,
  0, NOTE_E7, 0, NOTE_C7,
  NOTE_D7, NOTE_B6, 0, 0,
  NOTE_C7, 0, 0, NOTE_G6,
  0, 0, NOTE_E6, 0,
  0, NOTE_A6, 0, NOTE_B6,
  0, NOTE_AS6, NOTE_A6, 0,
  NOTE_G6, NOTE_E7, NOTE_G7,
  NOTE_A7, 0, NOTE_F7, NOTE_G7,
  0, NOTE_E7, 0, NOTE_C7,
  NOTE_D7, NOTE_B6, 0, 0
};

int noteDurations[] = {
  12, 12, 12, 12,
  12, 12, 12, 12,
  12, 12, 12, 12,
  12, 12, 12, 12,

  12, 12, 12, 12,
  12, 12, 12, 12,
  12, 12, 12, 12,
  12, 12, 12, 12,

  9, 9, 9,
  12, 12, 12, 12,
  12, 12, 12, 12,
  12, 12, 12, 12,

  12, 12, 12, 12,
  12, 12, 12, 12,
  12, 12, 12, 12,
  12, 12, 12, 12,

  9, 9, 9,
  12, 12, 12, 12,
  12, 12, 12, 12,
  12, 12, 12, 12,
};


byte mac[] =
{
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
IPAddress ip(192, 168, 0, 201);

EthernetServer server(80);

void setup()
{
  Serial.begin(9600);
  while (!Serial)
  {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.println(Ethernet.localIP());
  pinMode(43, INPUT_PULLUP);/* connected to toggle switch*/
  pinMode(45, OUTPUT);/*connected to LED*/

}

void loop()
{
  char req[1000];
  unsigned int req_ptr;
  EthernetClient client = server.available();
  if (client)
  {
    boolean currentLineIsBlank = true;
    req_ptr = 0;
    while (client.connected())
    {
      if (client.available())
      {
        char c = client.read();
        Serial.write(c);

        req[req_ptr] = c;
        req_ptr++;

        if (c == '\n' && currentLineIsBlank)
        {
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // the connection will be closed after completion of the response
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");
          client.print("done");
          client.println("<br />");
          client.println("</html>");
          break;
        }
        if (c == '\n')
        {
          currentLineIsBlank = true;
        }
        else if (c != '\r')
        {
          currentLineIsBlank = false;
        }
      }
    }

    delay(1);
    client.stop();

    if (strstr(&req[0], "GET /LOUD/") > 0)
    {
      int blink = 0, led = 0;
    pinMode(22, INPUT);/*this line causes execution to get hung up in server.available()*/
     
      while (digitalRead(43) == LOW)
      {
        int thisNote = 0;
 
        while ((thisNote < 78) && (digitalRead(43) == LOW))
        {
          int noteDuration = 1000 / noteDurations[thisNote];
          tone(53, melody[thisNote], noteDuration);

          blink++;
          if ((blink % 5) == 0)
          {
            if (led == 0)
            {
              digitalWrite(45, HIGH);
              led = 1;
            }
            else
            {
              digitalWrite(45, LOW);
              led = 0;
            }
          }
          delay(noteDuration * 1.30);
          noTone(53);
          thisNote++;
          EthernetClient client = server.available();
          if (client)
          {
            client.stop();
          }
        }

      }
    }
    else if (strstr(&req[0], "GET /QUIET/") > 0)
    {
    int blink = 0, led = 0;
      pinMode(53, INPUT); /*this line causes execution to get hung up in server.available()*/
      while (digitalRead(43) == LOW)
      {
        int thisNote = 0;
 
        while ((thisNote < 78) && (digitalRead(43) == LOW))
        {
          int noteDuration = 1000 / noteDurations[thisNote];
          tone(22, melody[thisNote], noteDuration);

          blink++;
          if ((blink % 5) == 0)
          {
            if (led == 0)
            {
              digitalWrite(45, HIGH);
              led = 1;
            }
            else
            {
              digitalWrite(45, LOW);
              led = 0;
            }
          }
          delay(noteDuration * 1.30);
          noTone(22);
          thisNote++;
          EthernetClient client = server.available();
          if (client)
          {
            client.stop();
          }
        }

      }
    }

  }

  if (digitalRead(43) == LOW)
  {
    digitalWrite(45, HIGH);
  }
  else
  {
    digitalWrite(45, LOW);
  }
}


Robin2

Pin 53 is the SS pin for SPI. Even if it is not being used for SPI purposes it should be set as OUTPUT to ensure that the Arduino acts as the SPI master.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

MarkT

Yes, you definitely shouldn't set SS as an input if you're using SPI, the hardware drops out into slave mode.

Anyway there's no reason to set it to high-Z for your purposes if you add diodes to the output pins.
[ I DO NOT respond to personal messages, I WILL delete them unread, use the forum please ]

jrmymllr

Pin 53 is the SS pin for SPI. Even if it is not being used for SPI purposes it should be set as OUTPUT to ensure that the Arduino acts as the SPI master.

...R
Ahhh, I see.  I assumed these header pins that are open were free and clear to use, but my unfamiliarity with Arduino and AVR is showing.  Thanks for the heads up!

jrmymllr

Yes, you definitely shouldn't set SS as an input if you're using SPI, the hardware drops out into slave mode.

Anyway there's no reason to set it to high-Z for your purposes if you add diodes to the output pins.
I know, I could add diodes but why if I can add code :)  Now I think I should definitely be looking at the schematic for this board.

Go Up