Coding an interrupt when it's too late to charge hardware/PCB design

Hello All,
I wanted to post this message in "Programming Questions", but for some reason when I go to that section, the webpage treats me as if I had logged out and won't respond to the "sign in". I therefore apologize in advance.
I've put an ATmega32U4 and the basic circuitry needed for an Arduino Micro or Leonardo onto a PCB that powers an RGB+white LED for a lightsaber reproduction. (Every Jedi is supposed to build their own, right?) The IDE recognizes the system as a Leonardo.
The accelerometers that detect movement are on a separate board, a commercial product called "Obsidian V3", and if they detect an impact, they generate a sound effect and also send a logic pulse that lasts for the duration of the sound effect. That's usually around 100 to 500 ms. They also have a user-controlled "lockup" state, which is lightsaber enthusiast lingo for "when two blades are crossed, and lots of angry buzzing and flashing goes on". This is emulated with a 160 ms long, 50% duty cycle of the same logic signal. This is Ch.1 of the attached tek000.png. I programmed the RGBW control to turn bright yellow while the Obsidian's logic signal was high, and Ch.2 in the scope captures is the inverted-logic signal telling the LED's to do this, but the "flash" when two lightsabers collide is much shorter in time (probably 10 ms or so), and the 80 ms "lockup" pulses also look terrible. It looks like the orange farm/construction equipment beacons when the local farmers are headed down the highway.
So I was trying to code the equivalent of a one-shot timer. I was failing miserably at this and only managed to increase the length of the yellow color pulses by my desired total pulse length (see tek0001) when I thought about interrupts.
I did not realize that I'd need an interrupt when I designed the PCB, so I used digital pin 4, D4, ATMega Pin 25, as can be seen in the attached. I now know that this pin isn't one of the ones that can be used for interrupts. What I'm looking for is help making the program switch to yellow from the regular color for a period that I can define without interrupts. I initially wanted to add a de-bounce time, too, but I also realized that human beings can't swing a sword around fast enough to make that necessary.
Below is the code that accidentally extends the yellow time by 20 ms instead of reducing the total yellow time to 20 ms as seen in tek0001.
Many thanks,

Chris

/*
  Code for making one potentiometer control 4 LEDs, red, green, blue and white with constant brightness
  Keeps white LED on at lower intensity for all colors to provide washed-out look
  Also shifts to white+yellow while a digital signal is set to a logic low for defined delay (digital signal otherwise lasts as long as its sound effect)
  Inverts the logic of the color percentages due to logic inversion of the MOSFET shunt switches
  Divides the 1024 steps into five parts: red, green, blue and white at either end
  Clay Shirky <clay.shirky@nyu.edu>, modified by Chris Richardson and Ignacio Azevedo
*/

// INPUT: Potentiometer should be connected to 5V and GND
// INPUT: Logic signal should be connected to 5V and GND
int potPin = 3; // Potentiometer output connected to analog pin 3
int potVal = 0; // Variable to store the input from the potentiometer
int flashPin = 4; // Digital signal from Obsidian connects to pin 4
int timeout = 1; // Variable for the flash on clash and lockup, for countdown

// OUTPUT: Use digital pins 5,6, 9 and 10 - the Pulse-width Modulation (PWM) pins
// LED's cathodes should be connected to digital GND
int whtPin = 5;   // White LED,   connected to digital pin 5
int redPin = 6;   // Red LED,   connected to digital pin 6
int grnPin = 9;  // Green LED, connected to digital pin 9
int bluPin = 10;  // Blue LED,  connected to digital pin 10

// Program variables
int whtVal = 0;   // Variables to store the values to send to the pins
int redVal = 0;
int grnVal = 0;
int bluVal = 0;

void setup()
{
  pinMode(whtPin, OUTPUT);   // sets the pins as output
  pinMode(redPin, OUTPUT);
  pinMode(grnPin, OUTPUT);
  pinMode(bluPin, OUTPUT);
  pinMode(flashPin, INPUT);

}

