- MultiPlus Wechselrichter Insel und Nulleinspeisung Conrad         
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
    Erfahrener Benutzer Robotik Visionär
    Registriert seit
    26.11.2005
    Ort
    bei Uelzen (Niedersachsen)
    Beiträge
    7.942
    Bei 2 Interrupts kann man ICP und den analogen Komparator (Vergleich mit 1,1 V Ref intern) nutzen. Auf den beiden Pins kann man die ICP Funktion nutzen, und damit wenigstens die Messung unabhängig von Latenzzeiten machen, ggf. auch ganz ohne Interrupts.

  2. #2
    Neuer Benutzer Öfters hier
    Registriert seit
    25.10.2010
    Beiträge
    26
    Hab gestern noch 2 Stunden probiert, irgendwie bekomm ich nur sinnlose Werte raus :-/
    Wie viel würde es denn wohl etwa an Ressourcen bringen, auf C umzusteigen?

    Gruß Basti

  3. #3
    Erfahrener Benutzer Robotik Einstein Avatar von wkrug
    Registriert seit
    17.08.2006
    Ort
    Dietfurt
    Beiträge
    2.188
    Hab gestern noch 2 Stunden probiert, irgendwie bekomm ich nur sinnlose Werte raus
    Bevor Du da die Flinte ins Korn wirfst, guck doch erst mal wo es hängt.
    Simulieren heisst hier das Zauberwort.
    Auch ein mit Bascom generiertes Programm sollte sich mit AVR Studio simulieren lassen.
    Dann kriegst Du schon raus ob es ein Timing Problem, oder ein Softwarefehler ist.

  4. #4
    Neuer Benutzer Öfters hier
    Registriert seit
    25.10.2010
    Beiträge
    26
    Zitat Zitat von wkrug Beitrag anzeigen
    Bevor Du da die Flinte ins Korn wirfst ...
    Niemals! Dann wirds ja nie fertig. Außerdem kann man ne Flinte immer mal gebrauchen...
    Ich hoff übers Wochenende, oder dann über die Feiertage findet sich ein bisschen Zeit da noch etwas rumzuprobieren.
    Evtl. bekomm ich das Programm ja im AVR Studio Sim zum laufen, muss ich mal schaun.

    Gruß Basti

  5. #5
    Erfahrener Benutzer Robotik Einstein Avatar von wkrug
    Registriert seit
    17.08.2006
    Ort
    Dietfurt
    Beiträge
    2.188
    Ok, Ich bin dann mal so frech und hau nen Code raus.
    Im Simulator hab ich das mal getestet - Da scheints zu funktionieren.
    Mit nem Controller kann ich leider nicht testen ( Kein ATMEGA 88 hier ).
    Ich hab das Prinzip mit dem Pinchange umgesetzt.
    Die Simulation war mit 8MHz, dabei kann ein Versatz ( Jitter ) von 30µS bei den Signalen entstehen.

    Code:
    /*****************************************************
    
    Project : Einzelimpulse zu Summensignal
    Version : 0.1
    Date    : 19.12.2014
    Author  :                  
    Company :          
    Comments: 
    
    
    Chip type           : ATmega88
    Program type        : Application
    Clock frequency     : 8,000000 MHz
    Memory model        : Small
    External SRAM size  : 0
    Data Stack size     : 256
    
    Zeitversatz beim Einlesen der Impulse 30µ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
    ********/
    
    #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]={1500,1500,1500,1500,1500,1500,1500,1500};   //Ermittelte Pulslängen
    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 15
    #define interpulspause 50                 //50 = 50µs
    #define interframepause 4000              //4000 = 4ms Interframepause
    
    //#define normal                          //Bestimmt ob die Impulsausgabe normal oder invers geschehen soll
    //#define revers
    #define portsungerade PINC
    #define portsgerade PIND
    #define outport PORTB.1
    // Pin change 8-14 interrupt service routine
    interrupt [PCINT1] void pin_change_isr1(void)
    {
    unsigned char uc_portungerade,uc_result;
    unsigned int ui_timer;
    ui_timer=TCNT1H;
    ui_timer=(ui_timer<<8)+TCNT1L;
    uc_portungerade=portsungerade&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
    interrupt [PCINT2] void pin_change_isr2(void)
    {
    unsigned char uc_portgerade,uc_result;
    unsigned int ui_timer;
    ui_timer=TCNT1H;
    ui_timer=(ui_timer<<8)+TCNT1L;
    uc_portgerade=portsgerade&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:
        outport=1;                     //Der erste Impuls
        ui_buffer=OCR1AH;              //Aktuelle Werte holen
        ui_buffer=(ui_buffer<<8)+OCR1AL;
        ui_buffer+=ui_pulslengh[0];    //Pulslänge dazuzählen
        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 1:                       //Die Pausen
        case 3:
        case 5:
        case 7:
        case 9:
        case 11:
        case 13:
        outport=0;
        ui_buffer=OCR1AH;              //Aktuelle Werte holen
        ui_buffer=(ui_buffer<<8)+OCR1AL;
        ui_buffer+=interpulspause;
        uc_low=ui_buffer&0x00FF;
        uc_high=(ui_buffer>>8)&0x00FF;
        OCR1AH=uc_high;
        OCR1AL=uc_low;
        break;
        case 2:
        outport=1;                     //Der zweite Impuls
        ui_buffer=OCR1AH;              //Aktuelle Werte holen
        ui_buffer=(ui_buffer<<8)+OCR1AL;
        ui_buffer+=ui_pulslengh[1];    //Pulslänge dazuzählen
        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 4:
        outport=1;                     //Der dritte Impuls
        ui_buffer=OCR1AH;              //Aktuelle Werte holen
        ui_buffer=(ui_buffer<<8)+OCR1AL;
        ui_buffer+=ui_pulslengh[2];    //Pulslänge dazuzählen
        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 6:
        outport=1;                     //Der vierte Impuls
        ui_buffer=OCR1AH;              //Aktuelle Werte holen
        ui_buffer=(ui_buffer<<8)+OCR1AL;
        ui_buffer+=ui_pulslengh[3];    //Pulslänge dazuzählen
        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 8:
        outport=1;                     //Der fünfte Impuls
        ui_buffer=OCR1AH;              //Aktuelle Werte holen
        ui_buffer=(ui_buffer<<8)+OCR1AL;
        ui_buffer+=ui_pulslengh[4];    //Pulslänge dazuzählen
        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 10:
        outport=1;                     //Der sechste Impuls
        ui_buffer=OCR1AH;              //Aktuelle Werte holen
        ui_buffer=(ui_buffer<<8)+OCR1AL;
        ui_buffer+=ui_pulslengh[5];    //Pulslänge dazuzählen
        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 12:
        outport=1;                     //Der siebte Impuls
        ui_buffer=OCR1AH;              //Aktuelle Werte holen
        ui_buffer=(ui_buffer<<8)+OCR1AL;
        ui_buffer+=ui_pulslengh[6];    //Pulslänge dazuzählen
        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 14:
        outport=1;                     //Der achte Impuls
        ui_buffer=OCR1AH;              //Aktuelle Werte holen
        ui_buffer=(ui_buffer<<8)+OCR1AL;
        ui_buffer+=ui_pulslengh[7];    //Pulslänge dazuzählen
        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;
        ui_buffer=OCR1AH;              //Aktuelle Werte holen
        ui_buffer=(ui_buffer<<8)+OCR1AL;
        ui_buffer+=interframepause;
        uc_low=ui_buffer&0x00FF;
        uc_high=(ui_buffer>>8)&0x00FF;
        OCR1AH=uc_high;
        OCR1AL=uc_low;
        break;
        
        default:
        uc_cyclecount=0;
        }
    uc_cyclecount++;
    if(uc_cyclecount>maxcycle){uc_cyclecount=0;}
    }
    
    // Declare your global variables here
    
    void main(void)
    {
    // Declare your local variables here
    
    // 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=In Func1=Out Func0=In 
    // State7=T State6=T State5=T State4=T State3=T State2=T State1=0 State0=T 
    PORTB=0x00;
    DDRB=0x02;
    
    // 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;
    
    // 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")
          
          // Place your code here
    
          };
    }
    Auch wenn mehrere Ports ihre Level zu gleichen Zeit ändern, sollte der Code funzen.
    Geändert von wkrug (19.12.2014 um 20:11 Uhr)

  6. #6
    Erfahrener Benutzer Robotik Visionär
    Registriert seit
    26.11.2005
    Ort
    bei Uelzen (Niedersachsen)
    Beiträge
    7.942
    Auch Bascom hat einen internen Simulator. So grundlegende Dinge wie der Timer und Interrupts sollten auch da funktionieren.

    Der Umstieg von Bascom auf C bringt vielleicht einen Faktor 2-3 bei der Geschwindigkeit . ist aber unterschiedlich je nach Aufgabe. Der Overhead bei der Interruptsroutine ist in Bascom recht groß - etwa 100 Zyklen extra gegenüber GCC bei einer eher kurzen ISR. In Bascom hat man den Vorteil das man leichter mit inline ASM kombinieren kann - das geht auch in C, aber nicht so einfach. Da Bascom einige Register normal nicht nutzt, kann man mit Bascom und ISR in ASM ggf. sogar schneller werden als mit GCC und ASM.

  7. #7
    Erfahrener Benutzer Robotik Einstein Avatar von wkrug
    Registriert seit
    17.08.2006
    Ort
    Dietfurt
    Beiträge
    2.188
    ....inline ASM kombinieren kann
    Das hatte ich schon ein paar Post's weiter vorne auch vorgeschlagen.
    Ob man's dann mit Bascom oder nen C-Compiler macht dürfte relativ egal sein.
    Auch bei CodeVision AVR lässt sich inline Assembler problemlos einbinden.
    Wie das bei AVR GCC geht weiss ich leider nicht.
    Wenn man in der Interruptroutine nur Assembler verwendet kann man zusätzlich die automatische Registersicherung abschalten, da Bascom normalerweise bei jedem ISR-Aufruf ja alle 32 Register sichert und wieder zurückschreibt.
    Bei ASM müssen nur das SREG und die Register gesichert werden, die man selber benotigt.
    Zusätzlich ist es sinnvoll den Controller mit der maximal möglichen Taktrate zu takten weil damit der Jitter minimiert wird.
    Also einen Typen wählen der mit 20MHz läuft und auch 20MHz verwenden.

    Ein Bekannter von mir hat mit Bascom und inline Assembler einen Testbildgenerator für Fernseher gebaut und das ist noch wesentlich zeitkritischer als Servoimpulse einlesen.
    Geändert von wkrug (20.12.2014 um 09:15 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
  •  

MultiPlus Wechselrichter Insel und Nulleinspeisung Conrad