A Steering wheel, hall effect, and LEDs....please help me interrupt

Status
Not open for further replies.

ratki

Member
I have a project where I am using a steering wheel that triggers a hall effect sensor as it rotates. The idea is that as you rotate the wheel, LEDs will chase up the strand. If you stop rotating, or go to slow, the LEDs will begin to extinguish. It randomly picks a color each time it goes through the cycle to chase up the strip. I would like to incorporate a "show" of sorts like a rainbow effect on the strip if the wheel has not been turned in say 1 minute or so. Then, if the wheel is turned again, the rainbow effect will extinguish, clearing the strip, and the LEDs will again chase up the strip as the wheel is turned. This is where I am stumped. I can't clear the rainbow to begin chasing the LEDS again.

This is my first attempt at using an interrupt and I honestly don't know if I am going about this the right way with what I have done so far. The attached code works as I have described above with the exception of the rainbow "show". I know that it does not work as written. The LEDs chase up and down the strip as they should and the code works fine without the rainbow part added in. I threw in the rainbow function in the loop of the attached code so it's execution can be seen because I feel that this is part of the problem (it seems to be all about the timing). I have tried it many different ways, too many to describe in detail. I would greatly appreciate any guidance I can get in regards to getting this to work.

Do I need to start over and rewrite what the interrupt is doing? Would it be better to poll the sensor and try and get it to work that way?

Code:
const int hallPin = 8;     // the number of the hall effect sensor pin
#include <Adafruit_NeoPixel.h> // Neopixel Library
#define Strip 11 // LED strip on pin 11
Adafruit_NeoPixel strip = Adafruit_NeoPixel(93, Strip, NEO_GRB + NEO_KHZ800); 

uint32_t color = strip.Color(0,0,0); 
uint32_t Red = strip.Color(0,255, 0);
uint32_t Green = strip.Color(255,0, 0);
uint32_t ColorOff = strip.Color(0, 0, 0);
uint32_t White = strip.Color(255,255,255);
uint32_t Yellow = strip.Color(255,255, 0);
uint32_t Blue = strip.Color(0, 0, 255);
uint32_t Pink = strip.Color(51, 255, 255);
uint32_t LtBlue = strip.Color(76, 0, 153);

int j = 0;
long randomNumber;
unsigned long startMillis;
unsigned long currentMillis;
const unsigned long period =170;  //time between rotations before LEDs start turning off




void setup() {
  
    randomSeed(analogRead(A1));
    startMillis = millis();  //initial start time
    strip.begin(); //enable LEDS
    strip.show();  //turn all LEDs off
  
    
  // initialize the hall effect sensor pin as an input:
  pinMode(hallPin, INPUT);     
   attachInterrupt(digitalPinToInterrupt(hallPin), toggle, CHANGE);
}



void loop(){
 
 
      currentMillis = millis();  //
      
      if (currentMillis - startMillis >= period){  //test whether the period has elapsed {

    
    // turn LED off:
     if ((j<93) && (j >-1)) { 
        strip.setPixelColor(j,ColorOff);
        strip.show();// turns LED #j off
        j=j-1;
     }
     
       startMillis = currentMillis;  
    
   }

  rainbow(30);  //XXX  this is where my problem lies  XXXX how to incorporate this so that after a period of time if the hall effect is not triggered,
                // this rainbow show will display but once the hall effect is triggered again, the LED strip extinguishes and the hall effect controls the LEDS
                //chasing up the strip
}



void toggle() {
  randomNumber = random(1,8);
  
 if (j <= 0) {
  switch (randomNumber) {// picks random color for chasing LEDs

    case 1:                  
      color = White;   
      break;
      
    case 2:                  
      color = Red;      
      break;
      
    case 3:                  
      color = Green;
      break;
      
    case 4:                  
      color = Yellow;
      break;
      
    case 5:                  
      color = Blue;
      break;

      case 6:                  
      color = LtBlue;
      break;

      case 7:                  
      color = Pink;
      break;
  }
}  
 
    // turn LEDs on one at a time as wheel is turned  
     if (j < 92) {
       strip.setPixelColor(j, color); //  Sets the LED #j to color
       strip.show(); //lights the LED #j to color
       j=j+1;  //increments j to the next LED in line 
     
    }
}
 



