- fchao-Sinus-Wechselrichter AliExpress         
Ergebnis 1 bis 7 von 7

Thema: Neue Idee für das Auslesen von Drehimpulsgebern

  1. #1
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    04.01.2005
    Ort
    Bayern
    Alter
    37
    Beiträge
    795

    Neue Idee für das Auslesen von Drehimpulsgebern

    Anzeige

    Praxistest und DIY Projekte
    Hallo,

    Ich habe mir ein kleines Prog zum Auslesen von Drehimpulsgebern geschrieben.

    Was haltet ihr davon, Funktionieren tut es bis jetzt sehr gut:

    Code:
    if( PINC & (1<<PINC0) ){ A_AKT = 0; }else{ A_AKT = 1; }
    if( PINC & (1<<PINC1) ){ B_AKT = 0; }else{ B_AKT = 1; }
    if( PINC & (1<<PINC2) ){ E_AKT = 0; }else{ E_AKT = 1; }
    
    
    if( A_AKT != A_ALT ){ 
    	if( B_FLAG ){ way = 1; }else{ A_FLAG = 1; }
    	A_ALT = A_AKT;
    }
    
    if( B_AKT != B_ALT ){ 
    	if( A_FLAG ){ way = 2; }else{ B_FLAG = 1; }
    	B_ALT = B_AKT;
    }
    
    
    
    if( way==1 ){ x--; LCD_Write_ZAHL( 40, x ); way=0; B_FLAG=0; }
    if( way==2 ){ x++; LCD_Write_ZAHL( 40, x ); way=0; A_FLAG=0; }

    funktionieren tut es so:

    zum Beispiel:


    Ändert sich A zuerst, so wird das A_Flag gesetzt
    ( Aber nur, wenn zuvor nicht das B_Flag gesetzt wurde )

    ändert sich nun auch B, stellt man fest, dass bereits ein A_Flag existiert,
    also kann man eine Drehrichtung und einen Impuls wahrnehmen.

    Way wird entsprechend gesetzt.


    Am Schluss wird, wenn way existiert das Gnaze ausgewertet.
    Und natürlich way und die Flags zurückgesetzt.


    Ist ein kurzer Code, funktioniert, eure Meinungen sind gefragt!
    Gruß,
    Franz

  2. #2
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    Haupsache uist, daß er funktionert

    Was mir auffällt ist, daß E_AKT und E_ALT nicht verwendet werden.

    Es werden recht viele Variablen gebraucht. Da viele Variablen nur ein Flag sind (also "wahr" oder "falsch" merken), könnte man die Flags zusammenfassen und den Code (d.h. was an Asm rauskommt) deutlich verkürzen.

    Dazu fasst man erst mal die Flags in einem Bitfield zusammen. Da die einzelnen Felder nur 1 Bit groß sind, kann für deren Zugriff/Abfrage sehr kurzer Code erzeugt werden, da das in einer einzigen Maschinen-Instruktion geht, und es werden weniger Register gebraucht, was Platz und Zeit beim Sichern der Register spart.

    Ausserdem wird der Wert von PINC in eine Variable gemerkt. Dadurch muss nicht 3* PINC gelesen werden, sondern man macht einen Schnappschuss und wertet den aus. Die Änderungen ergeben sich durch ein XOR, in wechsel steht eine 1 für jedes geänderte Bit.

    Der Vorschlag könnte dann so aussehen, wobei der C-Code länger wird, weil man noch eine Flag-Struktur definieren muss:
    Code:
    	struct
    	{
    		unsigned char a:1;
    		unsigned char b:1;
    		unsigned char way1:1;
    		unsigned char way2:1;
    	} flags = {.a=0, .b=0, .way1=0, .way2=0};
    	
    	uint8_t pin_alt = PINC;
    	int x = 0;
    	
    	while (1)
    	{
    		uint8_t pin_neu = PINC;
    		uint8_t wechsel = pin_neu ^ pin_alt;
    		
    		flags.way2 = flags.way1 = 0;
    		
    		if (wechsel & (1 << PINC0))
    		{
    			if (flags.b)	flags.way1 = 1;	else	flags.a = 1; 
    		}
    		
    		if (wechsel & (1 << PINC1))
    		{
    			if (flags.a)	flags.way2 = 1;	else	flags.b = 1; 
    		}
    		
    		pin_alt = pin_neu;
    		
    		if (flags.way1) { flags.b = 0; x--; LCD_Write_ZAHL (40, x); }
    		if (flags.way2) { flags.a = 0; x++; LCD_Write_ZAHL (40, x); }
    	}
    Am Ablauf hat sich nichts geändert (ausser Kleinigkeiten, etwa daß der neue Zustand von PINC immer gemerkt wird, etc), ansonsten ist's einfach ne Anregung zur Optimierung.

    Wenn man so proggt, kann man C-Code schreiben wie Heu, aber die kleinen AVRs werden einfach nicht voll...
    Disclaimer: none. Sue me.

  3. #3
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    04.01.2005
    Ort
    Bayern
    Alter
    37
    Beiträge
    795
    Da geb ich dir vollkommen Recht.

    Ich habe es auch schon so machen wollen. Aber das hat dann zum begreifen so kompliziert ausgesehen...
    Gruß,
    Franz

  4. #4
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    Frag einfach nach, wenn was unklar ist.
    Disclaimer: none. Sue me.

  5. #5
    Benutzer Stammmitglied
    Registriert seit
    18.06.2005
    Ort
    Hattenhofen
    Alter
    37
    Beiträge
    55
    Ic hätte dazu eine Frage: Das mit dem Bitfeld ist doch vom AVRStudio, oder? Gibts sowas auch beim avr-gcc?

    MfG
    Christian

  6. #6
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    04.01.2005
    Ort
    Bayern
    Alter
    37
    Beiträge
    795
    Hi,

    Der Befehl struct ist ein "allgemeiner" C-Befehl.
    Gruß,
    Franz

  7. #7
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    04.01.2005
    Ort
    Bayern
    Alter
    37
    Beiträge
    795
    Hi, ichhab noch eine kleinigkeit hinzuzufügen:

    Bei meinem Programmvorschlag muss noch folgende Zeile angehängt werden:

    if( DREH_A_NEU != DREH_B_NEU ){ DREH_WAY = 0; }

    Zu dem Zeitpunkt zu dem ein Imopuls registriert ist, müssen A und B gleich sein. Sie sind immer entweder beide HIGH oder beide LOW.

    Anders kann es passieren dass der Drehgeber mal in die falsche richtung dreht!

    das Ganze sieht dann so aus:


    Code:
    #define DREH_DDR		DDRC
    #define DREH_PIN		PINC
    #define DREH_PORT		PORTC
    #define DREH_A			0
    #define DREH_B			1
    #define DREH_P			2
    
    uint8_t DREH_A_NEU;
    uint8_t DREH_B_NEU;
    uint8_t DREH_A_ALT;
    uint8_t DREH_B_ALT;
    uint8_t DREH_A_FLAG;
    uint8_t DREH_B_FLAG;
    
    
    uint8_t DREH_FLAGS = 0;
    uint8_t DREH_WAY = 0;
    
    void DREHGEBER( void ){
    	
    	// PINS als Eingang schalten, Pullups einschalten
    	DREH_DDR &=~ (1<<DREH_A)|(1<<DREH_B)|(1<<DREH_P);
    	DREH_PORT |= (1<<DREH_A)|(1<<DREH_B)|(1<<DREH_P);
    	
    	// Eingänge abfragen
    	if( DREH_PIN & (1<<DREH_A) ){ DREH_A_NEU = 0; }else{ DREH_A_NEU = 1; }
    	if( DREH_PIN & (1<<DREH_B) ){ DREH_B_NEU = 0; }else{ DREH_B_NEU = 1; }
    	//if( DREH_PIN & (1<<DREH_P) ){ DREH_P_NEU = 0; }else{ DREH_P_NEU = 1; }
    	
    	if( DREH_A_NEU != DREH_A_ALT ){
    		if(DREH_B_FLAG){ DREH_WAY = 1; }else{ DREH_A_FLAG = 1; }
    		DREH_A_ALT = DREH_A_NEU;
    	}
    	
    	if( DREH_B_NEU != DREH_B_ALT ){
    		if(DREH_A_FLAG){ DREH_WAY = 2; }else{ DREH_B_FLAG = 1; }
    		DREH_B_ALT = DREH_B_NEU;
    	}	
    	
    	if( DREH_A_NEU != DREH_B_NEU ){ DREH_WAY = 0; }
    	
    }

    auswertung ( im hauptprogramm ):


    Code:
    while(1){
    
    	DREHGEBER();
    	
    	if( DREH_WAY == 1 ){ DREH_WAY=0; DREH_B_FLAG = 0; x--; }
    	if( DREH_WAY == 2 ){ DREH_WAY=0; DREH_A_FLAG = 0; x++; }
    	
    	if( x < 1 ){ x = 1;  }
    	if( x > 11){ x = 11; }
    	
    	if( x != y ){
    		switch( x ){
    			case 1  : LCD_WRITE_TEXT( 1, "        Menue      >" ); break;
    			case 2  : LCD_WRITE_TEXT( 1, "<   Konfiguration  >" ); break;
    			case 3  : LCD_WRITE_TEXT( 1, "<  Displayoptionen >" ); break;
    			case 4  : LCD_WRITE_TEXT( 1, "<  Referenzfahren  >" ); break;
    			case 5  : LCD_WRITE_TEXT( 1, "<       Eins       >" ); break;
    			case 6  : LCD_WRITE_TEXT( 1, "<       Zwei       >" ); break;
    			case 7  : LCD_WRITE_TEXT( 1, "<       Drei       >" ); break;
    			case 8  : LCD_WRITE_TEXT( 1, "<       Vier       >" ); break;
    			case 9  : LCD_WRITE_TEXT( 1, "<       Fünf       >" ); break;
    			case 10 : LCD_WRITE_TEXT( 1, "<       Sechs      >" ); break;
    			case 11 : LCD_WRITE_TEXT( 1, "<       Exit        " ); break;
    		}
    		LCD_Write_ZAHL( 40, x );
    		y = x;
    	}
    	
    	
    
    
    }
    Gruß,
    Franz

Berechtigungen

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

Labornetzteil AliExpress