- 3D-Druck Einstieg und Tipps         
Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 75

Thema: Mehrere RC Signale einlesen und mehrere Servos ausgeben

Hybrid-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #1
    Erfahrener Benutzer Robotik Einstein Avatar von Searcher
    Registriert seit
    07.06.2009
    Ort
    NRW
    Beiträge
    1.703
    Blog-Einträge
    133
    Hallo R2D2 Bastler.
    ich weiß ja, daß Du fleißig beim Testen bist. Mich hat das Mikrosekundenjagdfieber gepackt und ohne das Grobkonzept zu ändern hier noch eine Variante.

    Um die ISRs kurz zu halten werden jetzt Berechnungen in die Hauptschleife gelegt.
    Der Timer0 wir zur Pausenfüllung langsamer laufen gelassen, damit er weniger Overflow Interrupts erzeugt. (Die hab ich selbst noch nicht ausprobiert und weis nicht genau, was passiert, wenn der Prescaler während des Timerlaufs umgeschaltet wird.)

    Code:
    '===============================================================================
    'RC Eingang 1 an Pin 3 (PB1, PCINT9)
    'RC Eingang 2 an Pin 6 (PA7, PCINT7)
    'RC Eingang 3 an Pin 5 (PB2, INT0)
    'Servo 1 an Pin 13 (PA0)
    'Servo 2 an Pin 12 (PA1)
    'Servo 3 an Pin 11 (PA2)
    'Servo 4 an Pin 10 (PA3)
    '===============================================================================
    
    $regfile = "attiny84.dat"
    $crystal = 8000000                      'FuseBit CKDIV8 deaktivieren
    
    $hwstack = 50
    $swstack = 50
    $framesize = 50
    
    
    '-------------------------------------------------------------------------------------------------
    'Timer und konfigurieren
    '-------------------------------------------------------------------------------------------------
    
    Config Timer1 = Timer , Prescale = 8    'Timer für Einlesen RC Signale
    Start Timer1
    
    Config Timer0 = Timer , Prescale = 64   'Timer für Servoausgabe, Wert 125 entspricht 1ms, Wert 250 entspricht 2ms
    Enable Timer0
    On Timer0 Servoausgabe Nosave           'Register werden manuell in der ISR gesichert
    
    
    '-------------------------------------------------------------------------------------------------------------
    'Variablen definieren
    '-------------------------------------------------------------------------------------------------------------
    
    'Variablen fürs RC Einlesen
    Dim Rc_signal_1_start As Word
    Dim Rc_signal_2_start As Word
    Dim Rc_signal_3_start As Word
    
    Dim Rc_signal_1_stop As Word
    Dim Rc_signal_2_stop As Word
    Dim Rc_signal_3_stop As Word
    
    Dim Rc_signal_1_stop_flag As Byte
    Dim Rc_signal_2_stop_flag As Byte
    Dim Rc_signal_3_stop_flag As Byte
    
    
    Dim Impulslaenge_1 As Byte
    Dim Impulslaenge_2 As Byte
    Dim Impulslaenge_3 As Byte
    
    
    
    'Variablen für Berechnungen
    Dim Berechnung_1 As Word
    Dim Berechnung_2 As Word
    
    
    
    'Variablen für Servoausgabe
    Dim Kanal As Byte
    Dim Servoausgabe_1 As Byte
    Dim Servoausgabe_2 As Byte
    Dim Servoausgabe_3 As Byte
    Dim Servoausgabe_4 As Byte
    Dim Pausen_variable As Byte
    
    
    '-------------------------------------------------------------------------------------------------
    'Einigen Variablen Werte zuweisen
    '-------------------------------------------------------------------------------------------------
    
    Kanal = 1
    Pausen_variable = 0
    
    '-------------------------------------------------------------------------------------------------------------
    'Ein- und Ausgang festlegen
    '-------------------------------------------------------------------------------------------------------------
    
    Ddra = &B00001111                       'PA0 - PA3 werden Ausgänge
    Ddrb = &B00000000                       'PortB bleibt Eingang
    
    
    '-------------------------------------------------------------------------------------------------
    'Interrupt-Service-Routinen konfigurieren und freigeben
    '-------------------------------------------------------------------------------------------------
    
    'Info:
    'Alle Porta Pinchangeinterrupts sind in Bascom "PCINT0" zugeordnet.
    'Alle Portb Pinchangeinterrupts sind in Bascom "PCINT1" zugeordnet.
    
    
    Pcmsk1.pcint9 = 1                       'beim Flankenwechsel an PB1/PCINT9 (RC Eingang 1) Pinchangeinterrupt1 auslösen und in die Subroutine springen
    Enable Pcint1                           'Pinchangeinterrupt1 (1 weil auf PortB) zulassen
    On Pcint1 Rc_eingang_1 Nosave           'Register werden manuel in der ISR gesichert
    
    
    Pcmsk0.pcint7 = 1                       'beim Flankenwechsel an PA7/PCINT6 (RC Eingang 2) Pinchangeinterrupt0 auslösen und in die Subroutine springen
    Enable Pcint0                           'Pinchangeinterrupt0 (0 weil auf PortA) zulassen
    On Pcint0 Rc_eingang_2 Nosave           'Register werden manuel in der ISR gesichert
    
    
    Config Int0 = Change                    'beim Flankenwechsel an PB2/INT0 (RC Eingang 3) Int0 auslösen und in die Subroutine springen
    Enable Int0
    On Int0 Rc_eingang_3 Nosave             'Register werden manuel in der ISR gesichert
    
    Enable Interrupts
    
    
    '======================================================
    'Hauptprogramm
    '======================================================
    
    Do
    
      If Rc_signal_1_stop_flag = 1 Then     'Bearbeitung nur, wenn ISR Pulsende gefunden hat
          Disable Pcint1                    'Mögliche Korruption durch ISR vorbeugen
          Impulslaenge_1 = Rc_signal_1_stop - Rc_signal_1_start
          Enable Pcint1
          Rc_signal_1_stop_flag = 0
          Berechnung_1 = Impulslaenge_1
          Shift Berechnung_1 , Right , 3    'Division von Berechnung_1 durch 8
    
          If Berechnung_1 > 255 Then        'zu hohe Werte abfangen
             Berechnung_1 = 255
          End If
    
          If Berechnung_1 < 120 Then        'zu kleine Werte abfangen
            Berechnung_1 = 120
          End If
          Servoausgabe_1 = 256 - Berechnung_1       'Servoausgabe_ zum direkten Laden in TCNT0 vorbereiten (Cmd Load umgangen)
      End If
    
    
      If Rc_signal_2_stop_flag = 1 Then     'Bearbeitung nur, wenn ISR Pulsende gefunden hat
          Disable Pcint0                    'Mögliche Korruption durch ISR vorbeugen
          Impulslaenge_2 = Rc_signal_2_stop - Rc_signal_2_start
          Enable Pcint0
          Rc_signal_2_stop_flag = 0
          Berechnung_2 = Impulslaenge_2
          Shift Berechnung_2 , Right , 3    'Division von Berechnung_1 durch 8
    
          If Berechnung_2 > 255 Then        'zu hohe Werte abfangen
             Berechnung_2 = 255
          End If
    
          If Berechnung_2 < 120 Then        'zu kleine Werte abfangen
            Berechnung_2 = 120
          End If
          Servoausgabe_2 = 256 - Berechnung_2       'Servoausgabe_ zum direkten Laden in TCNT0 vorbereiten (Cmd Load umgangen)
      End If
    
      Servoausgabe_3 = 190
      Servoausgabe_4 = 190
    
    Loop
    
    
    
    '======================================================
    'ISR
    '======================================================
    
    Rc_eingang_1:
     $asm
       push r17                             'Register auf Stack sichern
       sbis pinb , 1                        'Skip next Instr if PINBx = 1
       rjmp Puls_ende1                      'Springe Puls_ende
       in r17 , tcnt1l                      'Timer1 low Byte holen
       sts {Rc_signal_1_start} , r17        'Speichere Timer1 low Byte nach Rc_signal_x_start low Byte
       in r17 , tcnt1h                      'Timer1 high Byte holen
       sts {Rc_signal_1_start} + 1 , r17    'Speichere Timer1 high Byte nach Rc_signal_x_start high Byte
       rjmp ende1                           'Springe zum Ende
      Puls_ende1:
       in r17 , tcnt1l                      'Timer1 low Byte holen
       sts {Rc_signal_1_stop} , r17         'Speichere Timer1 low Byte nach Rc_signal_x_stop low Byte
       in r17 , tcnt1h                      'Timer1 high Byte holen
       sts {Rc_signal_1_stop} + 1 , r17     'Speichere Timer1 high Byte nach Rc_signal_x_stop high Byte
       ldi r17 , 1
       sts {Rc_signal_1_stop_flag} , r17    'Setze Flag zur Bearbeitung von Impulslaenge in Hauptschleife
      Ende1:
       pop r17                              'Register vom Stack zurückholen
     $end Asm
    Return
    
    Rc_eingang_2:
     $asm
       push r17                             'Register auf Stack sichern
       sbis pinA , 7                        'Skip next Instr if PINBx = 1
       rjmp Puls_ende2                      'Springe Puls_ende
       in r17 , tcnt1l                      'Timer1 low Byte holen
       sts {Rc_signal_2_start} , r17        'Speichere Timer1 low Byte nach Rc_signal_x_start low Byte
       in r17 , tcnt1h                      'Timer1 high Byte holen
       sts {Rc_signal_2_start} + 1 , r17    'Speichere Timer1 high Byte nach Rc_signal_x_start high Byte
       rjmp ende2                           'Springe zum Ende
      Puls_ende2:
       in r17 , tcnt1l                      'Timer1 low Byte holen
       sts {Rc_signal_2_stop} , r17         'Speichere Timer1 low Byte nach Rc_signal_x_stop low Byte
       in r17 , tcnt1h                      'Timer1 high Byte holen
       sts {Rc_signal_2_stop} + 1 , r17     'Speichere Timer1 high Byte nach Rc_signal_x_stop high Byte
       ldi r17 , 1
       sts {Rc_signal_2_stop_flag} , r17    'Setze Flag zur Bearbeitung von Impulslaenge in Hauptschleife
      Ende2:
       pop r17                              'Register vom Stack zurückholen
     $end Asm
    Return
    
    Rc_eingang_3:
     $asm
       push r17                             'Register auf Stack sichern
       sbis pinB , 2                        'Skip next Instr if PINBx = 1
       rjmp Puls_ende3                      'Springe Puls_ende
       in r17 , tcnt1l                      'Timer1 low Byte holen
       sts {Rc_signal_3_start} , r17        'Speichere Timer1 low Byte nach Rc_signal_x_start low Byte
       in r17 , tcnt1h                      'Timer1 high Byte holen
       sts {Rc_signal_3_start} + 1 , r17    'Speichere Timer1 high Byte nach Rc_signal_x_start high Byte
       rjmp ende3                           'Springe zum Ende
      Puls_ende3:
       in r17 , tcnt1l                      'Timer1 low Byte holen
       sts {Rc_signal_3_stop} , r17         'Speichere Timer1 low Byte nach Rc_signal_x_stop low Byte
       in r17 , tcnt1h                      'Timer1 high Byte holen
       sts {Rc_signal_3_stop} + 1 , r17     'Speichere Timer1 high Byte nach Rc_signal_x_stop high Byte
       ldi r17 , 1
       sts {Rc_signal_3_stop_flag} , r17    'Setze Flag zur Bearbeitung von Impulslaenge in Hauptschleife
      Ende3:
       pop r17                              'Register vom Stack zurückholen
     $end Asm
    Return
    
    
    
    Servoausgabe:
    
     $asm
       push r16                             'Register auf Stack sichern
       in r16,sreg                          'Statusregister holen und halten
       push r17                             'Register auf Stack sichern
       lds r17 , {kanal}                    'hole Kanalnummer
    
       cpi r17 , 1                          'check Kanal und ...
       brne LABEL_KANAL_2                   '... "wenn nicht gleich" verzweige zum nächsten Kanal
       sbic porta , 0                       'Skip next instr. wenn PORTA.0 = 0 ist
       rjmp label_1                         'Springe zum LOW-setzen des Servosignals
       sts {kanal} , r17                    'Sichere Kanalnummer
       lds r17 , {Servoausgabe_1}           'Hole aufbereiteten Pulslängenwert für Timer0
       Out Tcnt0 , R17                      'Setze Timer0 mit Pulslängenwert
       sbi porta , 0                        'Setze Servosignal HIGH
       rjmp Ende_isr                        'Springe zum Ende der ISR
      Label_1:
       cbi porta , 0                        'Setze Servosignal nach LOW
       inc r17                              'Erhöhe Kanalnummer
    
    
      Label_kanal_2:                        'Bearbeitung von Kanal 2
       cpi r17 , 2                          'check Kanal und ...
       brne LABEL_KANAL_3                   '... "wenn nicht gleich" verzweige zum nächsten Kanal
       sbic porta , 1                       'Skip next instr. wenn PORTA.1 = 0 ist
       rjmp label_2                         'Springe zum LOW-setzen des Servosignals
       sts {kanal} , r17                    'Sichere Kanalnummer
       lds r17 , {Servoausgabe_2}           'Hole aufbereiteten Pulslängenwert für Timer0
       Out Tcnt0 , R17                      'Setze Timer0 mit Pulslängenwert
       sbi porta , 1                        'Setze Servosignal HIGH
       rjmp Ende_isr                        'Springe zum Ende der ISR
      Label_2:
       cbi porta , 1                        'Setze Servosignal nach LOW
       inc r17                              'Erhöhe Kanalnummer
    
    
      Label_kanal_3:                        'Bearbeitung von Kanal 3
       cpi r17 , 3                          'check Kanal und ...
       brne LABEL_KANAL_4                   '... "wenn nicht gleich" verzweige zum nächsten Kanal
       sbic porta , 2                       'Skip next instr. wenn PORTA.2 = 0 ist
       rjmp label_3                         'Springe zum LOW-setzen des Servosignals
       sts {kanal} , r17                    'Sichere Kanalnummer
       lds r17 , {Servoausgabe_3}           'Hole aufbereiteten Pulslängenwert für Timer0
       Out Tcnt0 , R17                      'Setze Timer0 mit Pulslängenwert
       sbi porta , 2                        'Setze Servosignal HIGH
       rjmp Ende_isr                        'Springe zum Ende der ISR
      Label_3:
       cbi porta , 2                        'Setze Servosignal nach LOW
       inc r17                              'Erhöhe Kanalnummer
    
    
      Label_kanal_4:                        'Bearbeitung von Kanal 4 mit anschließendem Pausenanfang
       cpi r17 , 4                          'check Kanal und ...
       brne LABEL_KANAL_5                   '... "wenn nicht gleich" verzweige zum nächsten Kanal
       sbic porta , 3                       'Skip next instr. wenn PORTA.3 = 0 ist
       rjmp label_4                         'Springe zum LOW-setzen des Servosignals
       sts {kanal} , r17                    'Sichere Kanalnummer
       lds r17 , {Servoausgabe_4}           'Hole aufbereiteten Pulslängenwert für Timer0
       Out Tcnt0 , R17                      'Setze Timer0 mit Pulslängenwert
       sbi porta , 3                        'Setze Servosignal HIGH
       rjmp Ende_isr                        'Springe zum Ende der ISR
      Label_4:
       cbi porta , 3                        'Setze Servosignal nach LOW
    
    'Pausenauffüllung
    
       'Pausenanfang
       inc r17
       sts {kanal} , r17                    'Sichere Kanalnummer
       ldi r17 , &B00000101                 'CS00 und CS02 für prescaler 1024 in Timer0 vorbereiten
       Out Tccr0b , R17                     'Timer0 läuft mit 128µs Auflösung
       ldi r17 , 162                        'Wert für ca 12ms bis zum nächsten OVF (162=256-94) bei prescaler 1024
       Out Tcnt0 , R17
       rjmp Ende_isr                        'Springe zum Ende der ISR
    
      'Pausenende
      Label_kanal_5:                        'Bearbeitung von Kanal 5 (Pausenende)
       ldi r17 , &B00000011                 'CS00 und CS01 für prescaler 64 in Timer0 vorbereiten
       Out Tccr0b , R17                     'Timer0 läuft wieder mit 8µs Auflösung
       ldi r17 , 1                          'Kanalnummer auf 1 setzen
       sts {kanal} , r17                    'Sichere Kanalnummer
      Ende_isr:
       pop r17                              'Register vom Stack zurückholen
       Out Sreg , R16                       'Statusregister zurückspeichern
       pop r16                              'Register vom Stack zurückholen
     $end Asm
    Return
    Hoffentlich liegt das Ziel auch am Weg
    ..................................................................Der Weg zu einigen meiner Konstruktionen

  2. #2
    Hallo Searcher,

    die Ausgabe ISR funtioniert super, nur die Eingabe scheint nun alles durcheinander zu bringen. Die Servos fahren auf Anschlag und reagieren nicht auf RC Eingaben. Beim Testen der Ausgabe-ISR mit den "alten" Eingabe-ISRs scheint sich das Zucken ganz minimal verbessert zu haben.

    Dir und allen anderen einen guten Rutsch ins neue Jahr

    Robert

  3. #3
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    15.01.2007
    Ort
    Göttingen
    Beiträge
    706
    Hallo Robert,

    jetzt melde ich mich doch mal auf diesem Weg

    Ich habe den Thread natürlich aufmerksam mitverfolgt, und auch den Ansatz, am Ende einer ISR die Interrupt-Flags von den anderen Mess-Interrupts zu löschen. So weit, so gut - aber von den ca. 120 (!) Taktzyklen, die so ein Sprung in eine ISR und wieder zurück braucht, vergehen fast die Hälfte NACH dem Return, weil eben alle Register wieder zurückgeschrieben werden müssen. Und wenn in dieser Zeit ein neuer Flanken-Interrupt ausgelöst wird, wird die ISR halt auch erst mit ein paar -zig Takten Verzögerung ausgeführt, d.h. mit Messfehlern beim Ablesen des Timers.

    Ich würde es tatsächlich mal so versuchen, dass in der Hauptschleife (!) immer nur einer der drei Interrupts freigegeben wird. Hat der Controller einen Impuls fertig gemessen, setzt er ein Flag, und daran erkennt das Hauptprogramm, dass jetzt der nächste Interrupt freigegeben werden muss, usw. So kannst Du m.E. zuverlässig verhindern, dass bei zwei sich überschneidenden Impulsen dadurch Messfehler entstehen, dass die Interrupts nur nacheinander ablaufen können. Und dass Dir durch mal ab und zu ein Impuls entgeht, dürfte bei einer Wiederholungsrate von ca. 20/Sekunde glaube ich keine Rolle spielen.

    Aber das ist vielleicht ein Projekt für´s nächste Jahr, in das ich Dir einen guten Rutsch wünsche!!

    Daniel

  4. #4
    Erfahrener Benutzer Robotik Einstein Avatar von Searcher
    Registriert seit
    07.06.2009
    Ort
    NRW
    Beiträge
    1.703
    Blog-Einträge
    133
    Allen ein Frohes Neues Jahr!

    Hallo Robert,
    Zitat Zitat von R2D2 Bastler Beitrag anzeigen
    die Ausgabe ISR funtioniert super, nur die Eingabe scheint nun alles durcheinander zu bringen. Die Servos fahren auf Anschlag und reagieren nicht auf RC Eingaben. Beim Testen der Ausgabe-ISR mit den "alten" Eingabe-ISRs scheint sich das Zucken ganz minimal verbessert zu haben.
    Das Fehler hat mich nicht schlafen lassen und mit dem neuen Jahr hat sich mir mindestens ein Fehler offenbart
    Die Variablen für Impulslaenge müssen wieder als Word deklariert werden. Also in dem letzten Code diese drei wieder als Word deklarieren.
    Code:
    Dim Impulslaenge_1 As Byte
    Dim Impulslaenge_2 As Byte
    Dim Impulslaenge_3 As Byte
    Die Hoffnung bei der µs/ns-Jagd ist, den Meß- und Ausgabefehler so gering zu kriegen, daß er unter die Ansprechschwelle der Servos fällt, also in die Totzeit fällt, so daß er sich nicht mehr rührt. Sicher vermeiden läßt er sich so wie bisher nicht.

    Man könnte noch versuchen eine SW-Hysterese in der Hauptschleife unterzubringen. Da die Auflösung des Timer0 8µs ist, muß sich der Ausgabewert (Impulslaenge) eines Servos gegenüber dem vorherigen Puls um mindestens 16µs in die entgegengesetzte Richtung geändert haben, bevor es zur Ausgabe an den Servo kommt. Betrifft die Änderung 8µs die gleiche Drehrichtung wie vorher, könnte man diese unverändert weitergeben. Bedeutet natürlich einen etwas größeren Sprung bei Drehrichtungsänderung und ist noch nicht ganz durchdacht...

    Auch wie Sauerbruch nochmal vorgeschlagen hat, die Eingänge nacheinander zu messen könnte Erfolg bringen - müßte man mal in Code umsetzen.

    Letzer Ausweg: Drei µC mit ICP die drei Eingänge messen lassen und falls notwendig die Meßdaten zum einem Haupcontroller übertragen, bearbeiten und ausgeben oder gleich an Ort und Stelle bearbeiten. Bischen aufwändig und nicht so herausfordernd

    Gruß
    Searcher
    Hoffentlich liegt das Ziel auch am Weg
    ..................................................................Der Weg zu einigen meiner Konstruktionen

  5. #5
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    16.02.2006
    Beiträge
    1.113
    Hallo zusammen,
    von mir auch die besten Wünsche für 2014 an alle.

    Zitat Zitat von Searcher Beitrag anzeigen
    Letzer Ausweg: Drei µC mit ICP die drei Eingänge messen lassen und falls notwendig die Meßdaten zum einem Haupcontroller übertragen, bearbeiten und ausgeben oder gleich an Ort und Stelle bearbeiten.
    Wir hatten ja schon festgestellt, dass es beim Einlesen der Signale nicht notwendig ist, die Länge jedes Impulses zu messen.
    Dann kannst du auch drei Eingänge über den Multiplexer nacheinander auf den ICP legen. Ich glaube immer noch, dass dies die erfolgversprechendste Variante wäre, da die HW die Zeitdauer des Impulses in das Register schreibt.
    Da auch die Ausgabe der Servo Signale in HW geschieht, sehe ich dabei gute Chancen für konstante Werte an den Servos.

  6. #6
    Erfahrener Benutzer Robotik Einstein Avatar von Searcher
    Registriert seit
    07.06.2009
    Ort
    NRW
    Beiträge
    1.703
    Blog-Einträge
    133
    Hallo,
    Zitat Zitat von for_ro Beitrag anzeigen
    Dann kannst du auch drei Eingänge über den Multiplexer nacheinander auf den ICP legen. Ich glaube immer noch, dass dies die erfolgversprechendste Variante wäre, da die HW die Zeitdauer des Impulses in das Register schreibt.
    @for_ro: sowas ähnliches geht mir auch schon eine Weile im Kopf rum und wollte schon Diodengatter bauen. Hab jetzt aber nochmal ins Datenblatt vom ATtiny84 geschaut. Der ICP Interrupt kann vom Ausgang des Analog Comparators ausgelöst werden und ein Eingang des Analog Comparators kann über den ADC-Multiplexer auf verschiedene Eingänge gelegt werden. Ist es das, was Du meinst?

    Würde wieder eine üble Bitfieselei werden um alles einzustellen und umzuschalten. Das nacheinander Messen wäre wohl wirklich eine verläßliche Methode um die "zufälligen" Interrupts in den Griff zu kriegen.

    Gruß
    Searcher
    Hoffentlich liegt das Ziel auch am Weg
    ..................................................................Der Weg zu einigen meiner Konstruktionen

  7. #7
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    16.02.2006
    Beiträge
    1.113
    Zitat Zitat von Searcher Beitrag anzeigen
    Der ICP Interrupt kann vom Ausgang des Analog Comparators ausgelöst werden und ein Eingang des Analog Comparators kann über den ADC-Multiplexer auf verschiedene Eingänge gelegt werden. Ist es das, was Du meinst?
    Ja, genau das.

    Zitat Zitat von Searcher Beitrag anzeigen
    Würde wieder eine üble Bitfieselei werden um alles einzustellen und umzuschalten.
    Das ist gar nicht so wild.
    • Du setzt den Bandgap auf 1, dann brauchst du keinen externen positiven Eingang mehr.
    • Du stoppst den ADC und schaltest den Multiplexer auf den negativen Input.
    • Du verbindest den AC mit dem ICP von Timer1
    • Du selektierst den gewünschten Flankenwechsel des AC und auch für den Input Capture

    Einige dieser Bits kannst du wahrscheinlich auch über Bascom Config Befehle setzen.

    Zum Umschalten der Eingänge musst du dann nur noch den Multiplexer umschalten und sicherheitshalber das ICP Flag löschen.
    Im schlechtesten Fall kann es dann 60ms dauern, bis alle 3 kanäle eingelesen wurden.

  8. #8
    Zitat Zitat von Searcher Beitrag anzeigen

    Das Fehler hat mich nicht schlafen lassen und mit dem neuen Jahr hat sich mir mindestens ein Fehler offenbart
    Die Variablen für Impulslaenge müssen wieder als Word deklariert werden. Also in dem letzten Code diese drei wieder als Word deklarieren.
    Code:
    Dim Impulslaenge_1 As Byte
    Dim Impulslaenge_2 As Byte
    Dim Impulslaenge_3 As Byte
    Das Jahr fängt definitiv gut an.

    DAS war der Fehler. Nachdem ich (wie Du gesagt hast) die Deklaration geändert habe, funktionierts. Ich konnte heute nur kurz testen, aber es sieht im Moment echt gut aus. Nur noch ganz selten hörbare und fühlbare Zuckungen, sichtbare Zuckungen waren praktisch nicht vorhanden. Werde morgen nochmal ausgiebig testen und den Code anschließend in mein Programm aufnehmen.

    Fortsetzung folgt...

    mfg
    Robert

  9. #9
    Erfahrener Benutzer Robotik Einstein Avatar von Searcher
    Registriert seit
    07.06.2009
    Ort
    NRW
    Beiträge
    1.703
    Blog-Einträge
    133
    Zitat Zitat von R2D2 Bastler Beitrag anzeigen
    Nur noch ganz selten hörbare und fühlbare Zuckungen, sichtbare Zuckungen waren praktisch nicht vorhanden. Werde morgen nochmal ausgiebig testen und den Code anschließend in mein Programm aufnehmen.
    Hört sich schon gut an, aber leider noch nicht semiperfekt.

    Zitat Zitat von for_ro
    Das ist gar nicht so wild.

    • Du setzt den Bandgap auf 1, dann brauchst du keinen externen positiven Eingang mehr.
    • Du stoppst den ADC und schaltest den Multiplexer auf den negativen Input.
    • Du verbindest den AC mit dem ICP von Timer1
    • Du selektierst den gewünschten Flankenwechsel des AC und auch für den Input Capture
    Das reizt mich, aber bevor ich/wir daran gehen noch eine Symptombehandlung. Jitterunterdrückung per SW-Hysterese nach diesem Muster zum Testen.

    Hab in der Hauptschleife nun eine SW-Hysterese untergebracht. Die Hysterese kann über die Konstante "Jitterausgleich" in Vielfachen von von 8µs eingestellt werden. Testweise auch kleinere Stufen, aber ich glaube, daß dann das Servo "weglaufen" könnte. Müßte man mal testen.

    Gruß
    Searcher

    Code:
    '===============================================================================
    'RC Eingang 1 an Pin 3 (PB1, PCINT9)
    'RC Eingang 2 an Pin 6 (PA7, PCINT7)
    'RC Eingang 3 an Pin 5 (PB2, INT0)
    'Servo 1 an Pin 13 (PA0)
    'Servo 2 an Pin 12 (PA1)
    'Servo 3 an Pin 11 (PA2)
    'Servo 4 an Pin 10 (PA3)
    '===============================================================================
    
    $regfile = "attiny84.dat"
    $crystal = 8000000                      'FuseBit CKDIV8 deaktivieren
    
    $hwstack = 50
    $swstack = 50
    $framesize = 50
    
    
    '-------------------------------------------------------------------------------------------------
    'Timer und konfigurieren
    '-------------------------------------------------------------------------------------------------
    
    Config Timer1 = Timer , Prescale = 8    'Timer für Einlesen RC Signale
    Start Timer1
    
    Config Timer0 = Timer , Prescale = 64   'Timer für Servoausgabe, Wert 125 entspricht 1ms, Wert 250 entspricht 2ms
    Enable Timer0
    On Timer0 Servoausgabe Nosave           'Register werden manuell in der ISR gesichert
    
    
    '-------------------------------------------------------------------------------------------------------------
    'Variablen definieren / Konstanten
    '-------------------------------------------------------------------------------------------------------------
    
    Const Jitterausgleich = 8               'Wert in µs um den sich gemessene Impulslaenge aendern darf/muss, bevor Servo gestellt wird
                                            'Nur in Vielfachen von 8 veraendern (8, 16, 32, ..)
    'Variablen fürs RC Einlesen
    Dim Rc_signal_1_start As Word
    Dim Rc_signal_2_start As Word
    Dim Rc_signal_3_start As Word
    
    Dim Rc_signal_1_stop As Word
    Dim Rc_signal_2_stop As Word
    Dim Rc_signal_3_stop As Word
    
    Dim Rc_signal_1_stop_flag As Byte
    Dim Rc_signal_2_stop_flag As Byte
    Dim Rc_signal_3_stop_flag As Byte
    
    
    Dim Impulslaenge_1 As Word
    Dim Impulslaenge_2 As Word
    Dim Impulslaenge_3 As Word
    
    Dim Impulslaenge_1_alt As Word
    Dim Impulslaenge_2_alt As Word
    Dim Impulslaenge_3_alt As Word
    Dim Impulslaengenaenderung As Integer   'wird nur einmal gebraucht, da nur Hilfswariable
    
    
    'Variablen für Berechnungen
    Dim Berechnung_1 As Word
    Dim Berechnung_2 As Word
    
    
    
    'Variablen für Servoausgabe
    Dim Kanal As Byte
    Dim Servoausgabe_1 As Byte
    Dim Servoausgabe_2 As Byte
    Dim Servoausgabe_3 As Byte
    Dim Servoausgabe_4 As Byte
    'Dim Pausen_variable As Byte
    
    
    '-------------------------------------------------------------------------------------------------
    'Einigen Variablen Werte zuweisen
    '-------------------------------------------------------------------------------------------------
    
    Kanal = 1
    'Pausen_variable = 0
    
    Impulslaenge_1_alt = 1500               'mit Servomittelstellung initialisieren (nicht essentiell)
    Impulslaenge_2_alt = 1500               'mit Servomittelstellung initialisieren (nicht essentiell)
    Impulslaenge_3_alt = 1500               'mit Servomittelstellung initialisieren (nicht essentiell)
    
    '-------------------------------------------------------------------------------------------------------------
    'Ein - Und Ausgang Festlegen
    '-------------------------------------------------------------------------------------------------------------
    
    Ddra = &B00001111                       'PA0 - PA3 werden Ausgänge
    Ddrb = &B00000000                       'PortB bleibt Eingang
    
    
    '-------------------------------------------------------------------------------------------------
    'Interrupt-Service-Routinen konfigurieren und freigeben
    '-------------------------------------------------------------------------------------------------
    
    'Info:
    'Alle Porta Pinchangeinterrupts sind in Bascom "PCINT0" zugeordnet.
    'Alle Portb Pinchangeinterrupts sind in Bascom "PCINT1" zugeordnet.
    
    
    Pcmsk1.pcint9 = 1                       'beim Flankenwechsel an PB1/PCINT9 (RC Eingang 1) Pinchangeinterrupt1 auslösen und in die Subroutine springen
    Enable Pcint1                           'Pinchangeinterrupt1 (1 weil auf PortB) zulassen
    On Pcint1 Rc_eingang_1 Nosave           'Register werden manuel in der ISR gesichert
    
    
    Pcmsk0.pcint7 = 1                       'beim Flankenwechsel an PA7/PCINT6 (RC Eingang 2) Pinchangeinterrupt0 auslösen und in die Subroutine springen
    Enable Pcint0                           'Pinchangeinterrupt0 (0 weil auf PortA) zulassen
    On Pcint0 Rc_eingang_2 Nosave           'Register werden manuel in der ISR gesichert
    
    
    Config Int0 = Change                    'beim Flankenwechsel an PB2/INT0 (RC Eingang 3) Int0 auslösen und in die Subroutine springen
    Enable Int0
    On Int0 Rc_eingang_3 Nosave             'Register werden manuel in der ISR gesichert
    
    Enable Interrupts
    
    
    '======================================================
    'Hauptprogramm
    '======================================================
    
    Do
    
      If Rc_signal_1_stop_flag = 1 Then     'Bearbeitung nur, wenn ISR Pulsende gefunden hat
          Disable Pcint1                    'Mögliche Korruption durch ISR vorbeugen
          Impulslaenge_1 = Rc_signal_1_stop - Rc_signal_1_start
          Enable Pcint1
          Rc_signal_1_stop_flag = 0
    
          Impulslaengenaenderung = Impulslaenge_1_alt - Impulslaenge_1       'SW-Hysterese
          If Abs(impulslaengenaenderung) >= Jitterausgleich Then
              Impulslaenge_1_alt = Impulslaenge_1
    
              Berechnung_1 = Impulslaenge_1
              Shift Berechnung_1 , Right , 3       'Division von Berechnung_1 durch 8
              If Berechnung_1 > 255 Then Berechnung_1 = 255       'zu hohe Werte abfangen
              If Berechnung_1 < 120 Then Berechnung_1 = 120       'zu kleine Werte abfangen
              Servoausgabe_1 = 256 - Berechnung_1       'Servoausgabe_ zum direkten Laden in TCNT0 vorbereiten (Cmd Load umgangen)
          End If
      End If
    
    
      If Rc_signal_2_stop_flag = 1 Then     'Bearbeitung nur, wenn ISR Pulsende gefunden hat
          Disable Pcint0                    'Mögliche Korruption durch ISR vorbeugen
          Impulslaenge_2 = Rc_signal_2_stop - Rc_signal_2_start
          Enable Pcint0
          Rc_signal_2_stop_flag = 0
    
          Impulslaengenaenderung = Impulslaenge_2_alt - Impulslaenge_2       'SW-Hysterese
          If Abs(impulslaengenaenderung) >= Jitterausgleich Then
              Impulslaenge_2_alt = Impulslaenge_2
    
              Berechnung_2 = Impulslaenge_2
              Shift Berechnung_2 , Right , 3       'Division von Berechnung_1 durch 8
              If Berechnung_2 > 255 Then Berechnung_2 = 255       'zu hohe Werte abfangen
              If Berechnung_2 < 120 Then Berechnung_2 = 120       'zu kleine Werte abfangen
              Servoausgabe_2 = 256 - Berechnung_2       'Servoausgabe_ zum direkten Laden in TCNT0 vorbereiten (Cmd Load umgangen)
          End If
      End If
    
      Servoausgabe_3 = 190
      Servoausgabe_4 = 190
    
    Loop
    
    
    
    '======================================================
    'ISR
    '======================================================
    
    Rc_eingang_1:
     $asm
       push r17                             'Register auf Stack sichern
       sbis pinb , 1                        'Skip next Instr if PINBx = 1
       rjmp Puls_ende1                      'Springe Puls_ende
       in r17 , tcnt1l                      'Timer1 low Byte holen
       sts {Rc_signal_1_start} , r17        'Speichere Timer1 low Byte nach Rc_signal_x_start low Byte
       in r17 , tcnt1h                      'Timer1 high Byte holen
       sts {Rc_signal_1_start} + 1 , r17    'Speichere Timer1 high Byte nach Rc_signal_x_start high Byte
       rjmp ende1                           'Springe zum Ende
      Puls_ende1:
       in r17 , tcnt1l                      'Timer1 low Byte holen
       sts {Rc_signal_1_stop} , r17         'Speichere Timer1 low Byte nach Rc_signal_x_stop low Byte
       in r17 , tcnt1h                      'Timer1 high Byte holen
       sts {Rc_signal_1_stop} + 1 , r17     'Speichere Timer1 high Byte nach Rc_signal_x_stop high Byte
       ldi r17 , 1
       sts {Rc_signal_1_stop_flag} , r17    'Setze Flag zur Bearbeitung von Impulslaenge in Hauptschleife
      Ende1:
       pop r17                              'Register vom Stack zurückholen
     $end Asm
    Return
    
    Rc_eingang_2:
     $asm
       push r17                             'Register auf Stack sichern
       sbis pinA , 7                        'Skip next Instr if PINBx = 1
       rjmp Puls_ende2                      'Springe Puls_ende
       in r17 , tcnt1l                      'Timer1 low Byte holen
       sts {Rc_signal_2_start} , r17        'Speichere Timer1 low Byte nach Rc_signal_x_start low Byte
       in r17 , tcnt1h                      'Timer1 high Byte holen
       sts {Rc_signal_2_start} + 1 , r17    'Speichere Timer1 high Byte nach Rc_signal_x_start high Byte
       rjmp ende2                           'Springe zum Ende
      Puls_ende2:
       in r17 , tcnt1l                      'Timer1 low Byte holen
       sts {Rc_signal_2_stop} , r17         'Speichere Timer1 low Byte nach Rc_signal_x_stop low Byte
       in r17 , tcnt1h                      'Timer1 high Byte holen
       sts {Rc_signal_2_stop} + 1 , r17     'Speichere Timer1 high Byte nach Rc_signal_x_stop high Byte
       ldi r17 , 1
       sts {Rc_signal_2_stop_flag} , r17    'Setze Flag zur Bearbeitung von Impulslaenge in Hauptschleife
      Ende2:
       pop r17                              'Register vom Stack zurückholen
     $end Asm
    Return
    
    Rc_eingang_3:
     $asm
       push r17                             'Register auf Stack sichern
       sbis pinB , 2                        'Skip next Instr if PINBx = 1
       rjmp Puls_ende3                      'Springe Puls_ende
       in r17 , tcnt1l                      'Timer1 low Byte holen
       sts {Rc_signal_3_start} , r17        'Speichere Timer1 low Byte nach Rc_signal_x_start low Byte
       in r17 , tcnt1h                      'Timer1 high Byte holen
       sts {Rc_signal_3_start} + 1 , r17    'Speichere Timer1 high Byte nach Rc_signal_x_start high Byte
       rjmp ende3                           'Springe zum Ende
      Puls_ende3:
       in r17 , tcnt1l                      'Timer1 low Byte holen
       sts {Rc_signal_3_stop} , r17         'Speichere Timer1 low Byte nach Rc_signal_x_stop low Byte
       in r17 , tcnt1h                      'Timer1 high Byte holen
       sts {Rc_signal_3_stop} + 1 , r17     'Speichere Timer1 high Byte nach Rc_signal_x_stop high Byte
       ldi r17 , 1
       sts {Rc_signal_3_stop_flag} , r17    'Setze Flag zur Bearbeitung von Impulslaenge in Hauptschleife
      Ende3:
       pop r17                              'Register vom Stack zurückholen
     $end Asm
    Return
    
    
    
    Servoausgabe:
    
     $asm
       push r16                             'Register auf Stack sichern
       in r16,sreg                          'Statusregister holen und halten
       push r17                             'Register auf Stack sichern
       lds r17 , {kanal}                    'hole Kanalnummer
    
       cpi r17 , 1                          'check Kanal und ...
       brne LABEL_KANAL_2                   '... "wenn nicht gleich" verzweige zum nächsten Kanal
       sbic porta , 0                       'Skip next instr. wenn PORTA.0 = 0 ist
       rjmp label_1                         'Springe zum LOW-setzen des Servosignals
       sts {kanal} , r17                    'Sichere Kanalnummer
       lds r17 , {Servoausgabe_1}           'Hole aufbereiteten Pulslängenwert für Timer0
       Out Tcnt0 , R17                      'Setze Timer0 mit Pulslängenwert
       sbi porta , 0                        'Setze Servosignal HIGH
       rjmp Ende_isr                        'Springe zum Ende der ISR
      Label_1:
       cbi porta , 0                        'Setze Servosignal nach LOW
       inc r17                              'Erhöhe Kanalnummer
    
    
      Label_kanal_2:                        'Bearbeitung von Kanal 2
       cpi r17 , 2                          'check Kanal und ...
       brne LABEL_KANAL_3                   '... "wenn nicht gleich" verzweige zum nächsten Kanal
       sbic porta , 1                       'Skip next instr. wenn PORTA.1 = 0 ist
       rjmp label_2                         'Springe zum LOW-setzen des Servosignals
       sts {kanal} , r17                    'Sichere Kanalnummer
       lds r17 , {Servoausgabe_2}           'Hole aufbereiteten Pulslängenwert für Timer0
       Out Tcnt0 , R17                      'Setze Timer0 mit Pulslängenwert
       sbi porta , 1                        'Setze Servosignal HIGH
       rjmp Ende_isr                        'Springe zum Ende der ISR
      Label_2:
       cbi porta , 1                        'Setze Servosignal nach LOW
       inc r17                              'Erhöhe Kanalnummer
    
    
      Label_kanal_3:                        'Bearbeitung von Kanal 3
       cpi r17 , 3                          'check Kanal und ...
       brne LABEL_KANAL_4                   '... "wenn nicht gleich" verzweige zum nächsten Kanal
       sbic porta , 2                       'Skip next instr. wenn PORTA.2 = 0 ist
       rjmp label_3                         'Springe zum LOW-setzen des Servosignals
       sts {kanal} , r17                    'Sichere Kanalnummer
       lds r17 , {Servoausgabe_3}           'Hole aufbereiteten Pulslängenwert für Timer0
       Out Tcnt0 , R17                      'Setze Timer0 mit Pulslängenwert
       sbi porta , 2                        'Setze Servosignal HIGH
       rjmp Ende_isr                        'Springe zum Ende der ISR
      Label_3:
       cbi porta , 2                        'Setze Servosignal nach LOW
       inc r17                              'Erhöhe Kanalnummer
    
    
      Label_kanal_4:                        'Bearbeitung von Kanal 4 mit anschließendem Pausenanfang
       cpi r17 , 4                          'check Kanal und ...
       brne LABEL_KANAL_5                   '... "wenn nicht gleich" verzweige zum nächsten Kanal
       sbic porta , 3                       'Skip next instr. wenn PORTA.3 = 0 ist
       rjmp label_4                         'Springe zum LOW-setzen des Servosignals
       sts {kanal} , r17                    'Sichere Kanalnummer
       lds r17 , {Servoausgabe_4}           'Hole aufbereiteten Pulslängenwert für Timer0
       Out Tcnt0 , R17                      'Setze Timer0 mit Pulslängenwert
       sbi porta , 3                        'Setze Servosignal HIGH
       rjmp Ende_isr                        'Springe zum Ende der ISR
      Label_4:
       cbi porta , 3                        'Setze Servosignal nach LOW
    
    'Pausenauffüllung
    
       'Pausenanfang
       inc r17
       sts {kanal} , r17                    'Sichere Kanalnummer
       ldi r17 , &B00000101                 'CS00 und CS02 für prescaler 1024 in Timer0 vorbereiten
       Out Tccr0b , R17                     'Timer0 läuft mit 128µs Auflösung
       ldi r17 , 162                        'Wert für ca 12ms bis zum nächsten OVF (162=256-94) bei prescaler 1024
       Out Tcnt0 , R17
       rjmp Ende_isr                        'Springe zum Ende der ISR
    
      'Pausenende
      Label_kanal_5:                        'Bearbeitung von Kanal 5 (Pausenende)
       ldi r17 , &B00000011                 'CS00 und CS01 für prescaler 64 in Timer0 vorbereiten
       Out Tccr0b , R17                     'Timer0 läuft wieder mit 8µs Auflösung
       ldi r17 , 1                          'Kanalnummer auf 1 setzen
       sts {kanal} , r17                    'Sichere Kanalnummer
      Ende_isr:
       pop r17                              'Register vom Stack zurückholen
       Out Sreg , R16                       'Statusregister zurückspeichern
       pop r16                              'Register vom Stack zurückholen
     $end Asm
    Return



    Hoffentlich liegt das Ziel auch am Weg
    ..................................................................Der Weg zu einigen meiner Konstruktionen

  10. #10
    Zitat Zitat von Searcher Beitrag anzeigen
    Müßte man mal testen.
    Na dafür bin ich ja da

    Ich hab den Code mal eingespielt, leider kam es zu Errors.

    Die Zeilen...
    Code:
    If Abs(impulslaengenaenderung) >= Jitterausgleich Then
    ...mag mein Bascom (1.11.9.8.) gar nicht.
    Keine Ahnung, ob's an meiner Version liegt.


    Habe den Code dann geändert in...
    Code:
    Dim A As Word 
    .
    .
    .
    A = Abs(impulslaengenaenderung)
          If A >= Jitterausgleich Then
    ... und schon klappte es.

    Die Servos würde ich nun als "jitterfrei" bezeichnen. Ich habe allerdings nicht die Möglichkeit, die tatsächlichen Werte zu betrachten (z.B. Oszi usw). Als Servos habe ich die billigsten HXT500 vom bösen Chinamann, sowie HS-82MG und HS-85MG dranhängen (Digitalservos hab ich keine zum Testen).

    Die Konstante "Jitterausgleich" habe ich auch mal auf 4 verkleinert, konnte aber keine Veränderung feststellen.

    mfg
    Robert

Seite 1 von 2 12 LetzteLetzte

Ähnliche Themen

  1. Mehrere analoge Werte über ein ADC einlesen möglich?
    Von HeXPloreR im Forum Elektronik
    Antworten: 2
    Letzter Beitrag: 07.08.2012, 17:18
  2. Schaltkreis für mehrere Servos
    Von Sebbokalypse im Forum Elektronik
    Antworten: 9
    Letzter Beitrag: 12.11.2009, 18:46
  3. Mehrere Signale umschalten
    Von flexxo im Forum Elektronik
    Antworten: 1
    Letzter Beitrag: 25.02.2007, 13:56
  4. Antworten: 9
    Letzter Beitrag: 02.04.2006, 17:53
  5. Mehrere Signale über einen Interrupt erkennen
    Von Minifriese im Forum Elektronik
    Antworten: 22
    Letzter Beitrag: 04.06.2004, 08:31

Berechtigungen

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

fchao-Sinus-Wechselrichter AliExpress