Port sketch from Uno to Attiny85 240502

Hello AAC forum,

Working on using PIR & switch to operate
an Adafruit Neopixel Ring 24.

To get started it was decided to keep things simple.

  1. If the switch is closed the Neopixel is solid green.
  2. If the switch is open the Neopixel is off, unless the
    PIR is triggered. If the switch is open
    and the PIR is triggered the Neopixel is solid blue
    for an interval of time.

A sketch was written and loaded onto the
Arduino Uno and the system works well as designed.
Eos_Neopixel_2_color_240425_KB.ino, attached.
Unable to attach sketch so sketch copied herewith at end of post,

The Arduino setup is shown at
Arduino_setup_240426.jpg, attached
allenpitts.com/PM/Eos_Arduino_setup_240426.jpg

To make the system smaller an ATtiny85 was
substituted for the Uno using the breadboard
as shown in the attached line drawing
EOS__LED3_PIR_SW_NeoPix_240423_Brdbrd.jpg.
allenpitts.com/PM/EOS__LED3_PIR_SW_NeoPix_240423_Brdbrd.jpg

But as shown in Test 240426.1 and
Test 240426.2, copied herewith below,
the sketch works perfectly on the Uno
but does not work on the breadboard.

So either the assumption that a sketch
that works on an Arduino Uno
will also work on an ATtiny is false
or
there is a defect in the breadboard
setup.
or
both.

Please accept a request to review
and help me figure how to get
the sketch that works on the
Arduino Uno rev3 work on the ATTiny85.

Thanks

Allen Pitts

***** Test Results *****
Test 240426.1 ATtiny85, PIR & switch

Preconditions

  1. Set up EOS__LED3_PIR_SW_NeoPix_240423_Brdbrd.jpg.
  2. Load Eos_Neopixel_2_color_240425_KB.ino with Internal Clock to 8MHZ
  3. SW1 closed.

Action 1: +5v Power to board

Expected Result:

  1. All Neopixel lights green constantly.
  2. LED3 oscillates at 500 ms intervals.

Actual Result:

  1. Neopixel does not light
  2. LED3 lights constantly

Note: With the conjecture that the PIR is failing, a measurement
was done at PIR out/pin 7.
Result: 3.2 volts for eight seconds when PIR triggered.
Then 1.5 volts until PIR retriggered. Retrigger: 3.2 volts for eight seconds.
This is as expected.

Action 2: Move SW1 from closed to open
Result: 2.1. Neopixel, no change
2.2 LED3 off

Action 3: Move SW1 from open to closed
Result: 3.1. Neopixel, no change
2.2 LED3 oscillates at .5 seconds

Action 4: Move SW1 from closed to open
Result: 4.1. Neopixel, no change
4.2 LED3 off

Test 240426.2 Arduino Uno, PIR & switch
Preconditions

  1. Set up EOS_Arduino_Setup_240426.jpg.
  2. Load Eos_Neopixel_2_color_240425_KB.ino with Internal Clock to 8MHZ
  3. SW1 open.
  4. PIR isolated.

Action 1: +5v Power to board

Expected Result:

  1. All Neopixel lights blue
  2. LED3 oscillates at 500 ms intervals.

Actual Result:

  1. All Neopixel lights blue
  2. LED3 oscillates at 500 ms intervals.

Action 2: Wait 30 seconds for PIR LOW

Expected Result:

  1. All Neopixel off
  2. LED3 oscillates at 500 ms intervals.

Actual Result:

  1. All Neopixel off
  2. LED3 oscillates at 500 ms intervals.

Action 3: Retrigger PIR

Expected Result:

  1. All Neopixel lights blue
  2. LED3 oscillates at 500 ms intervals.

Actual Result:

  1. All Neopixel lights blue
  2. LED3 oscillates at 500 ms intervals.
/* Eos_Neopixel_2_color_240425_KB.ino
This sketch uses two functions, runLED3 and runNeoPixel to operate one LED w runNeoPixel using the PIR and Switch closure as a trigger.

*/

//Library to run the Neopixel
#include <Adafruit_NeoPixel.h>

// Which pin on the Arduino is connected to the NeoPixels?
const int neoPixelPin = 4;

// Number of Neopixel LEDs in the Ring
#define LED_COUNT 24

// Declare our NeoPixel strip object:
Adafruit_NeoPixel strip(LED_COUNT, neoPixelPin, NEO_GRB + NEO_KHZ800);
// see strandTest_240124_colorWipe.ino for argument definitions



// constants won't change. Used here to set a pin number :
const int ledPin3 =  3;      // the number of the LED pin
const int PIN_PIR_SENSOR_INPUT = 2; //the number of the PIR PIN **********************
const int switchPin = 0;

// Variables will change :
int ledState3 = LOW;
int neoPixelState = LOW;             // A variable to track whether the Neopixel is currently showing color (ON) or not showing color (OFF)
int pirState = LOW;     //State of the PIR input to the Attiny
bool pirWasTriggered = false;  // A bool variable (True/False) to track whether the PIR went HIGH and the Attiny registered that the PIR went HIGH
bool switchIsClosed = false;

unsigned long previousMillis3 = 0;        // will store last time LED was updated
unsigned long previousMillis4 = 0;

const long interval3 = 500;
const long interval4 = 10000;            // interval LED4 stays on after a trigger from PIR

void setup() {

  // These lines are specifically to support the Adafruit Trinket 5V 16 MHz.
  // Any other board, you can remove this part (but no harm leaving it):
  //#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000)
  //  clock_prescale_set(clock_div_1);
  //#endif
  // END of Trinket-specific code.

  // set the digital pin as output:
  pinMode(ledPin3, OUTPUT);
  pinMode(PIN_PIR_SENSOR_INPUT, INPUT); //Define the pin input from the PIR sensor to the Attiny and INPUT *********************
  pinMode(switchPin, INPUT);  //240430  pinMode(switchPin, INPUT_PULLUP);

  //Neopixel setup commands
  strip.begin();           // INITIALIZE NeoPixel strip object (REQUIRED)
  strip.show();            // Turn OFF all pixels ASAP
  strip.setBrightness(50); // Set BRIGHTNESS to about 1/5 (max = 255)
}

void loop() {
  //Every loop this logic will be evaluated
  //If the PIR wasn't triggered recently (A HIGH hasn't been read), then check the PIR for HIGH/LOW
  if(pirWasTriggered == false){
    pirState = digitalRead(PIN_PIR_SENSOR_INPUT); //Read whether the input from the PIR sensor is LOW or HIGH and set that value to pirState ****************

    if(pirState == HIGH){ //If the input is HIGH, record that it was triggered
      pirWasTriggered = true;
    }
  }
  //runLED3 will perform the toggling ON/OFF of LED3 and the timing
  runLED3();
  //runNeoPixel will perform the toggling ON/OFF of NEOPIXEL and the timing
  runNeoPixel();
}

void runLED3() {
  unsigned long currentMillis3 = millis();

  if (currentMillis3 - previousMillis3 >= interval3) {
    // save the last time you blinked the LED
    previousMillis3 = currentMillis3;

    // if the LED is off turn it on and vice-versa:
    if (ledState3 == LOW) {
      ledState3 = HIGH;
    } else {
      ledState3 = LOW;
    }

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin3, ledState3);
  }
}


void runNeoPixel(){

  //Read the logic level of the Switch (HIGH/LOW), The Switch will read HIGH when OPEN and LOW when closed

  /*
  There are 4 Combinations and their meanings:
  1.) currentSwitchValue == LOW and switchIsClosed == false -> Switch is now CLOSED after having been OPEN
  2.) currentSwitchValue == LOW and switchIsClosed == true -> Switch is still CLOSED after having already been CLOSED
  3.) currentSwitchValue == HIGH and switchIsClosed == true -> Switch is now OPEN after having been CLOSED
  4.) currentSwitchValue == HIGH and switchIsClosed == false -> Switch is still OPEN after having already been OPEN
  */

  bool currentSwitchValue = digitalRead(switchPin); //Read the current value of the Switch Pin (HIGH/LOW)
  //This is combination 1 from the above list
  if( currentSwitchValue == LOW && switchIsClosed == false){  //If the Switch is CLOSED (LOW) and the switchIsClosed variable was set to False before, set switchIsClosed to True and turn ON LED4
    switchIsClosed = true;
    colorWipe(strip.Color(0,255,0)); // Set the neopixel to Green
    pirWasTriggered = false; //Set this false in case the PIR was triggered and then the Switch is CLOSED. Setting pirWasTriggered to false prevents the light turning back on from the interval4 timer after the Siwtch is OPEN again
    return; //exit the runLED4 function for this round of the loop
  }
  //This is combination 3 from the above list
  if( currentSwitchValue == HIGH && switchIsClosed == true){  //If the Switch is now OPEN (HIGH) and the switchIsClosed variable was set to True before, set switchIsClosed to False and turn OFF the neopixel ring
    switchIsClosed = false;
    //neopixel_off(); //Turn off the neopixel display by showing Black
    colorWipe(strip.Color(0,0,0)); // Set the neopixel to Black/Off
    pirWasTriggered = false; //Set this false in case the PIR was triggered and then the Switch is CLOSED. Setting pirWasTriggered to false prevents the light turning back on from the interval4 timer after the Siwtch is OPEN again
    return; //exit the runLED4 function for this round of the loop
  }
  //This is combination 2 from the above list
  if(switchIsClosed == true){
    return; //exit the function because LED4 is already ON and the PIR signal does not need to be read because LED4 is on because the Switch is CLOSED
  }

  //Combination 4 is the default state of the Switch being OPEN and we will proceed to the PIR logic below for this condition

  //If PIR wasn't triggered (didn't go HIGH), exit out of this function altogether with the 'return' command since nothing else needs to be done on LED4
  if(pirWasTriggered == false){
    return;
  }

  //If it's here that means PIR was triggered, and we can turn on the LED
  if(neoPixelState == LOW){ //Check if the neopixel state is currently LOW, set it HIGH and turn on the LED. 
  //This prevents taking time and resources to digitalWrite ledPin4 HIGH every loop when it is already HIGh
    previousMillis4 = millis(); //set the time of previousMillis4
    neoPixelState = HIGH;
    colorWipe(strip.Color(0,0,255)); // Set the neopixel to Blue 
  }
  
  //This timer is now tracking how long until LED4 is turned OFF
  unsigned long currentMillis4 = millis();

  if (currentMillis4 - previousMillis4 >= interval4) { //Once interval4 amount of time has passed since the LED4 was turned ON, it will enter this IF statement
    //set the LED to OFF
    neoPixelState = LOW;
    //neopixel_off();  //Turn off the neopixel display by showing Black
    colorWipe(strip.Color(0,0,0)); // Set the neopixel to Black/Off
    pirWasTriggered = false;
  }
}   


// 1.  Fill Strip Pixels One After Another with a Color
//Fill strip pixels one after another with a color. Strip is NOT cleared
// first; anything there will be covered pixel by pixel. Pass in color
// (as a single 'packed' 32-bit value, which you can get by calling
// strip.Color(red, green, blue) as shown in the loop() function above),
// and a delay time (in milliseconds) between pixels.
void colorWipe(uint32_t color) {
  for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
    strip.setPixelColor(i, color);         //  Set pixel's color (in RAM)
    strip.show();                          //  Update strip to match
  }
}


void neopixel_off(){
  strip.clear(); //Set all color values of the Neopixels to Black
  strip.show(); //Update and display the Black color (effectively this means the LEDs are OFF)
}

@AllenPitts - When you compile for the ATtiny85, what does the Output Monitor show as the memory usage?

The sketch should work with Attiny85. I am investigating the case using my following Attiny85 Dev Board (Fig-1) and Neopixel Ring 12.
Attiny85DevBoard
Figure-1:

Your sketch of UNO works for ATTiny85 in my Dev Board of Fig-1 without any modifications except re-mappings of the DPins (see sketch in Step-4).

Commens:
1. If your ATtiny85 fresh which means its Fuse bits are at factory settings and then the chip is running at 8 MHz internal clock.

2. Your UNO program is based on 16 MHz clock.

3. So, change the fuse bits (Low Fuse Byte = 0xE1 Internal 8 MHz is raised to 16 MHz by PLL circuit) using a ROM/AVR Programmer.

4. This is the sketch that I have compiled using ATTinyCore.

/* Eos_Neopixel_2_color_240425_KB.ino
  This sketch uses two functions, runLED3 and runNeoPixel to operate one LED w runNeoPixel using the PIR and Switch closure as a trigger.

*/

//Library to run the Neopixel
#include <Adafruit_NeoPixel.h>

// Which pin on the Arduino is connected to the NeoPixels?
const int neoPixelPin = 2;

// Number of Neopixel LEDs in the Ring
#define LED_COUNT 12//24

// Declare our NeoPixel strip object:
Adafruit_NeoPixel strip(LED_COUNT, neoPixelPin, NEO_GRB + NEO_KHZ800);
// see strandTest_240124_colorWipe.ino for argument definitions



// constants won't change. Used here to set a pin number :
const int ledPin3 =  1;      // the number of the LED pin
const int PIN_PIR_SENSOR_INPUT = 1; //the number of the PIR PIN **********************
const int switchPin = 0;//0;

