Dag mensen,
Ik ben al langere tijd programmeur en ben daarnaast wel eens wat aan het knutselen met elektronica (alleen heb ik nooit de 2 dingen gecombineerd)
Nu zou ik graag een klein projectje willen doen en een aantal rgb leds aansturen, ik heb hiervoor de ATMega168 gekozen.

Ik heb AVR Studio geinstalleerd, een programmer gemaakt en dergelijke. en ik ben al wat code aan het schrijven in C. Maar nu is het probleem: ik lijk geen duidelijke informatie te kunnen vinden over hoe ik nu eigenlijk 6 verschillende pwm signalen 0%-%100 op 6 pinnen kan krijgen.

Dus mijn vraag; hoe zou ik dit kunnen doen?

Alvast heel erg bedankt.

Met timers. Staat zeer duidelijk aangegeven in de datasheets. Zoek ook eens op "timer tutorials". :)

@Roland van Leusden:
hoe heb ik die pagina over het hoofd kunnen zien! :o , ziet er duidelijk uit, bedankt!.

@LED-Maniak:
had ik al op gezocht maar dit waren veel te algemene artikelen.

Je vult wat registers in, en het werkt...


void PWM0_init(void)
{								// Initialiseer Timer0 voor fast PWM
    TCNT0 = 0;
    TCCR0A = _BV(WGM00) | _BV(WGM01) | _BV(COM0A1) | _BV(COM0B1);
    TCCR0B = _BV(CS02);						// Prescaler = 256
    OCR0A = 32;							// PWM = 1/8
    OCR0B = 32;
    DDRD |= _BV(PD5) | _BV(PD6);				// PWM-uitgangen vrijgeven
}

void PWM1_init(void)
{								// Initialiseer Timer1 voor 8-bit fast PWM
    TCNT1 = 0;
    TCCR1A = _BV(WGM10) | _BV(COM1A1) | _BV(COM1B1);
    TCCR1B = _BV(WGM12) | _BV(CS12);				// Prescaler = 256
    OCR1A = 32;							// PWM = 1/8
    OCR1B = 32;
    DDRB |= _BV(PB1) | _BV(PB2);
}

void PWM2_init(void)
{								// Initialiseer Timer2 voor fast PWM
    TCNT2 = 0;
    TCCR2A = _BV(WGM20) | _BV(WGM21) | _BV(COM2A1) | _BV(COM2B1);
    TCCR2B = _BV(CS22);						// Prescaler = 256
    OCR2A = 32;							// PWM = 1/8
    OCR2B = 32;
    DDRD |= _BV(PD3);						// PD3 = PWM-uitgang
    DDRB |= _BV(PB3);						// PB3 = PWM-uitgang
}

Door de OCRxy-registers aan te passen stel je de puls/pause-verhouding in.

@pros:
Bedankt voor het voorbeeld ik snap het bijna behalve,
- Dit is voor 3 kanalen , ik wil er graag 6
- Ik wil de snelheid graag koppelen aan de kloksnelheid van de microcontroller (dus dezelfde frequentie) hoe zou ik dat moeten doen?
- Hoe kan ik de duty cycle van 0%-100% (8bit) instellen via een functie?
als je me daar nog mee kan helpen is het me duidelijk :)

@Ronald van Leusden:
De eerste link bleek niet bruikbaar te zijn ivm. allerlei dependencies op andere bestanden.

Je kent de systeemklok. Laten we zeggen 8000000Hz.
Je wil een PWM-frequentie van bv. 200Hz.
Bij 8-bit PWM moet de klok voor het PWM kanaal dus (200 x 256) = 51200Hz bedragen.
Deel de systeemklok door de PWM-klok: 8000000 / 51200 = 156.
Kijk nu in de datasheet naar mogelijke waarden voor de prescaler.

Bij Timer2 kan je bv. 128 als prescaler nemen. Dan is de PWM-frequentie iets hoger dan gewenst.
Bij Timer1 heb je minder keus. Ofwel 64, ofwel 256. Dat wordt dus 64.
Wil je de maximale snelheid, zet dan de prescaler op 1:


    TCCR0B = _BV(CS00);
    TCCR1B = _BV(WGM12) | _BV(CS10);
    TCCR2B = _BV(CS20);

Nu maakt dat voor het aansturen van LED's niet zoveel uit. Zolang je ze niet ziet flikkeren is het OK.
Moet het wèl precies, dan kan je bij sommige timers instellen tot waar ze moeten tellen.
Timer1 geeft bij de ATmegaxx8 de meeste mogelijkheden. Je kan hem --in Phase and Frequecy Correct mode-- laten tellen van 0 tot de waarde van ICR1 (1 ... 65535), en daarbij ook de puls/pause-verhouding instellen met een 16-bits getal.

Hoe kan ik de duty cycle van 0%-100% (8bit) instellen via een functie?


    unsigned char duty_cycle = 12;

    OCR0A = (duty_cycle * 2) + (duty_cycle / 2);     // Vermenigvuldigen met 2.5

Op die manier haal je maximaal 250. Voor de meeste toepassingen is dat OK. Bij een LED zie je echt het verschil niet tussen 250 en 254 (en zelfs niet tussen 240 en 254).

Op 4 december 2010 18:55:49 schreef Mervin:
- Dit is voor 3 kanalen , ik wil er graag 6

Toch niet, elke teller stuurt 2 PWM kanalen aan. De pulsbreedte stel je in door OCRxA en OCRxB in te stellen.