// Main program
void loop()
{
  potVal = analogRead(potPin);   // read the potentiometer value at the input pin

  if (digitalRead(flashPin) == 0 ) { // Loop for normal operation - no FoC or lockup

    if (potVal <= 205)  // Lowest fifth of range, White
    {
      whtVal = 0;       // White on 100%
      redVal = 255;         // Red off
      grnVal = 255;         // Green off
      bluVal = 255;         // Blue off
    }
    else if (potVal > 205 and potVal <= 410) // Second fifth, Red
    {
      whtVal = 127;         // White on 50%
      redVal = 0;       // red on 100%
      grnVal = 255;         // green off
      bluVal = 255;         // blue off
    }
    else if (potVal > 410 and potVal <= 615) // Third fifth, Green
    {
      whtVal = 127;         // White on 50%
      redVal = 255;       // red off
      grnVal = 0;        // green on 100%
      bluVal = 255;         // blue off
    }
    else if (potVal > 615 and potVal <= 820) // Fourth fifth, Blue
    {
      whtVal = 127;          // White on 50%
      redVal = 255;       // red off
      grnVal = 255;       // green off
      bluVal = 0;         // blue on 100%
    }

    else  // Last fifth
    {
      whtVal = 0;           // White on 100%
      redVal = 255;         // Red off
      grnVal = 255;         // Green off
      bluVal = 255;         // Blue off
    }
    analogWrite(whtPin, whtVal);   // Write values to LED pins
    analogWrite(redPin, redVal);
    analogWrite(grnPin, grnVal);
    analogWrite(bluPin, bluVal);
  }

  if (digitalRead(flashPin) == 1 && timeout == 1) { // Detects FoC or lockup pulse

    whtVal = 0;           // White on 100%
    redVal = 0;           // red on 100%
    grnVal = 15;          // green on 94%
    bluVal = 255;         // blue off
    analogWrite(whtPin, whtVal);   // Write values to LED pins
    analogWrite(redPin, redVal);
    analogWrite(grnPin, grnVal);
    analogWrite(bluPin, bluVal);
    delay(70);            // Countdown, bright yellow flash during this period
    timeout = 0;          // End of countdown
  }

  delay(10);            // Debounce time
  timeout = 1;          // Reset timeout for next flash (logic change on flashpin)

}

Pin change interrupts?
Or, controversially, no interrupt at all.

Please remember to use code tags when posting code.

I’m not certain what you’re trying to achieve from your description:

…if they detect an impact, they generate a sound effect and also send a logic pulse that lasts for the duration of the sound effect. That’s usually around 100 to 500 ms. They also have a user-controlled “lockup” state, which is lightsaber enthusiast lingo for “when two blades are crossed, and lots of angry buzzing and flashing goes on”. This is emulated with a 160 ms long, 50% duty cycle of the same logic signal. … but the “flash” when two lightsabers collide is much shorter in time (probably 10 ms or so), and the 80 ms “lockup” pulses also look terrible. It looks like the orange farm/construction equipment beacons when the local farmers are headed down the highway.

In the first part it seems that an impact generates something 100-500mS in length but then you say the impact pulse is 10mS.

You mention a one-shot function. Again, I may have interpreted your intent wrongly but try this just the same. You can change the MIN_YELLOW_TIME.

(Compiles, not tested.)

/*
 * Sketch: sketch_feb15d
 * Target: 32U4
 *
 */

#define MIN_YELLOW_TIME     100ul

// INPUT: Potentiometer should be connected to 5V and GND
// INPUT: Logic signal should be connected to 5V and GND
const uint8_t potPin = 3; // Potentiometer output connected to analog pin 3
const uint8_t flashPin = 4; // Digital signal from Obsidian connects to pin 4

// OUTPUT: Use digital pins 5,6, 9 and 10 - the Pulse-width Modulation (PWM) pins
// LED's cathodes should be connected to digital GND
const uint8_t whtPin = 5;   // White LED,   connected to digital pin 5
const uint8_t redPin = 6;   // Red LED,   connected to digital pin 6
const uint8_t grnPin = 9;  // Green LED, connected to digital pin 9
const uint8_t bluPin = 10;  // Blue LED,  connected to digital pin 10

// Program variables
uint8_t whtVal = 0;   // Variables to store the values to send to the pins
uint8_t redVal = 0;   
uint8_t grnVal = 0;
uint8_t bluVal = 0;

uint16_t potVal = 0; // Variable to store the input from the potentiometer

uint8_t
    state,
    lastIn,
    nowIn;

uint32_t
    timePulse,
    timeNow;


void setup()
{
    pinMode( whtPin, OUTPUT );   // sets the pins as output
    pinMode( redPin, OUTPUT );   
    pinMode( grnPin, OUTPUT );
    pinMode( bluPin, OUTPUT );
    pinMode( flashPin, INPUT );

    state = 0;
    lastIn = digitalRead( flashPin );
   
}//setup

