Showing posts with label Arduino. Show all posts
Showing posts with label Arduino. Show all posts

Thursday, August 1, 2013

Adafruit's Simple RF receiver, Testing on an Arduino

I just picked up Adafruit's Simple RF receiver right now I was testing the Momentary type (M4) Which means that while you press the keypad button the corresponding pin on the receiver goes high. I am hoping the next time I order something from them I remember to get the latching one instead because that is what I really need. Anyway since I don't have a project for this one in mind I just wanted to do some testing... so I just plugged it directly into my Arduino( avoiding the Serial pins since I needed those to display the pin states) This is the only way I could fit it on the board without putting it on a bread board. (quick and dirty!)

The VT pin isn't of to much concern for me right now so it just tucks in between the two pin banks :)

Check out the code below. This is great but if I don't want to constantly poll for buttons I may miss one. So my intention is to order a latching version, when you press the button on the keypad the pin goes high and stays high until you press it again. My thought is that if I am powering the receiver from the arduino then I can read it maybe once a second or even less often then when a high state is detected then I can simple "reboot" the receiver by dropping the +5v pin to ground. So until I get one in I will hope it resets back to ground on all the signal pins like I need

/*--------------------------------------------------------
Adafruit's Simple RF Receiver example
http://www.adafruit.com/products/1096                                  
Author: Chris Crumpacker                               
Date: August 2013 

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.
                                                           
Sketch Notes: This is set as if you put the reciever directly
onto an arduino with gnd in pin 2 and the VT pin in the 
gap between the pin banks.
--------------------------------------------------------*/

#define GROUNDPIN  2
#define POWERPIN   3

// Arduino Pin Numbers
int signalPin[4] = { 4, 5, 6, 7 };
// Reciever Pin Names
const char* pinName[] = { "D3", "D2", "D1", "D0" };
// Keyfob Pin Names
const char* buttonName[] = { "D", "C", "B", "A" };

int lastSignalState[] = { 0, 0, 0, 0 };
int signalState = 0;
float onTime = 0.00;

void setup() {
  // Set the ground pin to a Low output
  pinMode(GROUNDPIN, OUTPUT);
  digitalWrite(GROUNDPIN, LOW);
  
  // Set the +5v pin to a High output
  pinMode(POWERPIN,OUTPUT);
  digitalWrite(POWERPIN, HIGH);
  
  // Setting the signal pins as inputs
  for (int i = 0; i < 4; i++) {
    pinMode(signalPin[i], INPUT);
  }
  
  // Starting the serial interface
  Serial.begin(19200);
}

void loop(){
  // For each of the 4 pins we loop thru and check the state.
  for (int i = 0; i < 4; i++) {
    // Read the current pin
    signalState = digitalRead(signalPin[i]);
    
    if (signalState != lastSignalState[i]) {
      // if the state has changed...
      if (signalState == HIGH) {
        // ...and the current state is HIGH...
        Serial.print("Receiver Pin: ");
        Serial.println(pinName[i]);
        Serial.print("Keyfob Button: ");
        Serial.println(buttonName[i]);
        Serial.println("Switched ON");
        Serial.println("------------------------------");
        onTime = millis();
      } 
      else {
        // ...and the current State is LOW...
        Serial.print("Receiver Pin: ");
        Serial.println(pinName[i]);
        Serial.print("Keyfob Button: ");
        Serial.println(buttonName[i]);
        Serial.print("Switched OFF after ");
        Serial.print(((millis() - onTime) / 1000.00));
        Serial.println(" seconds");
        Serial.println("------------------------------");
      }
    }
    // save the current state to the last state array
    lastSignalState[i] = signalState;
  }
}

Monday, May 27, 2013

Using an Arduino board as an ISP via the ICSP header

**Moving this over from my instructables so it is also on my blog**

Here are the Gerber Files for an ATTiny84 and 85 along with the board stencils.

I won't go into how to use an Arduino as an ISP, there are plenty of instructables and other how-to's on the net for that.

http://www.instructables.com/id/Turn-Your-Arduino-Into-an-ISP/
http://www.instructables.com/id/Adding-ICSP-header-to-your-ArduinoAVR-board/
http://www.instructables.com/id/How-to-program-a-AVR-arduino-with-another-arduin/

What I needed was a simple way to program (and burn the bootloader) onto my ATtiny chips. I have made a breadboard breakout board (soon to be a different instructable) for my ATTiny84/44s as well as one for my ATTiny85/45s.



These sub-boards are for breadboard prototyping so I don't have to setup the crystal, the power, and the reset every time I want to move to a breadboard.

Step 1:




This is the ATTiny*4 Breadboard breakout. It's the board's traces are a mess I know. I made it with a sharpie marker as I didn't have access to a proper laser printer late at night when I made it. But it works like a charm.

The ICSP header breaks out the chip's MOSI, MISO, SCK, VCC, GND, and RESET pins. That is wired to a normal 6 wire cable. The other end is where the trick comes in.

Step 2:

Typically the ICSP on the arduino boards is used to program the chip on that board. So more like an "IN" as opposed to an "OUT". The reason for that is pin 5 is wired to the reset pin on that chip, and not the reset needed inside the "Arduino as ISP" sketch. I've see "how-to's" that tell you to cut those traces and rewire it. I had no interest in modifying my board permanently so I found it way easier to modify the cable.





Using an 8 pin cable I scavenged I remove the previous cable, then cut 6 wires from an old IDE ribbon cable. After that I pulled the 5th wire from the ribbon cable and made it about 3 inches longer, and did NOT put it into the punchdown for the header.

I punched the other wires in and cut them flush. I put a dab of super glue on both sides of the ribbon cable to try and prevent it from splitting down the cable any more. at the end of the reset pin (5th wire) I put a male connector on it so it would fit into the female pin 10 for programming.


Now all I need to do to program (or burn the bootloader) onto really any AVR that I have a bootloader for is attach this to the ICSP on the slave board and then the other end to my main arduino board and wire up pin 10 for reset. I am able to use the stock "Arduino as ISP" sketch with no mods to the boards or the sketch.

Wednesday, April 17, 2013

New code for the Rear Bike Light

I spent some time last night removing all the debug stuff so it would look cleaner and be easier to follow.

Original post here: http://crumpspot.blogspot.com/2013/04/power-led-bike-tail-light-with-arduino.html
Schmatic here: https://www.circuitlab.com/circuit/b6r5h8/rear-bike-light/


/*--------------------------------------------------------
Rear Bike Light Project                                    
Author: Chris Crumpacker                               
Date: October 2012 

Copyright (c) 2012 Chris Crumpacker.  All right reserved.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.
                                                           
Sketch Notes: This version contains 6 modes of blinking with 
multiple speeds for some modes. This works off of a single 
button, with short presses the program steps thru the 
modes/speeds. When long pressed it goes into a "sleep" 
mode where the high powered LEDs are turned off. 
It also has the ablity to store the current mode so when 
leaving sleep mode or being brought back up from a power 
down it will return to the previous mode it was in. 
There is also an interal tempurature sensor that will 
put it into a hidden (at least from the mode scrolling) 
"limp home mode" during a certain temp range or evenshut the 
LEDs down if it gets any higher.
--------------------------------------------------------*/

//-------------------------
// Includes
//-------------------------
#include 
#include 

//-------------------------
// Defines
//-------------------------
#define BUTTON_PIN       11                                                  // Button
#define ledPinl          9                                                   // Left LED
#define ledPinr          10                                                  // Right LED
#define powerPin         13                                                  // Case LED to show that the circuit has power
#define tempSensorPin    A5                                                  // Analog pin the case's Temp36 sensor is on

#define LONGPRESS_LEN    10                                                  // Min numberr of loops for a long press
#define DELAY            10                                                  // Delay per loop in ms
#define CONFIG_VERSION   "rbl1"                                              // ID of the settings block
#define memoryBase       32                                                  // Tell it where to store your config data in EEPROM                                                          //Constructor for the Simple Timer

enum { EV_NONE=0, EV_SHORTPRESS, EV_LONGPRESS };

//-------------------------
// Variables
//-------------------------
boolean ok = true;                                                           // bool for the EEPROM's config setup
int configAdress = 0;

boolean currentButton = LOW;
boolean button_was_pressed = false;
int previousButton;
int button_pressed_counter = 0;
int longPress = LONGPRESS_LEN;
int buttonCount = 0;
long previousMillis = 0;

boolean fromCheckTemp = false;
long previousTempTime = 0;
float tempLimp = 100;                                                         // In degrees (f)
float tempShutdown = 120;                                                     // In degrees (f)
int checkTempInterval = 30000;                                                // In Milliseconds

float freq;
float freqInitial = .002;
float freqChange = .002;
float freqLimit = .006;

int ledStep = 255;                                                            // How much to change the dimming (PWM) between each step for steps 6 to 9 and 10 to 13

int ledState = HIGH;

// The struct for the config saved to the EEPROM
struct StoreStruct {
    char* cVersion;                                                          // This is to detect if the settings stored in the EEPROM are for this config and sketch
    int bc;
} storage = { 
    CONFIG_VERSION,                                                          // Defaults
    0
};

//-------------------------
// Setup
//-------------------------
void setup() {
  Serial.begin(9600);                                                        // Sets up the serial port and speed
  pinMode(BUTTON_PIN, INPUT);                                                // Setting the button pin to an input
  digitalWrite(BUTTON_PIN, HIGH);                                            // Setting the button with a pull-up resistor, the button when grounded or "low" will be thought of as pressed
  pinMode(powerPin, OUTPUT);                                                 // Setting the pin for the LED on the board to show that power is on or will blink if in a sleep mode
  pinMode(ledPinl, OUTPUT);                                                  // External LED control pin 1
  pinMode(ledPinr, OUTPUT);                                                  // External LED control pin 2
  EEPROM.setMemPool(memoryBase, EEPROMSizeATmega328);                        // Set memorypool base to 32, assume Atmega328
  configAdress = EEPROM.getAddress(sizeof(StoreStruct));                     // Size of config object 
  ok = loadConfig();                                                         // Loads the config, and if it loads sets the bool "ok" to true
  buttonCount = storage.bc;                                                  // Sets the variable for the buttonCount to what is brought back from the storage
  checkTemp();                                                               // Checks the intial temp at start up
  freq = setFreq();                                                          // Sets the initial Frequency for the pulsing modes
  ledStep = setLEDStep();                                                    // Sets the initial LED PWM step value for the dimming modes
  digitalWrite(powerPin, ledState);                                          // Turns on the on board LED  
}

//-------------------------
// Functions
//-------------------------

   
// Loads the Config from EEPROM
bool loadConfig() {                                             
  EEPROM.readBlock(configAdress, storage);
  return (storage.cVersion == CONFIG_VERSION);
}

// Saves Config changes to the EEPROM
void saveConfig() {                                              
   EEPROM.writeBlock(configAdress, storage);
}

