Pages: [1]   Go Down
Author Topic: software PWN on attiny85  (Read 702 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Full Member
***
Karma: 3
Posts: 188
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
/*
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));
}
Logged

for(i = 0, i < 820480075, i++){ Design(); Code(); delay(1000); } // hellowoo.com

Valencia, Spain
Offline Offline
Faraday Member
**
Karma: 146
Posts: 5520
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The code implies it should go all the way down.

Not at all...

This sequence:

Code:
    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:
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));
  }
}
Logged

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

Offline Offline
Full Member
***
Karma: 3
Posts: 188
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

The code implies it should go all the way down.

Not at all...

This sequence:

Code:
    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:
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.
Logged

for(i = 0, i < 820480075, i++){ Design(); Code(); delay(1000); } // hellowoo.com

Valencia, Spain
Offline Offline
Faraday Member
**
Karma: 146
Posts: 5520
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

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

Denmark
Offline Offline
Edison Member
*
Karma: 35
Posts: 1073
Happy Hobbyist
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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));
}
« Last Edit: October 02, 2013, 02:45:38 pm by Erni » Logged

United Kingdom
Offline Offline
Tesla Member
***
Karma: 224
Posts: 6619
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.]
« Last Edit: October 02, 2013, 05:19:43 pm by dc42 » Logged

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.

Denmark
Offline Offline
Edison Member
*
Karma: 35
Posts: 1073
Happy Hobbyist
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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


Code:
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
Logged

Pages: [1]   Go Up
Jump to: