News:

SMF for DIYStompboxes.com!

Main Menu

Arduino/Attiny85 code help

Started by patrick398, July 08, 2020, 06:13:14 PM

Previous topic - Next topic

patrick398

So i'm trying to bend my tiny mind around coding and this is my first experience with anything like this so i'm crawling along. I want to use an ATtiny85 to control a relay and LED for bypass.
I have cobbled this code together from snippets i've found on the internet, had to edit it a few times so might have got confused, and it's possible it's complete jibberish.
Would someone mind taking a look? I'm going to be away from my workshop for a few days so can't actually try it out.

I need to edit the pin numbers to work with the '85 chip, but i think they're right for the arduino UNO. After a bit of fiddling it now verifies which is promising but i'm sure there's loads of mistakes in there. I can just about follow it and have a rough idea what's doing what. Debouncing is coming form the ezButton library.

//CHANGE PIN NUMBERS FOR ATTINY85


#include <ezButton.h>

/// constants won't change
const int LED_PIN    = 4; // Arduino pin connected to LED's pin
const int BUTTON_PIN = 7; // Arduino pin connected to button's pin
const int RELAY_PIN  = 3; // Arduino pin connected to relay's pin

ezButton button(BUTTON_PIN);  // create ezButton object that attach to pin 7;

// variables will change:
int relayState = LOW;   // the current state of relay
int ledState = LOW;     // the current state of LED
int lastButtonState;    // the previous state of button
int currentButtonState; // the current state of button

void setup() {
  pinMode(BUTTON_PIN, INPUT_PULLUP); // set arduino pin to input pull-up mode
  pinMode(RELAY_PIN, OUTPUT);        // set arduino pin to output mode
  pinMode(LED_PIN, OUTPUT);   // set arduino pin to output mode
  button.setDebounceTime(50); // set debounce time to 50 milliseconds
}

void loop() {
  button.loop(); // MUST call the loop() function first

  if (button.isPressed()) {

    // toggle state of relay
    relayState = !relayState;

    // control relay arccoding to the toggled state
    digitalWrite(RELAY_PIN, relayState);


    if (button.isPressed()) {
      digitalWrite(RELAY_PIN, HIGH); // turn on
    }
    else if (button.isPressed()) {
      digitalWrite(RELAY_PIN, LOW);  // turn off

      if (button.isPressed()) {

        // toggle state of LED
        ledState = !ledState;

        // control LED arccoding to the toggleed sate
        digitalWrite(LED_PIN, ledState);
      }
    }


  }
}




My brain hurts  :icon_exclaim:

ElectricDruid

I don't really speak Arduino, so I can't say much about the syntax. The only thing that jumps out is that I can't see anywhere where 'LOW' is defined. Does the Arduino environment give you Boolean variables like LOW and HIGH to use, or do you have to do that yourself?

The logic is still scrambled. You do the same test "if (button.isPressed()) {" about four times!

Do it once, and put *all* the stuff that happens when the button is pressed in that section.

Also this is not good:

if (button.isPressed()) {
     // Stuff
} else if (button.isPressed()) {
    // Other stuff
}


No wonder your brain hurts! Trying to make sense out of that will do that to a person!
You could just leave the condition out of the bottom half, in which case it will run whenever the button is *not* pressed (e.g. all the rest of the time, over and over again)
if (button.isPressed()) {
     // Stuff
} else {
    // Other stuff
}


Or you might want to test for some other event, but only when the button is not pressed - the "else" clause will only run if the first condition is not met. But I don't see any other conditions anywhere in your code.
if (button.isPressed()) {
     // Stuff
} else (some other condition){
    // Other stuff
}


I'd guess it could be like this:

if (button.isPressed()) {

    // toggle state of relay
    relayState = !relayState;

    // control relay arccoding to the toggled state
    digitalWrite(RELAY_PIN, relayState);

    // toggle state of LED
   ledState = !ledState;

    // control LED arccoding to the toggleed sate
    digitalWrite(LED_PIN, ledState);
}


If the button is pressed, we toggle the relay, and then write the new state, and then toggle the LED, and write its new state too. Job done!



vigilante397

#2
This is the code I used with ATTiny85, using the Arduino IDE (with added comments because I almost never comment my code while I'm writing it :P):

int chState = 0; //starts off

void setup() {
  pinMode(3, INPUT_PULLUP); //set pin modes
  pinMode(1, OUTPUT);
}

void loop() {
  int bypass = digitalRead(4); //read the status of the switch
  if (bypass == 0) //if the button has been pressed
  {
    if (byState == 0) //if the current state is off
    {
      digitalWrite(0, HIGH); //turn on
      byState = 1; //set the current state flag to on
      delay(100); //100ms debounce delay
    }
    else if (byState == 1) //if the current state is on
    {
      digitalWrite(0, LOW); //turn off
      byState = 0; //set current state flag to off
      delay(100); //100ms debounce delay
    }
  }
}
}


It's dirt simple, but I think it's pretty intuitive and it definitely gets the job done. I like the ATTiny85 because it's self-contained and tiny but still has enough IO to run a pair of switches, I recently did one for bypass and a channel switch with a single ATTiny85.
  • SUPPORTER
"Some people love music the way other people love chocolate. Some of us love music the way other people love oxygen."

www.sushiboxfx.com

niektb

#3
Quote from: ElectricDruid on July 08, 2020, 08:13:26 PM
Also this is not good:

if (button.isPressed()) {
     // Stuff
} else if (button.isPressed()) {
    // Other stuff
}


Agreed with ElectricDruid. You're checking twice for the same condition (if apple then ... otherwise if apple). This means that the 'other stuff' in the code snippet above will never execute.
Vigilante's approach will work for simple switching systems. However, if you have multiple states (for example if you incorporate series/parallel switching or whatever) you'd be better off using a simple state machine.

Okay, I'm drawing up a bit of code for a digitally-controlled PT2399 pedal, with some more modes that are controlled using a single footswitch (Ideas I'm toying with are a Tap Tempo Mode and a Bypass Mode, Modulation Mode etc.). The whole stuff is a little work-in-progress (only the mode switching and the RGB coloring is built-in yet, and quite rough still) so it's not guaranteed to work haha. This code is btw tested on a Arduino Nano.


/* HARDWARE DEFINITION */
// RGB LED Definition
const int pin_rgb_r       = 9;
const int pin_rgb_g       = 10;
const int pin_rgb_b       = 11;
// Footswitch
const int pin_footswitch  = 2;

/* FIRMWARE SETUP */
// Mode definitions and variables
#define MODE_BYPASS 0
#define MODE_TEMPO  1
#define MODE_MOD    2
#define MODE_TAILS  3
int mode = MODE_BYPASS;
#define MODE_BYPASS_COLOR 0xFF0000
#define MODE_TEMPO_COLOR  0xFFFF00
#define MODE_MOD_COLOR    0xFF00FF
#define MODE_TAILS_COLOR  0xFFFFFF

// Switch debounce variables
unsigned long debounce_time_ms = 200;
unsigned long debounce_timer = 0;
bool debouncing = false;

/* MAIN FUNCTIONS */
void setup() {
  // Initialize Serial Port
  Serial.begin(115200);
 
  // Initialize RGB LED
  pinMode(pin_rgb_r, OUTPUT);
  pinMode(pin_rgb_g, OUTPUT);
  pinMode(pin_rgb_b, OUTPUT);

  // Initialize Footswitch
  pinMode(pin_footswitch, INPUT);
  attachInterrupt(digitalPinToInterrupt(pin_footswitch), switchMode, FALLING);

  modeSetRGB();
}

void loop() {
  if (debouncing && (millis() - debounce_timer >= debounce_time_ms)) {
    attachInterrupt(digitalPinToInterrupt(pin_footswitch), switchMode, FALLING);
    debouncing = false;
  }
}

/* CORE FUNCTIONS */
void switchMode () {
  detachInterrupt(digitalPinToInterrupt(pin_footswitch)); // disable more interrupts
  debouncing = true;
  debounce_timer = millis();

  mode++;
  if (mode > MODE_TAILS)
    mode = MODE_BYPASS;

  modeSetRGB();
  Serial.println(mode);
}

void modeSetRGB(){
  if (mode = MODE_BYPASS)
    RGB_color(MODE_BYPASS_COLOR);
  else if (mode = MODE_TEMPO)
    RGB_color(MODE_TEMPO_COLOR);
  else if (mode = MODE_MOD)
    RGB_color(MODE_MOD_COLOR);
  else // mode = MODE_TAILS
    RGB_color(MODE_TAILS_COLOR); 
}