// Variables will change :
int ledState3 = LOW;
int neoPixelState = LOW;             // A variable to track whether the Neopixel is currently showing color (ON) or not showing color (OFF)
int pirState = LOW;     //State of the PIR input to the Attiny
bool pirWasTriggered = false;  // A bool variable (True/False) to track whether the PIR went HIGH and the Attiny registered that the PIR went HIGH
bool switchIsClosed = false;

unsigned long previousMillis3 = 0;        // will store last time LED was updated
unsigned long previousMillis4 = 0;

const long interval3 = 500;
const long interval4 = 10000;            // interval LED4 stays on after a trigger from PIR

void setup() {

  // These lines are specifically to support the Adafruit Trinket 5V 16 MHz.
  // Any other board, you can remove this part (but no harm leaving it):
  //#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000)
  //  clock_prescale_set(clock_div_1);
  //#endif
  // END of Trinket-specific code.

  // set the digital pin as output:
  pinMode(ledPin3, OUTPUT);
  pinMode(PIN_PIR_SENSOR_INPUT, INPUT); //Define the pin input from the PIR sensor to the Attiny and INPUT *********************
  pinMode(switchPin, INPUT_PULLUP);  //240430  pinMode(switchPin, INPUT_PULLUP);

  //Neopixel setup commands
  strip.begin();           // INITIALIZE NeoPixel strip object (REQUIRED)
  strip.show();            // Turn OFF all pixels ASAP
  strip.setBrightness(50); // Set BRIGHTNESS to about 1/5 (max = 255)
}

void loop() {
  //Every loop this logic will be evaluated
  //If the PIR wasn't triggered recently (A HIGH hasn't been read), then check the PIR for HIGH/LOW
  if (pirWasTriggered == false) {
    pirState = digitalRead(PIN_PIR_SENSOR_INPUT); //Read whether the input from the PIR sensor is LOW or HIGH and set that value to pirState ****************

    if (pirState == HIGH) { //If the input is HIGH, record that it was triggered
      pirWasTriggered = true;
    }
  }
  //runLED3 will perform the toggling ON/OFF of LED3 and the timing
  runLED3();
  //runNeoPixel will perform the toggling ON/OFF of NEOPIXEL and the timing
  runNeoPixel();
}

void runLED3() {
  unsigned long currentMillis3 = millis();

  if (currentMillis3 - previousMillis3 >= interval3) {
    // save the last time you blinked the LED
    previousMillis3 = currentMillis3;

    // if the LED is off turn it on and vice-versa:
    if (ledState3 == LOW) {
      ledState3 = HIGH;
    } else {
      ledState3 = LOW;
    }

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin3, ledState3);
  }
}


void runNeoPixel() {

  //Read the logic level of the Switch (HIGH/LOW), The Switch will read HIGH when OPEN and LOW when closed

  /*
    There are 4 Combinations and their meanings:
    1.) currentSwitchValue == LOW and switchIsClosed == false -> Switch is now CLOSED after having been OPEN
    2.) currentSwitchValue == LOW and switchIsClosed == true -> Switch is still CLOSED after having already been CLOSED
    3.) currentSwitchValue == HIGH and switchIsClosed == true -> Switch is now OPEN after having been CLOSED
    4.) currentSwitchValue == HIGH and switchIsClosed == false -> Switch is still OPEN after having already been OPEN
  */

  bool currentSwitchValue = digitalRead(switchPin); //Read the current value of the Switch Pin (HIGH/LOW)
  //This is combination 1 from the above list
  if ( currentSwitchValue == LOW && switchIsClosed == false) { //If the Switch is CLOSED (LOW) and the switchIsClosed variable was set to False before, set switchIsClosed to True and turn ON LED4
    switchIsClosed = true;
    colorWipe(strip.Color(0, 255, 0)); // Set the neopixel to Green
    pirWasTriggered = false; //Set this false in case the PIR was triggered and then the Switch is CLOSED. Setting pirWasTriggered to false prevents the light turning back on from the interval4 timer after the Siwtch is OPEN again
    return; //exit the runLED4 function for this round of the loop
  }
  //This is combination 3 from the above list
  if ( currentSwitchValue == HIGH && switchIsClosed == true) { //If the Switch is now OPEN (HIGH) and the switchIsClosed variable was set to True before, set switchIsClosed to False and turn OFF the neopixel ring
    switchIsClosed = false;
    //neopixel_off(); //Turn off the neopixel display by showing Black
    colorWipe(strip.Color(0, 0, 0)); // Set the neopixel to Black/Off
    pirWasTriggered = false; //Set this false in case the PIR was triggered and then the Switch is CLOSED. Setting pirWasTriggered to false prevents the light turning back on from the interval4 timer after the Siwtch is OPEN again
    return; //exit the runLED4 function for this round of the loop
  }
  //This is combination 2 from the above list
  if (switchIsClosed == true) {
    return; //exit the function because LED4 is already ON and the PIR signal does not need to be read because LED4 is on because the Switch is CLOSED
  }

  //Combination 4 is the default state of the Switch being OPEN and we will proceed to the PIR logic below for this condition

  //If PIR wasn't triggered (didn't go HIGH), exit out of this function altogether with the 'return' command since nothing else needs to be done on LED4
  if (pirWasTriggered == false) {
    return;
  }

  //If it's here that means PIR was triggered, and we can turn on the LED
  if (neoPixelState == LOW) { //Check if the neopixel state is currently LOW, set it HIGH and turn on the LED.
    //This prevents taking time and resources to digitalWrite ledPin4 HIGH every loop when it is already HIGh
    previousMillis4 = millis(); //set the time of previousMillis4
    neoPixelState = HIGH;
    colorWipe(strip.Color(0, 0, 255)); // Set the neopixel to Blue
  }

  //This timer is now tracking how long until LED4 is turned OFF
  unsigned long currentMillis4 = millis();

  if (currentMillis4 - previousMillis4 >= interval4) { //Once interval4 amount of time has passed since the LED4 was turned ON, it will enter this IF statement
    //set the LED to OFF
    neoPixelState = LOW;
    //neopixel_off();  //Turn off the neopixel display by showing Black
    colorWipe(strip.Color(0, 0, 0)); // Set the neopixel to Black/Off
    pirWasTriggered = false;
  }
}


