Sida 1 av 2

atMega644 PWM problem...

Postat: 13 januari 2008, 11:12:47
av erikbrannlund
Hej!

Jag har en "app" som ska bli väckarklocka men även styra sänglampan plus en del annat.
Nu försöker jag PWM:a en lysdiod men den fladdrar trots att jag i min enfald tycker att den inte borde.

Kod: Markera allt

void initTimer(void)
{
  OCR1A = 250;      // timer compare value 
  TCCR1B = _BV(WGM12) | 2; // Presc -> Clock/ 8 -> 250000 MHz -> int 2000 Hz
  TIMSK1 = _BV(OCIE1A); 
  sei();         /* enable interrupts */ 
	timerCounter = 0;
}


int pwm = 0;
unsigned int pwmcnt;
int pwmdir = 1;

int PWMMAX = 10;


int secs = 0;
ISR(TIMER1_COMPA_vect) 
{ 
	timerCounter++;				// inc timeout tick
	if (++tcount == 2000)		// one second tick 
	{
		tcount = 0;
		sec_flag = 1;
		UTCtime ++;
	}

  if (++pwmcnt == PWMMAX)
    pwmcnt = 0;

  cli();
  if ((pwmcnt % PWMMAX == 0) && (pwm != 0))
    PORTC = 0xF0;
  if (pwmcnt % PWMMAX == pwm)
    PORTC = 00;
    
   if (sec_flag)
        if (secs-- == 0)
        {
          pwm += pwmdir;
          secs = 100;
         }

      if (pwm == PWMMAX-1)
        pwmdir = -1;

      if (pwm == 0)
        pwmdir = 1;

  sei();
}


Jag tycker att Jag med den här koden borde få en blinkhastighet på 200 Hz men är jag kör på de lägre intensiteterna så flimrar lysdioden, med PWMMAX = 4 blir ljuset stabilt men skulle vilja ha lite fler steg.

Har jag ett hjärnsläpp modell större eller vad är fel.

/Erik

Postat: 13 januari 2008, 23:41:20
av cykze
Kommentera koden tack.

Indenteringarna är helt fel.

Interrupts stängs av automatiskt när en ISR-rutin anropas och aktiveras igen när den tar slut. Alltså är dina cli() och sei() överflödiga.

Postat: 14 januari 2008, 16:02:20
av erikbrannlund
Kommentarer var det...

Kod: Markera allt

//Den här funktionen startar timern...    
void initTimer(void)
{
  OCR1A = 250;      // timer compare value Interrupt var 250 "tick"
  TCCR1B = _BV(WGM12) | 2; // Presc -> Clock/ 8 -> 500000/250 MHz -> int 2000 Hz
  TIMSK1 = _BV(OCIE1A); 
  sei();         /* enable interrupts */ 
  timerCounter = 0;
}


//globala  variabler för PWM hanteringen
int pwm = 0;  // Vilken "pwm-nivå som används
unsigned int pwmcnt; ////pwmräknare, borde kanske byta till char jag kan i allafall inte köra med så stor PWM
int pwmdir = 1;  // Riktning att räkna upp eller ner pwm värdet

int PWMMAX = 10; //Antal PWM steg, borde ge 200Hz


int secs = 0; //Ingen direkt koppling till PWM delen
ISR(TIMER1_COMPA_vect) 
{ 
  timerCounter++;				// inc timeout tick  minns inte exakt vad den här var
  if (++tcount == 2000)		// one second tick kollar om  en sekund upplupit
  {
    tcount = 0;
    sec_flag = 1;
    UTCtime ++;
  }

  // Här kommer PWM delen
  if (++pwmcnt == PWMMAX)
    pwmcnt = 0;

  if ((pwmcnt % PWMMAX == 0) && (pwm != 0))
    PORTC = 0xF0;
  if (pwmcnt % PWMMAX == pwm)
    PORTC = 00;
    
   // Koden som följer räknar upp och ned  PWM värdet
  if (sec_flag)
    if (secs-- == 0)
    {
       pwm += pwmdir;
       secs = 100;
     }

  if (pwm == PWMMAX-1)
     pwmdir = -1;

  if (pwm == 0)
    pwmdir = 1;

}


Dessutom har jag försökt titta på utkurvan i ett "oscilloskåp" och kunde inte se annat än en kurva på ~200Hz. Tyvärr är skåpet inte riktigt hundra verkar vara ngt glapp eller annat mystiskt. Så hur kan en PWM signal på 200Hz ge ett synligt flimmer?

/Erik[/code]

Postat: 15 januari 2008, 01:50:38
av cykze
Okej. Jag tycker din kod verkar stämma. En lysdiod på 200 Hz borde inte flimra. :?