/* HELPER FUNCTIONS */
void RGB_color(int val) {
  int R = val >> 16;
  int G = (val >> 8) & 0xF;
  int B = val & 0xF;
 
  analogWrite(pin_rgb_r, R);
  analogWrite(pin_rgb_g, G);
  analogWrite(pin_rgb_b, B);
}


Now don't look at how I use interrupts, that might cloud your understanding of this code. Basically, the microcontroller idles around (and in my case, will probably be busy looking at pot values and controlling PT2399) till you press a button :)
What I want to zoom in on is the function switchMode(). Every state (or mode) of the pedal is represented by a numeric value (0 to 3) and a corresponding color. Every time you press a button, the function switchMode() is executed, which changes the mode to the next state and calls the modeSetRGB() function once which updates the RGB LED color. (and in your case, you could create a modeSetBypass() function which updates the Bypass relay f.e.

Okay bottomline: If this is too advanced for you yet, forget anything I said (in order to not get confused :icon_mrgreen: ) and stick with the basics. Otherwise, this might provide an interesting foundation for more complex switching  ;D

potul

Your code in the first post is really a mess... you are doing things twice (changing state of the relay, etc...). I have cleaned a little your code, and left only what should be there. I have also added something in the setup function to set the initial state of relay and LED, otherwise it remains undefined until you press the button the first time. Give it a try.
BTW, you are defining a couple of variables that are never used (lastButtonState and currentButtonState)


//CHANGE PIN NUMBERS FOR ATTINY85

#include <ezButton.h>

/// constants won't change
const int LED_PIN    = 4; // Arduino pin connected to LED's pin
const int BUTTON_PIN = 7; // Arduino pin connected to button's pin
const int RELAY_PIN  = 3; // Arduino pin connected to relay's pin

ezButton button(BUTTON_PIN);  // create ezButton object that attach to pin 7;

// variables will change:
int relayState = LOW;   // the current state of relay
int ledState = LOW;     // the current state of LED
int lastButtonState;    // the previous state of button
int currentButtonState; // the current state of button

void setup() {
  pinMode(BUTTON_PIN, INPUT_PULLUP); // set arduino pin to input pull-up mode
  pinMode(RELAY_PIN, OUTPUT);        // set arduino pin to output mode
  pinMode(LED_PIN, OUTPUT);   // set arduino pin to output mode
  button.setDebounceTime(50); // set debounce time to 50 milliseconds
  digitalWrite(RELAY_PIN, relayState);
  digitalWrite(LED_PIN, ledState);
}

void loop() {
  button.loop(); // MUST call the loop() function first

  if (button.isPressed()) {

    // toggle state of relay
    relayState = !relayState;

    // control relay arccoding to the toggled state
    digitalWrite(RELAY_PIN, relayState);
 
    // toggle state of LED
    ledState = !ledState;

    // control LED arccoding to the toggleed sate
   digitalWrite(LED_PIN, ledState);
   
  }
}


On the other side, I think the approach of toggling the relay and LEDs but not synchronizing them is not the best one.... Supposedly you always want the LED to be ON when the relay is ON, and viceversa, so you really don't need to keep track of both states, just one state should make it, unless you want to do more fancy stuff with the LED. So I would leave it like that:

//CHANGE PIN NUMBERS FOR ATTINY85

#include <ezButton.h>

/// constants won't change
const int LED_PIN    = 4; // Arduino pin connected to LED's pin
const int BUTTON_PIN = 7; // Arduino pin connected to button's pin
const int RELAY_PIN  = 3; // Arduino pin connected to relay's pin

ezButton button(BUTTON_PIN);  // create ezButton object that attach to pin 7;

// variables will change:
int relayState = LOW;   // the current state of relay
int lastButtonState;    // the previous state of button
int currentButtonState; // the current state of button

void setup() {
  pinMode(BUTTON_PIN, INPUT_PULLUP); // set arduino pin to input pull-up mode
  pinMode(RELAY_PIN, OUTPUT);        // set arduino pin to output mode
  pinMode(LED_PIN, OUTPUT);   // set arduino pin to output mode
  button.setDebounceTime(50); // set debounce time to 50 milliseconds
  digitalWrite(RELAY_PIN, relayState);
  digitalWrite(LED_PIN, relayState);
}

void loop() {
  button.loop(); // MUST call the loop() function first

  if (button.isPressed()) {

    // toggle state of relay
    relayState = !relayState;

    // control relay arccoding to the toggled state
    digitalWrite(RELAY_PIN, relayState);
 
    // control LED arccoding to the toggleed sate
   digitalWrite(LED_PIN, relayState);
   
  }
}

patrick398

Thanks so much for all the replies guys, really helpful info! As suspected that method of combining different snippets of code makes things confusing and convoluted, and makes sense that i ended up with the same instructions several times.
Thanks for all the pointers and for the additional code too, i'm going to spend the next few days going through it to try and properly understand every line. There's definitely a couple i don't understand so no doubt i'll be back with more questions :)

patrick398

Also, is this code setting the relay pin high on one button press, and low on another? So i can use this with a non-latching relay?
At some point i might want to include the optoisolator muting, but i'll try and get the main bypass working first. I'm cartwheeling before i can walk  :icon_lol:

potul

This code is basically setting both LED and relay LOW on startup, and then toggling both between HIGH and LOW on every button press.



patrick398

Quote from: potul on July 09, 2020, 10:25:48 AM
This code is basically setting both LED and relay LOW on startup, and then toggling both between HIGH and LOW on every button press.

Thanks! So the relay pin stays high until toggled low and I can use a non latching relay?

vigilante397

My personal opinion is that it's easiest to use a non-latching relay and put the LED in parallel with the coil, that way you only need to use one output pin to drive both.
  • SUPPORTER
"Some people love music the way other people love chocolate. Some of us love music the way other people love oxygen."

www.sushiboxfx.com

ElectricDruid

Quote from: patrick398 on July 09, 2020, 11:27:45 AM
Quote from: potul on July 09, 2020, 10:25:48 AM
This code is basically setting both LED and relay LOW on startup, and then toggling both between HIGH and LOW on every button press.

Thanks! So the relay pin stays high until toggled low and I can use a non latching relay?

Yes. As written, that's what it expects.

knutolai

Any luck with the code I sent you? It's verified as working with the bounce2 library.

patrick398

Quote from: knutolai on July 10, 2020, 10:39:00 AM
Any luck with the code I sent you? It's verified as working with the bounce2 library.

I didn't have any latching relays so wanted to try get something working with the non-latching ones i have :)

patrick398

Haven't tried the code properly with a relay but used a momentary toggle to switch an LED and that all seems to work well. Just sketching a circuit on Kicad and it occurred to me i'd need a transistor to drive the relay. Can i set it up like this and use it to also drive the LED?
Thanks again for all your help. I'm having a lot of fun with the arduino!




potul

If you always want the LED in sync with the Relay, yes, you can do it this way. Looking at the schematic, there is no limiting resistor for the LED.. is this OK?


niektb

Don't you need to connect pin 12 of the relay to 5V also?

patrick398

#16
Quote from: potul on July 22, 2020, 02:27:27 AM
If you always want the LED in sync with the Relay, yes, you can do it this way. Looking at the schematic, there is no limiting resistor for the LED.. is this OK?

Ah yes i need a CLR, thanks!
I can't think of any reason why i wouldn't want to LED to always be in sync with the relay.

Quote from: niektb on July 22, 2020, 02:47:41 AM
Don't you need to connect pin 12 of the relay to 5V also?

The relay is connected to 5 volts through the transistor. When the ATtiny85 senses a button press it puts a voltage on the base of the transistor to turn it on, which turns the relay on. Another button press cuts the voltage to the base, so the transistor and relay both turn off

niektb

Aaah yes my bad, I've seen low-side relay switching too often  :icon_mrgreen:

ElectricDruid

Quote from: patrick398 on July 22, 2020, 03:18:23 AM
Quote from: niektb on July 22, 2020, 02:47:41 AM
Don't you need to connect pin 12 of the relay to 5V also?

The relay is connected to 5 volts through the transistor. When the ATtiny85 senses a button press it puts a voltage on the base of the transistor to turn it on, which turns the relay on. Another button press cuts the voltage to the base, so the transistor and relay both turn off

Nope, I still don't get it. If that's the case (and it clearly is) then doesn't pin 12 need to be connected to ground? I don't see how that coil operates with only one wire attached to it.

potul

Definitively, there is something wrong in the relay connection. I would review the whole thing.

I would put the relay coil between 5v and the transistor collector. And do the same with the LED and CLR (in parallel with the relay)