- Labornetzteil AliExpress         
Ergebnis 1 bis 10 von 60

Thema: Mehrere Servo-Signale einlesen, ggf. manipulieren, ausgeben

Hybrid-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #1
    Neuer Benutzer Öfters hier
    Registriert seit
    25.10.2010
    Beiträge
    26
    Hier mal meine aktuellen Ergebnisse

    Ich hoffe einigermaßen sinnvoll programmiert und verständlich kommentiert.
    Immerhin spreche ich GCC erst seit ner knappen Woche

    Gruß Basti

    Jitter konnte ich allein mit Analog Oszi nicht wirklich feststellen, und das obwohl ich alle Werte ca alle 100ms per UART ausgegeben habe.
    Evtl kann das ja mal jemand nachmessen der besseres Gerät hat?

    main.c
    Code:
    #include <avr/io.h>
    #include <stdlib.h>
    #include <stdint.h>
    
    
    #include "inout.h"
    
    
    /* define CPU frequency in Mhz here if not defined in Makefile */
    #ifndef F_CPU
    #define F_CPU 16000000UL
    #endif
    
    
    int main(void)
    {
        //Ein- und Ausgabe initialisieren
        init_inout();
    
    
        while(1)
        {
            set_ch(1,get_ch(1));
            set_ch(2,get_ch(2));
            set_ch(3,get_ch(3));
            set_ch(4,get_ch(4));
            set_ch(5,get_ch(5));
            set_ch(6,get_ch(6));
        }; //Endlosschleife
        
    }
    inout.h
    Code:
    //Name: inout.c
    //Autor: Bastian Schroll
    //Date:  31.12.2014
    //Description:
    //Ließt 6 getrennte Servo Kanäle über INT0 und INT1 ein
    //Die Eingangs Signale werden dem Programm per get_ch(KANAL) zur Verfügung gestellt
    //Nach Verarbeitung der Signale können diese per set_ch(KANAL,PULSLÄNGE) wieder Ausgegeben werden
    //Dabei werden die Signale auf PORTA.0 - .5 per Compare INT generiert
    
    
    #ifndef INOUT_H
    #define INOUT_H
    
    
    // **************************
    //         Prototypen
    // **************************
    void init_inout(void);//Initialisiert INT0 und INT1 sowie Timer1 und Timer0
    uint16_t get_ch(uint8_t channel); //Liefert aktuellen Wert zurück
    void set_ch(uint8_t channel, uint16_t puls); //Setzt Kanal 1-6 (Min. 1000 - Max. 2000)
    
    
    
    
    // **************************
    //         Deklarationen
    // **************************
    uint8_t (fail_flag); //Flag für Fail Safe Modus
    
    
    #endif
    inout.c
    Code:
    //Name: inout.c
    //Autor: Bastian Schroll
    //Date:  31.12.2014
    //Description:
    //Ließt 6 getrennte Servo Kanäle über INT0 und INT1 ein
    //Die Eingangs Signale werden dem Programm per get_ch(KANAL) zur Verfügung gestellt
    //Nach Verarbeitung der Signale können diese per set_ch(KANAL,PULSLÄNGE) wieder Ausgegeben werden
    //Dabei werden die Signale auf PORTA.0 - .5 per Compare INT generiert
    
    
    #include <avr/io.h>
    #include <stdint.h>
    #include <avr/interrupt.h>
    
    
    #include "inout.h"
    
    
    // **************************
    //         Prototypen
    // **************************
    void init_inout(void);//Initialisiert INT0 und INT1 sowie Timer1 und Timer0
    uint16_t get_ch(uint8_t channel); //Liefert aktuellen Wert zurück
    void set_ch(uint8_t channel, uint16_t puls); //Setzt Kanal 1-6 (Min. 1000 - Max. 2000)
    
    
    
    
    // **************************
    //         Deklarationen
    // **************************
    //IN
    volatile uint16_t (input_channel)[7]; //Array für die einzelnen Kanäle
    uint8_t (fail_flag); //Flag für Fail Safe Modus
    
    
    volatile uint16_t (input_channel_tmp)[7]; //Array für Timer1 Messwerte
    uint8_t (in_ch_cnt); //Counter für aktuellen Kanal
    uint8_t (fail_cnt); //Zähler für Fehlmessungen
    
    
    //OUT
    volatile uint16_t (output_channel)[7]; //Array für die einzelnen Kanäle
    
    
    uint32_t (sig_rest) = 320000; //Wird auf 20ms gesetzt und dann wird jede Ch Ausgabe abgezogen. Was übrig bleibt muss Pause sein
    uint8_t (out_ch_cnt); //Counter für aktuellen Kanal
    
    
    
    
    void init_inout(void)
    {
        //PORTA als Ausgang
        DDRA = 0b11111111;    
    
    
        //INT0 und INT1 als Eingang (vermutlich unnötig bei INT Konfiguration?)
        DDRD &= ~((1 << DDD2) | (1 << DDD3));
        //Beide INT auf steigene Flanke konfigurieren
        MCUCR |= ((1 << ISC01) | (1 << ISC00)); //INT0
        MCUCR |= ((1 << ISC11) | (1 << ISC10)); //INT1
        //INT0 und INT1 aktivieren
        GICR |= ((1 << INT0) | (1 << INT1));
    
    
        //Timer0 auf Pres 256 (~4ms)
        TCCR0 |= (1 << CS02);
        //Timer0 Overflow INT aktivieren
        TIMSK |= (1 << TOIE0);
    
    
        //Timer1 Prescaler auf 1 stellen
        TCCR1B |= (1 << CS10);
        //Timer1 CompareA Interrupt aktivieren
        TIMSK |= (1 << OCIE1A);
    
    
        //Interrupts anschalten
        sei();
    };
    
    
    
    
    //ISR von INT0
    ISR(INT0_vect)
    {    
        //speichere Zählerstand von Timer1
        input_channel_tmp[in_ch_cnt] = TCNT1;
        //Ch Zähler erhöhen
        in_ch_cnt++;
        //Timer0 zurücksetzen
        TCNT0 = 0;
        //bei letztem Kanal INT0 auf fallende Flanke
        if(in_ch_cnt == 6){MCUCR &= ~(1 << ISC00);}
    }
    
    
    
    
    //ISR von INT1
    ISR(INT1_vect)
    {
        //speichere Zählerstand von Timer1
        input_channel_tmp[in_ch_cnt] = TCNT1;
        //Ch Zähler erhöhen
        in_ch_cnt++;
        //Timer0 zurücksetzen
        TCNT0 = 0;
        //bei letztem Kanal INT0 auf fallende Flanke
        if(in_ch_cnt == 6){MCUCR &= ~(1 << ISC10);}
    }
    
    
    
    
    //Erkennt die lange Synronitäts Pause im Eingangssignal
    //Wenn länger als 4ms kein Interrupt passiert wird diese ISR geworfen.
    ISR(TIMER0_OVF_vect)
    {
        //Prüfen ob wirklich alle INT kamen (Alle Signale erfasst)
        if(in_ch_cnt == 7)
        {    
            //Wenn ja, Fail Flag und Zähler zurücksetzen
            fail_flag = 0;
            fail_cnt = 0;
            
            uint8_t i;
               for (i=1; i<=6; i++){
                //Aktuelles Eingangssignal = Endwert - Startwert
                input_channel[i] = input_channel_tmp[i] - input_channel_tmp[i-1];
               }
        }
        else
        {    
            //Wenn mehr als 5 Fehlmessungen detektiert wurden, wird das Fail Flag gesetzt
            fail_cnt++;
            if(fail_cnt >= 5){fail_flag = 1;}
        }
        //Kanalzähler zurücksetzen
        in_ch_cnt = 0; 
        //Beide INT auf steigene Flanke konfigurieren
        MCUCR |= ((1 << ISC01) | (1 << ISC00)); //INT0
        MCUCR |= ((1 << ISC11) | (1 << ISC10)); //INT1
    }
    
    
    
    
    //Kümmert sich um die Ausgabe der 6 Signale
    ISR(TIMER1_COMPA_vect)
    {        
        //Wenn Ch1 beginnt, PORTA.0 auf High
        if(out_ch_cnt == 0)
        {
            PORTA = 1;
        }    
    
    
        //Solange noch nicht alle Channel abgearbeitet
        if(out_ch_cnt <= 6)
        {
            //Bit in PORTA weiter schieben
            PORTA = (1 << out_ch_cnt);
            //Kanal Zähler erhöhen
            out_ch_cnt ++;
            //CompareA Register von T1 auf den Wert des Kanals setzen
            OCR1A = TCNT1 + output_channel[out_ch_cnt];
            //Zeit von den 20ms Gesamtlänge abziehen
            sig_rest -= output_channel[out_ch_cnt];
        }
        else //Wenn alle Kanäle durch sind
        {    
            //PORTA abschalten
            PORTA = 0;
            //Prüfen ob noch mehr Zeit, als ein kompletter Durchlauf abzuwarten ist
            if(sig_rest > 65536)
            {
                //Einen vollen Zyklus abwarten und vom Rest-Zeitzähler abziehen
                OCR1A = TCNT1 + 65536;
                sig_rest -= 65536;    
            }
            else//Wenn kein kompletter Durchlauf mehr möglich ist
            {
                //Die restliche Zeit warten und alles für einen neuen Durchgang voreinstellen
                OCR1A = TCNT1 + sig_rest;    
                out_ch_cnt = 0;    
                sig_rest = 320000 - 60000; //Entsprich 20ms bei Timer1 16MHZ/Prescaler1    
                //Da dir ISR natürlich auch ein wenig Rechnenzeit verbraucht ziehen wir einfach 60.000 Ticks ab
                //Damit kommen wir dann laut Oszi auf exakt 20ms Versatz zwischen den Pulsen (ausporbiert)    
            }
        }
    }
    
    
    
    
    //Liefert Wert des Kanals zurück
    uint16_t get_ch(uint8_t channel)
    {
        return input_channel[channel] / 16;
    }
    
    
    
    
    //Zum setzen einzelner Kanäle
    void set_ch(uint8_t channel, uint16_t puls)
    {    
        //Wert auf Min und Max begrenzen
        if(puls < 1000){puls = 1000;}
        else if(puls > 2000){puls = 2000;}
    
    
        output_channel[channel] = puls * 16;
    }
    Geändert von Bomberpilot (31.12.2014 um 11:40 Uhr)

Ähnliche Themen

  1. Mehrere RC Signale einlesen und mehrere Servos ausgeben
    Von R2D2 Bastler im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 74
    Letzter Beitrag: 10.01.2022, 08:35
  2. RC-Signal einlesen verändern und wieder ausgeben.
    Von DanielSan im Forum Arduino -Plattform
    Antworten: 1
    Letzter Beitrag: 21.03.2013, 11:58
  3. Atmel128 Spannungen einlesen und Ausgeben (Display3000)
    Von Gantenbein im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 2
    Letzter Beitrag: 31.08.2007, 21:41
  4. Mehrere Signale umschalten
    Von flexxo im Forum Elektronik
    Antworten: 1
    Letzter Beitrag: 25.02.2007, 13:56
  5. Servoimpulse einlesen und ausgeben
    Von moelski im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 3
    Letzter Beitrag: 21.08.2006, 07:24

Berechtigungen

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

Solar Speicher und Akkus Tests