Sida 1 av 2

Software PWM problem...

Postat: 4 juni 2006, 01:24:54
av Korken
Hej all!

Jag har gjort en software PWM som inte vill fungera som jag vill...
Det är så att själva PWMen fungerar som den ska men inte styrningen.

Problemet är när jag försöker få ett ljus att lysa fullt sen bli svagare som går i en loop upp å ner så stannar den på första "steget" och ändrar sig inte ett dugg.

Vad kan felet vara?

Koden (OSCCAL_calibration() är inte med för att den är stor och onödig att ha med):

Kod: Markera allt

#include <avr/interrupt.h>
#include <avr/delay.h>
#include <avr/signal.h>
#include <inttypes.h>

void OSCCAL_calibration(void);

typedef volatile unsigned char BYTE;

BYTE dutyCycle = 0;
BYTE tickCount = 0x00;

int main(void)
{
	OSCCAL_calibration();
	DDRD = 0xFF;
	// Increase the oscillator to 2 Mhz for timer:
	CLKPR = (1<<CLKPCE);        // set Clock Prescaler Change Enable
    // set prescaler = 4, Inter RC 8Mhz / 4 = 2Mhz
	CLKPR = (1<<CLKPS1);
	
	// Initialize Timer0.
    // Enable timer0 compare interrupt
	TIMSK0 = (1<<OCIE0A);

	// Sets the compare value
	OCR0A = 1;
	
	// Set Clear on Timer Compare (CTC) mode, CLK/8 prescaler
	TCCR0A = (1<<WGM01)|(0<<WGM00)|(1<<CS01);
	
	while(1)
	{
		for(int i = 1; i <= 255; i++)
		{
			dutyCycle = i;
			_delay_loop_2(10000);
		}	
			
		for(int i = 254; i > 1; i--)
		{
			dutyCycle = i;
			_delay_loop_2(10000);
		}
	}
	
	return 0;
}

SIGNAL(SIG_OUTPUT_COMPARE0)
{
	if (tickCount == 0) {
	   PORTD = 0xFF;
	}

	if (tickCount == dutyCycle) {
	   PORTD = 0x00;
	}
	
	tickCount++;
}
//Emil

Postat: 4 juni 2006, 02:08:09
av bearing
Om _delay_loop_2 tar ms som argument tar det 43 minuter innan den har dimmat upp fullt. (Förutsatt att din klockfrekvens stämmer med delayfunktionen, kan ju ta längre tid också...)

Kanske bara är det som är fel?

Har du mätt signalen med olika duty för att testa att PWM-en funkar?

Postat: 4 juni 2006, 11:48:49
av cykze
Vad är egentligen anledningen till varför du vill sköta PWM:en i mjukvaran? Hårdvaru-PWM är betydligt smidigare och bättre.

Kopplingen mellan looparna och interruptrutinen verkar väldigt osäker. Jag tycker att det vore bättre att sköta PWM:en antingen från en interrupt _eller_ från någon loop. Att försöka kombinera dom är att be om trubbel.

bearing: Argumentet till _delay_loop_2() anger hur många delays på 4/f_osc som ska göras.

Postat: 4 juni 2006, 12:34:46
av Korken
Jag gör detta för att få det att dimma upp å ner, som ett litet test.
Och jag har teta att ha massa olika värden på delay grejen men det har inte hjälpt.

Varför jag har den i mjukvaran? Jo, därför att det sen ska vara till fläktstyrning av 8st fläktar och jag har bara 3st PWM utgångar.
"Kopplingen mellan looparna och interruptrutinen verkar väldigt osäker." <-- Vad menar du?

//Emil

Postat: 4 juni 2006, 13:36:21
av bearing
Global interrupt enable sätts inte i koden vi ser. SEI och CLI heter instruktionerna.

Postat: 4 juni 2006, 13:39:24
av Korken
Vet, den sätts i OSCCAL_calibration().

//Emil

Postat: 4 juni 2006, 13:57:00
av bearing
Är det inte ganska låg frekvens på PWMen?

Frekvensen blir (väl) 2000000 / 8 / 256 / 256 = 3.8 Hz.
Periodtiden motsvarar 524288 instruktioner, vilket borde vara betydligt fler än i delayen i FOR-looparna.

Postat: 4 juni 2006, 16:48:13
av Korken
2000000 / 8 != 3.8

Det ända jag gör är minskar den till 2MHz och delar på 8, sen att det är en byte som måste gå i själva timern men det är fortfarande inte 3.8Hz.
Jag fick det till 976,6Hz. :?

Det du nog har sett fel är att jag kör OCR0A registret på 1 och inte 255. :)

Postat: 4 juni 2006, 17:31:25
av bearing
Jaha, borde sett att du körde interrupt vid compare och inte vid overflow...

Du får alltså ett interrupt var 8:nde instruktionscykel? möjligtvis blir det var 16:ende.

Då är det nog det som är felet. Den hinner förmodligen inte ens köra klart interruptet innan den ska in i det igen.
Den kommer iaf knappt ha någon tid alls över att köra koden i main() om den är så mycket i interruptet.

Kör interruptet mer sällan och nollställ tickCount när den nått en lägre siffra än att den slår runt. Då kanske du kan få samma frekvens men med lite lägre upplösning på pulsbredden. Det gör nog inte något när det gäller fläktar. Det räcker säkert att tockCount bara kör till 20 så får du en upplösning på 5% och betydligt minder tid i interrupten.

Postat: 4 juni 2006, 22:41:07
av Korken
Ok, jag vet inte varför men när jag sänkte uCn till 1MHz så fungerade det plötsligt.
Men, man får tacka för all hjälp som jag har fått! :D

//Emil

Postat: 4 juni 2006, 23:13:25
av bearing
OK? Verkar helskumt.

Du borde ändå följa något av tipsen i mitt förra inlägg om du ska ha 8 st ifsatser i interruptet.

Postat: 5 juni 2006, 09:06:10
av Korken
Jo, jag ska ändra sen så den bara går till 10. För jag ska 10% hopp i styrnignen så det borde räcka.
Men, tack för tipset! :D

//Emil

Postat: 5 juni 2006, 10:17:53
av JimmyAndersson
Korken: Vad programmerar du i? Är det t.ex MikroC ?

Postat: 5 juni 2006, 11:58:30
av Icecap
MikroC är ju till PIC.... och Korken inkluderar en massa AVR-filer....

Postat: 5 juni 2006, 12:42:45
av lgrfbs
Kolla MikroElektronika COMPILERS men just nu finns inte mikroC till AVR men de har en massa trevliga program.