Hallo liebes Forum. Ich habe vor, einen Drehencoder STEC11B03 an den Atmega32 anzuschliessen. Es gibt bereits viele aufschlussreiche Beiträge im Forum zu diesem Thema (Natürlich auch vom AVR-Meister peter dannegger) jedoch sind diese eher für Fortgeschrittene und Profis. Mein Problem: Wie wird der Encoder eingentlich angeschlossen (Pull-ups / Entprellung )??? Im Datenblatt finde ich keinen Anschlussplan... Könnte mich jemand aufklären??? Liebe Grüße
...willst du uns veräppeln? Schau mal ganz genau ins Datenblatt vom großen C, Seite 4!!! Klaus.
Sven B. wrote: > Es gibt bereits viele aufschlussreiche Beiträge im Forum zu diesem Thema > (Natürlich auch vom AVR-Meister peter dannegger) jedoch sind diese eher > für > Fortgeschrittene und Profis. ??? Meinst Du damit, Anfänger dürfen nur schlecht funktionierenden Code benutzen? > Mein Problem: Wie wird der Encoder eingentlich angeschlossen (Pull-ups / > Entprellung )??? Pullups oder interne Pullups des MC. HW-Entprellung nein, stört sonst die SW-Entprellung. > Im Datenblatt finde ich keinen Anschlussplan... Einfach auf 2 LEDs legen und langsam drehen. Ändern sich beide Signale mal gleichzeitig, ists falsch. Es gibt nur 3 Anschlußmöglichkeiten. Peter
Hallo Peter. Danke für Deine Antwort. Wäre diese Beschaltung (s. Anhang) richtig ? Irgendwie tue ich mich schwer damit... P.S. Nein Klaus, ich möchte hier niemanden veräppeln. Ich suche nur etwas Unterstützung. Du bist sicherlich auch nicht als Profi auf die Welt gekommen. Liebe Grüße
Pull-Up-Widerstände beim Schalten gegen 5V sind nicht wirklich sinvoll. Da der Mega die Pull-Ups schon eingebaut hat, lass alles Hühnerfutter einfach weg. 0V (GND) an den Encoder, drei Leitungen an die Mega-Eingänge, dort die internen Pull-Ups aktivieren, fertig. Die Eingänge sind dann zwar active low, das macht aber nichts, die Peter'schen Funktionen für Drehgeber und Taster berücksichtigen das. Oliver
Nachtrag: Das mit deine Widerständen hätte doch gepasst, trotzdem: Lass auch den Schalter nach Masse schalten. Das ist einfacher. Oliver
Danke Oliver. Habe ich Dich richtig verstanden ? Meinstest Du diese Beschaltung ? Werden die Taster(im Drehencoder) also softwaremäßg entprellt ? Verstehe ich das richtig ? Gruß
...zumal das alles auch im Datenblatt steht - aber wer nicht nachschaut, findet das auch nicht. Klaus.
@ Klaus. Sorry Klaus. Sei mir bitte nicht böse, aber ich muß mich da völlig unverständlich ausgedrückt haben. Ich meinte eigentlich nicht die Beschaltung des Encoders hinsichtlich der Entprellung und Pullups. Siehe mein Anhang. Ok. Ich habe anfangs viel komplizierter gedacht als es ist... Pullups, entprellung etc. Nicht gleich böse sein. :o) Gruß
Hallo! Ich habe nun den Drehencoder richtig angeschlossen und versuche den in Gang zu kriegen. Vergeblich. Wie kann ich denn auf dem einfachsten Weg den Drehencoder auf Funktion überprüfen. ( Habe leider kein Ossi da ) Diesen Code nutze ich: http://www.mikrocontroller.net/attachment/highlight/22223 Peter Dannegger schrieb : Einfach auf 2 LEDs legen und langsam drehen. Ändern sich beide Signale mal gleichzeitig, ists falsch. Es gibt nur 3 Anschlußmöglichkeiten. Leider leuchten die LED´s sporadisch (wenn dann beide gleichzeitig) auf. Beim Anschliessen eines LCD´s bekomme ich Zahlen wie -20 etc. die sich wahrlos ändern?? Hat Jemand noch ein wenig Geduld übrig? Gruß
>Diesen Code nutze ich: >http://www.mikrocontroller.net/attachment/highlight/22223 Tu das nicht. Nimm den hier: http://www.mikrocontroller.net/attachment/1971/ENCODE.C Oliver
OK. Danke Oliver. Ich Probiere das mal aus und melde mich gleich wieder. Bin sehr gespannt. Danke erstmal
Peter Dannegger wrote: > Einfach auf 2 LEDs legen und langsam drehen. Ändern sich beide Signale > mal gleichzeitig, ists falsch. Kann schwierig werden. Ich habe Encoder, bei denen beide Signale sich optisch immer gleichzeitig verändern. Erst wenn man etwas zeitlich besser Auflösendes (Oszi im Einmal-Trigger-Modus oder LA) anschließt, sieht man den Versatz. Das liegt daran, dass die zwischen den Rastungen ziemlich kräftig weiter gezogen werden. Dafür war ich am LA-Bild total erstaunt. Das Prellen war durchweg im Bereich von maximal einigen 100 ns, und oft genug war mit den 10 ns, die mein alter LA auflöst, gar kein Prellen feststellbar.
OK. Ich denke die beste Methode wird sein, wenn ich das ganze mal anstatt als signal an einer LED - auf einem LCD ausgebe. Ich krame das mal kurz raus und melde mich gleich wieder. danke erstmal für die tips.
ok. ich habe ein LCD und versuche die Signaländerungen auf dem LCD auszugeben. ( In diesem Fall : enc_delta; ) Controllerfrequenz : 16 MHz Drehencoder PORTB: A - Pin0; B - Pin1 Code :
1 | #include <avr\io.h> |
2 | #include <avr\interrupt.h> |
3 | #include <avr\signal.h> |
4 | |
5 | #include "glcd.h" |
6 | #include "font_small.h" |
7 | |
8 | #define PHASE_A (PINB & 1<<PINB0) // PINB.0
|
9 | #define PHASE_B (PINB & 1<<PINB1) // PINB.1
|
10 | |
11 | |
12 | volatile char enc_delta; // -128 ... 127 |
13 | |
14 | |
15 | int main( void ) |
16 | {
|
17 | lcd_init(); |
18 | lcd_clear(); |
19 | lcd_set_cursor(0,LINE0); |
20 | lcd_puts(small_font,"LCD Test ist OK"); |
21 | |
22 | TCCR0 = 1<<CS01; //divide by 8 * 256 |
23 | TIMSK = 1<<TOIE0; //enable timer interrupt |
24 | |
25 | sei(); |
26 | for(;;) |
27 | {
|
28 | lcd_set_cursor(0,LINE1); |
29 | lcd_puts(small_font,enc_delta); |
30 | }
|
31 | }
|
32 | |
33 | |
34 | SIGNAL (SIG_OVERFLOW0) |
35 | {
|
36 | static char enc_last = 0x01; |
37 | char i = 0; |
38 | |
39 | if( PHASE_A ) |
40 | i = 1; |
41 | |
42 | if( PHASE_B ) |
43 | i ^= 3; // convert gray to binary |
44 | |
45 | i -= enc_last; // difference new - last |
46 | |
47 | if( i & 1 ){ // bit 0 = value (1) |
48 | enc_last += i; // store new as next last |
49 | |
50 | enc_delta += (i & 2) - 1; // bit 1 = direction (+/-) |
51 | }
|
52 | }
|
Es tut sich leider nichts... Auf dem LCD erscheint : LCD Test ist OK Die Variable enc_delta wird leider nicht ausgegeben :o( Was mache ich falsch ? Liegt es an der Frequenz ? Gruß
> lcd_puts(small_font,enc_delta);
kann mit Sicherheit keine Interwerte ausgeben, sondern nur Strings.
Probiers mal mit
1 | #include <stdlib.h> |
2 | ...
|
3 | char outstring[20]; |
4 | itoa(enc_delta, outstring, 10); |
5 | lcd_puts(small_font,outstring); |
Oliver
...wenn da jetzt nicht 2 fässer auf einmal aufgemacht werden :) du musst doch nur detektieren, ob 2 pins am uC unterschiedlich auf masse gezogen werden, erst a dann b -> lass led1 leuchten / erst b dann a -> lass led2 leuchten...sowas kann man mit nem flipflop sogar analog lösen :) also lass erstmal das lcd weg und versuche, die LOGIKAUSWERTUNG sauber hinzubekommen - sonst sind es auf einmal exponentiell mehr fehlerquellen!!! und ich wollte nicht "böse" sein, aber es schien, dass du nichtmals VERSCHT hast, das datenblatt und dessen timingdiagramme zu interpretieren! Klaus.
Ok Oliver. Ich dachte beim volatile char enc_delta; handelt es sich um eine character-Variable. Ups... Aber auch das habe ich schon bereits ausprobiert... ... for(;;) { lcd_clear(); char outstring[20]; itoa(enc_delta,outstring,10); //convertieren ins 10-er System lcd_set_cursor(0,LINE1); lcd_puts(small_font,outstring); _delay_ms(200); } .. AUSGABE auf dem LCD: Werte zwischen 1 und 255 die sich selbständig (unsinnig) ändern ??? was soll das ganze?
P.S. Das Drehen des Drehencoders(links oder rechts) wirkt sich nicht auf die Ausgabe aus. D.h. Das Ding funktioniert nicht.
Und noch was. Wenn ich den Drehencoder ganz herausnehme, tut sich immernoch das gleiche auf dem LCD. Werte zwischen 1 und 255 sporadisch springen um.
Sven B. wrote: > Werte zwischen 1 und 255 die sich selbständig (unsinnig) ändern ??? > > was soll das ganze? Tja. dann wird sich wohl dein enc_delta ständig ändern. Hast du jetzt eigentlich die externen Pullup Widerstände noch dran? Wenn nein: Ich seh in deinem Code nirgends, wo du die internen einschaltest.
Sven B. wrote: > Und noch was. > Wenn ich den Drehencoder ganz herausnehme, tut sich immernoch > das gleiche auf dem LCD. > Werte zwischen 1 und 255 sporadisch springen um. In dem Fall ist dann alles klar. Ein Eingang, den du offen lässt, fängt sich alle mögliche elektromagnetische Strahlung aus der Umgebung ein. -> interne Pullup Widerstände einschalten hilft ungemein.
Sven B. wrote: > Ich dachte beim volatile char enc_delta; handelt es sich um eine > character-Variable. Ups... Dann waere es immer noch falsch. Dir fehlen offensichtlich die C-Grundlagen, die solltest du dir erst aneignen und dich dann an Mikrocontroller wagen. > AUSGABE auf dem LCD: > > Werte zwischen 1 und 255 die sich selbständig (unsinnig) ändern ??? Laut deinem Schaltplan haengt der Drehgeber an D0-D2, abgefragt wird B0 & B1, richtig initialisiert (Portrichtung & Pullup) wird keins von beiden. > was soll das ganze? Das frage ich mich auch...
Hallo Peter. Danke für die Antwort. Eingänge definiert. Interne Pullup-Widerstände sind an. int main( void ) { lcd_init(); lcd_clear(); lcd_set_cursor(0,LINE0); lcd_puts(small_font,"LCD Test ist OK"); DDRB &= ~(_BV(PB1) | _BV(PB0)); //eingang PORTB = (_BV(PB1) | _BV(PB0)); //pullup TCCR0 = 1<<CS01; //divide by 8 * 256 TIMSK = 1<<TOIE0; //enable timer interrupt sei(); for(;;) { lcd_clear(); char outstring[20]; itoa(enc_delta,outstring,10); //convertieren ins 10-er System lcd_set_cursor(0,LINE1); lcd_puts(small_font,outstring); _delay_ms(200); } } Ergebnis: Sieht gut aus! Peter Du bist der Beste! Ich danke Dir vielmals! Mal wieder habt Ihr mir sehr geholfen :o) Gruß ( freu )
Hast du denn gar kein Stück Messmittel in Reichweite, das irgendwie zu einer zeitlichen Darstellung zweier Signale taugt? Hier wäre ein schneller Hack:
1 | #include <stdbool.h> |
2 | #include <stdint.h> |
3 | |
4 | #define F_CPU 16000000ul
|
5 | |
6 | #include <avr/io.h> |
7 | #include <avr/interrupt.h> |
8 | |
9 | static void ioinit(void) |
10 | {
|
11 | TCCR0 = (1<<CS01) | (1<<CS00); //divide by 64 * 256 => ~ 1 ms clock ticks |
12 | TIMSK = 1<<TOIE0; //enable timer overflow interrupt |
13 | |
14 | #define BAUD 9600
|
15 | #include <util/setbaud.h> |
16 | UBRRH = UBRRH_VALUE; |
17 | UBRRL = UBRRL_VALUE; |
18 | #if USE_2X
|
19 | UCSRA |= (1 << U2X); |
20 | #else
|
21 | UCSRA &= ~(1 << U2X); |
22 | #endif
|
23 | |
24 | UCSRB = (1 << TXEN); |
25 | |
26 | sei(); |
27 | }
|
28 | |
29 | static void tx_char(char c) |
30 | {
|
31 | while ((UCSRA & (1 << UDRE)) == 0) |
32 | /* wait */; |
33 | UDR = (uint8_t)c; |
34 | }
|
35 | |
36 | |
37 | volatile static bool updated; |
38 | volatile static uint8_t data; |
39 | |
40 | int main( void ) |
41 | {
|
42 | ioinit(); |
43 | |
44 | for(;;) |
45 | {
|
46 | if (updated) |
47 | {
|
48 | if (data & 2) tx_char('1'); |
49 | else tx_char('0'); |
50 | if (data & 1) tx_char('1'); |
51 | else tx_char('0'); |
52 | tx_char(' '); |
53 | updated = false; |
54 | }
|
55 | }
|
56 | |
57 | return 0; |
58 | }
|
59 | |
60 | |
61 | ISR(TIMER0_OVF_vect) |
62 | {
|
63 | if (updated) |
64 | return; /* not yet processed */ |
65 | |
66 | static uint8_t lastval; |
67 | uint8_t thisval = PINB; |
68 | |
69 | thisval &= 3; /* only PINB0 & PINB1 to consider */ |
70 | if (thisval != lastval) |
71 | {
|
72 | lastval = thisval; |
73 | data = thisval; |
74 | updated = true; |
75 | }
|
76 | }
|
Der sollte auf der UART Zeichenfolgen 00 01 11 10 usw. ausgeben. Deine Timerinterruptrate von 1/(128 µs) halte ich für ziemlich heftig. Üblich sind Raten von 200 Hz ... 1 kHz, um einen Drehgeber zu pollen. Das wird natürlich nur dann ein Problem, wenn dein Geber mehr prellt als meiner, den ich da oben genannt habe.
Hallo Jörg Wunsch! Was zum Messen habe ich leider nicht da. kann mir von meinem Ausbildungsgeld kein Ossi kaufen. Könnte mir von der Arbeit ein Ossi mitbringen, aber die Leute haben Angst daß ich das kaputt mache. Das mit dem UART ist ja eine tolle Idee. Danke für den Tip und Code. Damit werde ich mich auch ein bißchen anfreunden ;o) Ich danke Euch allen nochmal und wünsche ein schönes WE ! Sven
> kann mir von meinem Ausbildungsgeld kein Ossi kaufen.
Nenn's bitte Oszi oder Scope. Oder gleich ganz.
Mit "Ossi" meinst du abfällig eine ganze Bevölkerungsgruppe ;-)
Ja ihr habt Recht! Sorry ich meinte auch Osziloskop :o) Wollte niemanden beleidigen !
@Jörg, welche Bevölkerungsschicht hat Dir denn vorgeschwebt ?? Was ist ein "Ossi" ?? :-(
Guten Tag. Würde es gehen mit dem Code von Sven B. bis 1000 zu drehen und nicht bis 255 ?
Gast aus Prenzlau wrote: > Guten Tag. > > Würde es gehen mit dem Code von Sven B. bis 1000 zu drehen und nicht bis > 255 ? Die Limitierung in seinem Code entsteht ja nur dadurch, dass er enc_delta als char ausgeführt hat (das sollte man sowieso besser zu einem signed char oder noch besser zu einem int8_t machen). Ersetz ihn durch einen 16-Bit Datentyp und du kannst bis 16384 zählen. Mach einen 32 Bit Type draus und es geht noch höher. Den Drehencoder decodieren ist eine Sache. Was du dann mit dem Änderungswert machst ist eine andere Sache.
Karl heinz Buchegger wrote: > Die Limitierung in seinem Code entsteht ja nur dadurch, dass er > enc_delta als char ausgeführt hat (das sollte man sowieso besser zu > einem signed char oder noch besser zu einem int8_t machen). Ersetz ihn > durch einen 16-Bit Datentyp und du kannst bis 16384 zählen. Mach einen > 32 Bit Type draus und es geht noch höher. Dann aber nicht vergessen, den Zugriff atomar zu machen (siehe auch atomic.h).
Route_66 wrote: > @Karl heinz Buchegger > 16 Bit geht von 0...65535 oder -32768...32767. Kann nur sagen: hatte heute noch keinen Kaffee und draussen schneits und überhaupt :-) Danke
Hallo nochmal. Sorry Karl, es ist doch nicht so einfach... Wenn ich die variable richtung als: volatile unit8_t richtung=0; definiere, kommt leider keine Änderung (0...255). Habe ich es doch nicht verstanden ?
1 | #include <avr/io.h> |
2 | #include "glcd.h" |
3 | #include "font_big.h" |
4 | #include <avr\interrupt.h> |
5 | |
6 | #define Schalter_A PINB0 // Schalter A im Drehgeber
|
7 | #define Schalter_B PINB1 // Schalter B im Drehgeber
|
8 | #define Geber PINB // Drehgeber Port
|
9 | |
10 | volatile unsigned char richtung = 0; // 0 ... 255 |
11 | volatile char outstring_alt[5]; |
12 | |
13 | int main (void) |
14 | {
|
15 | char outstring[5]; |
16 | |
17 | DDRB &= ~(_BV(PB1) | _BV(PB0)); //Eingänge |
18 | PORTB = (_BV(PB1) | _BV(PB0)); //Pullup |
19 | |
20 | TCCR0 = (1<<CS01) | (1<<CS00); //divide by 64 * 256 |
21 | TIMSK = 1<<TOIE0; |
22 | |
23 | lcd_init(); |
24 | lcd_clear(); |
25 | |
26 | sei(); |
27 | for(;;) |
28 | {
|
29 | |
30 | strcpy(outstring_alt,outstring); |
31 | itoa(richtung, outstring, 10); |
32 | |
33 | if(strcmp(outstring,outstring_alt)!=0) |
34 | {
|
35 | lcd_set_cursor(0,LINE3);lcd_puts(big_font,outstring_alt,WHITE); |
36 | }
|
37 | lcd_set_cursor(0,LINE3);lcd_puts(big_font,outstring,BLACK); |
38 | |
39 | }
|
40 | |
41 | }
|
42 | |
43 | |
44 | ISR(TIMER0_OVF_vect) |
45 | {
|
46 | static unsigned char alter_status = 0,step = 0; |
47 | unsigned char neuer_status; |
48 | |
49 | neuer_status = Geber & (_BV(Schalter_A) | _BV(Schalter_B)); // änderung einlesen |
50 | |
51 | if ((neuer_status ^ step)==(_BV(Schalter_A) | _BV(Schalter_B))) |
52 | {
|
53 | if ((neuer_status ^ alter_status)==_BV(Schalter_A)) |
54 | richtung +=1; // Es war nach rechts |
55 | else
|
56 | richtung -=1; // Es war nach links |
57 | step = neuer_status; |
58 | }
|
59 | alter_status = neuer_status; |
60 | |
61 | |
62 | }
|
Bei volatile unit8_t richtung=0; gibt es sowieso eine Fehlermeldung :o) Versuch mit ... volatile uint8_t richtung=0; ... Gruß
Code den man nicht versteht einfach nur so zusammenzukopieren, hat nocht nie funktioniert.
Gast aus Prenzlau wrote: > Ändert sich auch nicht > > Der Wert bleibt immer zwischen 0 und 255. Ja? Was erwartest du? Ein uint8_t, wie der Name schon sagt, ist ein unsigned (also ohne Vorzeichen) int mit 8 Bit. Mit 8 Bit kann man ohne Vorzeichen von 0 bis 255 zählen. Wie wärs mit einem uint16_t Der hat, wie der Name schon sagt, 16 Bit
Richtig. volatile uint16_t richtung=0; .... if (richtung>=1000) richtung=0; ... Vorsicht,daß Du keinen Krampf beim Drehen bekommst... Sven
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.