PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Neue Idee für das Auslesen von Drehimpulsgebern



Kaiser-F
14.02.2006, 20:59
Hallo,

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

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


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!

SprinterSB
15.02.2006, 11:52
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:

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... :-)

Kaiser-F
15.02.2006, 12:34
Da geb ich dir vollkommen Recht.

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

SprinterSB
15.02.2006, 12:44
Frag einfach nach, wenn was unklar ist.

clupus
15.02.2006, 21:38
Ic hätte dazu eine Frage: Das mit dem Bitfeld ist doch vom AVRStudio, oder? Gibts sowas auch beim avr-gcc?

MfG
Christian

Kaiser-F
15.02.2006, 21:41
Hi,

Der Befehl struct ist ein "allgemeiner" C-Befehl.

Kaiser-F
16.02.2006, 17:39
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:



#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 ):



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;
}




}