// 1.  Fill Strip Pixels One After Another with a Color
//Fill strip pixels one after another with a color. Strip is NOT cleared
// first; anything there will be covered pixel by pixel. Pass in color
// (as a single 'packed' 32-bit value, which you can get by calling
// strip.Color(red, green, blue) as shown in the loop() function above),
// and a delay time (in milliseconds) between pixels.
void colorWipe(uint32_t color) {
  for (int i = 0; i < strip.numPixels(); i++) { // For each pixel in strip...
    strip.setPixelColor(i, color);         //  Set pixel's color (in RAM)
    strip.show();                          //  Update strip to match
  }
}


void neopixel_off() {
  strip.clear(); //Set all color values of the Neopixels to Black
  strip.show(); //Update and display the Black color (effectively this means the LEDs are OFF)
}

5. Memory usage:
2640 bytes of flash (Limit: 6586 bytes)
51 bytes of RAM

Hello xfpd,

This is the output when the sketch is compiled.

Using library Adafruit NeoPixel at version 1.12.0 in folder: C:\Users\pitts\OneDrive\Documents\Arduino\libraries\Adafruit_NeoPixel
"C:\Users\pitts\AppData\Local\Arduino15\packages\arduino\tools\avr-gcc\7.3.0-atmel3.6.1-arduino7/bin/avr-size" -A "C:\Users\pitts\AppData\Local\Temp\arduino\sketches\1CE7446D611D28F4E73AFF8B2890CD63/Eos_Neopixel_2_color_240425_KB.ino.elf"
Sketch uses 2726 bytes (33%) of program storage space. Maximum is 8192 bytes.
Global variables use 54 bytes (10%) of dynamic memory, leaving 458 bytes for local variables. Maximum is 512 bytes.

A couple of folks asked if there was enough memory because there is a lot
more meory on the Uno than on the Attiny.

But it looks like there is plenty of memory on the ATTiny for this sketch.

Thanks.

Allen

1 Like

Hello Golam,

> So, change the fuse bits (Low Fuse Byte = 0xE1 Internal 8 MHz is raised to 16 MHz by PLL circuit) using a ROM/AVR Programmer.

Not sure what this means.
To program the ATtiny85 the MC is put in
a Sparkfun Tiny Programmer

Then, if it is new ATtiny in the Arduino IDE Tools > Burn Bootloader
Then at Tools > Board (ATTiny 25/45/85), Clock (internal 8 MHZ),
Processor (ATtiny85), Programmer (USBTinyISP)
Then Sketch > Upload Using Programmer

Not familiar with "fuse bits' or "ROM/AVR Programmer", what they are, where they are, or how they are used.

Is this something that would make a sketch that runs on the Arduino give
unpredictable results on the ATtiny85?

Thanks.

Allen

When you burn bootloader, the fuse bits should have been correctly set.

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