Moin, vielleicht hilft Dir ja das weiter
https://www.roboternetz.de/phpBB2/dl...le&file_id=169
Hallo an Alle!
Ich benötige eine ISR die alle 1µs aufgerufen wird. Ich habe versucht mir dafür den ungenutzten TIMER1 des M32-Boards zu konfigurieren, aber da ich auf diesem Gebiet Null Durchblick habe, ist es mir bislang nicht gelungen.
Kann mir bitte jemand den Code geben mit dem TIMER1 dementsprechend konfiguriert wird und wie die ISR dann aussehen muss?
Danke schonmal im Vorraus!
Moin, vielleicht hilft Dir ja das weiter
https://www.roboternetz.de/phpBB2/dl...le&file_id=169
Ich habe bereits bis Unendlich gezählt. Zweimal, und zurück
Das habe ich auch schon gefunden, nur leider habe ich keinen Schimmer wie ich das was da rauskommt in C schreiben muss.
Hallo
1µs ist aber wenig. Das m32 taktet mit 16MHz, ein Takt dauert 1s/16000000Hz = 0,0000000625 Sekunde. Eine Mikrosekunde dauert 0,000001s oder 0,000001s/0,0000000625s = 16Takte! (verblüffend;)
Was willst du denn mit der 1µs anstellen?
Gruß
mic
Bild hier
Atmel’s products are not intended, authorized, or warranted for use
as components in applications intended to support or sustain life!
Ich möchte damit meine Servos steuern, dies habe ich bislang über den schon vorhandenen Timer0 gemacht, wo ich meine Routine für die Steuerung mit hinzugeschrieben habe:
if(servo_timer>servo1_pos_d) PORTD &= ~IO_PD6; else PORTD |= IO_PD6;
if(servo_timer>servo2_pos_d) PORTC &= ~IO_PC4; else PORTC |= IO_PC4;
if(servo_timer>servo3_pos_d) PORTC &= ~IO_PC6; else PORTC |= IO_PC6;
if(servo_timer<200) servo_timer++; else servo_timer=0;
Allerdings ist die Auflösung bei 100µs recht bescheiden (ca. 17 mögliche Servo-Positionen).
Beim näheren darüber nach denken muss ich aber feststellen das 1µs wirklich etwas wenig sind, 10µs wären (mit dann ca. 170 möglichen Positionen) ja fast schon auf 1° genau. Also 10µs reichen!
Ach, es geht um Servoimpulse, alles klar.
Vielleicht wäre das eine Basis:
(Aus https://www.roboternetz.de/community...l=1#post522751)Code:// Servoansteuerung mit 16Bit-Timer1 (mit arexx cat16) mic 18.1.2011 // Die 8 Servos werden an Port B und C angeschlossen: // Servo0 - PB0 // Servo1 - PB1 // Servo2 - PC2 // Servo3 - PC3 // Servo4 - PC4 // Servo5 - PC5 // Servo6 - PC6 // Servo7 - PC7 #include <avr/io.h> #include <avr/interrupt.h> volatile uint8_t count_20ms; volatile uint16_t servo[9] ={1700, 1700, 1700, 1700, 1700, 1700, 1111, 1111, 40000}; // Servopositionen void sleep(uint8_t pause); // 1/50 Sekunde blockierende Pause int main(void) { cli(); // für 16MHz-ATMega16 TCCR1A = (0<<WGM11)|(0<<WGM10); // CTC-Mode 4 TCCR1B = (0<<WGM13)|(1<<WGM12); TCCR1B |= (0<<CS12)|(1<<CS11)|(0<<CS10); // prescaler /8 TIMSK = (1<<OCIE1A); // MatchCompare-Interrupt erlauben DDRB = 0b00000011; // Datenrichtung Servoausgänge setzen DDRC = 0b11111100; sei(); sleep(100); while(1) // Demo { cli(); servo[0]=2500; servo[1]=servo[2]=1600; sei(); sleep(50); cli(); servo[0]=servo[1]=servo[2]=1700; sei(); sleep(50); } return(0); } ISR(TIMER1_COMPA_vect) { static uint8_t nr=8; // Nummer des aktuellen Servos PORTB &= ~0b00000011; // alle Servoimpulse low PORTC &= ~0b11111100; if(nr < 3) // Impuls für Servo oder Pause? (8 Servos) { if(nr<2) PORTB |= (1<<nr); // Impulsleitung des aktuellen Servos else PORTC |= (1<<nr); // auf High setzen und OCR1A = servo[nr]; // Impulslänge in OCR1A laden servo[8] -= servo[nr]; // Impulslänge von der Pause abziehen nr++; // nächstes Servo } else { OCR1A = servo[8]; // servo[8] ist die Impulspause servo[8] = 40000; // Startwert 20ms laden nr = 0; // beim nächsten ISR-Aufruf Impuls // für Servo 0 erzeugen if(count_20ms) count_20ms--; // blockierende Pause aktiv? } } void sleep(uint8_t pause) // 1/50 Sekunde blockierende Pause { count_20ms=pause+1; while(count_20ms); }
Das Programm wurde für einen 16MHz-Mega16 geschrieben, sollte aber auch auf dem Mega32 laufen. Der Timer1 läuft im CTC-Mode mit Prescaler/8 von 0 bis 40000 in 20ms. Während eines Zyklus werden nacheinander jeweils die Impulse für bis zu 8 Servos erzeugt. Die Servopositionen sind in servo[0] bis servo[7] gespeichert, 2000 sind eine Millisekunde (0,001s). In servo[8] ist der Wert für das Zyklusende gespeichert, ein kleinerer Wert (muss aber größer als die Summe der Servos sein, z.B TCNT1+=10) erhöht die Wiederholfrequenz. Mit if(nr < 3) kann man die Anzahl der verwendeten Servos ändern.
Gruß
mic
Bild hier
Atmel’s products are not intended, authorized, or warranted for use
as components in applications intended to support or sustain life!
Wird denn in dem Beispiel der Timer1 (ISR(TIMER1_COMPA_vect)) alle 10µs ausgeführt? Und was muss ich wie ändern um das auf dem Mega32 mit 10µs auszuführen?
Warum bestehst du nun auf den 10µs? Diese Variante ruft die ISR in einem 20ms-Zyklus genau Servos+1 mal auf. Viel Resourcenschonender gehts nimmer und das auch noch quasi fertig zur Verwendung. Du brauchst nur noch die Pins eintragen:
Code:// Servoansteuerung mit 16Bit-Timer1 mic 10.1.2012 // Drei Servos an PD6,PC4 und PC6 // https://www.roboternetz.de/community/threads/56242-Problem-beim-Konfigurieren-von-TIMER1-beim-M32-Board #include <avr/io.h> #include <avr/interrupt.h> volatile uint8_t count_20ms; volatile uint16_t servo[9] ={1700, 1700, 1700, 1700, 1700, 1700, 1111, 1111, 40000}; // Servopositionen void sleep(uint8_t pause); // 1/50 Sekunde blockierende Pause int main(void) { cli(); // für 16MHz-ATMega16 TCCR1A = (0<<WGM11)|(0<<WGM10); // CTC-Mode 4 TCCR1B = (0<<WGM13)|(1<<WGM12); TCCR1B |= (0<<CS12)|(1<<CS11)|(0<<CS10); // prescaler /8 TIMSK = (1<<OCIE1A); // MatchCompare-Interrupt erlauben //DDRB = 0b00000011; // Datenrichtung Servoausgänge setzen //DDRC = 0b11111100; DDRC |= (1<<PC6)|(1<<PC4); DDRD |= (1<<PD6); sei(); sleep(100); while(1) // Demo { cli(); servo[0]=2500; servo[1]=servo[2]=1600; sei(); sleep(50); cli(); servo[0]=servo[1]=servo[2]=1700; sei(); sleep(50); } return(0); } ISR(TIMER1_COMPA_vect) { static uint8_t nr=8; // Nummer des aktuellen Servos //PORTB &= ~0b00000011; // alle Servoimpulse low //PORTC &= ~0b11111100; PORTC &= ~((1<<PC6)|(1<<PC4)); PORTD &= ~(1<<PD6); if(nr < 3) // Impuls für Servo oder Pause? (8 Servos) { //if(nr<2) PORTB |= (1<<nr); // Impulsleitung des aktuellen Servos //else PORTC |= (1<<nr); // auf High setzen und if(nr==0) PORTD |= (1<<PD6); else if(nr==1) PORTC |= (1<<PC4); else if(nr==2) PORTC |= (1<<PC6); OCR1A = servo[nr]; // Impulslänge in OCR1A laden servo[8] -= servo[nr]; // Impulslänge von der Pause abziehen nr++; // nächstes Servo } else { OCR1A = servo[8]; // servo[8] ist die Impulspause servo[8] = 40000; // Startwert 20ms laden nr = 0; // beim nächsten ISR-Aufruf Impuls // für Servo 0 erzeugen if(count_20ms) count_20ms--; // blockierende Pause aktiv? } } void sleep(uint8_t pause) // 1/50 Sekunde blockierende Pause { count_20ms=pause+1; while(count_20ms); }
Bild hier
Atmel’s products are not intended, authorized, or warranted for use
as components in applications intended to support or sustain life!
Na ja, eigentlich wollte ich gerne meine eigene Methode verwenden, weil ich gerne möglichst viel von dem was da passiert verstehen möchte. Und das tut man am besten wenn man es sich selber erarbeitet hat.
Ich habe das o.g. Beispiel mal kopiert und ausprobiert. Die Servos gehen beim Programmstart auf die fest eingestellten Positionen, aber wenn man in der Hauptschleife andere Werte einstellt, tut sich gar nichts.
Geändert von dirty_bird_981 (11.01.2012 um 00:06 Uhr)
Lesezeichen