Go Down

Topic: software PWN on attiny85 (Read 829 times) previous topic - next topic

hilukasz

I have a pin (PB2) that doesn't have PWM on it and used the following code to get it to do software PWN. It works, however it doesn't seem to fade all the way day to 0 brightness, any idea why this would be happening? The code implies it should go all the way down.

Code: [Select]
/*
Modified version of Ernst Christensen's code
*/

int redLED= 2;


void setup(){
  //for (int z=0;z<1;z++){
    pinMode(redLED,OUTPUT);
  //} //for z
}


void loop(){
  for (int x=0;x<255;x++){
    spwm(x,redLED,15);
  }
  for (int x=254;x>0;x--){
    spwm(x,redLED,15);
  }
}


void spwm(int freq,int spin,int sp){
  //on
  digitalWrite(spin,HIGH);
  delayMicroseconds(sp*freq);
 
  // off
  digitalWrite(spin,LOW);
  delayMicroseconds(sp*(255-freq));
}
for(i = 0, i < 820480075, i++){ Design(); Code(); delay(1000); } // hellowoo.com

fungus


The code implies it should go all the way down.


Not at all...

This sequence:

Code: [Select]

    digitalWrite(spin,HIGH);
    delayMicroseconds(sp*freq);
    digitalWrite(spin,LOW);

Doesn't take 0 clock cycles to execute. The LED will be on for the time it takes to do multiply sp*freq, call/return from delayMicroseconds, do the digitalWrite(LOW), etc.

You might also get a CPU interrupt in the middle of it, slowing it down even more and causing bright flashes.

Try this:
Code: [Select]

void spwm(int freq,int spin,int sp){
  if (sp!=0) {
    //on
    digitalWrite(spin,HIGH);
    delayMicroseconds(sp*freq);
 
    // off
    digitalWrite(spin,LOW);
    delayMicroseconds(sp*(255-freq));
  }
}

No, I don't answer questions sent in private messages (but I do accept thank-you notes...)

hilukasz



The code implies it should go all the way down.


Not at all...

This sequence:

Code: [Select]

    digitalWrite(spin,HIGH);
    delayMicroseconds(sp*freq);
    digitalWrite(spin,LOW);

Doesn't take 0 clock cycles to execute. The LED will be on for the time it takes to do multiply sp*freq, call/return from delayMicroseconds, do the digitalWrite(LOW), etc.

You might also get a CPU interrupt in the middle of it, slowing it down even more and causing bright flashes.

Try this:
Code: [Select]

void spwm(int freq,int spin,int sp){
  if (sp!=0) {
    //on
    digitalWrite(spin,HIGH);
    delayMicroseconds(sp*freq);
 
    // off
    digitalWrite(spin,LOW);
    delayMicroseconds(sp*(255-freq));
  }
}




this acts the same way. I am running 8mhz if that matters? there is a small flash at the end of the fade down.
for(i = 0, i < 820480075, i++){ Design(); Code(); delay(1000); } // hellowoo.com

fungus


I am running 8mhz if that matters?


Nope.


there is a small flash at the end of the fade down.


Anything else you're not telling us...?

Maybe a video would help.
No, I don't answer questions sent in private messages (but I do accept thank-you notes...)

Erni

#4
Oct 02, 2013, 09:31 pm Last Edit: Oct 02, 2013, 09:45 pm by Erni Reason: 1
If you want a longer period where the LED is Off you can  use the sketch below.

To avoid flicker don't use the values 0 and 255 in your for loops.

It runs smoother if you use 8MHx than 1MHz

Code: [Select]
int redLED= 3;


void setup(){
 pinMode(redLED,OUTPUT);
}

void loop(){
 for (int x=1;x<254;x++){
   spwm(x,redLED,15);
 }
 for (int x=254;x>0;x--){
   spwm(x,redLED,15);
 }
}


void spwm(int freq,int spin,int sp){
 //on
 if  (freq>16){
   digitalWrite(spin,HIGH); //on
 }

 delayMicroseconds(sp*freq);

 // off
 digitalWrite(spin,LOW);
 delayMicroseconds(sp*(255-freq));
}

dc42

#5
Oct 03, 2013, 12:13 am Last Edit: Oct 03, 2013, 12:19 am by dc42 Reason: 1
There is a long-standing bug in delayMicroseconds(), which was reported years ago but the core maintainers have chosen to ignore. If you pass zero to it, you get a very long delay instead of a very short delay. So your code will not work as expected when sp (or freq) is zero. Use "if (sp != 0) { delayMicroseconds(sp*freq); }" instead.

As fungus already explained, the various calls will take a non-zero amount of time to execute, which will also contribute to the problem.

[EDIT: The above assumes that the attiny85 core you are using has the same bug as the standard Arduino core.]
Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

Erni

Another option would be to skip the delayMicroseconds(), and use the principle from BlinkWithoutDelay sketch.


Code: [Select]
int p=1;
unsigned  int fadeTime =900;
unsigned long int now =micros();
unsigned  int pwmTime=0;

void setup()
{
  pinMode (3, OUTPUT);
}

void loop()
{
  if((micros()-now)<pwmTime)
  {
    PORTB |=(1<<PB3);
  }
  else{
    PORTB &= ~(1<<PB3);
  }

  if((micros()-now)>fadeTime){
    now=micros();
    if(pwmTime==fadeTime){
      p=-1;
    }
    if(pwmTime==0){
      p=1;
    }
    pwmTime=pwmTime+(1*p);
  }


}// loop

Go Up