A strange issue with digitalWrite

I'm having a strange problem with digitalWrite. I have some writes that are not occurring that are immediately before another write. See the code below (this is on an Uno R3):

#include <EEPROM.h>

enum ACTIVE_OUTPUT_STATES {NONE, INPUT0, INPUT1, INPUT2};
enum POWER_STATES {ON, OFF};

const int EEPAddress = 50;

const int PixelData = 2;
const int PowerSW = 3;
const int PowerLED = 4;
const int PowerEnable = 19;
const int Input0SW = 5;
const int Input0LED = 6;
const int Input1SW = 7;
const int Input1LED = 8;
const int Input2SW = 9;
const int Input2LED = 10;
const int Input0Enable = 11;
const int Input1Enable = 12;
const int Input2Enable = 13;

const int debounceTime = 80;  //ms
const int messageTime = 1000; //ms
const int timeoutTime = 250; //ms

int OutputMemory;
int LastMessage = 0;
int x = 4;


ACTIVE_OUTPUT_STATES ActiveOutput = NONE;
POWER_STATES Power = OFF;

void setup() {
  // assign pinmodes

  Serial.begin(9600);



  pinMode(PixelData, OUTPUT);

  pinMode(PowerSW, INPUT);
  pinMode(PowerLED, OUTPUT);
  pinMode(PowerEnable, OUTPUT);

  pinMode(Input0SW, INPUT);
  pinMode(Input0LED, OUTPUT);
  pinMode(Input0Enable, OUTPUT);

  pinMode(Input1SW, INPUT);
  pinMode(Input1LED, OUTPUT);
  pinMode(Input1Enable, OUTPUT);

  pinMode(Input2SW, INPUT);
  pinMode(Input2LED, OUTPUT);
  pinMode(Input2Enable, OUTPUT);

  //set initial states of outputs;
  digitalWrite(PowerLED, LOW);
  //setting PowerLED high for debug purposes, this shoudl be changed to LOW before release
  digitalWrite(PowerEnable, LOW);
  digitalWrite(Input0LED, LOW);
  digitalWrite(Input0Enable, LOW);
  digitalWrite(Input1LED, LOW);
  digitalWrite(Input1Enable, LOW);
  digitalWrite(Input2LED, LOW);
  digitalWrite(Input2Enable, LOW);
  // initialize state machines


  Serial.println("Setup Complete\n\n");
}