// Main program
void loop()
{
    timeNow = millis();
    switch( state )
    {
        case    0:
            //show colours according to pot value
            NoContact();
            
            //check if flash pin transitions from low to high
            nowIn = digitalRead( flashPin );
            if( nowIn != lastIn )
            {
                lastIn = nowIn;
                if( nowIn == HIGH )
                {
                    //yellow
                    whtVal = 0;           // White on 100%
                    redVal = 0;           // red on 100%
                    grnVal = 15;          // green on 94%
                    bluVal = 255;         // blue off
                    analogWrite(whtPin, whtVal);   // Write values to LED pins
                    analogWrite(redPin, redVal);
                    analogWrite(grnPin, grnVal);
                    analogWrite(bluPin, bluVal);
                    
                    timePulse = timeNow;
                    state = 1;
                    
                }//if
                
            }//if            
                    
        break;

        case    1:
            //flash pin transitioned high; show yellow for a minimum of MIN_YELLOW_TIME
            if( (timeNow - timePulse) >= MIN_YELLOW_TIME )
            {
                //after that minimum time period, return to state 0 if/when the flash pin returns low
                if( digitalRead( flashPin ) == LOW )
                    state = 0;
                        
            }//if
            
        break;
        
    }//switch
        
}//loop

void NoContact( void )
{
    potVal = analogRead(potPin);   // read the potentiometer value at the input pin
    
    // Loop for normal operation - no FoC or lockup    
    if (potVal <= 205)  // Lowest fifth of range, White
    {                  
        whtVal = 0;       // White on 100%
        redVal = 255;         // Red off
        grnVal = 255;         // Green off
        bluVal = 255;         // Blue off
    }
    else if (potVal > 205 and potVal <= 410) // Second fifth, Red
    {
        whtVal = 127;         // White on 50%
        redVal = 0;       // red on 100%
        grnVal = 255;         // green off
        bluVal = 255;         // blue off
    }
    else if (potVal > 410 and potVal <= 615) // Third fifth, Green
    {
        whtVal = 127;         // White on 50%
        redVal = 255;       // red off
        grnVal = 0;        // green on 100%
        bluVal = 255;         // blue off
    }
    else if (potVal > 615 and potVal <= 820) // Fourth fifth, Blue
    {
        whtVal = 127;          // White on 50%
        redVal = 255;       // red off
        grnVal = 255;       // green off
        bluVal = 0;         // blue on 100%
    }
    
    else  // Last fifth
    {
        whtVal = 0;           // White on 100%
        redVal = 255;         // Red off
        grnVal = 255;         // Green off
        bluVal = 255;         // Blue off
    }
    
    analogWrite(whtPin, whtVal);   // Write values to LED pins
    analogWrite(redPin, redVal);
    analogWrite(grnPin, grnVal);
    analogWrite(bluPin, bluVal);
    
}//NoContact

OK, first things first.

You need to go and read the forum instructions so that you can go back and modify your original post (not re-post it) - using the “More → Modify” option below the right hand corner of your post - to mark up your code as such using the “</>” icon in the posting window. Just highlight each section of code (or output if you later need to post that) from the IDE and click the icon.

In fact, the IDE itself has a “copy for forum” link to put these markings on a highlighted block for you so you then just paste it here in a posting window. But even before doing that, don’t forget to use the “Auto-Format” (Ctrl-T) option first to make it easy to read. While you were lucky so far, If you do not post it as “code” it can easily be quite garbled and is generally more difficult to read due to the font.

It is inappropriate to attach it as a “.ino” file unless it is clearly too long to include in the post proper. People can usually see the mistakes directly and do not want to have to actually load it in their own IDE. And even that would also assume they are using a PC and have the IDE running on that PC.

Also tidy up your blank space. Do use blank lines, but only single blanks between complete functional blocks.

Why might we think this is more important than just having your question answered? Because it is really difficult to write code properly - as with any other task requiring care - if everything is not well organised!


That said, I cannot see why an interrupt would be of any value to you in this project. :roll_eyes:

Hi Paul__B, Blackfin, and MemberFormerlyKNownAsAWOL,

I've followed your instructions and modified my original post using the IDE's dedicated copy function. It does look much better that way.
I will look into Pin Interrupts for my own betterment.
I should have been clearer about the 10 ms flashes: I meant to say that when I watch the movies, the duration of the flashes, to my eyes, looks like about 10 ms. 50 ms is definitely too long, it just doesn't look like an electric flash.
I'll try Blackfin's code - many thanks for that, it's above and beyond the call.
Many thanks to all three of you,

Chris

Hi Again,

Blackfin's code worked with a tiny tweak - what I wanted was a maximum flash (yellow) time, and after this time elapses, I want the color to go back to normal, regardless of the status of the flashPin. To a lover of the 555 IC, a classic one-shot timer. I just erased the "if" statement regarding the flash pin, played around, and came to a flash time of about 20 ms that looks right. I've attached a scope shot of the flash signal (Ch.2) going low for those 20 ms, triggered by the input from the Obsidian (Ch.1).

Many thanks!
Chris

/*
   Sketch: sketch_feb15d
   Target: 32U4

*/

#define MAX_YELLOW_TIME     20ul

