News:

SMF for DIYStompboxes.com!

Main Menu

ATtiny85 code issues

Started by patrick398, September 09, 2020, 06:24:12 AM

Previous topic - Next topic

patrick398

Hello all, hoping someone can give me a few pointers here. I'm programming an Attiny85 using arduino but it's not working as expected and i can't figure out why.

What should happen is this:
I want ATtiny85 pin 0 (TRIGGER_IN) to read the voltage coming from a flip flop elsewhere in the circuit. If it's HIGH it sends pin 1 (TRIGGER_OUT) HIGH after a delay period defined by analogRead (pin 2),  and is HIGH for a duration defined by PULSE (50ms).
Simply put, if pin 0 is HIGH, pin 1 flashes high for 50 ms after a delay between 0-1543 ms set by a pot.
If pin 0 is LOW pin 1 is also LOW.

Pin2 is reading a potentiometer, the voltage dictates the delay period from TRIGGER_IN detecting a HIGH voltage and TRIGGER_OUT outputing a HIGH voltage. I need a delay period of between 0-1500 ms so i figured since the analogRead is between 0 and 1023 i could just multiply that by 1.5 to get my desired range.

Seems relatively straight forward but i can seem to get it to work. Are there some glaring errors in my code?

int TRIGGER_IN = 0; // arduino pin (5) connected to flip flop output
int TRIGGER_OUT = 1; // arduino pin (6) connected to bass drum trigger
int PULSE = 50; // Set trigger out pulse length as 50 ms
int POT_PIN = 2; // arduino pin (7) connected to pot wiper
int readValue; // variable to read pot




void setup() {
  // put your setup code here, to run once:
  pinMode (TRIGGER_IN, INPUT); // define TRIGGER_IN as an input (could try using just input_pullup)
  pinMode (TRIGGER_OUT, OUTPUT); // define TRIGGER_OUT as an output
  pinMode (POT_PIN, INPUT); // define POT_PIN as an input

}

void loop() {
  // put your main code here, to run repeatedly:

  readValue = analogRead (POT_PIN) * 1.5; // read pots value between 0 and 1023 and times it by 1.5

  if (TRIGGER_IN = HIGH) { // detect state of TRIGGER_IN
    delay (readValue); // delay for period set by POT_PIN
    digitalWrite (TRIGGER_OUT, HIGH); // if it's high write TRIGGER_OUT high
    delay (PULSE);
  }


  else (TRIGGER_IN = LOW); { // detect state of TRIGGER_IN
    digitalWrite (TRIGGER_OUT, LOW); // if it's low write TRIGGER_OUT low
  }
}


Thank you!

niektb

