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
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
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ß
@ 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ß
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
volatilecharenc_delta;// -128 ... 127
13
14
15
intmain(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
staticcharenc_last=0x01;
37
chari=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ß
...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?
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
staticvoidioinit(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
staticvoidtx_char(charc)
30
{
31
while((UCSRA&(1<<UDRE))==0)
32
/* wait */;
33
UDR=(uint8_t)c;
34
}
35
36
37
volatilestaticboolupdated;
38
volatilestaticuint8_tdata;
39
40
intmain(void)
41
{
42
ioinit();
43
44
for(;;)
45
{
46
if(updated)
47
{
48
if(data&2)tx_char('1');
49
elsetx_char('0');
50
if(data&1)tx_char('1');
51
elsetx_char('0');
52
tx_char(' ');
53
updated=false;
54
}
55
}
56
57
return0;
58
}
59
60
61
ISR(TIMER0_OVF_vect)
62
{
63
if(updated)
64
return;/* not yet processed */
65
66
staticuint8_tlastval;
67
uint8_tthisval=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 ;-)
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
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