//--Button Handling--
// This function determines if the button press is short or long and is made to report back to a switch case
void handle_button(int longPress, int modeType)
{
  int button_now_pressed = !digitalRead(BUTTON_PIN);                         // pin low -> pressed
  
  if (!button_now_pressed && button_was_pressed) {
//Short press
    if (button_pressed_counter < longPress) { 
        if (modeType == 1){
          /*Short press from one of the pulsing modes. This increments the button count, 
          updates the Frequency and possibly the LEDStep and also stores the new buttonCount away in the EEPROM*/
          previousButton = buttonCount;
          ++buttonCount;
          storage.bc = buttonCount;
          saveConfig();
          setFreq();
          setLEDStep();
        } else if (modeType == 2){
          /*Short press from one of the dimming PWM modes. This increments the button count, 
          updates the Frequency and the LEDStep and also stores the new buttonCount away in the EEPROM*/
          previousButton = buttonCount;
          ++buttonCount; 
          storage.bc = buttonCount;
          saveConfig(); 
          setFreq();
          setLEDStep(); 
        } else if (modeType == 3) { 
          /*Short press for the sleep modes 14 and 15. This starts us back to the first mode (0) and sets 
          the frequency and the LED step as well as store the button count to the EEPROM*/ 
          buttonCount = 0;
          storage.bc = buttonCount;                                        //Stores the buttonCount to EEPROM
          saveConfig();
          setFreq(); 
          setLEDStep();
          fromCheckTemp = false;
        }
//Long Press
    } else { 
      if (modeType == 1 || modeType == 2){
        /*Long press for any of the "awake" modes. It puts the external LEDs to sleep in mode 14 or sleep mode. 
        Also it sets the previous button so when exiting the sleep mode it knows what to go back to*/
        previousButton = buttonCount;                              
        buttonCount = 14;
      } else if (modeType == 3) {   
        /*Long press from one of the sleep modes. This sets the button count back to the previous button, 
        updates the Frequency and the LEDStep and also stores the new buttonCount away in the EEPROM*/ 
        buttonCount = previousButton;
        storage.bc = buttonCount; 
        saveConfig();
        setFreq(); 
        setLEDStep();
        fromCheckTemp = false;
      }
    }
  } 

  if (button_now_pressed){
    ++button_pressed_counter;
  } else {
    button_pressed_counter = 0;
  }
    
  button_was_pressed = button_now_pressed;
}

//Checks the tempurature inside the circuit enclosure, 
void checkTemp() {
  unsigned long currentTempTime = millis();                                  // Set the current time
  if(currentTempTime - previousTempTime > 20000){
    previousTempTime = currentTempTime;
    float Vcc = readVcc();                                                   // Calculating the Supply Voltage
    Vcc = Vcc / 1000;                                                        // Converting from mV to Volts
    int reading = analogRead(tempSensorPin);                                 // Reading the voltage from the sensor pin
      
//  Converting that reading to voltage
    float voltage = reading * Vcc;
    voltage /= 1024.0; 
    
//  Print out the temperature in Celcius
    float temperatureC = (voltage - 0.5) * 100 ;                    //converting from 10 mv per degree wit 500 mV offset to degrees ((volatge - 500mV) times 100)
    
//  Now convert to Fahrenheight
    float temperatureF = (temperatureC * 9.0 / 5.0) + 32.0;
     
    if (temperatureF > tempLimp && temperatureF < tempShutdown) {
      //To Hot but not shutting down send to limp home mode
      buttonCount = 15;
      fromCheckTemp = true;
    } else if (temperatureF >= tempShutdown && buttonCount != 14) {
      //Shutting down
      buttonCount = 14;
      fromCheckTemp = true;
    } else if (fromCheckTemp) {
      fromCheckTemp = false;
      buttonCount = previousButton;
    } else {
      fromCheckTemp = false;
    }
  } else {
    //Holder for stuff to do while waiting on the time to check temp again
  }
}

//When starting up with a stored button count we need to find and set the appropriate Frequency "freq" for the button count
float setFreq() { 
  if (buttonCount == 0 || buttonCount == 3) {
    freq = freqInitial;
  } 
  else if (buttonCount == 1 || buttonCount == 4) {
    freq = freqInitial + freqChange;
  } 
  else if (buttonCount == 2 || buttonCount == 5) {
    freq = freqInitial + freqChange + freqChange;
  }
  else {
    freq = freqInitial;
  }
  return freq;
}

//When starting up with a stored button count we need to find and set the appropriate LED brightness "ledStep" for the button count
int setLEDStep() { 
  if (buttonCount == 6 || buttonCount == 10){
    ledStep = 255;
  } 
  else if (buttonCount == 7 || buttonCount == 11) {
    ledStep = 191;
  } 
  else if (buttonCount == 8 || buttonCount == 12) {
    ledStep = 127;
  } 
  else if (buttonCount == 9 || buttonCount == 13) {
    ledStep = 64;
  }
  else {
    ledStep = 255;
  }
  return ledStep;
}

//***************************//
//******Blinking Modes*******//
//***************************//

//"bothFlipFlopPulse" The LEDs pulse back and forth (3 speeds)
void bothFlipFlopPulse() {
  float ledIn;
  float ledOutL;
  float ledOutR;
  longPress = 10;
  checkTemp();
  setFreq();  
  for (ledIn = 4.712; ledIn < 10.995; ledIn = ledIn + freq)      // This sets the start of the LED (ledOutL) pulse on the sin wave to the first zero crossing 4.712 and ends it on the next 10.995.
    {
      ledOutL = sin(ledIn) * 127.5 + 127.5;                      // Making the sin wave all positive numbers and setting it to a scale of 0-255 for the PWM range
      ledOutR = 255 - (sin(ledIn) * 127.5 + 127.5);              // This inverts ledOutR so it pulses to the high as ledOutR pulses to the low
      analogWrite(ledPinl, ledOutL);
      analogWrite(ledPinr, ledOutR);
    }
    
    handle_button(longPress,1);                    // Sets the Button function to run and read the button state, then returns the event, EV_SHORT, EV_LONG, or EV_NONE    
}

//"bothPulse" Like "bothFlipFlopPulse" but with both LEDs on the same sin wave (3 speed)
void bothPulse() {
  float ledIn;
  float ledOutL;
  float ledOutR;
  longPress = 10; 
  for (ledIn = 4.712; ledIn < 10.995; ledIn = ledIn + freq)      //This sets the start of the LED (ledOutL) pulse on the sin wave to the first zero crossing 4.712 and ends it on the next 10.995.
    {
      int out = sin(ledIn) * 127.5 + 127.5;                      //Both LEDs will follow the sin wave but we also have to make it all positive numbers and set to a scale of 0-255 for the PWM range
      analogWrite(ledPinl, out);
      analogWrite(ledPinr, out);
    }
    
  handle_button(longPress,1);
}

//"bothStepped" - Both LEDs on, stepping down the brightness with each button press (4 settings from full bright to rather dim)
void bothStepped() {
  longPress = 75;
  checkTemp();
  setLEDStep();
  analogWrite(ledPinl, ledStep);                                //Turns them both on together 
  analogWrite(ledPinr, ledStep);
  
  handle_button(longPress,2);
  delay(DELAY);
}

//"singleStepped" - Just one LED on, stepping down the brightness with each button press (4 settings from full bright to rather dim)
void singleStepped(){
  longPress = 75;
  checkTemp();
  setLEDStep();
  analogWrite(ledPinl, ledStep);
  digitalWrite(ledPinr, LOW);
    
  handle_button(longPress,2);
  delay(DELAY);
}

//"sleep" external LEDs off but blink the power led on the circuit board.
void sleep() {
  longPress = 75;                     
  checkTemp();
  digitalWrite(ledPinl, LOW);                                    //Turns off both High Power LEDs
  digitalWrite(ledPinr, LOW); 
  
  // Blinks the powerPin light by checking the current time vs. the last time it went thru, once it is over the 1000 ms limit it changes the light's state
  unsigned long currentMillis = millis();
  if(currentMillis - previousMillis > 1000){
    previousMillis = currentMillis;
    if (ledState == LOW){
      ledState = HIGH;
    }
    else {
      ledState = LOW;
    }
    digitalWrite(powerPin, ledState);
  }
      
  handle_button(longPress,3); 
  delay(DELAY);    
}

//"limpHome" The limp home mode, Like mode 1 the LEDs pulse back and forth, But slowly and only to half brightness.
void limpHome() {
  float ledIn;
  float ledOutL;
  float ledOutR;
  checkTemp();
  longPress = 75;
  for (ledIn = 4.712; ledIn < 10.995; ledIn = ledIn + .002)      // This sets the start of the LED (ledOutL) pulse on the sin wave to the first zero crossing 4.712 and ends it on the next 10.995.
    {
      ledOutL = sin(ledIn) * 100 + 127.5;                        // Making the sin wave all positive numbers and setting it to a scale of 0-255 for the PWM range
      ledOutR = 255 - (sin(ledIn) * 127.5 + 127.5);              // This inverts ledOutR so it pulses to the high as ledOutR pulses to the low
      analogWrite(ledPinl, ledOutL);
      analogWrite(ledPinr, ledOutR);
    }
    
  unsigned long currentMillis = millis();
  if(currentMillis - previousMillis > 1000){
    previousMillis = currentMillis;
    
    if (ledState == LOW){
      ledState = HIGH;
    }
    else {
      ledState = LOW;
    }
    digitalWrite(powerPin, ledState);
  }
    
  handle_button(longPress,3);
  delay(DELAY); 
}

//-------------------------
// THE LOOP
//-------------------------
void loop(){  
  //Set what mode the LEDs are in based on how many times the button is pressed.
  while (buttonCount < 3)
  {
    bothFlipFlopPulse();
  }
  while (buttonCount >= 3 && buttonCount < 6)
  {
    bothPulse();
  }
  while (buttonCount >= 6 && buttonCount < 10)
  {
    bothStepped();
  }
  while (buttonCount >= 10 && buttonCount < 14)
  {
    singleStepped();
  }
  while (buttonCount == 14)
  {
    sleep(); 
  }
  while (buttonCount == 15)
  {
    limpHome(); 
  }
  delay(DELAY);
}

Tuesday, April 16, 2013

Power LED bike tail light with Arduino control

I needed a new bike light and I went about looking at off the shelf ones but what I wanted wasn't available. At least not all in the same light. SO like usual I decided to build my own. I'm going to write up an instructable on this since it is rather complex but I used two 1watt power LEDs inside the hollowed out shell of an old cheapy rear bike light I had. I then put the ardunio controller along with two separate MOSFET circuits as a current limiters for each LED (a lot of credit goes to Dan Goldwater for his excellent instructable on High Power LED drivers), then added a LiPo battery and built in charger and one button all to an altoids tin. Here is an early video of the prototype.


 The board laid out ready to be fitted to the Altoids tin

 LEDs mounted with lenses to the old light housing

 The charger port gets hidden when the top is closed.




Here is it in daylight from across the street.


 All done and working!


Oh and I'm still able to program it since I added in a header for my FTDI cable.

UPDATE: Here is the full schematic, note Circuit labs doesn't have a decent facsimile to the TMP36 analog temperature sensor so i just used a Pot, kind of the same functionality when you think about it. just different input.



I'll be the first to admit that the code here is not the best. The debug function is nasty but serves a purpose and keeps things (in my mind) a bit cleaner and allows me to having different logging levels during troubleshooting. Now that the code is well tested I could probably remove it all but I'll bet it would mess up all my timing since the serial prints won't be there.  I'll work on making schematics for the wiring, since right now it is mostly in my head or on a whiteboard. Anyway here's the code.

UPDATE: New Code for Rear Bike Light --> I've made a new post with all the serial debugging removed. It is cleaner but I'm still not sure about the timing and that is mostly to do with the button press durations. That is where a huge majority of my debugging was so the difference between a "long" press and a "short" one will be drastically quicker. I'll test this some time soon.


/*--------------------------------------------------------
Rear Bike Light Project                                    
Author: Chris Crumpacker                               
Date: October 2012 

Copyright (c) 2012 Chris Crumpacker.  All right reserved.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.
                                                           
Sketch Notes: This version contains 6 modes of blinking with 
multiple speeds for some modes. This works off of a single 
button, with short presses the program steps thru the 
modes/speeds. When long pressed it goes into a "sleep" 
mode where the high powered LEDs are turned off. 
It also has the ablity to store the current mode so when 
leaving sleep mode or being brought back up from a power 
down it will return to the previous mode it was in. 
There is also an interal tempurature sensor that will 
put it into a hidden (at least from the mode scrolling) 
"limp home mode" during a certain temp range or evenshut the 
LEDs down if it gets any higher.
--------------------------------------------------------*/

//-------------------------
// Includes
//-------------------------
#include 
#include 

//-------------------------
// Defines
//-------------------------
#define BUTTON_PIN       11                                                  // Button