#1
The line
else (TRIGGER_IN = LOW); { // detect state of TRIGGER_IN
feels wrong to me. I think the ';' might terminate the line and so the body between the brackets never (or always, i'm not sure) executes.

I think you want to change it to just
else

Also, what do you want to happen in case the TRIGGER_IN stays high for longer than the delay+PULSE? (because with your current code, the delayed TRIGGER_OUT is executed again)

EDIT:
Also, what definitely is wrong is the way you do your checks in the IF-statement! Use '==' instead of '='! (because now you assign the value to TRIGGER_IN, meaning it will always execute)

EDIT 2:
And shouldn't you use digitalRead() when checking the state of TRIGGER_IN?


int TRIGGER_IN = 0; // arduino pin (5) connected to flip flop output
int TRIGGER_OUT = 1; // arduino pin (6) connected to bass drum trigger
int PULSE = 50; // Set trigger out pulse length as 50 ms
int POT_PIN = 2; // arduino pin (7) connected to pot wiper
int readValue; // variable to read pot

void setup() {
  pinMode (TRIGGER_IN, INPUT); // define TRIGGER_IN as an input (could try using just input_pullup)
  pinMode (TRIGGER_OUT, OUTPUT); // define TRIGGER_OUT as an output
  pinMode (POT_PIN, INPUT); // define POT_PIN as an input
}

void loop() {
  readValue = analogRead (POT_PIN) * 1.5; // read pots value between 0 and 1023 and times it by 1.5

  if (digitalRead(TRIGGER_IN) == HIGH)  // detect state of TRIGGER_IN
  {
    delay (readValue); // delay for period set by POT_PIN
    digitalWrite (TRIGGER_OUT, HIGH); // if it's high write TRIGGER_OUT high
    delay (PULSE);
  }
  else
  {
    digitalWrite (TRIGGER_OUT, LOW); // if it's low write TRIGGER_OUT low
  }
}


patrick398

Thanks so much for the help. I've just hooked it up and it's kind of working which is a lot further than i got. The pot doesn't seem to affect the delay. When i send pin0 HIGH pin1 goes HIGH for 50ms after a delay period which seems to fluctuate slightly but the pot does not affect this.

Quote from: niektb on September 09, 2020, 06:50:12 AM
Also, what do you want to happen in case the TRIGGER_IN stays high for longer than the delay+PULSE? (because with your current code, the delayed TRIGGER_OUT is executed again)

Good point...if i hold TRIGGER_IN HIGH, TRIGGER OUT stays HIGH after a short delay. Do i need another if statement to negate that?


Quote from: niektb on September 09, 2020, 06:50:12 AM
EDIT:
Also, what definitely is wrong is the way you do your checks in the IF-statement! Use '==' instead of '='! (because now you assign the value to TRIGGER_IN, meaning it will always execute)

Thanks, i'll have to read up on the difference between them

Quote from: niektb on September 09, 2020, 06:50:12 AM
EDIT 2:
And shouldn't you use digitalRead() when checking the state of TRIGGER_IN?

Yes i did actually spot that after i started the topic :)

niektb

#3
Have you tried Serial.println() to see what values you actually get from analogRead()?

Quote from: patrick398 on September 09, 2020, 07:16:22 AM
Good point...if i hold TRIGGER_IN HIGH, TRIGGER OUT stays HIGH after a short delay. Do i need another if statement to negate that?
I think removing the 'else' part (but leaving the digitalWrite(TRIGGER_OUT, LOW);) would already solve the stay high issue:


void loop() {
  readValue = analogRead (POT_PIN) * 1.5; // read pots value between 0 and 1023 and times it by 1.5

  if (digitalRead(TRIGGER_IN) == HIGH)  // detect state of TRIGGER_IN
  {
    delay (readValue); // delay for period set by POT_PIN
    digitalWrite (TRIGGER_OUT, HIGH); // if it's high write TRIGGER_OUT high
    delay (PULSE);
  }

  digitalWrite (TRIGGER_OUT, LOW); // if it's low write TRIGGER_OUT low
}

FiveseveN

Quote from: niektb on September 09, 2020, 07:50:10 AM
Have you tried Serial.println() to see what values you actually get from analogRead()?
I second that.
There's also a map() function that remaps ranges. Useful for pots in case you need a more complex transformation.
Quote from: R.G. on July 31, 2018, 10:34:30 PMDoes the circuit sound better when oriented to magnetic north under a pyramid?

patrick398

You can't serial.print on attiny85 so i tried to set it up using the arduino itself. Now when i try and set up the arduino to program the attiny85 again i get an error message and when i try and burn the bootloader i get:

avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 4 of 10: not in sync: resp=0x00

This happened to me before and it took ages to fix and i never really worked out what happened. Lots of uninstalling and reinstalling programs and libraries if i remember correctly.  :icon_exclaim:

FiveseveN

Wait, why would you need to (re?)burn the bootloader? Are you using a new chip?

Quotei tried to set it up using the arduino itself.
You're saying you tried to upload the same sketch to an Uno, right? Did you remember set the board options? Does the IDE recognize the Uno? What other information does the console offer if you enable verbose output?
You can use software serial on the ATtiny: https://www.hackster.io/porrey/easy-serial-on-the-attiny-2676e6
Quote from: R.G. on July 31, 2018, 10:34:30 PMDoes the circuit sound better when oriented to magnetic north under a pyramid?

patrick398

Quote from: FiveseveN on September 09, 2020, 09:33:51 AM
Wait, why would you need to (re?)burn the bootloader? Are you using a new chip?

Quotei tried to set it up using the arduino itself.
You're saying you tried to upload the same sketch to an Uno, right? Did you remember set the board options? Does the IDE recognize the Uno? What other information does the console offer if you enable verbose output?
You can use software serial on the ATtiny: https://www.hackster.io/porrey/easy-serial-on-the-attiny-2676e6

Yeah i changed all the settings and it uploaded to the arduino. When i switched the settings back to program the attiny85 it kept coming back with the error message.  Seems to be a fairly common problem and there doesn't seem to be a single solution, and nothing i have tried so far has worked. It's very frustrating. Last time it happened it took me days to resolve and i'm not even sure what fixed it.

patrick398

Ok back in business (THANK GOD)
in case anyone suffers similar issues in the future (or when i inevitably need to fix this again, go here: https://www.instructables.com/id/How-to-Program-an-Attiny85-From-an-Arduino-Uno/)

I'm going to follow your suggestion and sort out the serial print

Thanks again!

patrick398

I gave up trying to get serial monitor working with the attiny, but i have got the code working on the arduino and the circuit hooked up to the arduino works.
I have the serial monitor printing the readValue from the pot and it's working properly. When i send TRIGGER_IN HIGH, TRIGGER_OUT goes HIGH and i can control the delay of this, but the problem is as previously mentioned, it seems to execute a few times if i hold TRIGGER_IN HIGH for more than a split second. It is affected by where the pot is set too. Obviously when the readValue is lower (and the delay is less) it has time to execute the code many times in the time it takes me to connect TRIGGER_IN to 5v and then release.

How would i go about making sure the code only executes once when TRIGGER_IN goes HIGH?

here's what i have:

int TRIGGER_IN = 5; // arduino pin (5) connected to flip flop output
int TRIGGER_OUT = 3; // arduino pin (6) connected to bass drum trigger
int PULSE = 50; // Set trigger out pulse length as 50 ms
int POT_PIN = A0; // arduino pin (7) connected to pot wiper
int readValue; // variable to read pot

void setup() {
  Serial.begin (9600);
  pinMode (TRIGGER_IN, INPUT); // define TRIGGER_IN as an input (could try using just input_pullup)
  pinMode (TRIGGER_OUT, OUTPUT); // define TRIGGER_OUT as an output
  pinMode (POT_PIN, INPUT); // define POT_PIN as an input
}

void loop() {
  readValue = analogRead (POT_PIN) * 1.5; // read pots value between 0 and 1023 and times it by 1.5
Serial.println(readValue);
  if (digitalRead(TRIGGER_IN) == HIGH)  // detect state of TRIGGER_IN
  {
    delay (readValue); // delay for period set by POT_PIN
    digitalWrite (TRIGGER_OUT, HIGH); // if it's high write TRIGGER_OUT high
    delay (PULSE);
  }

  digitalWrite (TRIGGER_OUT, LOW); // if it's low write TRIGGER_OUT low
}

patrick398

Weirdly when i try that same code (with pin number changes) on the ATtiny85 the pot stops working...i've tried using a few different pins for the pot, thinking i need a specific one to function as an analog in but nothing seems to work. Strange!

patrick398

Alright i think i'm pretty much there...if anybody is still listening to my ramblings.
The problem i was having seemed to be in the labelling of the attiny85 pins and how they're referenced in the code. I got rid of defining POT_PIN as an INPUT in the setup. It is defined as pin 4 in the globals but i also had to set up a global variable stating that readValue = analogRead(2). That seemed to be the key. Despite the fact that they're the same pin it's referenced as two different numbers. Maybe that's wrong and i'm misunderstanding something, but it works!

Now back to the issue of stopping it executing more than once when TRIGGER_IN goes HIGH. What's the best way to do that? I could set up another if statement checking the length of time it senses the pin being HIGH....

Thanks again!

anotherjim

Long time since I've used my programmer's brain...
When looking for a state change, it's always worth making it find the opposite case first then and only then acting...
loop1
Is it low?
no then loop1
Yes!
loop2
Is it high?
no then loop2
Yes!
Do the thing
Back to loop1

This way it will never scoot back and repeat while the state is still high.

FiveseveN

Quote from: patrick398 on September 09, 2020, 04:39:52 PM
Now back to the issue of stopping it executing more than once when TRIGGER_IN goes HIGH. What's the best way to do that?
I can't vouch for the best way since my programming is amateurish at best, but I would usually use a flag to remember the state. Which I hear is bad because global variables bad (even 1 bit?!). Something like so:

bool triggered = false;
...

if (digitalRead(TRIGGER_IN) == HIGH && !triggered)  // TRIGGER_IN is HIGH and 'triggered' is not true
  {
    triggered = true; // set the flag
delay (readValue); // delay for period set by POT_PIN
    digitalWrite (TRIGGER_OUT, HIGH); // if it's high write TRIGGER_OUT high
    delay (PULSE);
  } else if (digitalRead(TRIGGER_IN) == LOW) // if TRIGGER_IN is LOW
  {
triggered = false; // reset the flag
  }

digitalWrite (TRIGGER_OUT, LOW); // write TRIGGER_OUT low
Quote from: R.G. on July 31, 2018, 10:34:30 PMDoes the circuit sound better when oriented to magnetic north under a pyramid?

ElectricDruid

Quote from: patrick398 on September 09, 2020, 04:39:52 PM
Now back to the issue of stopping it executing more than once when TRIGGER_IN goes HIGH. What's the best way to do that?

I suspect that you don't want to detect when TRIGGER_IN is high (which it looks like is what you've written), but instead when *it goes high*. The first is something that occurs and then continues to occur, the second is something that occurs once only (or at least only once until the TRIGGER_IN goes low again).

I don't know enough about Arduino code to tell you how to make that differentiation, but I'm sure there's a way. It's common enough problem that many people must have solved it already. Try a few searches for detecting "Input goes high" or "Input rising edge" or similar on Arduino sites and see what you come up with.


potul

Quote from: ElectricDruid on September 09, 2020, 07:48:36 PM
Quote from: patrick398 on September 09, 2020, 04:39:52 PM
Now back to the issue of stopping it executing more than once when TRIGGER_IN goes HIGH. What's the best way to do that?

I suspect that you don't want to detect when TRIGGER_IN is high (which it looks like is what you've written), but instead when *it goes high*. The first is something that occurs and then continues to occur, the second is something that occurs once only (or at least only once until the TRIGGER_IN goes low again).

