- fchao-Sinus-Wechselrichter AliExpress         
Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 20

Thema: Codebeispiel für Lesen von RC5 Code mit Interrupt-Routine

  1. #1
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    28.03.2004
    Beiträge
    185

    Codebeispiel für Lesen von RC5 Code mit Interrupt-Routine

    Anzeige

    E-Bike
    Die hier bisher vorgeschlagene Lösung mittels eines Levels-Interrupts Intx GetRC5 anzustoßen hat den Nachteil, dass:
    - die ISR für die ganze Zeit des Codempfangs (bis zu 130ms) den MC blockiert
    - GetRC5 viele Fehler liest, da die Synchronisation wegen der fehlenden ersten Flanke wackelt
    - zwei Interrupts belegt werden (Timer0 und INTx)

    hier der alte Code: siehe https://www.roboternetz.de/phpBB2/ze...ag.php?t=18140
    Code:
     $regfile = "m16def.dat"                                    'Controllertyp,
     $framesize = 32                                            'Stackanweisungen
     $swstack = 32
     $hwstack = 64
     $crystal = 8000000                                         'Die Frequenz des verwendeten Quarzes
     $baud = 9600                                               'Die Baudrate für RS232 Ausgabe.
    
     $lib "mcsbyte.lbx"
    
     'RC5 benötigt Timer0 Interrupt !
     Config Rc5 = Pind.3
     On Int1 Int1_int                                           'Nosave würde 52 Takte = 6,5uS sparen
     Enable Int1
     Config Int1 = Falling
     Enable Interrupts
    
     'Rückgabewerte der ISR
     Dim Address_rc5 As Byte , Command_rc5 As Byte , Rc5_flag As Bit
    
     Do
        If Rc5_flag = 1 Then
          Reset Rc5_flag
            Print "toggle:" ; Command_rc5.7;
            'clear the toggle bit
            Command_rc5 = Command_rc5 And &B01111111
            Print " Adresse:" ; Address_rc5 ; " Code:" ; Command_rc5
        End If
        'Waitms 100
     Loop
    
    End
    
    'Lesen der RC5 Codes
    Int1_int:                                                   'Interrupt Handler For Int1
       Disable Int1
       Enable Interrupts                                        'für Timer0 Overflow GetRC5
       Getrc5(address_rc5 , Command_rc5)
       Set Rc5_flag                                             'Flag für RC5 Daten
       Gifr = Gifr Or &H80                                      'clear Flag Int1
       Enable Int1
    Return
    Codelänge: 444Word = 888Byte


    Hier eine Lösung, die den BASCOM-Befehl GetRC5 nur mit der Timer0-Overflow-ISR nachbildet.
    Vorteile:
    - ISR dauert nur ca. 8µs alle 178µs (Timer0-Overflow), d.h. ca. 5% MC-Last (keine Blockierung)
    - liest den RC5 Code fehlerfrei, da er sich auf jede Flanke synchronisiert
    - belegt nur den Timer0-Interrupt
    Code:
     'Decodierung eines RC5-Codes
    
      $regfile = "m16def.dat"                                   'Controllertyp
      $framesize = 32                                           'Stackanweisungen
      $swstack = 32
      $hwstack = 64                                             'Achtung ISR=32 Byte
      $crystal = 8000000                                        'bei Änderung den Timer0 neu einstellen!!
      $baud = 9600                                              'Die Baudrate für RS232 Ausgabe.
    
      $lib "mcsbyte.lbx"                                        'ACHTUNG:numeric<>string conversion routines only for bytes
    
      Config Portb.0 = 0
      Input_pin Alias Pinb.0                                    'Pin für TSOP1736
    
      Config Timer0 = Timer , Prescale = 8
      On Timer0 Timer_irq
      Const Timervorgabe = 78                                   'Timeraufruf alle 178µs (10 Samples = 1 Bit = 1,778ms)
      Enable Timer0                                             'Hier werden die Timer aktiviert
      Enable Interrupts
    
      'Timing für 10 Samples Per Bit = 1,778ms
      Const Samples_early = 8                                   'Flanke Frühestens Nach 8 Samples
      Const Samples_late = 12                                   'Flanke Spätestens Nach 12 Samples
      Const Samples_min = 3                                     'Flanke Vor 3 Samples - > Paket Verwerfen
    
      'Variablen der ISR
      Dim Sample As Byte                                        'eigentlich Bit, spart aber 46Byte ROM
      Dim Ir_lastsample As Byte                                 'zuletzt gelesenes Sample
      Dim Ir_bittimer As Byte                                   'zählt die Aufrufe von Timer_IRQ
      Dim Ir_data_tmp As Word                                   'Bitstream
      Dim Ir_bitcount As Byte                                   'Anzahl gelesener Bits
    
    
      'Rückgabewerte der ISR
      Dim Address_rc5 As Byte , Command_rc5 As Byte , Rc5_flag As Bit
    
      Do
        If Rc5_flag = 1 Then
          Reset Rc5_flag
            Print "toggle:" ; Command_rc5.7;
            'clear the toggle bit
            Command_rc5 = Command_rc5 And &B01111111
            Print " Adresse:" ; Address_rc5 ; " Code:" ; Command_rc5
        End If
        'Waitms 100
      Loop
    
    End
    
    
    Timer_irq:
      Timer0 = Timervorgabe
      Sample = Not Input_pin
    
      'bittimer erhöhen (bleibt bei 255 stehen)
      If Ir_bittimer < 255 Then Incr Ir_bittimer
    
      'flankenwechsel erkennen
      If Ir_lastsample <> Sample Then
    
         If Ir_bittimer <= Samples_min Then
           'flanke kommt zu früh: paket verwerfen
           Ir_bitcount = 0
         Else
           'nur Flankenwechsel in Bit-Mitte berücksichtigen
           If Ir_bittimer >= Samples_early Then
               If Ir_bittimer <= Samples_late Then
                 'Bit speichern
                  Shift Ir_data_tmp , Left , 1
                  Ir_data_tmp = Ir_data_tmp + Sample
                  Incr Ir_bitcount
               Else
                  'Flankenwechsel zu spät: Neuanfang mit gemessener Flanke
                  Ir_bitcount = 1
                  Ir_data_tmp = Sample
               End If
               'bittimer zurücksetzen wenn Timer > Samples_early
               Ir_bittimer = 0
           End If
         End If
    
        'Kontrolle des Startbits auf 1
         If Ir_bitcount = 1 Then Ir_bitcount = Ir_data_tmp.0
    
         'Alle 14 Bits gelesen?
         If Ir_bitcount >= 14 Then
           Command_rc5 = Ir_data_tmp                            'Bit 6 und 7 siehe unten
           Shift Ir_data_tmp , Right , 6
           Address_rc5 = Ir_data_tmp And &B00011111
           'For extended RC5 code, the extended bit is bit 6 of the command.
           Command_rc5.6 = Not Ir_data_tmp.6
           'The toggle bit is stored in bit 7 of the command
           Command_rc5.7 = Ir_data_tmp.5
           'Paket erfolgreich gelesen
           Set Rc5_flag
           'paket zurücksetzen
           Ir_bitcount = 0
         End If
    
      End If
      'sample im samplepuffer ablegen
      Ir_lastsample = Sample
    
    Return
    Codelänge: 483Word = 966 Byte, d.h. zusätzlich nur 78 Byte

  2. #2
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    28.03.2004
    Beiträge
    185
    da ich mich wunderte, warum Bascom bei den paar Codezeilen 966 Byte verbraucht, habe ich den Bascom-Code mal 1:1 in Avr-gcc umgeschrieben:
    Code:
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <stdlib.h> 	// wg. char-print
    
    // interner RC-Oszillator 
    #define F_CPU 8.0E6
    
    //'Timeraufruf alle 178µs (10 Samples = 1 Bit = 1,778ms)
    #define INTERRUPT_PRELOADER 78 
    
    #define UART_BAUD_RATE 9600    //  die gewünschte Baudrate
    #define UART_BAUD_SELECT (F_CPU/(UART_BAUD_RATE*16L)-1) 
    
    //UART -----------------------------------------------------------
    char myCharBuffer[10];
    char *myCharPtr;  
    
    void UART_init(void){ 
       UBRRL |= (uint8_t) UART_BAUD_SELECT;
       UCSRB = (1<<RXEN)|(1<<TXEN); 	//Sender & Empfänger aktivieren
       UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); 	//Asynchron 8N1
    }
    
    void UART_transmit(uint8_t c){
       while(!(UCSRA & (1<<UDRE)));
       UDR = c;
    }
    
    void UART_transmit_string(uint8_t *string){
        while(!(UCSRA & (1<<UDRE)));
       while( *string){ UART_transmit (*string++); }
    }
    
    void UART_transmit_byte(uint8_t b){
    	myCharPtr = myCharBuffer;
    	myCharPtr = itoa( b,myCharPtr,10); 
    	UART_transmit_string(myCharBuffer);
    }
    
    //Timing für 10 Samples Per Bit = 1,778ms
    #define Samples_early 8	//Flanke Frühestens Nach 8 Samples
    #define Samples_late 12	//Flanke Spätestens Nach 12 Samples
    #define Samples_min 3	//Flanke Vor 3 Samples - > Paket Verwerfen
    
    //Variablen der ISR
    volatile uint8_t Sample;			//eigentlich Bit
    volatile uint8_t Ir_lastsample;	//zuletzt gelesenes Sample
    volatile uint8_t Ir_bittimer; 	//zählt die Aufrufe von Timer_IRQ
    volatile uint16_t  Ir_data_tmp; 	//Bitstream
    volatile uint8_t Ir_bitcount; 	//Anzahl gelesener Bits
    
    //Rückgabewerte der ISR
    volatile uint8_t Address_rc5; 
    volatile uint8_t Command_rc5; 
    volatile uint8_t Rc5_flag; //eigentlich Bit
    
    // Initialisierung der Hardware
    void ioinit()
    { 
        // Initialisiert Timer0
    	TCCR0 |= (1<<CS01); 	//Prescale=8
    	// TCNT0  = INTERRUPT_PRELOADER; 			//Counter
    	TIMSK |= (1<<TOIE0); 	//Timer Overflow Interrupt
    }
    
    // Das Hauptprogramm 
    int main()
    {
        // Peripherie initialisieren
        ioinit();
    	UART_init();
    	
    	//Pin für TSOP1736
    	DDRB &= ~(1<<DDB0);	//  Eingang eh vorhanden
    
        // Interrupts aktivieren
        sei();
    
        // Eine Endlosschleife.  
        while (1)
        {
    		if (Rc5_flag == 1)
    		{
    		Rc5_flag = 0;
    		UART_transmit_string("\r\ntoggle:");
    		UART_transmit_byte((Command_rc5 & (1<<7))>>7);
    		
    		//clear the toggle bit
            Command_rc5 &= 0b01111111;
    		
    		UART_transmit_string(" Adresse:");
    		UART_transmit_byte(Address_rc5);
    		UART_transmit_string(" Code:");
    		UART_transmit_byte(Command_rc5);
    		}
    	}
    }
    
    // Die Interrupt Service Routine (ISR) 
    SIGNAL(SIG_OVERFLOW0)
    {
        TCNT0 = INTERRUPT_PRELOADER;
    	Sample = !(PINB & (1<<PINB0));
    
        //'bittimer erhöhen (bleibt bei 255 stehen)
        if (Ir_bittimer < 255) Ir_bittimer += 1; 
    
        //flankenwechsel erkennen
        if (Ir_lastsample != Sample)
        {
    		if (Ir_bittimer <= Samples_min) 
    			{
    			//flanke kommt zu früh: paket verwerfen
    			Ir_bitcount = 0;
    			}
    		else
    			{
    			//nur Flankenwechsel in Bit-Mitte berücksichtigen
    			if (Ir_bittimer >= Samples_early)
    				{
    				if (Ir_bittimer <= Samples_late) 
    					{
    					//Bit speichern
    					Ir_data_tmp = (Ir_data_tmp << 1);
    					Ir_data_tmp = Ir_data_tmp + Sample;
    					Ir_bitcount +=1;
    					}
    					else
    					{
    					//Flankenwechsel zu spät: Neuanfang mit gemessener Flanke
    					Ir_bitcount = 1;
    					Ir_data_tmp = Sample;
    					}
    			   //bittimer zurücksetzen wenn Timer > Samples_early
    			   Ir_bittimer = 0;
    				}
    			}
    
    		//Kontrolle des Startbits auf 1
    		if (Ir_bitcount == 1) Ir_bitcount = Ir_data_tmp & 1; //Bit 0
    
    		//Alle 14 Bits gelesen?
    		if (Ir_bitcount >= 14)
    			{
    			Command_rc5 = Ir_data_tmp & 0x3F ; //Bit 6 und 7 siehe unten
    			Ir_data_tmp = (Ir_data_tmp >> 6);
    			Address_rc5 = Ir_data_tmp & 0b00011111;
    			//For extended RC5 code, the extended bit is bit 6 of the command.
    			if ((Ir_data_tmp & (1<<6))==0) Command_rc5 |= (1<<6);
    			//The toggle bit is stored in bit 7 of the command
    			Command_rc5 |= ( (Ir_data_tmp & (1<<5)) <<2 );
    			//Paket erfolgreich gelesen
    			Rc5_flag=1;
    			//paket zurücksetzen
    			Ir_bitcount = 0;
    			}
    
      }
      //sample im samplepuffer ablegen
      Ir_lastsample = Sample;
    }
    Trotz Compiler-Direktive "OPTIMIZE = -O2" beträgt die Codelänge in C erstaunliche 912Byte (gegenüber 966Byte in Bascom).

    Fazit: Bascom macht hier keine schlechte Figur. Das Hauptproblem von Bascom ist das fehlende Registerrechnen. Ständig wird alles vom RAM hin- und hergeschaufelt. Da in GCC die Variablen für die ISR mit Volatile definiert werden müssen, kommt diese WINAVR-Optimierung nicht zum Zuge. (Volatile erfordert ca. 82 Byte zusätzlichen Code).

    Markant ist in AVR-gcc die fehlende Push-Pop Orgie in der ISR:
    Code:
    ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ ISR SIG_OVERFLOW0 in AVR-GCC ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
    ROM:00BD                 push    r1
    ROM:00BE                 push    r0
    ROM:00BF                 in      r0, SREG
    ROM:00C0                 push    r0
    ROM:00C1                 clr     r1
    ROM:00C2                 push    r18
    ROM:00C3                 push    r24
    ROM:00C4                 push    r25
    ...
    ROM:016D                 pop     r25
    ROM:016E                 pop     r24
    ROM:016F                 pop     r18
    ROM:0170                 pop     r0
    ROM:0171                 out     SREG, r0
    ROM:0172                 pop     r0
    ROM:0173                 pop     r1
    ROM:0174                 reti
    bekanntlich langt hier Bascom ordentlich zu
    Code:
    ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ ISR Timer0 in Bascom ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
    ROM:008F                 push    r0
    ROM:0090                 push    r1
    ROM:0091                 push    r2
    ROM:0092                 push    r3
    ROM:0093                 push    r4
    ROM:0094                 push    r5
    ROM:0095                 push    r7
    ROM:0096                 push    r10
    ROM:0097                 push    r11
    ROM:0098                 push    r16
    ROM:0099                 push    r17
    ROM:009A                 push    r18
    ROM:009B                 push    r19
    ROM:009C                 push    r20
    ROM:009D                 push    r21
    ROM:009E                 push    r22
    ROM:009F                 push    r23
    ROM:00A0                 push    r24
    ROM:00A1                 push    r25
    ROM:00A2                 push    r26
    ROM:00A3                 push    r27
    ROM:00A4                 push    r28
    ROM:00A5                 push    r29
    ROM:00A6                 push    r30
    ROM:00A7                 push    r31
    ROM:00A8                 in      r24, SREG
    ROM:00A9                 push    r24
    ...
    ROM:0154                 pop     r24
    ROM:0155                 out     SREG, r24
    ROM:0156                 pop     r31
    ROM:0157                 pop     r30
    ROM:0158                 pop     r29
    ROM:0159                 pop     r28
    ROM:015A                 pop     r27
    ROM:015B                 pop     r26
    ROM:015C                 pop     r25
    ROM:015D                 pop     r24
    ROM:015E                 pop     r23
    ROM:015F                 pop     r22
    ROM:0160                 pop     r21
    ROM:0161                 pop     r20
    ROM:0162                 pop     r19
    ROM:0163                 pop     r18
    ROM:0164                 pop     r17
    ROM:0165                 pop     r16
    ROM:0166                 pop     r11
    ROM:0167                 pop     r10
    ROM:0168                 pop     r7
    ROM:0169                 pop     r5
    ROM:016A                 pop     r4
    ROM:016B                 pop     r3
    ROM:016C                 pop     r2
    ROM:016D                 pop     r1
    ROM:016E                 pop     r0
    ROM:016F                 reti

  3. #3
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    06.11.2004
    Beiträge
    1.693
    Codelänge: 483Word = 966 Byte
    Der Code belegt nur noch 956Bytes, wenn in Bascom unter Options/Compiler/Output die Option Optimize Code ausgewählt wird.

    Soll keine Kritik sein, ich wollte es nur als Tipp erwähnen.

  4. #4
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    28.03.2004
    Beiträge
    185
    Schalter ist bekannt - was Bascom Optimize nennt ist mit Blick auf die WINAVR-Compilerdirektiven peinlich.
    Habe in den Foren eher schlechtes zu den Bascom-Schalter gelesen, darum ist er bei mir als Standard deaktiviert.

  5. #5
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    30.01.2005
    Ort
    HH
    Beiträge
    215
    Hallo!

    Ich habe heute versucht dein Beispiel zu verwenden. Leider funktioniert es nicht. Ich verwende einen Mega32 mit 16MHz und einen TSOP1738
    Den Timer0 habe ich wie folgt eingestellt:
    Code:
      Config Timer0 = Timer , Prescale = 64
      On Timer0 Timer_irq
      Const Timervorgabe = 846                                  'Timeraufruf alle 178µs (10 Samples = 1 Bit = 1,778ms)
      Enable Timer0                                             'Hier werden die Timer aktiviert
      Enable Interrupts
    
      'Timing für 10 Samples Per Bit = 1,778ms
      Const Samples_early = 8                                   'Flanke Frühestens Nach 8 Samples
      Const Samples_late = 12                                   'Flanke Spätestens Nach 12 Samples
      Const Samples_min = 3                                     'Flanke Vor 3 Samples - > Paket Verwerfen
    Kommt das so hin?

    Ach ja, mit dem Bascom GetRc5-Befehl funktioniert alles.

    MfG
    Martin

  6. #6
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    28.03.2004
    Beiträge
    185
    nimm zur Not zur Berechnung von
    Code:
    Const Timervorgabe =
    das Tool AVR Timer-Berechnung von Frank
    https://www.roboternetz.de/phpBB2/dl...le&file_id=169
    Das Tool berücksichtigt leider nicht die 52 Takte aus der PUSH-Orgie von 26 Registern (siehe Code oben) und kommt dann
    bei 8 Mhz auf Const Timervorgabe = 81 (anstatt 78 ) bzw
    bei 16 Mhz auf Const Timervorgabe = 212.

    eine Erklärung zur Timerberechnung findest Du hier:
    https://www.roboternetz.de/wissen/index.php/Avr unter 4. Timer/Counter

  7. #7
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    Zitat Zitat von -tomas-
    da ich mich wunderte, warum Bascom bei den paar Codezeilen 966 Byte verbraucht, habe ich den Bascom-Code mal 1:1 in Avr-gcc umgeschrieben [...]Trotz Compiler-Direktive "OPTIMIZE = -O2" beträgt die Codelänge in C erstaunliche 912Byte (gegenüber 966Byte in Bascom).
    Mal abgesehen davon, daß du durch deine Programmierung ineffizenten Code erzwingst:

    Wenn man auf Laufzeit optimiert und nicht auf Größe, darf man auch nicht erwarten, daß auf Größe optimiert wird... (BTW, mit -=O2 bekomm ich mit deinem Code 834 Bytes).

    Bereits das entfernen eines überflüssigen(!) Qualifiers bringt ne Codeersparnis von über 40 Bytes... Wieviel weiter noch überflüssig sind ist wohl müssig nachzuschauen. Innerhalb von einigen Minuten hätte man den Code locker unter 700 Bytes
    Disclaimer: none. Sue me.

  8. #8
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    28.03.2004
    Beiträge
    185
    @SprinterSB
    ich war selber erschrocken, wie ineffizent der Bascom-Code in WINAVR ist:
    Bascom-Code mal 1:1 in Avr-gcc umgeschrieben
    Die Unterschiede zwischen Bascom und GCC liegen nicht nur in den Sprachelementen - die Intelligenz sollte VOR dem Rechner sitzen

    ... aber bitte jetzt keine weitere Grundsatz-Diskussion zu Bascom<->WINAVR !

  9. #9
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    Darum geht es auch nicht.

    Wenn du es 1:1 übertragen möchtest, dann musst du auch die lokalen Variablen volatile machen. Versuch das mal, und GCC macht Code, der locker doppelt so groß ost wie der von BASCOM...
    Disclaimer: none. Sue me.

  10. #10
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    30.01.2005
    Ort
    HH
    Beiträge
    215
    Oh mann! Hatte wohl gestern wieder ein Brett vorm Kopf!!! Was hab ich da ausgerechnet????

    Vielen Dank! Mit Const Timervorgabe = 212 funktioniert es einwandfrei!
    Das Tool kannte ich noch nicht, wieder was gelernt!

    MfG
    Martin

Seite 1 von 2 12 LetzteLetzte

Berechtigungen

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

12V Akku bauen