#define LONGPRESS_LEN    10                                                  // Min numberr of loops for a long press
#define DELAY            10                                                  // Delay per loop in ms
#define CONFIG_VERSION   "rbl1"                                              // ID of the settings block
#define memoryBase       32                                                  // Tell it where to store your config data in EEPROM                                                          //Constructor for the Simple Timer

enum { EV_NONE=0, EV_SHORTPRESS, EV_LONGPRESS };

//-------------------------
// Pin Assignment
//-------------------------
int ledPinl = 9;                                                             // Left LED
int ledPinr = 10;                                                            // Right LED
int powerPin = 13;                                                           // Case LED to show that the circuit has power
int tempSensorPin= A5;                                                       // Analog pin the case's Temp36 sensor is on

//-------------------------
// Variables
//-------------------------
boolean ok = true;                                                           // bool for the EEPROM's config setup
int configAdress = 0;

boolean currentButton = LOW;
boolean button_was_pressed = false;
int previousButton;
int button_pressed_counter = 0;
int longPress = LONGPRESS_LEN;
int buttonCount = 0;
long previousMillis = 0;

boolean fromCheckTemp = false;
long previousTempTime = 0;
float tempLimp = 100;                                                         // In degrees (f)
float tempShutdown = 120;                                                     // In degrees (f)
int checkTempInterval = 30000;                                                // In Milliseconds

float freq;
float freqInitial = .002;
float freqChange = .002;
float freqLimit = .006;

int ledStep = 255;                                                            // How much to change the dimming (PWM) between each step for steps 6 to 9 and 10 to 13

int ledState = HIGH;
int debugLevel = 1;                                                           // 0 = off, 1 = low, 2 = high, 3 = verbose

// The struct for the config saved to the EEPROM
struct StoreStruct {
    char* cVersion;                                                          // This is to detect if the settings stored in the EEPROM are for this config and sketch
    int bc;
} storage = { 
    CONFIG_VERSION,                                                          // Defaults
    0
};

//-------------------------
// Setup
//-------------------------
void setup() {
  Serial.begin(9600);                                                        // Sets up the serial port and speed
  pinMode(BUTTON_PIN, INPUT);                                                // Setting the button pin to an input
  digitalWrite(BUTTON_PIN, HIGH);                                            // Setting the button with a pull-up resistor, the button when grounded or "low" will be thought of as pressed
  pinMode(powerPin, OUTPUT);                                                 // Setting the pin for the LED on the board to show that power is on or will blink if in a sleep mode
  pinMode(ledPinl, OUTPUT);                                                  // External LED control pin 1
  pinMode(ledPinr, OUTPUT);                                                  // External LED control pin 2
  EEPROM.setMemPool(memoryBase, EEPROMSizeATmega328);                        // Set memorypool base to 32, assume Atmega328
  configAdress = EEPROM.getAddress(sizeof(StoreStruct));                     // Size of config object 
  ok = loadConfig();                                                         // Loads the config, and if it loads sets the bool "ok" to true
  buttonCount = storage.bc;                                                  // Sets the variable for the buttonCount to what is brought back from the storage
  checkTemp("setup");                                                        // Checks the intial temp at start up
  freq = setFreq("setup");                                                   // Sets the initial Frequency for the pulsing modes
  ledStep = setLEDStep("setup");                                             // Sets the initial LED PWM step value for the dimming modes
  digitalWrite(powerPin, ledState);                                          // Turns on the on board LED  
}

//-------------------------
// Functions
//-------------------------

// Debug Function
/*
This function allows you to print valuable information from within each function.
For each function that calls the debug you first need to set 
"debugFuncName" variable first for example:  
  char* debugFuncName = "xyzFunction";

Now the function name is just a string so you can make it whatever you like but for
consistancy I keep it the name of the function it's self. Now any time a new variable is set 
you can call the debug to print it to the serial monitor like so:
  debug(variable,"human readable yet short variable description",debugFuncName,fromFunc);
  
The "fromFunc" part is needed when your base function is calling anothering function to do work.
For example if you have multiple functions that repeat but you check a global button state monitor
you would want to know that the variable is being set in the button monitor on behalf of each 
particular function. 

When calling the button monitor from each function I would pass 
the debugFuncName variable like this:
  buttonMonitor(debugFuncName);
  
In that button monitor the sending fuction name variable is passed in like this:
  void buttonMonitor(char* fromFunc){...}
  
If you don't intend to do this nested funtion calling you can remove the last part of the debug
function decleration. or if just one debug trace doesn't need it you can just use an empty set like this:
  debug(variable,"human readable yet short variable description",debugFuncName,"");
*/
void debug(int msgLevel,float variable, char* message, char* inFunc, char* fromWhere){
  boolean printToSerial;
  
  if (debugLevel == 3 && (msgLevel == 3 || msgLevel == 2 || msgLevel == 1)){
    //Verbose logging
    printToSerial = true;
  } else if (debugLevel == 2 && (msgLevel == 2 || msgLevel == 1)) {
    //High logging
    printToSerial = true;    
  }else if (debugLevel == 1 && msgLevel == 1) {
    //Low logging
    printToSerial = true;
  } else if (debugLevel == 0) {
    //Debugging disabled
    printToSerial = false;
  } else {
    //Debug level not high enough to trace out to serial
    printToSerial = false;
  }
  /*If the debug level is high enough for the msgLevel of the debug trace
  it will be printed to serial if not it will be ignored*/ 
  if (printToSerial == true) {
    Serial.print(variable); 
    Serial.print(" ");
    Serial.print(message); 
    Serial.print(" in "); 
    Serial.print(inFunc); 
    Serial.print(" from "); 
    Serial.println(fromWhere);
  }
}
    
// Loads the Config from EEPROM
bool loadConfig() {                                             
  EEPROM.readBlock(configAdress, storage);
  return (storage.cVersion == CONFIG_VERSION);
}

// Saves Config changes to the EEPROM
void saveConfig() {                                              
   EEPROM.writeBlock(configAdress, storage);
}