void rainbow(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256; j++) {
    for(i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i+j) & 255));
    }
    strip.show();
    delay(wait);
  }
}



// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}





 void colorWipe(uint32_t c) {
   for (uint16_t i = 0; i < strip.numPixels(); i++) {
      strip.setPixelColor(i, c);
      strip.show();
    }
  }
 
Try

Code:
   if( j == -1 ) rainbow(30);


In function rainbow, a loop of 256 times 30ms means you will be in this function for over 7 seconds, so you need a way to break out. Your local variable is also called j, so change that to k and again test the value of j to break out of the loop.

Code:
void rainbow(uint8_t wait) {
  uint16_t i, k;

  for(k=0; k<256; k++) {
    for(i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i+k) & 255));
    }
    strip.show();
    if( j > -1 ) break;
    delay(wait);
  }
}

Edit to add, your variable j should be declared volatile. volatile int j;
 
You probably need to ban the use of the delay function (except in very specific cases), and learn to use the 'Blink without delay' programming style:

Here is the library I wrote for this:

Meissner_config.h:

Code:
// -*- arduino -*-
// Meissner delay library
// based on http://www.gammon.com.au/blink
//
// Copyright (C) 2014-2019, Michael Meissner (arduino@the-meissners.org)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#ifndef MEISSNER_DELAY_H
#define MEISSNER_DELAY_H	1

#include <stddef.h>
#include <stdlib.h>
#include <inttypes.h>

#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"

#else
#include "WProgram.h"
#include "WConstants.h"
#endif

class Delay {
 private:
  unsigned long	init_time;			// time when begin was called
  unsigned long	interval;			// interval in milliseconds to return true
  bool		repeat;				// whether to repeat the timer
  bool		immediate;			// immediate return true on the next call

 public:
  // constructor, destructor
  Delay (void) : init_time (0UL), interval (0UL), repeat (false), immediate (false) {}
  ~Delay (void) {}

  // register that delay_done will return true in the future
  void
  begin (unsigned long amount, bool r = false, bool imm = false)
  {
    init_time = millis ();
    interval  = amount;
    repeat    = r;
    immediate = imm;
  }

  // clear any potential delay
  void
  clear (void)
  {
    init_time = 0UL;
    interval  = 0UL;
    repeat    = false;
    immediate = false;
  }

  // Mark that the next call to delay_done will return true
  // If we are passed true, do not reset the timers.
  void
  run_immediate (bool no_reset = false)
  {
    if (!no_reset)
      {
	init_time = 0UL;
	interval  = 0UL;
	repeat    = false;
      }

    immediate = true;
  }

  // register a time in the future
  void
  run_delay (unsigned long amount)
  {
    init_time = millis ();
    interval  = amount;
    repeat    = false;
    immediate = false;
  }

  // register a time in the future with repeat
  void
  run_delay_repeat (unsigned long amount)
  {
    init_time = millis ();
    interval  = amount;
    repeat    = true;
    immediate = false;
  }

  // Return true if the delay is done
  bool delay_done (void);
};
#endif	/* MEISSNER_DELAY_H */