// INPUT: Potentiometer should be connected to 5V and GND
// INPUT: Logic signal should be connected to 5V and GND
const uint8_t potPin = 3; // Potentiometer output connected to analog pin 3
const uint8_t flashPin = 4; // Digital signal from Obsidian connects to pin 4

// OUTPUT: Use digital pins 5,6, 9 and 10 - the Pulse-width Modulation (PWM) pins
// LED's cathodes should be connected to digital GND
const uint8_t whtPin = 5;   // White LED,   connected to digital pin 5
const uint8_t redPin = 6;   // Red LED,   connected to digital pin 6
const uint8_t grnPin = 9;  // Green LED, connected to digital pin 9
const uint8_t bluPin = 10;  // Blue LED,  connected to digital pin 10

// Program variables
uint8_t whtVal = 0;   // Variables to store the values to send to the pins
uint8_t redVal = 0;
uint8_t grnVal = 0;
uint8_t bluVal = 0;

uint16_t potVal = 0; // Variable to store the input from the potentiometer

uint8_t
state,
lastIn,
nowIn;

uint32_t
timePulse,
timeNow;


void setup()
{
  pinMode( whtPin, OUTPUT );   // sets the pins as output
  pinMode( redPin, OUTPUT );
  pinMode( grnPin, OUTPUT );
  pinMode( bluPin, OUTPUT );
  pinMode( flashPin, INPUT );

  state = 0;
  lastIn = digitalRead( flashPin );

}//setup

// Main program
void loop()
{
  timeNow = millis();
  switch ( state )
  {
    case    0:
      //show colours according to pot value
      NoContact();

      //check if flash pin transitions from low to high
      nowIn = digitalRead( flashPin );
      if ( nowIn != lastIn )
      {
        lastIn = nowIn;
        if ( nowIn == HIGH )
        {
          //yellow
          whtVal = 0;           // White on 100%
          redVal = 0;           // red on 100%
          grnVal = 15;          // green on 94%
          bluVal = 255;         // blue off
          analogWrite(whtPin, whtVal);   // Write values to LED pins
          analogWrite(redPin, redVal);
          analogWrite(grnPin, grnVal);
          analogWrite(bluPin, bluVal);

          timePulse = timeNow;
          state = 1;

        }//if

      }//if

      break;

    case    1:
      //flash pin transitioned high; show yellow for a maximum of MAX_YELLOW_TIME
      if ( (timeNow - timePulse) >= MAX_YELLOW_TIME )
      {
        //after that maximum time period, return to state 0 regardless of the state of the flashPin
        state = 0;

      }//if

      break;

  }//switch

}//loop

void NoContact( void )
{
  potVal = analogRead(potPin);   // read the potentiometer value at the input pin

  // Loop for normal operation - no FoC or lockup
  if (potVal <= 205)  // Lowest fifth of range, White
  {
    whtVal = 0;       // White on 100%
    redVal = 255;         // Red off
    grnVal = 255;         // Green off
    bluVal = 255;         // Blue off
  }
  else if (potVal > 205 and potVal <= 410) // Second fifth, Red
  {
    whtVal = 127;         // White on 50%
    redVal = 0;       // red on 100%
    grnVal = 255;         // green off
    bluVal = 255;         // blue off
  }
  else if (potVal > 410 and potVal <= 615) // Third fifth, Green
  {
    whtVal = 127;         // White on 50%
    redVal = 255;       // red off
    grnVal = 0;        // green on 100%
    bluVal = 255;         // blue off
  }
  else if (potVal > 615 and potVal <= 820) // Fourth fifth, Blue
  {
    whtVal = 127;          // White on 50%
    redVal = 255;       // red off
    grnVal = 255;       // green off
    bluVal = 0;         // blue on 100%
  }

  else  // Last fifth
  {
    whtVal = 0;           // White on 100%
    redVal = 255;         // Red off
    grnVal = 255;         // Green off
    bluVal = 255;         // Blue off
  }

  analogWrite(whtPin, whtVal);   // Write values to LED pins
  analogWrite(redPin, redVal);
  analogWrite(grnPin, grnVal);
  analogWrite(bluPin, bluVal);

}//NoContact

There is absolutely no need for an interrupt in an application like this.

Get rid of all the delay() statements and use non-blocking code for timed intervals, as explained in this excellent tutorial.

jremington:
There is absolutely no need for an interrupt in an application like this.

Get rid of all the delay() statements and use non-blocking code for timed intervals, as explained in this excellent tutorial.

I’ve given etobol karma for such a well presented and documented project (pleasing to an aged minion).
I’m also puzzled by your comment re delays…I can’t see them in the code provided , appreciate an expansion to
edificate this nuance. :confused:

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