- 12V Akku mit 280 Ah bauen         
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
    Zitat Zitat von Searcher Beitrag anzeigen
    Ist es richtig, daß es 6 Servosignale (jedes zwischen 1ms und 2ms high) auf 6 verschiedenen Leitungen sind.

    Wenn das erste Signal low geht, geht direkt ohne Pause das zweite Signal auf high. Geht das auf low, sofort das dritte auf high usw.

    Da alle Signale verschiedene Längen haben können, ist die Schlußpause bis zum 20ms Raster, bis das erste Signal wieder high wird, unbestimmt lang und ist abhängig von den high Zeiten aller 6 Signale. (20ms minus Gesamthighzeit = Lowschlußpause)

    Du hast jetzt das erste, dritte, fünfte Signal per Dioden zusammengeführt und auf INT0 Pin vom µC gelegt. Das Gleiche mit dem zweiten, vierten und sechsten Signal auf INT1.
    Bis hierhin absolut korrekt...

    Zitat Zitat von Searcher Beitrag anzeigen
    Nun möchtest Du die Signale messen, modifizieren und in einem 4ms Raster ausgeben.

    Erstes Signal ab Zeitpunkt 0 ausgeben, zB 1,5ms lang high, dann low und bis 4ms warten, dann zweites Signal auf high, zB 1,2ms high, dann low, wieder bis Zeitpunkt 8ms warten, nächstes high usw.

    Die Ausgabe der Signale sollen alle auf dem gleichen µC Pin passieren.
    Will die 6 Signale wieder getrennt voneinander ausgeben. Die sollen dann quasi direkt zu den einzelnen Servos.

    Die Ausgabe wird jetzt etwas anders realisiert.
    Die mache ich jetzt im Prinzip etwa so wie sie auch mein Empfänger macht.
    Schiebe einfach ein Bit durchs Port und warte per Compare Register immer so lange wie es an sein muss. (Dadruch ensteht der direkte Wechsel - ein Pin geht LOW, anderer gleichzeitig HIGH)
    Danach warte ich dann noch so lange bis 20ms voll sind.

    Das ganze mit Timer1 und Prescaler 1 (Eingabe UND Ausgabe) also mehr Auflösung wird sich nicht rausholen lassen.
    (Aktuell läuft Timer0 nur mit um die lange Pause zum synchronisieren zu erkennen. Der wird bei jedem INT resetet, läuft er nach 4ms über, gabs zu lange kein Signal mehr, also wird alles auf Anfang gestellt)

    Aktuell bin ich soweit, das nun beides funktioniert. Jitter scheint extrem gering zu sein, kann gerade nicht genau messen. Probiere ich aber noch.
    Muss noch optimieren. Aber ich reiche natürlich alles an Infos nach

    Gruß Basti

    EDIT:
    Wie am besten mit Analog Oszi den Jitter messen?
    Bekomm die Flanke leider nur bis 200uS/Div. ins Bild. Dort kann man auf jeden Fall einen Jitter < 10uS erahnen.
    Vermutlich noch kleiner, aber das hat dann mit messen weis Gott nix mehr zu tun.
    Geändert von Bomberpilot (28.12.2014 um 00:22 Uhr)

  2. #2
    Aktuell bin ich soweit, das nun beides funktioniert. Jitter scheint extrem gering zu sein, kann gerade nicht genau messen. Probiere ich aber noch.
    Muss noch optimieren. Aber ich reiche natürlich alles an Infos nach
    Ja, Ich freue mich auf diese Informationen. Das klingt sehr gut, das beides funktioniert.

    Gruß
    Enre



    iphone 6 tasche
    Geändert von bigbenball (31.12.2014 um 01:59 Uhr)

  3. #3
    Erfahrener Benutzer Robotik Einstein Avatar von wkrug
    Registriert seit
    17.08.2006
    Ort
    Dietfurt
    Beiträge
    2.237
    Nachtrag:
    Ich hab mir mal nen ATMEGA88 beschafft und meine Idee mit den PinChanges realisiert.
    Das klappt auch, wenn alle Servoimpulse zur gleichen Zeit eintreffen.
    Code:
    /*****************************************************
    This program was produced by the
    CodeWizardAVR V1.25.3 Standard
    Automatic Program Generator
    © Copyright 1998-2007 Pavel Haiduc, HP InfoTech s.r.l.
    http://www.hpinfotech.com
    
    Project : Einzelimpulse zu Summensignal
    Version : 1.0
    Date    : 30.12.2014
    Author  :                    
    Company : Germany         
    Comments: 
    
    
    Chip type           : ATmega88
    Program type        : Application
    Clock frequency     : 16,00000 MHz
    Memory model        : Small
    External SRAM size  : 0
    Data Stack size     : 256
    
    Zeitversatz beim Einlesen der Impulse 15µs!
    *****************************************************/
    
    /********
    PC0 = Kanal 1
    PC1 = Kanal 3
    PC2 = Kanal 5
    PC3 = Kanal 7
    PD0 = Kanal 2
    PD1 = Kanal 4
    PD2 = Kanal 6
    PD3 = Kanal 8
    PB1 = Summensignalausgang
    PB2 = Syncsignal startet bei Pausenbeginn
    ********/
    
    #include <mega88.h>
    
    volatile unsigned int ui_timerold[8];    //Speicherwerte für die Steigende Flanke der entsprecheden Kanäle
    volatile unsigned int ui_pulslengh[8]={3000,3000,3000,3000,3000,3000,3000,3000};   //Ermittelte Pulslängen
    volatile unsigned int ui_lastchange;       //Letzter Impulsstart für Summensignalgenerierung
    volatile unsigned char uc_oldgerade=0;     //Zwischenspeicher für den alten Zustand der geraden Kanäle 2,4,6,8
    volatile unsigned char uc_oldungerade=0; //Zwischenspeicher für den alten Zustand der geraden Kanäle 1,3,5,7
    volatile unsigned char uc_cyclecount;     //Zyklenzähler für die Impulsausgabe
    #define maxcycle 17                       //Maximale Zyklenzahl für die Impulsausgabe
    #define minlengh 1200                      //Minimal zulässige Impulslänge 600µs
    #define midlengh 3000                      //Servo Mittelstellung
    #define maxlengh 5400                     //Maximal zulässige Impulslänge 2700µs
    #define interpulspause 1000                //1000 = 500µs
    #define interframepause 12000              //12000 = 6ms Interframepause
    
    //#define normal                          //Bestimmt ob die Impulsausgabe normal oder invers geschehen soll
    //#define revers                          //zur Zeit noch nicht implementiert - Bedingte Assemblierung
    #define portsungerade PINC                //Ungerade Kanäle auf Port C
    #define portsgerade PIND                  //Gerade Kanäle auf Port D
    #define outport PORTB.1                   //Summen Ausgangssignal
    #define syncport PORTB.2                  //Sync Signal für Oszilloskop
    
    // Pin change 8-14 interrupt service routine Kanal 1,3,5,7
    interrupt [PCINT1] void pin_change_isr1(void)
    {
    unsigned char uc_portungerade,uc_result,uc_low,uc_high;
    unsigned int ui_timer;
    uc_portungerade=portsungerade;
    uc_low=TCNT1L;
    uc_high=TCNT1H;
    ui_timer=uc_high;
    ui_timer=ui_timer<<8;
    ui_timer+=uc_low;
    uc_portungerade&=0x0F;
    uc_result=uc_portungerade^uc_oldungerade;
    if(uc_result&0x01)
        {
        if(uc_portungerade&0x01)        //Es war ne steigende Flanke
            {
            ui_timerold[0]=ui_timer;
            }
        else                            //Es war ne fallende Flanke
            {
            ui_pulslengh[0]=ui_timer-ui_timerold[0];
            };
        }
    
    if(uc_result&0x02)
        {
        if(uc_portungerade&0x02)        //Es war ne steigende Flanke
            {
            ui_timerold[2]=ui_timer;
            }
        else                            //Es war ne fallende Flanke
            {
            ui_pulslengh[2]=ui_timer-ui_timerold[2];
            };
        }
        
    if(uc_result&0x04)
        {
        if(uc_portungerade&0x04)        //Es war ne steigende Flanke
            {
            ui_timerold[4]=ui_timer;
            }
        else                            //Es war ne fallende Flanke
            {
            ui_pulslengh[4]=ui_timer-ui_timerold[4];
            };
        }
        
    if(uc_result&0x08)
        {
        if(uc_portungerade&0x08)        //Es war ne steigende Flanke
            {
            ui_timerold[6]=ui_timer;
            }
        else                            //Es war ne fallende Flanke
            {
            ui_pulslengh[6]=ui_timer-ui_timerold[6];
            };
        }
    uc_oldungerade=uc_portungerade;
    }
    
    // Pin change 16-23 interrupt service routine Kanal 2,4,6,8
    interrupt [PCINT2] void pin_change_isr2(void)
    {
    unsigned char uc_portgerade,uc_result,uc_low,uc_high;
    unsigned int ui_timer;
    uc_portgerade=portsgerade;
    uc_low=TCNT1L;
    uc_high=TCNT1H;
    ui_timer=uc_high;
    ui_timer=ui_timer<<8;
    ui_timer+=uc_low;
    uc_portgerade&=0x0F;
    uc_result=uc_portgerade^uc_oldgerade;
    if(uc_result&0x01)
        {
        if(uc_portgerade&0x01)        //Es war ne steigende Flanke
            {
            ui_timerold[1]=ui_timer;
            }
        else                            //Es war ne fallende Flanke
            {
            ui_pulslengh[1]=ui_timer-ui_timerold[1];
            };
        }
    
    if(uc_result&0x02)
        {
        if(uc_portgerade&0x02)        //Es war ne steigende Flanke
            {
            ui_timerold[3]=ui_timer;
            }
        else                            //Es war ne fallende Flanke
            {
            ui_pulslengh[3]=ui_timer-ui_timerold[3];
            };
        }
        
    if(uc_result&0x04)
        {
        if(uc_portgerade&0x04)        //Es war ne steigende Flanke
            {
            ui_timerold[5]=ui_timer;
            }
        else                            //Es war ne fallende Flanke
            {
            ui_pulslengh[5]=ui_timer-ui_timerold[5];
            };
        }
        
    if(uc_result&0x08)
        {
        if(uc_portgerade&0x08)        //Es war ne steigende Flanke
            {
            ui_timerold[7]=ui_timer;
            }
        else                            //Es war ne fallende Flanke
            {
            ui_pulslengh[7]=ui_timer-ui_timerold[7];
            };
        }
    uc_oldgerade=uc_portgerade;
    }
    
    // Timer 1 output compare A interrupt service routine
    interrupt [TIM1_COMPA] void timer1_compa_isr(void)
    {
    unsigned char uc_low,uc_high;
    unsigned int ui_buffer;
    switch(uc_cyclecount)
        {
        case 0:                       //Die Pausen
        syncport=0;                    //Sychronosationsimpuls stoppen
        outport=1;
        uc_low=OCR1AL;
        uc_high=OCR1AH;
        ui_buffer=uc_high;              //Aktuelle Werte holen
        ui_buffer=(ui_buffer<<8)+uc_low;
        ui_lastchange=ui_buffer;
        ui_buffer+=interpulspause;     //Preimpuls dazuzählen und einfügen
        uc_low=ui_buffer&0x00FF;
        uc_high=(ui_buffer>>8)&0x00FF;
        OCR1AH=uc_high;
        OCR1AL=uc_low;
        break;
        
        case 1:
        outport=0;                     //Der erste Impuls
        ui_buffer=ui_lastchange+ui_pulslengh[0];
        uc_low=ui_buffer&0x00FF;       //OCR Register für nächsten Interrupt vorbelegen
        uc_high=(ui_buffer>>8)&0x00FF;
        OCR1AH=uc_high;
        OCR1AL=uc_low;
        break;
        
        case 2:                       //Pausen zwischen den Impulsen einfügen
        case 4:
        case 6:
        case 8:
        case 10:
        case 12:
        case 14:
        case 16:
        outport=1;
        uc_low=OCR1AL;
        uc_high=OCR1AH;
        ui_buffer=uc_high;              //Aktuelle Werte holen
        ui_buffer=(ui_buffer<<8)+uc_low;
        ui_lastchange=ui_buffer;
        ui_buffer+=interpulspause;     //Pause zwischen den Impulsen dazuzählen und einfügen
        uc_low=ui_buffer&0x00FF;
        uc_high=(ui_buffer>>8)&0x00FF;
        OCR1AH=uc_high;
        OCR1AL=uc_low;
        break;
        
        case 3:
        outport=0;                     //Der zweite Impuls
        ui_buffer=ui_lastchange+ui_pulslengh[1];
        uc_low=ui_buffer&0x00FF;       //OCR Register für nächsten Interrupt vorbelegen
        uc_high=(ui_buffer>>8)&0x00FF;
        OCR1AH=uc_high;
        OCR1AL=uc_low;
        break;
        
        case 5:
        outport=0;                     //Der dritte Impuls
        ui_buffer=ui_lastchange+ui_pulslengh[2];
        uc_low=ui_buffer&0x00FF;       //OCR Register für nächsten Interrupt vorbelegen
        uc_high=(ui_buffer>>8)&0x00FF;
        OCR1AH=uc_high;
        OCR1AL=uc_low;
        break;
        
        case 7:
        outport=0;                     //Der vierte Impuls
        ui_buffer=ui_lastchange+ui_pulslengh[3];
        uc_low=ui_buffer&0x00FF;       //OCR Register für nächsten Interrupt vorbelegen
        uc_high=(ui_buffer>>8)&0x00FF;
        OCR1AH=uc_high;
        OCR1AL=uc_low;
        break; 
        
        case 9:
        outport=0;                     //Der fünfte Impuls
        ui_buffer=ui_lastchange+ui_pulslengh[4];
        uc_low=ui_buffer&0x00FF;       //OCR Register für nächsten Interrupt vorbelegen
        uc_high=(ui_buffer>>8)&0x00FF;
        OCR1AH=uc_high;
        OCR1AL=uc_low;
        break; 
        
        case 11:
        outport=0;                     //Der sechste Impuls
        ui_buffer=ui_lastchange+ui_pulslengh[5];
        uc_low=ui_buffer&0x00FF;       //OCR Register für nächsten Interrupt vorbelegen
        uc_high=(ui_buffer>>8)&0x00FF;
        OCR1AH=uc_high;
        OCR1AL=uc_low;
        break; 
        
        case 13:
        outport=0;                     //Der siebte Impuls
        ui_buffer=ui_lastchange+ui_pulslengh[6];
        uc_low=ui_buffer&0x00FF;       //OCR Register für nächsten Interrupt vorbelegen
        uc_high=(ui_buffer>>8)&0x00FF;
        OCR1AH=uc_high;
        OCR1AL=uc_low;
        break; 
        
        case 15:
        outport=0;                     //Der achte Impuls
        ui_buffer=ui_lastchange+ui_pulslengh[7];
        uc_low=ui_buffer&0x00FF;       //OCR Register für nächsten Interrupt vorbelegen
        uc_high=(ui_buffer>>8)&0x00FF;
        OCR1AH=uc_high;
        OCR1AL=uc_low;
        break; 
        
        case 17:
        syncport=1;                    //Syncpuls Starten
        outport=0;
        ui_buffer=OCR1AH;              //Aktuelle Werte holen
        ui_buffer=(ui_buffer<<8)+OCR1AL;
        ui_buffer+=interframepause;    //Pause zwischen den Frames also nach 8 Impulsen einfügen
        uc_low=ui_buffer&0x00FF;
        uc_high=(ui_buffer>>8)&0x00FF;
        OCR1AH=uc_high;
        OCR1AL=uc_low;
        break;
        
        }
    uc_cyclecount++;
    if(uc_cyclecount>maxcycle){uc_cyclecount=0;}
    }
    
    // Declare your global variables here
    
    void main(void)
    {
    // Declare your local variables here
    unsigned char uc_i;
    // Crystal Oscillator division factor: 1
    #pragma optsize-
    CLKPR=0x80;
    CLKPR=0x00;
    #ifdef _OPTIMIZE_SIZE_
    #pragma optsize+
    #endif
    
    // Input/Output Ports initialization
    // Port B initialization
    // Func7=In Func6=In Func5=In Func4=In Func3=In Func2=Out Func1=Out Func0=In 
    // State7=T State6=T State5=T State4=T State3=T State2=T State1=0 State0=T 
    PORTB=0x00;
    DDRB=0x06;
    
    // Port C initialization
    // Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
    // State6=T State5=T State4=T State3=P State2=P State1=P State0=P 
    PORTC=0x0F;
    DDRC=0x00;
    
    // Port D initialization
    // Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
    // State7=T State6=T State5=T State4=T State3=P State2=P State1=P State0=P 
    PORTD=0x0F;
    DDRD=0x00;
    
    // Timer/Counter 0 initialization
    // Clock source: System Clock
    // Clock value: Timer 0 Stopped
    // Mode: Normal top=FFh
    // OC0A output: Disconnected
    // OC0B output: Disconnected
    TCCR0A=0x00;
    TCCR0B=0x00;
    TCNT0=0x00;
    OCR0A=0x00;
    OCR0B=0x00;
    
    // Timer/Counter 1 initialization
    // Clock source: System Clock
    // Clock value: 1000,000 kHz
    // Mode: Normal top=FFFFh
    // OC1A output: Discon.
    // OC1B output: Discon.
    // Noise Canceler: Off
    // Input Capture on Falling Edge
    // Timer 1 Overflow Interrupt: Off
    // Input Capture Interrupt: Off
    // Compare A Match Interrupt: On
    // Compare B Match Interrupt: Off
    TCCR1A=0x00;
    TCCR1B=0x02;
    TCNT1H=0x00;
    TCNT1L=0x00;
    ICR1H=0x00;
    ICR1L=0x00;
    OCR1AH=0x00;
    OCR1AL=0x00;
    OCR1BH=0x00;
    OCR1BL=0x00;
    
    // Timer/Counter 2 initialization
    // Clock source: System Clock
    // Clock value: Timer 2 Stopped
    // Mode: Normal top=FFh
    // OC2A output: Disconnected
    // OC2B output: Disconnected
    ASSR=0x00;
    TCCR2A=0x00;
    TCCR2B=0x00;
    TCNT2=0x00;
    OCR2A=0x00;
    OCR2B=0x00;
    
    // External Interrupt(s) initialization
    // INT0: Off
    // INT1: Off
    // Interrupt on any change on pins PCINT0-7: Off
    // Interrupt on any change on pins PCINT8-14: On
    // Interrupt on any change on pins PCINT16-23: On
    EICRA=0x00;
    EIMSK=0x00;
    PCICR=0x06;
    PCMSK1=0x0F;
    PCMSK2=0x0F;
    PCIFR=0x06;
    
    // Timer/Counter 0 Interrupt(s) initialization
    TIMSK0=0x00;
    // Timer/Counter 1 Interrupt(s) initialization
    TIMSK1=0x02;
    // Timer/Counter 2 Interrupt(s) initialization
    TIMSK2=0x00;
    
    // Analog Comparator initialization
    // Analog Comparator: Off
    // Analog Comparator Input Capture by Timer/Counter 1: Off
    ACSR=0x80;
    ADCSRB=0x00;
    
    while(PINC.0==0);              //Warten auf Impulse
    while(PINC.0>0);
    // Watchdog Timer initialization
    // Watchdog Timer Prescaler: OSC/128k
    // Watchdog Timer interrupt: Off
    #pragma optsize-
    #asm("wdr")
    WDTCSR=0x1E;
    WDTCSR=0x0E;
    #ifdef _OPTIMIZE_SIZE_
    #pragma optsize+
    #endif
    
    // Global enable interrupts
    #asm("sei")
    
    while (1)
          {
          #asm("wdr")
          for (uc_i=0;uc_i<8;uc_i++)
            {
            if(ui_pulslengh[uc_i]<minlengh||ui_pulslengh[uc_i]>maxlengh)
                {
                ui_pulslengh[uc_i]=midlengh;
                }
            };
          };
    }
    Der Code braucht 630 Words, also 1260Byte
    Geändert von wkrug (30.12.2014 um 10:42 Uhr)

  4. #4
    Neuer Benutzer Öfters hier
    Registriert seit
    25.10.2010
    Beiträge
    26
    Gut zu wissen, den Code werde ich mal in der Hinterhand halten.
    Allerdings ganz schön viel Code, im Vergleich zu meinem ^^
    Wie groß ist das ganze kompilliert? Mein Code kommt auf 1634 byte, lauffähig...

    Gruß Basti

  5. #5
    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
  •  

12V Akku bauen