// HISTORY
// $Log: Meissner_Delay.h,v $
// Revision 1.10  2019/01/14 02:16:10  michaelmeissner
// Update copyright.
//
// Revision 1.9  2018/03/18 21:48:03  michaelmeissner
// Add optional argument to run_immedate to suppress reseting init_time, interval, or repeat.
//
// Revision 1.8  2016/04/03 22:43:31  michaelmeissner
// Make (C) in copyright be upper case.
//
// Revision 1.7  2016/03/21 13:58:56  michaelmeissner
// Update copyright year.
//
// Revision 1.6  2015/01/12 02:15:13  michaelmeissner
// Move delay_done code from .h file to .cpp file.
//
// Revision 1.5  2015/01/11 14:46:48  michaelmeissner
// Add run_immediate, run_delay, and run_delay_repeat.
//
// Revision 1.4  2015/01/10 03:13:13  michaelmeissner
// Relicense under the MIT copyright so that we can link in neopixel patterns written by others.
//
// Revision 1.3  2015/01/01 23:35:08  michaelmeissner
// Add ability to run immediately.
//
// Revision 1.2  2015/01/01 19:15:32  michaelmeissner
// Update copyright year
//
// Revision 1.1  2014/12/31 13:54:50  michaelmeissner
// Initial version.
//

Meissner_Delay.cpp:

Code:
// -*- arduino -*-
// Meissner delay library
// based on http://www.gammon.com.au/blink
//
// Copyright (C) 2014-2019, Michael Meissner (arduino@the-meissners.org)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include <stddef.h>
#include <stdlib.h>
#include <inttypes.h>

#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"

#else
#include "WProgram.h"
#include "WConstants.h"
#endif

#include <Meissner_Delay.h>



// Return true if the delay is done

bool
Delay::delay_done (void)
{
  bool ret = false;

  if (immediate)
    {
      immediate = false;
      ret = true;
    }

  else if (init_time != 0UL)
    {
      if ((millis () - init_time) >= interval)
	ret = true;
    }

  if (ret)
    init_time = (repeat) ? millis () : 0UL;

  return ret;
}


// HISTORY
// $Log: Meissner_Delay.cpp,v $
// Revision 1.6  2019/01/14 02:16:25  michaelmeissner
// Update copyright.
//
// Revision 1.5  2016/03/21 13:59:10  michaelmeissner
// Update copyright year.
//
// Revision 1.4  2015/01/12 02:14:38  michaelmeissner
// Move delay_done code from .h file to .cpp file.
//
// Revision 1.3  2015/01/10 03:13:41  michaelmeissner
// Relicense under the MIT copyright so that we can link in neopixel patterns written by others.
//
// Revision 1.2  2015/01/01 19:15:50  michaelmeissner
// Update copyright year
//
// Revision 1.1  2014/12/31 13:55:33  michaelmeissner
// Initial version.
//

Usage would be something like:

Code:
const unsigned long ELAPSED_TIME_DELAY	= 1000UL;                 // once a second
Delay timer;

// ...

void setup ()
{
  // ...
  // track every second, repeating the delay, but don't fire immediately
  timer.begin (ELAPSED_TIME_DELAY, true, false);
}

// ...

void loop ()
{
  // ...
  if (timer.delay_done ()) {
    // ...
  }
}
 
Last edited:
rcarr,

Thanks for your response! Your suggestions did the trick as far as getting the rainbow function to stop and allow the LED chasing to begin. It immediately made sense to me as soon as I saw it, I was at a point I probably should have stepped away and came back at it later.

I've got more to figure out such as clearing the strip after the rainbow exits before the LED chase begins. And also putting in the idle time after the chase, prior to the rainbow. I'm going to work on those issues but just wanted to drop in and say thank you. I appreciate your time and help.

Could I ask if you would have approached this project differently? I guess in regards to the interrupt, I feel like I have a lot of stuff going on in that routine, but with my lack of experience that is the only way I could get it to run the way I wanted. Trying to get better and would greatly appreciate any insight.

Thanks again! I'm going to get to work on these other issues.
 
Mr. Meissner, thanks for your reply. I am going to look at the information you provided and by the looks of it , may be back with some questions. I consider myself a novice but am taking all opportunities I can to improve my coding. Thank you for taking the time to try and help out, it is much appreciated.
 
Status
Not open for further replies.
Back
Top