so... habe jetzt ein paar Ports der m32 frei gemacht ;-> Welche sind jetzt genau PWM-Ports (ohne software-pwm?) ? Wie kann man von da aus eine Led dimmen?
mfG
Philip
Druckbare Version
so... habe jetzt ein paar Ports der m32 frei gemacht ;-> Welche sind jetzt genau PWM-Ports (ohne software-pwm?) ? Wie kann man von da aus eine Led dimmen?
mfG
Philip
Beim ATMEGA 8 Dil Variante sind das.
OC1A = PIN 15
OC1B = PIN 16
OC2 = PIN 17
Diese 3 Pins können als PWM arbeiten.
OC1A und OC1B laufen mit dem Timer 1
OC2 mit Timer 2
Bei einem anderen Controller nach OC Pins suchen.
Die Timer werden für den entsprechenden PWM Mode konfiguriert und die OCx Pins aktiviert und ein passender Prescaler gewählt.
Je nach dem Wert den man ins Comparematch Register schreibt kommt dann eine entsprechende Pulsweite raus.
Man kann gerade Timer 1 sehr vielseitig PWM- mässig programmieren. Vom 8Bit PWM bis 16Bit PWM ( 9 und 10Bit gehen auch soweit ich weiss ) ist da einiges möglich. Auch ein Ausgangssignal mit 50% Duty Cycle und änderbarer Frequenz.
Fast PWM solltest Du nicht machen, weil da keine Werte mit 0 ( = kein Signal ) möglich ist.
Initialisierungsstrings müsste ich jetzt zusammensuchen, da ich jetzt nicht ganz genau weiss was Du konkret brauchst hilft Dir das auch wenig.
Alles läuft dann in Hardware und benötigt deshalb keine zusätzliche Rechenleistung mehr, ausser zum Schreiben der Comparematch Register.
Danke schonmal, aber ich meinte die pins vom atmega32. Hast du ein Beispielcode?
Ok die Pins 40 Pin Dil Variante:
OC0 = PIN 4 Timer0
OC1A = PIN 19 Timer1
OC1B = PIN 18 Timer 1
OC2 = PIN 21 Timer 2
Der Code ist für nen ATMEGA 16 mit 8MHz Quarz und sollte auch auf nem 32 laufen.
Code in "C" für CodeVision:
Du musst jetzt nur noch die OCR Register mit Werten füllen und das Ding macht PWM.Code:// Timer 1 overflow interrupt service routine
interrupt [TIM1_OVF] void timer1_ovf_isr(void)
{
OCR1AL=uc_redtable[uc_red]; /* Werte für die PWM's übernehmen */
OCR1BL=uc_greentable[uc_green];
}
// Timer 2 overflow interrupt service routine
interrupt [TIM2_OVF] void timer2_ovf_isr(void)
{
OCR2=uc_bluetable[uc_blue]; /* Werte für die PWM's übernehmen */
}
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 1000,000 kHz
// Mode: Phase Correct PWM top=00FFh
// OC1A output: Non-Inv.
// OC1B output: Non-Inv.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: On
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0xA1;
TCCR1B=0x02;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: 1000,000 kHz
// Mode: Phase Correct PWM top=FFh
// OC2 output: Non-Inverted PWM
ASSR=0x00;
TCCR2=0x62;
TCNT2=0x00;
OCR2=0x00;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x45;
Timer 1 ist, da die Bereiche mit Timer 2 zusammen passen mussten und DMX ohnehin nicht mehr als 256 Werte kennt, auf 8 Bit Modus eingestellt.
Timer 0 hab ich in diesem Beispiel nicht für PWM Erzeugung verwendet.
In den Overflow Interrupts bei Timer 1 und Timer 2 werden die aktuellen Helligkeitswerte in die OCR Register übernommen. Das vermeidet Glitches, Du kannst das aber auch ignorieren wenn Dich die Interrupts stören. Der Code ist Teil meiner DMX RGB Lampe mit High Power LED's.
Timer 0 ist hier nicht für die PWM Generierung verwendet - Ich brauchte nur 3 PWM Quellen.
Das Ganze ist nur ein Beispiel, man kann die PWM Quellen sehr vielseitig konfigurieren. Datenblatt lesen ist aber da Pflicht!
Hallo
Ich würde das weiterhin mit Soft-PWM lösen. Irgendein Timer läuft ja eh meist schon mit, da muss man dann nur noch seine eigene Funktion einklinken:
Für einen 8MHz-Mega8 auf Basis der 36kHz des Timer2 (aus der asuro-Lib). Soll das nun ein Mega8 oder ein Mega32 werden? Oder gar der RP6?Code:#include <avr/io.h>
#include <avr/interrupt.h>
#define led1_init DDRD |= (1<<PD2) // LEDs an PD2 und PD3
#define led1_on PORTD |= (1<<PD2)
#define led1_off PORTD &= ~(1<<PD2)
#define led2_init DDRD |= (1<<PD3)
#define led2_on PORTD |= (1<<PD3)
#define led2_off PORTD &= ~(1<<PD3)
volatile unsigned char p=0;
volatile unsigned char led1_pwm=0, led2_pwm=0;
void pause_ms(unsigned int dauer)
{
while(dauer--)
{
p=36;
while(p); // p wird in der ISR runtergezählt
}
}
int main(void)
{
cli();
// Timer2: FastPWM, no prescaling, no OC2-Pin
TCCR2 = (1 << WGM20) | (1 << WGM21) | (0 << COM20) | (0 << COM21) | (1 << CS20);
OCR2 = 0x91; // duty cycle for 36kHz
TIMSK |= (1 << TOIE2);
led1_init;
led2_init;
sei();
while(1)
{
led1_pwm+=15;
if(led2_pwm) led2_pwm /=2; else led2_pwm=255;
pause_ms(500);
}
return(0);
}
SIGNAL (SIG_OVERFLOW2)
{
static char led_pwm=0;
TCNT2 += 0x25; // Frequenzkorrektur 36kHz
if(led_pwm)
{
if(led_pwm>led1_pwm) led1_off;
if(led_pwm>led2_pwm) led2_off;
}
else
{
if(led1_pwm) led1_on;
if(led2_pwm) led2_on;
}
led_pwm++;
if(p) p--; // 1/36000 Sek.
}
Gruß
mic
Danke schon mal für die antworten, werde es mal testen ;)
Soll ein Mega32 werden.
mfG
Philip
Zitat:
so... habe jetzt ein paar Ports der m32 frei gemacht
Das hört sich für mich jetzt so an als ob er das RP6-M32 Erweiterungsboard meint und keinen einzelnen MEGA32.
Du musst da natürlich die Pinbelegung beachten.
PD5 / OC1A ist auf der M32 als Hardware PWM Port verfügbar die anderen aber alle nicht (OC2 ist mit dem Buzzer verbunden, wenn Du den nicht brauchst... ).
--> Software PWM ist schon die bessere Lösung gibt hier im Forum ja Libs dazu.
Im Prinzip ist das schon richtig, aber das erzeugt auch eine Menge Prozessorlast. Wenns möglich ist würde ich immer Hardware PWM den Vorzug geben.Zitat:
Software PWM ist schon die bessere Lösung gibt hier im Forum ja Libs dazu.
Es sei denn man braucht mehr Ausgänge, oder die Ausgänge müssen frei wählbar sein, oder die Timer sind mit anderen Aufgaben belegt.