//--Button Handling--
// This function determines if the button press is short or long and is made to report back to a switch case
void handle_button(int longPress, char* fromFunc,int modeType)
{
  char* debugFuncName = "handle_button";
  int button_now_pressed = !digitalRead(BUTTON_PIN);                         // pin low -> pressed
  
  if (!button_now_pressed && button_was_pressed) {
//Short press
    if (button_pressed_counter < longPress) { 
        debug(1,buttonCount,"Short Pressed",debugFuncName,fromFunc);
        debug(2,freq*100,"Frequence",debugFuncName,fromFunc);
        debug(2,ledStep,"LED step value",debugFuncName,fromFunc);
        debug(2,buttonCount,"buttonCount",debugFuncName,fromFunc);
        debug(1,button_pressed_counter,"Cycles - Button was Pressed for this many cycles",debugFuncName,fromFunc);
        if (modeType == 1){
          /*Short press from one of the pulsing modes. This increments the button count, 
          updates the Frequency and possibly the LEDStep and also stores the new buttonCount away in the EEPROM*/
          previousButton = buttonCount;
          debug(2,previousButton,"PreviousButton should now be set to old button count",debugFuncName,fromFunc);
          ++buttonCount;
          debug(2,buttonCount,"buttonCount incremented by 1",debugFuncName,fromFunc);
          storage.bc = buttonCount;
          saveConfig();
          setFreq(debugFuncName);
          setLEDStep(debugFuncName);
          debug(1,storage.bc,"storage.bc of buttonCount via short press",debugFuncName,fromFunc);
          debug(1,buttonCount,"------------------------------------------------------",debugFuncName,fromFunc);
        } else if (modeType == 2){
          /*Short press from one of the dimming PWM modes. This increments the button count, 
          updates the Frequency and the LEDStep and also stores the new buttonCount away in the EEPROM*/
          previousButton = buttonCount;
          debug(2,previousButton,"PreviousButton should now be set to old button count",debugFuncName,fromFunc);
          ++buttonCount; 
          debug(2,buttonCount,"buttonCount incremented by 1",debugFuncName,fromFunc);
          storage.bc = buttonCount;
          saveConfig(); 
          setFreq(debugFuncName);
          setLEDStep(debugFuncName); 
          debug(1,storage.bc,"storage.bc of buttonCount via short press",debugFuncName,fromFunc);
          debug(1,buttonCount,"------------------------------------------------------",debugFuncName,fromFunc);
        } else if (modeType == 3) { 
          /*Short press for the sleep modes 14 and 15. This starts us back to the first mode (0) and sets 
          the frequency and the LED step as well as store the button count to the EEPROM*/      
          debug(1,buttonCount,"Short button press",debugFuncName,fromFunc);
          buttonCount = 0;
          debug(2,buttonCount,"buttonCount should now be 0",debugFuncName,fromFunc);
          storage.bc = buttonCount;                                  //Stores the buttonCount to EEPROM
          saveConfig();
          debug(1,storage.bc,"storage.bc of buttonCount via Short press",debugFuncName,fromFunc);
          setFreq(debugFuncName); 
          setLEDStep(debugFuncName);
          fromCheckTemp = false;
          debug(1,buttonCount,"------------------------------------------------------",debugFuncName,fromFunc); 
        }
//Long Press
    } else { 
        debug(1,buttonCount,"Long Press",debugFuncName,fromFunc);
        debug(1,button_pressed_counter,"Cycles - Button was Pressed for this many cycles",debugFuncName,fromFunc);
        if (modeType == 1 || modeType == 2){
          /*Long press for any of the "awake" modes. It puts the external LEDs to sleep in mode 14 or sleep mode. 
          Also it sets the previous button so when exiting the sleep mode it knows what to go back to*/
          previousButton = buttonCount;                              
          buttonCount = 14;
          debug(2,previousButton,"previous buttonCount",debugFuncName,fromFunc);
          debug(2,buttonCount,"new buttonCount should be 14 for Sleep",debugFuncName,fromFunc); 
          debug(1,buttonCount,"------------------------------------------------------",debugFuncName,fromFunc);
        } else if (modeType == 3) {   
          /*Long press from one of the sleep modes. This sets the button count back to the previous button, 
          updates the Frequency and the LEDStep and also stores the new buttonCount away in the EEPROM*/ 
          buttonCount = previousButton;
          debug(2,previousButton,"previous button",debugFuncName,fromFunc);
          debug(2,buttonCount,"buttonCount now should be set to previous button",debugFuncName,fromFunc);
          storage.bc = buttonCount; 
          saveConfig();
          setFreq(debugFuncName); 
          setLEDStep(debugFuncName);
          debug(1,storage.bc,"storage.bc of buttonCount via Long press",debugFuncName,fromFunc);
          debug(1,buttonCount,"------------------------------------------------------",debugFuncName,fromFunc);
          fromCheckTemp = false;
        }
    }
//No Press
  } else {
    debug(3,buttonCount,"No button was pressed",debugFuncName,fromFunc);
  }

  if (button_now_pressed)
    ++button_pressed_counter;
  else
    button_pressed_counter = 0;
    debug(3,button_pressed_counter,"--Button Pressed Counter--",debugFuncName,fromFunc);
    
  button_was_pressed = button_now_pressed;
}