void loop() {
  //
  //  digitalWrite(PowerEnable, LOW);
  //  delay(1000);
  //  digitalWrite(PowerEnable, HIGH);
  //  delay(1000);
  switch (Power)
  {
    case OFF:
      if (!digitalRead(PowerSW)) {
        x = debounce(PowerSW);
        if (x) {
          Serial.println("Power On\n");
          digitalWrite(PowerEnable, HIGH);
          digitalWrite(PowerLED, HIGH);
          Power = ON;
        }
      }
      break;
    case ON:
      if (!digitalRead(PowerSW)) {
        x = debounce(PowerSW);
        if (x) {
          Power = OFF;
          Serial.println("Power Off\n");
          digitalWrite(PowerEnable, LOW);
          digitalWrite(PowerLED, LOW);
        }
      }
      break;
    default:
      Serial.println("Power Error \n\n");
      Power = OFF;
      break;
  }

I have an LED hooked up to PowerLED and PowerEnable is hooked up to the gate of a FET. Currently the state changes are working and when I push the button (PowerSW) the LED turns off and on as expected. However, the PowerEnable writes aren't occurring.

As a sanity check I wrote a little PowerEnable toggle (you can see it commented out at the top of loop()) and that works so I know the HW is ok. Does anyone know why the PowerEnable digitalWrite isn't working?

Please post the entire sketch, for one thing so we can see what 'debounce()' does.

  • Is anything connected to pin 28?
  • Are you using I2C?

The only thing connected to pin 28 is that GPIO output. I2C is not being used.

Here's the entire sketch:

#include <EEPROM.h>

enum ACTIVE_OUTPUT_STATES {NONE, INPUT0, INPUT1, INPUT2};
enum POWER_STATES {ON, OFF};

const int EEPAddress = 50;

const int PixelData = 2;
const int PowerSW = 3;
const int PowerLED = 4;
const int PowerEnable = 19;
const int Input0SW = 5;
const int Input0LED = 6;
const int Input1SW = 7;
const int Input1LED = 8;
const int Input2SW = 9;
const int Input2LED = 10;
const int Input0Enable = 11;
const int Input1Enable = 12;
const int Input2Enable = 13;

const int debounceTime = 80;  //ms
const int messageTime = 1000; //ms
const int timeoutTime = 250; //ms

int OutputMemory;
int LastMessage = 0;
int x = 4;


ACTIVE_OUTPUT_STATES ActiveOutput = NONE;
POWER_STATES Power = OFF;

void setup() {
  // assign pinmodes

  Serial.begin(9600);



  pinMode(PixelData, OUTPUT);

  pinMode(PowerSW, INPUT);
  pinMode(PowerLED, OUTPUT);
  pinMode(PowerEnable, OUTPUT);

  pinMode(Input0SW, INPUT);
  pinMode(Input0LED, OUTPUT);
  pinMode(Input0Enable, OUTPUT);

  pinMode(Input1SW, INPUT);
  pinMode(Input1LED, OUTPUT);
  pinMode(Input1Enable, OUTPUT);

  pinMode(Input2SW, INPUT);
  pinMode(Input2LED, OUTPUT);
  pinMode(Input2Enable, OUTPUT);

  //set initial states of outputs;
  digitalWrite(PowerLED, LOW);
  //setting PowerLED high for debug purposes, this shoudl be changed to LOW before release
  digitalWrite(PowerEnable, LOW);
  digitalWrite(Input0LED, LOW);
  digitalWrite(Input0Enable, LOW);
  digitalWrite(Input1LED, LOW);
  digitalWrite(Input1Enable, LOW);
  digitalWrite(Input2LED, LOW);
  digitalWrite(Input2Enable, LOW);
  // initialize state machines


  Serial.println("Setup Complete\n\n");
}

void loop() {
  //
  //  digitalWrite(PowerEnable, LOW);
  //  delay(1000);
  //  digitalWrite(PowerEnable, HIGH);
  //  delay(1000);
  switch (Power)
  {
    case OFF:
      if (!digitalRead(PowerSW)) {
        x = debounce(PowerSW);
        if (x) {
          Serial.println("Power On\n");
          digitalWrite(PowerEnable, HIGH);
          digitalWrite(PowerLED, HIGH);
          Power = ON;
        }
      }
      break;
    case ON:
      if (!digitalRead(PowerSW)) {
        x = debounce(PowerSW);
        if (x) {
          Power = OFF;
          Serial.println("Power Off\n");
          digitalWrite(PowerEnable, LOW);
          digitalWrite(PowerLED, LOW);
        }
      }
      break;
    default:
      Serial.println("Power Error \n\n");
      Power = OFF;
      break;
  }
  //  switch(ActiveOutput)
  //  {
  //    case NONE:
  //      Serial.println("No Output\n");
  //      if(digitalRead(Input0Enable) == LOW){
  //		Serial.println("Output 0 Active\n");
  //        ActiveOutput = INPUT0;
  //        EEPROM.write(EEPAddress, ActiveOutput);
  //      }
  //      else if(digitalRead(Input1Enable) == LOW){
  //		Serial.println("Output 1 Active\n");
  //        ActiveOutput = INPUT1;
  //        EEPROM.write(EEPAddress, ActiveOutput);
  //      }
  //      else if(digitalRead(Input2Enable) == LOW){
  //        Serial.println("Output 2 Active\n");
  //		ActiveOutput = INPUT2;
  //        EEPROM.write(EEPAddress, ActiveOutput);
  //      }
  //      break;
  //   case INPUT0:
  //      Serial.println("Output 0 Active\n");
  //      digitalWrite(Input0Enable, HIGH);
  //      digitalWrite(Input0LED, HIGH);
  //      if(digitalRead(Input1Enable) == LOW){
  //		Serial.println("Output 1 Active\n");
  //        ActiveOutput = INPUT1;
  //        EEPROM.write(EEPAddress, ActiveOutput);
  //      }
  //      else if(digitalRead(Input2Enable) == LOW){
  //		Serial.println("Output 2 Active\n");
  //        ActiveOutput = INPUT2;
  //        EEPROM.write(EEPAddress, ActiveOutput);
  //      }
  //      break;
  //   case INPUT1:
  //      Serial.println("Output 1 Active\n");
  //      digitalWrite(Input1Enable, HIGH);
  //      digitalWrite(Input1LED, HIGH);
  //      if(digitalRead(Input0Enable) == LOW){
  //        ActiveOutput = INPUT0;
  //        EEPROM.write(EEPAddress, ActiveOutput);
  //      }
  //      else if(digitalRead(Input2Enable) == LOW){
  //        ActiveOutput = INPUT2;
  //        EEPROM.write(EEPAddress, ActiveOutput);
  //      }
  //      break;
  //   case INPUT2:
  //      Serial.println("Output 2 Active\n");
  //      digitalWrite(Input2Enable, HIGH);
  //      digitalWrite(Input2LED, HIGH);
  //      if(digitalRead(Input0Enable) == LOW){
  //        ActiveOutput = INPUT0;
  //        EEPROM.write(EEPAddress, ActiveOutput);
  //      }
  //      else if(digitalRead(Input1Enable) == LOW){
  //        ActiveOutput = INPUT1;
  //        EEPROM.write(EEPAddress, ActiveOutput);
  //      }
  //      break;
  //   default:
  //      Serial.println("Active Output Error\n");
  //      ActiveOutput = NONE;
  //      break;
  //  }
}




int debounce(int buttonPin) {
  int buttonState = 0;
  int initialTime = millis();
  int pushTime = millis();

  while (1) {
    buttonState = digitalRead(buttonPin);
    if (buttonState && ((millis() - pushTime) > debounceTime)) {
      return 1;
    }
    if (buttonState && ((millis() - initialTime) > timeoutTime)) {
      return 0;
    }
  }
}

This function can never respond to the timeout value. It will always return a 1 because 'debounceTime' and 'timeoutTime' are both constants and debounceTime will always be reached first.

const int debounceTime = 80;  //ms
const int messageTime = 1000; //ms
const int timeoutTime = 250; //ms
...

int debounce(int buttonPin) {
  int buttonState = 0;
  int initialTime = millis();
  int pushTime = millis();

  while (1) {
    buttonState = digitalRead(buttonPin);
    if (buttonState && ((millis() - pushTime) > debounceTime)) {
      return 1;
    }
    if (buttonState && ((millis() - initialTime) > timeoutTime)) {
      return 0;
    }
  }
}

That is true about the issues in debounce() but how does that affect the digitalWrite in loop()

Which pin corresponds to digital output number 19 on an Arduino Uno R3?

const int PowerEnable = 19;

Output 19 is pin 28.

jremington:
Which pin corresponds to digital output number 19 on an Arduino Uno R3?

const int PowerEnable = 19;

A5/SCL

19 = A5/SCL = physical pin 28.

As stated earlier if I load a simple toggle of PowerEnable the HW behaves as expected. The problem seems to be related to the code I posted above.

It appears I've fixed it by adding a small delay after the serial write. See below:

  switch (Power)
  {
    case OFF:
      if (!digitalRead(PowerSW)) {
        x = debounce(PowerSW);
        if (x) {
          Serial.println("Power On\n");
          delay(50);
          digitalWrite(PowerEnable, HIGH);
          digitalWrite(PowerLED, HIGH);
          Power = ON;
        }
      }
      break;
    case ON:
      if (!digitalRead(PowerSW)) {
        x = debounce(PowerSW);
        if (x) {
          Power = OFF;
          Serial.println("Power Off\n");
          delay(50);
          digitalWrite(PowerEnable, LOW);
          digitalWrite(PowerLED, LOW);
        }
      }
      break;
    default:
      Serial.println("Power Error \n\n");
      Power = OFF;
      break;
  }

Does anyone know why this works?

wsender:
It appears I've fixed it by adding a small delay after the serial write.

Does anyone know why this works?

My guess would be that your 'debounce' function is not working and the power is being turned off immediately after it is turned on. Try instead, replacing the 'debounce' function with a 'delay(50);'.

Can you modify your simple toggle sketch to toggle both PowerEnable and PowerLED? If PowerLED is toggling correctly with your full sketch, I don't see why PowerEnable would not also be toggling, which leaves the possibility that there is something wrong with the hardware. I would also comment out the #include statement for EEPROM.h, although that should not be using I2C unless you have a library installed for external EEPROM that uses the same filename.

posted before I read your post about the sketch working after adding a delay()

int debounce(int buttonPin) {
  int buttonState = 0;
  int initialTime = millis();
  int pushTime = millis();

Ah, declare initialTime and pushTime as unsigned long, not int.