Men jag undrar varför du kör med modulus i din kod. Den första if-satsen ser ju till att pwmcnt bara går mellan 0 och PWMMAX-1. Du borde därför kunna jämföra "pwmcnt" istället för "pwmcnt % PWMMAX".

Det borde vara okej att använda "elseif" också...

Kod: Markera allt

// Här kommer PWM delen
  if (++pwmcnt == PWMMAX)
    pwmcnt = 0;

  if ((pwmcnt == 0) && (pwm != 0))
    PORTC = 0xF0;
  else if (pwmcnt == pwm)
    PORTC = 00;
edit: Går det till och med att skriva om sista if-else-if:en till:

Kod: Markera allt

  if (pwmcnt == pwm)
    PORTC = 0x00;
  else if (pwmcnt == 0)
    PORTC = 0xF0;
?

Postat: 15 januari 2008, 12:04:23
av erikbrannlund
Modulus beror på att jag inte nollade pwmcnt tidigare. Eftersom det flimrar för mig så har jag ändrat koden åtskilliga gånger.
Men flimret inte bara att koden verkar stämma "skåpet" säger 200 Hz dessutom men likafullt flimrar det. Ju kortare puls desto mer flimmer.
Kopplingen är som följer.

Ut på porten till basen på en BC337:a.
Emittern till jord.
Spänningen från STK-500 till Powerled.
Powerled till resistor.
Resistor till kollektor.

/Erik

Postat: 15 januari 2008, 12:40:53
av cykze
Har du inget motstånd mellan porten och basen?

Postat: 15 januari 2008, 18:22:05
av erikbrannlund
Nej kolla det har jag inte! Förslag på lämpligt motstånd? Men kan flimret verkligen bero på den saken.

/Erik

Postat: 15 januari 2008, 22:15:07
av cykze
Hur mycket ström låter du LED:en dra?

Har du provat om det blir flimmer med en vanlig lysdiod?

Sen blir väl förresten frekvensen 100 Hz, och inte 200 Hz, eftersom en tänd-släck-cykel är en period.

Kan du inte låta en separat timer sköta PWM:en istället? Då ställer du in pulskvoten genom att helt enkelt ändra motsvarande OCR-register. Då får du ju fler "intensitetsnivåer" också.

Postat: 16 januari 2008, 11:47:37
av erikbrannlund
LED drar 200-300 mA enligt min "Classe-multimeter".

Lös lysdiod flimrade sist jag provade. Lysdiod på STK-plattan flimrade inte.

Ja, jo 100 Hz blir det men även det borde vara "oflimrigt".

Tyvärr är den timern upptagen!

/Erik

Postat: 16 januari 2008, 12:02:24
av sodjan
> Ut på porten till basen på en BC337:a.

Utan motstånd = i princip kortslutning !
Vad tycker din processor om det ?
Är du säker på att processorn/koden inte startar om hela tiden ?

Postat: 16 januari 2008, 22:31:52
av erikbrannlund
Jag har satt ett motstånd i serie mellan porten och 337:an efter första påpekandet kanske lite liten ~150 ohm.
Nej processorn snurrade snällt på kanske beronde på att den går på 3.3 V.

/Erik

Postat: 17 januari 2008, 20:14:14
av cykze
erikbrannlund:
> Lös lysdiod flimrade sist jag provade. Lysdiod på STK-plattan flimrade inte.

Om vissa lysdioder flimrar medan andra inte gör det så är det nog inte AVR:en eller ditt program det är fel på i alla fall. Vad som kan vara fel vet jag däremot inte. :(

Postat: 18 januari 2008, 11:24:19
av erikbrannlund
Nu har jag bytt till ett större motstånd mellan port och bas på trissan, 10k blev det. Jag undrar hur jag tänkte när jag inte hade ngt motstånd, inte alls mest troligt. Eventuellt blev flimret mindre men jag har inte haft tid att testa så mycket. Vad som däremot hände är att ADC:n inte stördes lika kraftigt av påslaget ljus, tidigare indikerade den 3-4 grader högre temperatur både inne och ute när lyset var på.

Postat: 22 februari 2008, 08:41:32
av erikbrannlund
Bumpar denna: Jo flimret blev bättre med motståndet men det försvann inte helt. Däremot om jag slår av ADC:n och inte får några interrupt så blir ljuset helt plötsligt stabilt. Kanske beroende på mina försök att översampla för en högre upplösning enligt ngn appnote från ATMEL.

/Erik

Postat: 24 februari 2008, 11:19:43
av cykze
Vilken frekvens har du på ADC-klockan? Alltså vilken prescaler kör du med och vilken frekvens kör själva AVR:en med?