I don't know enough about Arduino code to tell you how to make that differentiation, but I'm sure there's a way. It's common enough problem that many people must have solved it already. Try a few searches for detecting "Input goes high" or "Input rising edge" or similar on Arduino sites and see what you come up with.

You can also use existing libraries for button debouncing. They usually have events triggered on button push, button release, button hold, etc...

patrick398

#16
Thanks for all the replies, i went and did some reading on state detection etc.. definitely what i'm after.
I've got that part working well now, but it seems something about that is stopping the analogRead reading the pot value. The led flashes for 50ms when the pin goes HIGH but doesn't remain on which is good, but the delay isn't being applied. I can't see why this would be the case

//don't forget 10k pulldown on TRIGGER_IN



int TRIGGER_IN = 0; // arduino pin (5) connected to flip flop output
int TRIGGER_OUT = 1; // arduino pin (6) connected to bass drum trigger
int PULSE = 50; // Set trigger out pulse length as 50 ms
int POT_PIN = 4; // arduino pin (3) connected to pot wiper
int readValue = analogRead(2); // variable to read pot, analog read defined as analog pin 2 even though pot pin is previously defined as pin 4
int triggerState = 0;
int lastTriggerState = 0;

void setup() {
  pinMode (TRIGGER_IN, INPUT); // define TRIGGER_IN as an input (could try using just input_pullup)
  pinMode (TRIGGER_OUT, OUTPUT); // define TRIGGER_OUT as an output
 
}

void loop() {
   readValue = analogRead(POT_PIN); // read pots value between 0 and 1023
   triggerState = digitalRead(TRIGGER_IN); // read the trigger in pin


  if (triggerState != lastTriggerState) { // is trigger state not equal to last trigger state
  if (triggerState == HIGH) { // if trigger state has changed...
 
    delay (readValue); // delay for period set by POT_PIN
    digitalWrite (TRIGGER_OUT, HIGH); // if it's high write TRIGGER_OUT high
    delay (PULSE);
  }

lastTriggerState = triggerState;

  digitalWrite (TRIGGER_OUT, LOW); // if it's low write TRIGGER_OUT low
}

}


I tried this but it also stopped the pot working and didn't stop the trigger_out remaining high when trigger_in is held high. Thanks for the help!

Quote from: FiveseveN on September 09, 2020, 05:11:13 PM
Quote from: patrick398 on September 09, 2020, 04:39:52 PM
Now back to the issue of stopping it executing more than once when TRIGGER_IN goes HIGH. What's the best way to do that?
I can't vouch for the best way since my programming is amateurish at best, but I would usually use a flag to remember the state. Which I hear is bad because global variables bad (even 1 bit?!). Something like so:

bool triggered = false;
...

if (digitalRead(TRIGGER_IN) == HIGH && !triggered)  // TRIGGER_IN is HIGH and 'triggered' is not true
  {
    triggered = true; // set the flag
delay (readValue); // delay for period set by POT_PIN
    digitalWrite (TRIGGER_OUT, HIGH); // if it's high write TRIGGER_OUT high
    delay (PULSE);
  } else if (digitalRead(TRIGGER_IN) == LOW) // if TRIGGER_IN is LOW
  {
triggered = false; // reset the flag
  }

digitalWrite (TRIGGER_OUT, LOW); // write TRIGGER_OUT low



patrick398

After some more tweaking i got the pot working again but the timings seemed to be way off. I was using programming with the internal 8mhz clock as suggested whenever i've read about programming attiny85 with arduino. I just used the 1mhz internal clock and now the timings seem spot on.
Is it ok to use the 1mhz clock?

patrick398

Is it possible to also use the ATtiny to read the frequency of incoming pulses (from a separate tap tempo circuit) and output the same tempo but on the off beat? I stupidly thought this might be quite straight forward but the more i read the harder it seems  :icon_redface:

niektb

Quote from: patrick398 on September 11, 2020, 10:07:30 AM
Is it possible to also use the ATtiny to read the frequency of incoming pulses (from a separate tap tempo circuit) and output the same tempo but on the off beat? I stupidly thought this might be quite straight forward but the more i read the harder it seems  :icon_redface:

The attiny (and all avr microcontrollers for that matter) are not very equipped to perform multiple tasks in parallel, especially not for starting programmers. If you want to do so, you need to read up on interrupts and how you can use them. Unfortunately, many things can go wrong with interrupts :/

It can definitely work. I think the flow chart would look something like this:


the loop() function idles indefinitely until a rising edge is detected on either TAP_TEMPO or TRIGGER_IN. the interrupt function will do something with an asynchronous timer to create a delay without interfering with the other interrupt, and returns to idle. When the timer reaches the delay time, it will trigger an interrupt and fires the Timer function (which performs the action that is required, like setting TRIGGER_OUT)