//Checks the tempurature inside the circuit enclosure, 
void checkTemp(char* fromFunc) {
  char* debugFuncName = "checkTemp";
  unsigned long currentTempTime = millis();                                  // Set the current time
  if(currentTempTime - previousTempTime > 20000){
    previousTempTime = currentTempTime;
    float Vcc = readVcc();                                                   // Calculating the Supply Voltage
    Vcc = Vcc / 1000;                                                        // Converting from mV to Volts
    debug(3,Vcc,"Vcc in V",debugFuncName,fromFunc);
    int reading = analogRead(tempSensorPin);                                 // Reading the voltage from the sensor pin
    debug(3,reading,"Temp_Sensor_Pin_Reading",debugFuncName,fromFunc);
      
//  Converting that reading to voltage
    float voltage = reading * Vcc;
    voltage /= 1024.0; 
    debug(3,voltage,"reading Voltage converted",debugFuncName,fromFunc);
    
//  Print out the temperature in Celcius
    float temperatureC = (voltage - 0.5) * 100 ;                    //converting from 10 mv per degree wit 500 mV offset to degrees ((volatge - 500mV) times 100)
    debug(2,temperatureC,"temp in C",debugFuncName,fromFunc);
    
//  Now convert to Fahrenheight
    float temperatureF = (temperatureC * 9.0 / 5.0) + 32.0;
    debug(1,temperatureF,"temp in F",debugFuncName,fromFunc);
     
    if (temperatureF > tempLimp && temperatureF < tempShutdown) {
      buttonCount = 15;
      fromCheckTemp = true;
      debug(1,buttonCount,"Open a window! it's getting stuffy. I'll turn the lights down",debugFuncName,fromFunc);
    } else if (temperatureF >= tempShutdown && buttonCount != 14) {
      buttonCount = 14;
      fromCheckTemp = true;
      debug(1,buttonCount,"It's getting Hot in here, so take off all your clothes. I'll shut down the lights in the mean time",debugFuncName,fromFunc);
    } else if (fromCheckTemp) {
      fromCheckTemp = false;
      buttonCount = previousButton;
      debug(2,buttonCount,"buttonCount set back to previous",debugFuncName,fromFunc);
      debug(1,buttonCount,"Awwww yeahhhh! It's business time.",debugFuncName,fromFunc);
    } else {
      fromCheckTemp = false;
      debug(1,buttonCount,"Awwww yeahhhh! It's business time.",debugFuncName,fromFunc);
    }
    debug(1,buttonCount,"------------------------------------------------------",debugFuncName,fromFunc);
  } else {
    //Holder for stuff to do while waiting on the time to check temp again
  }
debug(3,buttonCount,"------------------------------------------------------",debugFuncName,fromFunc);  
}

//When starting up with a stored button count we need to find and set the appropriate Frequency "freq" for the button count
float setFreq(char* fromFunc) {
  char* debugFuncName = "setFreq";
  debug(3,buttonCount,"Setting Frequency",debugFuncName,fromFunc);  
  if (buttonCount == 0 || buttonCount == 3) {
    freq = freqInitial;
  } 
  else if (buttonCount == 1 || buttonCount == 4) {
    freq = freqInitial + freqChange;
  } 
  else if (buttonCount == 2 || buttonCount == 5) {
    freq = freqInitial + freqChange + freqChange;
  }
  else {
    freq = freqInitial;
  }
  debug(3,freq*100,"Frequency set to",debugFuncName,fromFunc); 
  debug(3,buttonCount,"------------------------------------------------------",debugFuncName,fromFunc);
  return freq;
}

//When starting up with a stored button count we need to find and set the appropriate LED brightness "ledStep" for the button count
int setLEDStep(char* fromFunc) {
  char* debugFuncName = "setLEDStep";
  debug(3,buttonCount,"Setting LEDStep",debugFuncName,fromFunc);   
  if (buttonCount == 6 || buttonCount == 10){
    ledStep = 255;
  } 
  else if (buttonCount == 7 || buttonCount == 11) {
    ledStep = 191;
  } 
  else if (buttonCount == 8 || buttonCount == 12) {
    ledStep = 127;
  } 
  else if (buttonCount == 9 || buttonCount == 13) {
    ledStep = 64;
  }
  else {
    ledStep = 255;
  }
  debug(3,ledStep,"LED Step value",debugFuncName,fromFunc);
  debug(3,buttonCount,"------------------------------------------------------",debugFuncName,fromFunc);
  return ledStep;
}

//***************************//
//******Blinking Modes*******//
//***************************//

//"bothFlipFlopPulse" The LEDs pulse back and forth (3 speeds)
void bothFlipFlopPulse() {
  char* debugFuncName = "bothFlipFlopPulse";
  float ledIn;
  float ledOutL;
  float ledOutR;
  longPress = 10;
  debug(3,buttonCount,"buttonCount ",debugFuncName,"");
  checkTemp(debugFuncName);
  setFreq(debugFuncName);  
  for (ledIn = 4.712; ledIn < 10.995; ledIn = ledIn + freq)      // This sets the start of the LED (ledOutL) pulse on the sin wave to the first zero crossing 4.712 and ends it on the next 10.995.
    {
      ledOutL = sin(ledIn) * 127.5 + 127.5;                      // Making the sin wave all positive numbers and setting it to a scale of 0-255 for the PWM range
      ledOutR = 255 - (sin(ledIn) * 127.5 + 127.5);              // This inverts ledOutR so it pulses to the high as ledOutR pulses to the low
      analogWrite(ledPinl, ledOutL);
      analogWrite(ledPinr, ledOutR);
    }
    
    handle_button(longPress,debugFuncName,1);                    // Sets the Button function to run and read the button state, then returns the event, EV_SHORT, EV_LONG, or EV_NONE    
}

//"bothPulse" Like "bothFlipFlopPulse" but with both LEDs on the same sin wave (3 speed)
void bothPulse() {
  char* debugFuncName = "bothPulse";
  float ledIn;
  float ledOutL;
  float ledOutR;
  longPress = 10;
  checkTemp(debugFuncName);
  setFreq(debugFuncName);  
  for (ledIn = 4.712; ledIn < 10.995; ledIn = ledIn + freq)      //This sets the start of the LED (ledOutL) pulse on the sin wave to the first zero crossing 4.712 and ends it on the next 10.995.
    {
      int out = sin(ledIn) * 127.5 + 127.5;                      //Both LEDs will follow the sin wave but we also have to make it all positive numbers and set to a scale of 0-255 for the PWM range
      analogWrite(ledPinl, out);
      analogWrite(ledPinr, out);
    }
    
  handle_button(longPress,debugFuncName,1);
}

//"bothStepped" - Both LEDs on, stepping down the brightness with each button press (4 settings from full bright to rather dim)
void bothStepped() {
  char* debugFuncName = "bothStepped";
  longPress = 75;
  checkTemp(debugFuncName);
  setLEDStep(debugFuncName);
  analogWrite(ledPinl, ledStep);                                //Turns them both on together 
  analogWrite(ledPinr, ledStep);
  
  handle_button(longPress,debugFuncName,2);
  delay(DELAY);
}

//"singleStepped" - Just one LED on, stepping down the brightness with each button press (4 settings from full bright to rather dim)
void singleStepped(){
  char* debugFuncName = "singleStepped";
  debug(3,buttonCount,"button Count",debugFuncName,"");
  longPress = 75;
  checkTemp(debugFuncName);
  setLEDStep(debugFuncName);
  analogWrite(ledPinl, ledStep);
  digitalWrite(ledPinr, LOW);
    
  handle_button(longPress,debugFuncName,2);
  delay(DELAY);
}

//"sleep" external LEDs off but blink the power led on the circuit board.
void sleep() {
  char* debugFuncName = "sleep";
  longPress = 75;
  debug(3,fromCheckTemp," = From Check Temp",debugFuncName,"");                      
  checkTemp(debugFuncName);
  digitalWrite(ledPinl, LOW);                                    //Turns off both High Power LEDs
  digitalWrite(ledPinr, LOW); 
  
  // Blinks the powerPin light by checking the current time vs. the last time it went thru, once it is over the 1000 ms limit it changes the light's state
  unsigned long currentMillis = millis();
  if(currentMillis - previousMillis > 1000){
    previousMillis = currentMillis;
    if (ledState == LOW){
      ledState = HIGH;
    }
    else {
      ledState = LOW;
    }
    digitalWrite(powerPin, ledState);
  }
      
  handle_button(longPress,debugFuncName,3); 
  delay(DELAY);    
}

//"limpHome" The limp home mode, Like mode 1 the LEDs pulse back and forth, But slowly and only to half brightness.
void limpHome() {
  char* debugFuncName = "limpHome";
  float ledIn;
  float ledOutL;
  float ledOutR;
  debug(3,fromCheckTemp," = From Check Temp",debugFuncName,"");
  checkTemp(debugFuncName);
  longPress = 75;
  for (ledIn = 4.712; ledIn < 10.995; ledIn = ledIn + .002)      // This sets the start of the LED (ledOutL) pulse on the sin wave to the first zero crossing 4.712 and ends it on the next 10.995.
    {
      ledOutL = sin(ledIn) * 100 + 127.5;                        // Making the sin wave all positive numbers and setting it to a scale of 0-255 for the PWM range
      ledOutR = 255 - (sin(ledIn) * 127.5 + 127.5);              // This inverts ledOutR so it pulses to the high as ledOutR pulses to the low
      analogWrite(ledPinl, ledOutL);
      analogWrite(ledPinr, ledOutR);
    }
    
  unsigned long currentMillis = millis();
  if(currentMillis - previousMillis > 1000){
    previousMillis = currentMillis;
    
    if (ledState == LOW){
      ledState = HIGH;
    }
    else {
      ledState = LOW;
    }
    digitalWrite(powerPin, ledState);
  }
    
  handle_button(longPress,debugFuncName,3);
  delay(DELAY); 
}

//-------------------------
// THE LOOP
//-------------------------
void loop()
{
  char* debugFuncName = "loop";
  
  //Set what mode the LEDs are in based on how many times the button is pressed.
  while (buttonCount < 3)
  {
    bothFlipFlopPulse();
  }
  while (buttonCount >= 3 && buttonCount < 6)
  {
    bothPulse();
  }
  while (buttonCount >= 6 && buttonCount < 10)
  {
    bothStepped();
  }
  while (buttonCount >= 10 && buttonCount < 14)
  {
    singleStepped();
  }
  while (buttonCount == 14)
  {
    sleep(); 
  }
  while (buttonCount == 15)
  {
    limpHome(); 
  }
  delay(DELAY);
}

Digispark - Ultrasonic Range finder

I had an HC-SR04 Ultrasonic range detector laying around and wanted to do something fun with it and my new digi spark. I set it up so that as objects became closer to the HC-SR04 the RGB would go from Green to red. (Blue when out of range)



One note here with the PWM, don't power it from a computer's USB port. you need to not have anything on pin 4, so I just powered it directly with 5volts to the 5v pin.



/* HC-S04 on a DigiSpark with and RGB Shield
Author: Chris Crumpacker
Date: January 2013
Copyright (c) 2013 Chris Crumpacker.  All right reserved.

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details. 

Sketch Notes: The HC-S04 Ultrasonic detector is attached to Pins 3 and 5. The RGB shield is set to use pins 0, 1, and 4 for PWM. As something comes closer to the detector the RGB goes from green to red.

Using the NewPing library from Teckel http://arduino.cc/forum/index.php?topic=106043.0 I did have to remove the timer functions to get it working against the digispark. I have version 1.5 and Teckel mentioned support for the atTiny was going to be added in V1.6

Other than the pin numbering for PWM pins nothing here is DigiSpark specific
and would work on any arduino once the pics are updated */

#include <NewPing.h>

#define TRIGGER_PIN 3
#define ECHO_PIN 5
#define RED_PIN 0
#define GREEN_PIN 1
#define BLUE_PIN 4
#define MAX_DISTANCE 60

NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.

void setup() {
  pinMode(RED_PIN, OUTPUT);
  pinMode(GREEN_PIN, OUTPUT);
  pinMode(BLUE_PIN, OUTPUT);
}
void loop() {
  uint8_t distance = sonar.ping_cm();

  if (distance) {
    uint8_t greenValue = map(distance, 1, MAX_DISTANCE, 0, 255);  //Map the distance range to a range of 0 to 255 to the pwm value for the Green LED
    uint8_t redValue = 255 - greenValue;
    analogWrite(GREEN_PIN, greenValue);
    analogWrite(RED_PIN, redValue);
    digitalWrite(BLUE_PIN, LOW);
  } else {
    //Out of range, turn the LED blue
    digitalWrite(GREEN_PIN, LOW);
    digitalWrite(RED_PIN, LOW);   
    digitalWrite(BLUE_PIN, HIGH);
  }
  delay(100);
}