-
        

Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 12

Thema: Mathematik: 100kHz ISR

  1. #1
    Neuer Benutzer Öfters hier
    Registriert seit
    31.12.2009
    Ort
    Ahrensburg
    Alter
    25
    Beiträge
    24

    Mathematik: 100kHz ISR

    Anzeige

    Hallo zusammen,
    Ich verzweifle daran, eine 100kHz ISR an einem mit 16 MHz getakteten µC hinzubekommen (Servoansteuerung). Könnt ihr mir auf die Sprünge helfen, was das Prescalen etc. angeht, oder was ich auch für Werte gut verwenden kann?

    lg
    Merlin

  2. #2
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    15.06.2008
    Ort
    Wien
    Beiträge
    162
    Wenn ich dich richtig verstanden habe möchtest du alle 160 Zyklen eine ISR auslösen. (16MHz/100kHz)

    Das kannst du am besten mithilfe des Datenblatts lösen (Timer).
    Allerdings ist stark darauf zu achten das innerhalb der ISR nicht viel gemacht wird da du nur 160 Taktzyklen Zeit hast! (Außer du verwendest innerhalb der ISR cli() und sei(), was allerdings bei servoansteuerungen nicht günstig ist)

    Nur mal so als Frage: wozu brauchst du dafür 100kHz speed??

    MFG

  3. #3
    Neuer Benutzer Öfters hier
    Registriert seit
    31.12.2009
    Ort
    Ahrensburg
    Alter
    25
    Beiträge
    24
    Hey XBert,
    Die 100kHz hätte ich gern, um für 1 ms eine Auflösung von 100 zu haben, um die Dinger möglichst genau ansteuern zu können.
    Das mit dem Datenblatt werde ich mir mal anschauen, aber ist das nicht bei allen ATmega32ern gleich mit den Prescalern? Mein Punkt ist dass ich das Controllerboard erst in ca. ner Woche bekomme und bis dahin schonmal ein wenig in die Programmierung reinmöchte

    Merlin

  4. #4
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    15.06.2008
    Ort
    Wien
    Beiträge
    162
    Ich habs bei meiner Servo-Ansteuerung so gemacht das ich den timer nur da auslöse wenn ich ihn brauche -> Tabellen mit Zeiten und servo-nummer der größe nach sortieren und immer nach der differenz zwischen 2 Servos den timer auslösen und nach dem letzten warten bis die insgesamt 20ms vorbei sind.

    z.B.:
    Code:
    servo1: 1,5ms
    servo2: 2ms
    servo3: 1ms
    
    timer (beim ersten mal) = 1ms;
    timer (beim zweiten mal) = 0,5ms;
    ...
    timer (am ende) = 20ms-letzerServo
    Ich hoffe du verstehst was ich meine

    EDIT: ich hab vergessen zu sagen das alle servo-pins am anfang auf high gesetzt werden und dann nach ablauf des timers die Servos deren Zeit "abgelaufen" ist auf low gesetzt werden.

    LG

  5. #5
    Neuer Benutzer Öfters hier
    Registriert seit
    31.12.2009
    Ort
    Ahrensburg
    Alter
    25
    Beiträge
    24
    Zugegeben verstehe ich zwar das Prinzip, aber die Umsetzung erschließt sich mir nicht ganz, kannst du mir da noch nen Ansatz geben?

    Merlin

  6. #6
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    15.06.2008
    Ort
    Wien
    Beiträge
    162
    ich werds versuchen:

    Pseudocode:
    Code:
    #define SERVO1_LOW PORTA&=~(1<<0)
    ...
    #define SERVO8_LOW PORTA&=~(1<<7)
    
    servozeiten[anzahlServos];
    servozahl[anzahlServos];
    servo_count = 9;
    
    init(){
        for(/*alle servos*/){
           servozeiten[i] = 1,5ms; //natürlich musst du das in taktzyklen umrechnen
           servozahl[i] = i;
        }
    }
    
    main(){
        init();
        for(;;){/*tu was (zb Servos setzen)*/}
    }
    
    ISR(){
        switch(servo_count){
            case 0:
               SERVO1_LOW;break;
            case 1:
               SERVO2_LOW;break;
            ....
            case 9:
                //sortieren von servozeiten und servozahl (dafür hast du 2^16 zyklen zeit, da der timer max 16bit hat)
                //differenz zwischen servozeiten brechnen
                //warten bis 20ms vorbei sind (bitte nicht mit delay_ms() sondern den timer so oft setzen und nichts tun bis die 20ms vorbei sind)
                //Pins auf high setzen
        }
        //timer auf nächsten IR setzen
    }
    Ich hoffe ich hab nix vergessen

    LG

  7. #7
    Erfahrener Benutzer Robotik Einstein Avatar von wkrug
    Registriert seit
    17.08.2006
    Ort
    Dietfurt
    Beiträge
    1.892
    @Merlin321
    So eine Servoansteuerung passiert eigentlich immer mit einem Puls von 1...2ms gefolgt von einer Pause mit ca. 20ms.

    Ich bau für meine Servoansteuerungen immer eine ISR im Comparematch Interrupt auf.

    Dazu verwendest Du einen 16Bit Timer (Timer 1) und lässt diesen mit Prescaler 8 laufen.
    Dabei entspricht dann ein Count 0,5µs, also 1ms einem Zählerwert von 2000.

    Der Trick dabei ist nun die Servoimpulse, falls man mehrere Servos verwendet, nacheinander zu erzeugen und nach dem letzten Impuls eine Pause einzufügen, die die gewünschten 20ms voll macht.

    Beispiel:
    Du hast 4 Servos mit 1,5ms = 6ms.
    Die Pause wäre somit 20ms-6ms=14ms = Counterwert 28000.
    Die Servoimpulse werden dann, gesteuert von einer Variablen, nacheinander an verschiedenen Ausgängen ausgegeben.
    Dazu wird der Zählerstand des TCNT1 Registers ausgelesen, der Wert der gewünschten Servoimpulslänge dazugezählt und dieser ins OCR1A Register für den nächsten Comparematch Interrupt reingeschrieben.
    Nun folgt die Pause, wo kein Ausgang aktiv ist und somit kein Servo angesteuert wird.
    Mit dieser Methode kann man bis zu 8 Servos ansteuern und der Controller langweilt sich dabei sogar noch.

    Codeschnipsel für 2 Servos:
    Code:
    // Timer 1 Comparematch A interrupt service Routine
    interrupt [TIM1_COMPA] void timer1_compa_isr(void)
    {
    unsigned int ui_buffer=0;
    ui_buffer=TCNT1;
    
    if(uc_servocount==0)
    {
        SERVO1=0;
        SERVO2=0;
        ui_buffer+=ui_pause;
        OCR1A=ui_buffer;
    }
    
    if(uc_servocount==1)
    {
        SERVO1=1;
        SERVO2=0;
        ui_buffer+=ui_servo1;
        OCR1A=ui_buffer;
    }
    
    if (uc_servocount==2)
    {
        SERVO1=0;
        SERVO2=1;
        ui_buffer+=ui_servo2;
        OCR1A=ui_buffer;
    }
    
    uc_servocount++;
    if(uc_servocount>2){uc_servocount=0;}
    }

  8. #8
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    11.12.2007
    Ort
    weit weg von nahe Bonn
    Alter
    33
    Beiträge
    2.380
    XBert, deine methiode hat allerdings das problem, wenn da sehr viele Servos denselben wert haben, werden die Servos immer ein wenig aus der spur gehen, je mehr Servos denselben wert haben

    ich hätte da ne idee die etwas speicherintensiv ist, aber locker mit 8/16/32 Servos klarkommt

    man nehme ein char array, das der auflösung für die servosteuerung entspricht, also 1mS(vollausschlag links/rechts) / x Steps, wobei x der anzahl an timerüberläufen entspricht, die in 1mS möglich sind ...

    jetzt richtet man sich also den timer ein und das array von der größe x

    man legt sich ausserdem eine indexvariable und eine countervariable an

    bei counter == 0 schaltet man alle pins auf HIGH und setzt die indexvariable auf 0

    in der ISR lässt man jetzt 1ms nichts passieren (mindeststellzeit)

    dann geht man mit der indexvariable bei jedem step ein stück vorran durch das array ... jedes byte in dem array steht für 8 Servos (je bit ein servo) bei der ersten gefundenen 1(also das bit nicht der wert) wird die leitung für den jeweiligen servo auf LOW gezogen

    wenn also bei position 0 ein wert von 4 steht (3tes bit 1) wird der impus des 3ten servo bei 1ms abgeschaltetn (linker anschlag) und wenn bei position x eine 3 steht (1tes und 2tes bit) werden die Servos 1 und 2 gestoppt (rechter anschlag)

    abschliessend setzt man den index wieder auf 0 und wartet dann 18mS und macht wieder garnichts (man sollte eventuell alle impulsleitungen auf LOW setzen bevor man das tut, kann ja passieren man hat ne 1 übersehen hat )

    um die position der Servos zu ändern, wartet man zunächst mit
    while ( index != 0 ) ;
    dass der timer in die pausephase geht, löscht das bit der alten position und schreibt die neue position ... die position für jeden servo sollte man sich immer in einer variable speichern

    alles zusammen braucht man dafür x + 10-12 bytes arbeitsspeicher, aber das sollte so ganz ordentlich funktionieren

  9. #9
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    15.06.2008
    Ort
    Wien
    Beiträge
    162
    Zitat Zitat von Ceos
    XBert, deine methiode hat allerdings das problem, wenn da sehr viele Servos denselben wert haben, werden die Servos immer ein wenig aus der spur gehen, je mehr Servos denselben wert haben
    Der meinung bin ich nicht, da es zb bei HS-645MG analog Servos eine "dead bandwidth" von 8µs gibt. in diesen 8µs sollte es einem µC (bei 16MHz -> 8µs ~ 128 zyklen) wohl möglich sein 20 oder mehr pins auf low zu setzen;

  10. #10
    Erfahrener Benutzer Robotik Einstein Avatar von Dirk
    Registriert seit
    30.04.2004
    Ort
    NRW
    Beiträge
    3.791
    Hallo Merlin321,

    zu Deiner Frage am Anfang dieses Posts:
    Hier die Initialisierung für eine 100kHz ISR mit Timer1 (M32):
    Code:
    #define F_TIMER1			100000		// Timer 1 frequency (100kHz)
    
    	cli();
    	// Timer 1: Normal port operation, mode 4 (CTC), clk/8
    	TCCR1A =  (0 << COM1A1) 
    			| (0 << COM1A0) 
    			| (0 << COM1B1) 
    			| (0 << COM1B0) 
    			| (0 << FOC1A) 
    			| (0 << FOC1B) 
    			| (0 << WGM11) 
    			| (0 << WGM10);
    	TCCR1B =  (0 << ICNC1) 
    			| (0 << ICES1) 
    			| (0 << WGM13) 
    			| (1 << WGM12) 
    			| (0 << CS12) 
    			| (1 << CS11) 
    			| (0 << CS10);
    	OCR1A = ((F_CPU/8/F_TIMER1)-1);	// 19 at 100kHz
    Als ISR nimmst du den TIMER1_COMPA_vect.

    Gruß Dirk

Seite 1 von 2 12 LetzteLetzte

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •