-
Ich benutze myAVR Workpad und als Progammer mySmartUSB.
Board ist selbsthergestellt. Codeoptimierung hat Workpad nicht
Workpad motz beim von mir geposteten Code nicht.
Ich habe ihn dennoch so abgeändert wie du es vorgeschlagen hat.
Mit meinem Code(Auch mit dem der deine änderungen enthält) bekomme ich momentan ein ausgangssignal von 2ms High und ca 26.5ms Low.
Eigentlich sollte es 1.5ms high und 18.5ms Low sein.
-
@Besserwessi
Es war zu Beginn etwas verwirrend, denn Timer hätte auch eine variable sein können. BTW, mit Semikolon ist es keine Präprozessoranweisung... Aber natürlich hast Du Recht, denn jetzt ist es klarer.
@hosti
Kommentier mal alles unnötige aus der ISR. Die wird alle 163 Takte aufgerufen! Möglicherweise gehen hier ein paar IRQs verloren... Dass der Compiler keine Warnungen meldet, wundert mich.
Besser noch: wähle wie oben beschrieben einen Prescaler von 8 und ändere die TCNT0 Werte.
Gruß
-
Mein Code sieht nun wie folgt aus, aber das funktioniert gar nicht mehr...
Ich kriegs irgendwie echt nicht hin
Code:
#include <avr/io.h> // I/O Port definitions
#include <avr/interrupt.h> // Interrupt macros
#define F_CPU 16000000
#define timer 96 //0.01ms
//
volatile int ms1 = 0;
volatile int ms2 = 0;
volatile int ms3 = 0;
void timer_init(void)
{
TCCR0 |= (1<<CS01); //Prescaler 8
TCNT0 = timer;
TIMSK |= (1<<TOIE0); //Interupts aktivieren
TIFR |= (1<<TOV0);
};
ISR(TIMER0_OVF_vect)
{
TCNT0 = timer;
//Endausschlag LINKS
if(ms1>=150)
PORTB &= ~(1<<PORTB1);
else
PORTB |= (1<<PORTB1);
if(ms1<=2000)
ms1++;
else
ms1 = 0;
TCNT0 = timer;
if(ms2>=150)
PORTB &= ~(1<<PORTB2);
else
PORTB |= (1<<PORTB2);
if(ms2<=2000)
ms2++;
else
ms2 = 0;
if(ms3>=150)
PORTB &= ~(1<<PORTB3);
else
PORTB |= (1<<PORTB3);
if(ms3<=2000)
ms3++;
else
ms3 = 0;
};
int main(void)
{
sei();
timer_init();
DDRB |= (1<<PORTB1) | (1<<PORTB2) | (1<<PORTB3); //B... AUSGANG
PORTB &= ~((1<<PORTB1) | (1<<PORTB2) | (1<<PORTB3)); //B.. Low
//GLOBALE INTERUPTS AKTIVIERT
while(1)
{
}
}
-
Probier das:
Code:
#include <avr/io.h> // I/O Port definitions
#include <avr/interrupt.h> // Interrupt macros
#define F_CPU 16000000
#define timer 235 //0.01ms
volatile int ms1 = 0;
volatile int ms2 = 0;
volatile int ms3 = 0;
void timer_init(void){
TCNT0 = timer;
TIMSK |= (1<<TOIE0); //Interupts aktivieren
sei();
TCCR0 |= (1<<CS01); //Prescaler 8
}
ISR(TIMER0_OVF_vect){
TCNT0 = timer;
//Endausschlag LINKS
if(ms1>=150){
PORTB &= ~(1<<PORTB1);
if(ms1<=2000)
ms1++;
else
ms1 = 0;
}
else
PORTB |= (1<<PORTB1);
/*
if(ms2>=150)
PORTB &= ~(1<<PORTB2);
else
PORTB |= (1<<PORTB2);
if(ms2<=2000)
ms2++;
else
ms2 = 0;
if(ms3>=150)
PORTB &= ~(1<<PORTB3);
else
PORTB |= (1<<PORTB3);
if(ms3<=2000)
ms3++;
else
ms3 = 0;
*/
}
int main(void){
DDRB |= (1<<PORTB1) | (1<<PORTB2) | (1<<PORTB3); //B... AUSGANG
PORTB &= ~((1<<PORTB1) | (1<<PORTB2) | (1<<PORTB3)); //B.. Low
//GLOBALE INTERUPTS AKTIVIERT
timer_init();
while(1){
}
return 0;
}
-
danke für deine bemühungen.
Mit dieser methode passiert leider garnichts. Der Pin wird einfach auf High gelegt(mehr oder weniger)
-
Ja sicher, hab ich wohl was Vergessen...
Code:
#include <avr/io.h> // I/O Port definitions
#include <avr/interrupt.h> // Interrupt macros
#define F_CPU 16000000
#define timer 238 //0.01ms
volatile int ms1 = 0;
volatile int ms2 = 0;
volatile int ms3 = 0;
void timer_init(void){
TCNT0 = timer;
TIMSK |= (1<<TOIE0); //Interupts aktivieren
sei();
TCCR0 |= (1<<CS01); //Prescaler 8
}
ISR(TIMER0_OVF_vect){
TCNT0 = timer;
//Endausschlag LINKS
if(ms1>=150){
PORTB &= ~(1<<PORTB1);
if(ms1<=3800)
ms1++;
else{
ms1 = 0;
}
}
else
PORTB |= (1<<PORTB1);
ms1++;
/*
if(ms2>=150)
PORTB &= ~(1<<PORTB2);
else
PORTB |= (1<<PORTB2);
if(ms2<=2000)
ms2++;
else
ms2 = 0;
if(ms3>=150)
PORTB &= ~(1<<PORTB3);
else
PORTB |= (1<<PORTB3);
if(ms3<=2000)
ms3++;
else
ms3 = 0;
*/
}
int main(void){
DDRB |= (1<<PORTB1) | (1<<PORTB2) | (1<<PORTB3); //B... AUSGANG
PORTB &= ~((1<<PORTB1) | (1<<PORTB2) | (1<<PORTB3)); //B.. Low
//GLOBALE INTERUPTS AKTIVIERT
timer_init();
while(1){
}
return 0;
}
Jetzt aber.
Die 3800 kannst Du noch etwas optimieren.
Gruß
PS Mit der OCUnit geht es wirklich besser.
-
Danke dir, das gibt mir ein gutes signal. Nicht perfekt aber kommt nahe hin.
Nur habe ich auch jetz wieder abweichungen zum theoretischen Zeit Wert.
Also ich meine wen ich in einer bestimmten Zeit Interupts abfange und mir dann berechne das ich meine Variable auf einen bestimmten Wert hochzählen muss um z.B. 1.5ms zu bekommen. Wieso habe ich den praktisch abweichungen?
EDIT:
Betreffen der OCUnit(HardwarePWM?)
Ich hab das schon einmal probiert aber nicht alle 3 PWM's des Atmega sauber zum laufen gekriegt.
-
-
Hi!
Ja, aber ich hatte gehofft, dass sie jetzt geringer sind. Das wäre zu prüfen.
Für solche Abweichungen kann es viele Möglichkeiten geben: IRQs werden übergangen, weil die ISR zu lange dauert, Timer werden nicht sofort initialisiert (auf gewünschten Wert gesetzt), Resets werden ständig ausgelöst, Quarz ist falsch gewählt oder fehlerhaft.
Für lange ISR sind natürlich der eigene Code verantwortlich aber es hängt auch am Compiler, wieviel Code dieser daraus macht. Daher fragte ich ja auch, ob Du die Optimierung eingeschaltet hast. Der GCC hat davon verschiedene. Probier doch einfach mal den.
Ansonsten ist Deine Lösung leider wirklich nicht zu empfehlen.
Wenn man eine PWM per Hardware hinbekommt, dann sind die anderen nur noch Makulatur, weil sie identisch sind. Gut, es gibt Unterschiede zwischen 8 und 16Bit Countern.
Gruß
-
Ich finde einfach komisch das der code auf einem Atmega644 mit 16Mhz perfekt funktioniert hat und auf dem atmega8 nicht mehr.
Klingt für mich einfach irgendwie nach falsch eingestelltem Quarz