Software PWM problem...

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
cykze
EF Sponsor
Inlägg: 1539
Blev medlem: 8 april 2004, 10:40:28
Ort: Uppsala

Inlägg av cykze »

(0<<WGM00) är det samma som 0. En miss?

Vilken AVR använder du?

Man brukar aktivera interrupts globalt, sei(), efter att alla interruptinställningar gjorts. Vanligtvis placeras den precis innan huvudloopen startar.

> "Kopplingen mellan looparna och interruptrutinen verkar väldigt osäker." <-- Vad menar du?

Jag tänkte främst på din jämförelse med variabeln 'dutyCycle'. Visserligen har du så långa delays i looparna i main(), så det inte borde ställa till med några problem. Men lösningen känns ändå inte 100% säker.

Om du kör med samma frekvens på alla 8 kanaler så borde du kunna få in det i en vanlig timer-interrupt.

Kan man inte göra något sånt här?

Kod: Markera allt

volatile uint8_t pwm[8];

timerinterrupten()
{
    static uint8_t counter = 0;
    uint8_t i;

    if (counter == 0)
        PORTB = 0x00;

    for (i=0; i<sizeof(pwm); i++)
        if (counter > pwm[i])
            PORTB |= _BV(i);

    counter++;
}
Varje element i pwm laddas med varsin dutycycle (0-255), och hela PORTB används för PWM.

edit: Lite kodfix och stavfel
edit2: kodfix igen
Senast redigerad av cykze 6 juni 2006, 14:12:52, redigerad totalt 2 gånger.
Användarvisningsbild
JimmyAndersson
Inlägg: 26603
Blev medlem: 6 augusti 2005, 21:23:33
Ort: Oskarshamn (En bit utanför)
Kontakt:

Inlägg av JimmyAndersson »

"MikroC är ju till PIC.... och Korken inkluderar en massa AVR-filer.... "
Icecap: Oj, jag såg inte AVR-prylarna. :oops:
Användarvisningsbild
Korken
Inlägg: 2230
Blev medlem: 3 februari 2006, 19:19:36
Ort: Luleå, Porsön

Inlägg av Korken »

JimmyAndersson skrev:Korken: Vad programmerar du i? Är det t.ex MikroC ?
I Programmers Notepad.

//Emil
Användarvisningsbild
Korken
Inlägg: 2230
Blev medlem: 3 februari 2006, 19:19:36
Ort: Luleå, Porsön

Inlägg av Korken »

cykze:
Jo, de var en smart lösning. Men, vad är _BV(i) i din kod?
Gärna lite info för den ser väldigt användbar ut. :)

//Emil
Användarvisningsbild
cykze
EF Sponsor
Inlägg: 1539
Blev medlem: 8 april 2004, 10:40:28
Ort: Uppsala

Inlägg av cykze »

_BV(i) är samma sak som (1<<i), och är definierat i någon av headerfilerna. Det är en smaksak vilket skrivsätt man använder.

Koppla koden så att den körs från en timer. Hur ofta timern körs avgör frekvensen på signalen.

Det första den gör är att nollställa alla pinnar på PortB. Sen är det en räknare som räknar upp med ett för varje interrupt. Efter 256 interrupt slår räknare om till 0 och PortB nollställs igen. Genom att sätta olika värden i arrayen pwm får man motsvarande pinne på PortB att gå hög någonstans mellan 0 - 255. pwm[0] = 127 gör t ex att man borde få en dutycycle på 50% på pinnen PB0.

Jag har inte testat koden själv, men jag tycker det borde fungera acceptabelt.
Användarvisningsbild
Korken
Inlägg: 2230
Blev medlem: 3 februari 2006, 19:19:36
Ort: Luleå, Porsön

Inlägg av Korken »

Ok, ja måste säga att de va en smart lösning!

//Emil
Diger_s
Inlägg: 56
Blev medlem: 5 juli 2006, 22:47:06
Ort: Norrköping
Kontakt:

Inlägg av Diger_s »

Hej.
Detta är mitt första inlägg och passande nog har det med software PWM att göra.
Jag håller på med en vidareutveckling av Fagge RGB-fönsterbelysning. Det blir inte lika snyggt då jag inte vill lära mig löda ytmonterat men jag hade tänkt att utveckla konceptet så man kan styra lampan från datorn och (i framtiden) köra synkroniserade mönster mellan olika lampor.

Men jag får inte min software PWM att fungera och jag har suttit många timmar och felsökt. Koden väldigt förenklad är som följer:

Kod: Markera allt

#define __AVR_ATtiny45__
#include <avr/io.h>
#include <avr/interrupt.h>
 
//#include "main.h"

volatile uint8_t next;	

//main pwm
ISR(TIM1_OVF_vect){
	static uint8_t softcount = 255;
	static uint8_t current;
	if(++softcount == 0){
		current = next;
		PORTB = 0x00;
	}
	if(softcount == current) PORTB=0x08;
}

ISR(TIM0_OVF_vect){
	static uint8_t count = 0;
	//PORTB ^= 0x08;
	if(++count == 1){
		++next;
		//PORTB ^= 0x08;
	} 
}

int main(){
	sei();
	TCCR1 = 0x00; //prescaler timer1
	TCCR0B = 0x05; //prescaler timer0
	TIMSK |= 0x06; //interrupt
	
	next = 0;
	PORTB = 0x00;
	for(;;){}
	return 0;
}
Jag vet inte vad som är fel, jag har fyllt for-loopen med nop;ar och bytt plats på sei(); men utan resultat. Det jag har kommit fram till hittils är att det har något att göra med interrupten. Det verkar som om avren resettar sig på något vis. LEDen på PORTB blinkar frenetiskt (flashar) när jag avkommenterar PORTB ^= 0x08;, oavsätt vart jag avkommenterar den. Sätter jag TCCR1 = 0x01 slutar det att fungera.

Är det någon som vet varför den beter sig som den gör?
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> Det verkar som om avren resettar sig på något vis.

I PIC-världen brukar det tyda på att man har watchdog enablat...
Diger_s
Inlägg: 56
Blev medlem: 5 juli 2006, 22:47:06
Ort: Norrköping
Kontakt:

Inlägg av Diger_s »

Det har redan slagit mig och jag har provat att lägga in wdt_reset() lite här och var utan resuiltat.
Diger_s
Inlägg: 56
Blev medlem: 5 juli 2006, 22:47:06
Ort: Norrköping
Kontakt:

Inlägg av Diger_s »

Det är löst. Det var så enkelt att den avr-gcc version inte förstod vad attiny45 var för någon krets och sådeles förmodligen komplierade fel. En nergradering och många timmar senare fungerar faktiskt den kod jag skrivit.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> Det har redan slagit mig och jag har provat att lägga in wdt_reset() lite här och var utan resuiltat.

Är det inte mycket enklare att bara *stänga av* WDT ?

> Det var så enkelt att den avr-gcc version inte förstod vad attiny45 var för någon krets

Dåligt att den då inte kunde säga det !
Diger_s
Inlägg: 56
Blev medlem: 5 juli 2006, 22:47:06
Ort: Norrköping
Kontakt:

Inlägg av Diger_s »

Jag hade förståss fulhackat Makefile lite ;-)
Läste att ATTiny45 är av varianten avr2 för avr-gcc och satte sådeles MCU_TARGET till avr2 och satte __AVR_ATtiny45__ det första jag gjorde i main.c. Det intressanta var att cggvesionen var 4.1.1 och den version jag nedgraderade till var 3.4.5. Där förstod den vad ATTiny45 var.

Men nu fungerar det som det ska. När jag börjar bli färdig ska jag försöka posta lite bilder på projektet.
Skriv svar