Forum: Mikrocontroller und Digitale Elektronik C Programm für Drehimpulsgeber funktioniert nicht


von max2d (Gast)


Lesenswert?

Hallo,

ich möchte die Impulse eines Drehimpulsgebers mit einem PIC16F887 
auswerten, und die Umdrehungen auf einer 7-Segment Anzeige ausgeben.

Ich habe volgenden Ansatz.
PIN A und PIN B des Drehgebers werden mit Interrupt Eingängen des µC 
verbunden.
Sobald sich ein Pegel ändert wird ein Interrupt ausgelöst und der 
aktuelle Pegel der PINs wird gespeichert.
Bei einem erneuten Interrupt wird der alte Pegel an den PINs mit dem 
aktuellen verglichen.

Sobald der aktuelle Pegel von PIN B und der alte Pegel von PIN A gleich 
sind soll der Zähler hochgezählt werden. Bei Ungleichheit reduziert.

Hier mein Programm:
1
#include <htc.h>
2
__CONFIG (LVP_OFF & WDTE_OFF);              //Low Voltage Programming OFF
3
                                            // Watch dog timer off
4
5
6
7
void interrupt IOC_ISR (void);
8
unsigned int count = 0;
9
unsigned int a_akt = 0;         //Aktueller Status von PIN A
10
unsigned int b_akt = 0;         //Aktueller Status von PIN B
11
unsigned int a_alt = 0;         //Alter Status von PIN A
12
unsigned int b_alt = 0;         //Alter Status von PIN B
13
unsigned int flag  = 0;
14
15
void main (void)
16
{
17
    OPTION_REG = 0b11000000;    //Pull-up nicht geschalten (Externe Pulldowns)
18
                                //Interrupt on rising
19
    INTCON = 0b10001001;        //GIE =1
20
                                //RBIE=1
21
                                //RBIF=1
22
    IOCB   = 0b00110000;        //Interrupt für RB4 und 5 freischalten
23
                                //Hier ist Drehgeber angeschlossen
24
    ANSELH= 0;                  //Eingänge Digital
25
    TRISD = 0;                  //PORTD als Ausgang (Hier 2 BCD ->7 Segment)
26
    TRISB4 = 1;                 //PIN RB4 als Eingang
27
    TRISB5 = 1;                 //PIN RB5 als Eingang
28
29
    while (1)
30
    {
31
        if (count == 0)         //7-Segment: 00
32
        {
33
            PORTD = 0b00000000; 
34
        }
35
36
        if (count == 1)         //7-Sement: 11
37
        {
38
            PORTD = 0b00010001;
39
        }
40
41
        if (count ==2)
42
        {
43
            PORTD = 0b00100010;
44
        }
45
46
        if (count == 3)
47
        {
48
            PORTD = 0b00110011;
49
        }
50
51
        if (count == 4)
52
        {
53
            PORTD = 0b01000100;
54
        }
55
56
        if (count == 5)
57
        {
58
            PORTD = 0b01010101;
59
        }
60
    }
61
}
62
63
64
65
void interrupt IOC_ISR (void)   //ISR
66
{
67
    if (RBIF && RBIE && (flag == 0))    //Sobald Interrupt ausgelöst wird RB4 und RB5
68
    {                                   //in Variable a_akt und b_akt einlesen
69
        RBIF = 0;
70
        PORTB = 0xf0;
71
        if (RB4 || RB5)
72
        {
73
            a_akt = RB4;
74
            b_akt = RB5;
75
            flag  = 1;
76
        }
77
    }
78
79
    if (RBIF && RBIE && flag)           //Soabld Interrupt ausgelöst wird und bereits
80
    {                                   //die Variable a_akt bzw. b_akt beschrieben wurde
81
        RBIF = 0;                       //diese in a_alt und b_alt kopieren
82
        flag = 0;
83
        PORTB= 0xf0;
84
        if (RB4 || RB5)
85
        {
86
            a_alt = a_akt;
87
            b_alt = b_akt;
88
89
90
                if (b_akt == a_alt)     //wenn b_akt gleich a_alt zähler um 1 erhöhen
91
                {
92
                    count++;
93
                }
94
95
                if (b_akt != a_alt)     //wenn b_akt ungleich a_alt zähler um 1 reduzieren
96
                {
97
                    count--;
98
                }
99
        }
100
    }
101
}

Das Problem ist, dass der Zähler anscheinend nicht hochgezählt wird. Ich 
kann so viel drehen wie ich will, die Anzeige bleibt immer bei 00.
Die Signale vom Drehgeber, welchen ich übrigens Hardwareseitig entprellt 
habe kommen am µC auch an.

Ich hoffe Ihr könnt mir weiterhelfen. Bin hier echt am verzweifeln.

Gruß

Max

von Karl H. (kbuchegg)


Lesenswert?

max2d schrieb:

> Ich hoffe Ihr könnt mir weiterhelfen. Bin hier echt am verzweifeln.

'Verzweifeln' ist der falsche Ansatz und der Fehlersuche nicht 
zuträglich.

'Systematisches Vorgehen' wäre richtig.

Du hast offenbar irgendwas am PortD hängen, mit dem sich dein Programm 
bemerkbar machen kann. Ein paar LED oder ev. sogar eine 7-Segment 
Anzeige.
Das ist schon mal die halbe Miete und das wichtigste überhaupt. Denn es 
ist nicht verboten, diese Teile erst mal anders zu verwenden, wie du dir 
das im Endeffekt vorgestellt hast. Also schmeiss die Ausgabe aus der 
Hauptschleife raus (mach dir aber eine Funktion um Zahlen auszugeben) 
und benutzt diese Ausgabemöglichkeit um damit zuallererst mal 
festzustellen:

* wird der Interrupt überhaupt ausgelöst.


Im Hauptprogramm schreibst du '0' auf die Anzeige (ausserhalb der while 
Schleife) und in der ISR lässt du dann '1' ausgeben.

Startest du das Programm, musst du die 0 sehen. Drehst du am Encoder 
(und nur dann), dann muss die Anzeige auf 1 wechseln.

Damit weißt du schon mal, dass die Interrupt Funktion aufgerufen wird. 
Etwas das du vorher nicht mit Sicherheit wusstest.
Bzw. es könnte auch anders rum sein, dass dein Interrupt nicht ausgelöst 
wird oder zu früh ausgelöst oder wie auch immer. Das alles kannst du mit 
Hilfe der Anzeige feststellen. Anstatt "Ich glaube das das alles 
funktioniert" bist du dann bei "Ich WEISS, dass das alles funktioniert / 
nicht funktioniert".

Und so hangelst du dich weiter durch.
Wenn du sicher bist, dass die Interrupt Funktion aufgerufen wird, dann 
kann man die Anzeige zb dazu benutzen, sich mal den Status der diversen 
Variablen bzw. Flags ausgeben zu lassen.


Dann verzweifelst du auch nicht mehr sondern betreibst systematische 
Fehlersuche, in dem du in deinem Programm alle Schritte verfolgst und 
kontrollierst, ob jeweils das erwartete auch tatsächlich passiert.
Und dann wirds auch was mit Debuggging und wenn deine Idee tragfähig ist 
dann funktioniert es am Ende auch, nachdem du alle Problemstellen aus 
dem Weg geräumt hast.

: Bearbeitet durch User
von max2d (Gast)


Lesenswert?

Vielen Dank für deine schnelle und so ausführliche Antwort.

Ich habe einen Fehler gefunden.
Sobald ich in der ISR neben RBIF und RBIE den Zustand der flag abfrage, 
wird der Interrupt nichtmehr gehandhabt. Die flag hat aber den richtigen 
Zustand.

Hier das Programm:
1
#include <htc.h>
2
__CONFIG (LVP_OFF & WDTE_OFF);              //Low Voltage Programming OFF
3
                                            // Watch dog timer off
4
5
6
7
void interrupt IOC_ISR (void);
8
void anzeige (void);
9
unsigned int count = 0;
10
unsigned int a_akt = 0;         //Aktueller Status von PIN A
11
unsigned int b_akt = 0;         //Aktueller Status von PIN B
12
unsigned int a_alt = 0;         //Alter Status von PIN A
13
unsigned int b_alt = 0;         //Alter Status von PIN B
14
unsigned int flag  = 0;
15
16
17
void main (void)
18
{
19
    OPTION_REG = 0b11000000;    //Pull-up nicht geschalten (Externe Pulldowns)
20
                                //Interrupt on rising
21
    INTCON = 0b10001001;        //GIE =1
22
                                //RBIE=1
23
                                //RBIF=1
24
    IOCB   = 0b00110000;        //Interrupt für RB4 und 5 freischalten
25
                                //Hier ist Drehgeber angeschlossen
26
    ANSELH= 0;                  //Eingänge Digital
27
    TRISD = 0;                  //PORTD als Ausgang (Hier 2 BCD ->7 Segment)
28
    TRISB4 = 1;                 //PIN RB4 als Eingang
29
    TRISB5 = 1;                 //PIN RB5 als Eingang
30
31
    while (1)
32
    {
33
        anzeige ();
34
    }
35
}
36
37
38
void anzeige (void)
39
{
40
        if (count == 0)         //7-Segment: 00
41
        {
42
            PORTD = 0b00000000; 
43
        }
44
45
        if (count == 1)         //7-Sement: 11
46
        {
47
            PORTD = 0b00010001;
48
        }
49
50
        if (count ==2)
51
        {
52
            PORTD = 0b00100010;
53
        }
54
55
        if (count == 3)
56
        {
57
            PORTD = 0b00110011;
58
        }
59
60
        if (count == 4)
61
        {
62
            PORTD = 0b01000100;
63
        }
64
65
        if (count == 5)
66
        {
67
            PORTD = 0b01010101;
68
        }    
69
}
70
void interrupt IOC_ISR (void)   //ISR
71
{
72
    
73
    if (RBIF && RBIE  )          //Hier ohne abrage der Flag, wenn ich mit                                (RBIF && RBIE && (flag==0))  abfrage   keine funktion!!!!
74
    {                                   
75
        RBIF = 0;
76
        PORTB = 0xf0;
77
        if (RB4 || RB5)
78
        {
79
            count = 1;
80
            a_akt = RB4;
81
            b_akt = RB5;
82
            flag  = 1;
83
            
84
        }
85
    }
86
87
88
}

von DrWright (Gast)


Lesenswert?

Der PinChange Interrupt ist bei Drehencodern schonmal sehr schlecht, 
benutz lieber einen Timer und frag die Eingänge periodisch ab.

Hier meine Routine zum Auslesen eines Drehencoders an PIND2 und PIND3, 
die gegen Masse geschaltet werden.
1
volatile struct{
2
  uint8_t last;
3
  int8_t steps;
4
}encoder;
5
6
ISR(TIMER0_OVF_vect) // 600x/sec
7
{
8
  // Drehencoder auswerten
9
  uint8_t P1 = (PIND &(1<<PD2)), P2 = (PIND &(1<<PD3));
10
  if (P1 != encoder.last)
11
  {    
12
    if ((!encoder.last &&! P2) || (encoder.last && P2))
13
    {      
14
      encoder.steps += 1;      
15
    }
16
    else if ((encoder.last &&! P2) || (!encoder.last && P2))
17
    {
18
      encoder.steps -= 1;      
19
    }
20
    encoder.last = P1;  
21
  }
22
}
23
24
uint8_t Encoder_GetSteps(void)
25
{
26
  cli();
27
  uint8_t tmp = encoder.steps;
28
  encoder.steps = 0;
29
  sei();
30
  return tmp;
31
}

Ich hab keine Probleme mit der Prellung, auch bei schnellen rotieren.
Ich benutze den Encoder für die Menubedienung über ein LCD.

von DrWright (Gast)


Lesenswert?

1
int8_t Encoder_GetSteps(void)
2
{
3
  cli();
4
  int8_t tmp = encoder.steps;
5
  encoder.steps = 0;
6
  sei();
7
  return tmp;
8
}

So ists richtig

von m.n. (Gast)


Lesenswert?

DrWright schrieb:
> ISR(TIMER0_OVF_vect) // 600x/sec

Mein Drehgeber liefert 4096 Flanken/U. Du meinst, dass da 600x/sec 
reichen?
:-)

von MaWin (Gast)


Lesenswert?

max2d schrieb:
> Hier mein Programm

RB4 und RB5 sind doch Konstanten und nicht die Pins des Ports, oder ist 
das beim PIC anders?

von MaWin (Gast)


Lesenswert?

max2d schrieb:
> Die Signale vom Drehgeber, welchen ich übrigens Hardwareseitig entprellt
> habe kommen am µC auch an.

Das könntest du dir natürlich sparen wenn du den Drehgeber ordentlich 
auswerten würdest und nicht mit unsäglichen Flankeninterrupts arbeiten 
würdest.

http://www.dse-faq.elektronik-kompendium.de/dse-faq.htm#F.29

von spontan (Gast)


Lesenswert?

>Mein Drehgeber liefert 4096 Flanken/U. Du meinst, dass da 600x/sec
<reichen?
>:-)

Du solltest wissen ob das reicht, oder ob die Abtastfrequenz höher sein 
muß.
Drehzahl, Anzahl der Flanken pro Umdehung und schon kannst Du die 
Frequenz der Drehgeberpulse berechnen.

Meinen ist immer der ganz falsche Ansatz, wissen mußt Du es.

Ist die Frequenz hoch, so kanns irgendwann mit der Interruptlösung (by 
the way, die ist nur Mist) auch eng werden. Hardwaremäßige Entprellung 
hat auch eine Grenzfrequenz...

Schau doch mal bei extremen Drehgeberfrequenzen nach PICs mit 
Zweipahsen-Eingang. Die haben eine leistungsfähige Hardware auf dem 
Chip... und Du hast dann keine Sorgen mit der Frequenz.

von m.n. (Gast)


Lesenswert?

spontan schrieb:
> Drehzahl, Anzahl der Flanken pro Umdehung und schon kannst Du die
> Frequenz der Drehgeberpulse berechnen.

Gut, ich habe mal gerechnet: 30kHz brauche ich.

von polling (Gast)


Lesenswert?

m.n. schrieb:
>
> Gut, ich habe mal gerechnet: 30kHz brauche ich.

Popcorn, Füße hoch. Der Einzelkämpfer ist wieder unterwegs :-)

von Stampede (Gast)


Lesenswert?

MaWin schrieb:
> RB4 und RB5 sind doch Konstanten und nicht die Pins des Ports, oder ist
> das beim PIC anders?

So ist es. PORTBbits.RB4 wäre korrekt.

von m.n. (Gast)


Lesenswert?

max2d schrieb:
> Sobald sich ein Pegel ändert wird ein Interrupt ausgelöst und der
> aktuelle Pegel der PINs wird gespeichert.

Das machst Du genau richtig!

polling schrieb:
> Popcorn, Füße hoch. Der Einzelkämpfer ist wieder unterwegs :-)

Sagt ja sonst keiner was Vernüftiges, außer altbekannten Vorurteilen :-)

von MaWin (Gast)


Lesenswert?

m.n. schrieb:
> Das machst Du genau richtig!

Sagt der Troll, der seit Monaten den groben Unfug der völlig falschen 
flankeninterruptgesteuerten Drehgeberauswertung hier propagiert.

Die Folgen sieht man an max2d:

Es funktioniert nicht.

von ich (Gast)


Lesenswert?

m.n. schrieb:
> Sagt ja sonst keiner was Vernüftiges, außer altbekannten Vorurteilen :-)

Manchmal kommen die Vorurteile auch von Erfahrungen, die man gemacht hat 
und nun vermeidet...

von m.n. (Gast)


Lesenswert?

MaWin schrieb:
> Die Folgen sieht man an max2d:
>
> Es funktioniert nicht.

Das liegt aber daran, dass er einen PIC anstatt eines AVR verwendet.

@max2d
Warte noch ein wenig, bis heute Abend W.S. in seiner hoffentlich 
geheizten Dachstube bei einer Flasche "Rote Toscana" sitzt und Dir dann 
genau erklären wird, wie man es mit Interrupts auf einem PIC zum Laufen 
bekommt.
Die jetzigen Lästerer werden sich dann neidisch wieder in ihre Ecken 
verkriechen - bis der nächste Frager kommt :-)

von ich (Gast)


Lesenswert?

m.n. schrieb:
> [..]neidisch wieder in ihre Ecken verkriechen

Der war gut :-)

von Karl H. (kbuchegg)


Lesenswert?

m.n. schrieb:

> Die jetzigen Lästerer werden sich dann neidisch wieder in ihre Ecken
> verkriechen

worauf soll ich da neidisch sein?

Möglich das er da in seiner Syntax für den Portzugriff einen Fehler hat. 
Kann durchaus sein. Auch fehlt mindestens 1 volatile. Aber selbst wenn 
das mit externen Interrupts bei ihm funktioniert, bin ich deswegen nicht 
neidisch. Bis jetzt bin ich mit den Ratschlägen alter Bekannter immer 
gut gefahren, egal ob Tastenauswertung oder Drehencoder. Die 
funktionieren auf Anhieb und sind robust, ohne dass ich mich groß drum 
kümmern muss oder externe Hardware, wie irgendwelche 
Entprellkondensatoren, brauchen würde.

von m.n. (Gast)


Lesenswert?

Karl Heinz schrieb:
> worauf soll ich da neidisch sein?

Dass andere Leute Sachen in den Griff bekommen, wozu sie selbst (die 
Lästerer) nicht in der Lage sind.

Karl Heinz schrieb:
> Bis jetzt bin ich mit den Ratschlägen alter Bekannter immer
> gut gefahren, egal ob Tastenauswertung oder Drehencoder.

Du hattest ja schon einmal geschrieben, dass Du mich nicht kennst und 
meine Programme daher nichts taugen würden. Du machst Dir nicht einmal 
die Mühe, zu verstehen, welche Schaltungsdetails für welche Aufgabe 
sinnvoll oder auch garnicht notwendig sind. Ein Sonnenbad der 
Vorurteile!
Letztlich ist dies aber ein Armutszeugnis, was Du Dir damit ausstellst.

Zeig mir doch irgendeines der erprobten Programme, dass 
Drehgeber/Lineargeber mit 30kHz auswerten könnte?
Aber verkriech Dich bitte nicht hinter der Standardausrede: soetwas 
braucht man nicht.

von Tany (Gast)


Lesenswert?

2 Argumente im
http://www.mikrocontroller.net/articles/Drehgeber

>[...] 1.Die Auflösung wird auf ein Viertel reduziert, weil nur jede >steigende 
Flanke von A ausgewertet wird.
Falsch, PINChange reagiert auf jede Änderung. Somit ist's möglich, jede 
Flanke zu bewerten

> 2.Pendelt der Encoder zwischen zwei Codes, bei denen A seinen Pegel
>wechselt...
Man kann per SW unterdrücken. M.N hat der Anfang/ Ansatz mitgebracht, 
ihr wolltet davon aber nicht wissen. Ich hab's längst gemacht, es geht 
mit jedem Encoder AUF ANHIEB! mit oder ohne Kondensator.

euch noch einen schönen Feierabend.

von René K. (cyprius)


Lesenswert?

Tany schrieb:
> Man kann per SW unterdrücken. M.N hat der Anfang/ Ansatz mitgebracht,
> ihr wolltet davon aber nicht wissen. Ich hab's längst gemacht, es geht
> mit jedem Encoder AUF ANHIEB! mit oder ohne Kondensator.

Warum sollte man denn etwas per Software halbgar unterdrücken oder 
"zurecht"frickeln, wenn es doch bereits eine solide Lösung gibt, welche 
ohne Tricks auskommt?

von Justus S. (jussa)


Lesenswert?

René K. schrieb:
> Warum sollte man denn etwas per Software halbgar unterdrücken oder
> "zurecht"frickeln, wenn es doch bereits eine solide Lösung gibt, welche
> ohne Tricks auskommt?

was erwartest du denn von jemandem, der nur Teile von Artikeln zitiert, 
damit es sie als falsch bezeichnen kann?

von MaWin (Gast)


Lesenswert?

m.n. schrieb:
> Zeig mir doch irgendeines der erprobten Programme, dass
> Drehgeber/Lineargeber mit 30kHz auswerten könnte?

Beispielsweise die

http://www.dse-faq.elektronik-kompendium.de/dse-faq.htm#F.29

auch 100kHz oder in Assembler 1MHz oder in Hardware 10MHz.

Nur Interruptflankengesteuerten haben mit hohen Abtastraten Probleme, 
weil entweder Interrupts auftreten während Interrupts noch bearbeitet 
werden, also verloren gehen oder aufgeschoben werden, und Überläufe im 
Gegensatz zur pegelgesteuerten nicht erkannt werden
und weil die notwendige Entprellung, beispielsweise per RC Glied, auch 
eine niedrige Endfrequenz ergibt.

Aber das wirst du in deinem Messias Flanken Wahn nie begreifen.

von max2d (Gast)


Lesenswert?

Danke für eure Antworten.
Da sich die Mehrheit dafür ausgesprochen hat das ganze mit einem Timer 
Interrupt zu realisieren habe ich es mal probiert. Leider funktionierts 
nicht.
Warum? Der Timer funktioniert (habe ich getestet )
1
#include <htc.h>
2
__CONFIG (LVP_OFF & WDTE_OFF);              //Low Voltage Programming OFF
3
                                            // Watch dog timer off
4
5
void anzeige (void);
6
7
unsigned int count = 0;
8
unsigned int flag  = 0;
9
unsigned int a_akt = 0;
10
unsigned int b_akt = 0;
11
unsigned int a_alt = 0;
12
unsigned int b_alt = 0;
13
unsigned int a_zw  = 0;
14
unsigned int b_zw  = 0;
15
16
void main (void)
17
{
18
19
    T1CON = 0b01110001;
20
    GIE    = 1;
21
    PEIE   = 1;
22
    TMR1IE = 1;
23
    TMR1L = 200;
24
    TMR1H = 200;
25
26
    TRISD = 0;
27
   
28
    TRISB1= 1;
29
    TRISB0 = 1;
30
    ANSELH= 0;
31
32
    while (1)
33
    {
34
        anzeige ();
35
    }
36
}
37
38
39
void anzeige (void)
40
{
41
        if (count == 0)         //7-Segment: 00
42
        {
43
            PORTD = 0b00000000; 
44
        }
45
46
        if (count == 1)         //7-Sement: 11
47
        {
48
            PORTD = 0b00010001;
49
        }
50
51
        if (count ==2)
52
        {
53
            PORTD = 0b00100010;
54
        }
55
56
        if (count == 3)
57
        {
58
            PORTD = 0b00110011;
59
        }
60
61
        if (count == 4)
62
        {
63
            PORTD = 0b01000100;
64
        }
65
66
        if (count == 5)
67
        {
68
            PORTD = 0b01010101;
69
        }    
70
}
71
72
73
void interrupt timer (void)
74
{
75
    if (TMR1IF)
76
    {
77
        TMR1L = 200;
78
        TMR1H = 200;
79
        TMR1IF= 0;
80
        
81
        
82
        a_zw = RB0;             //Aktuellen Stand des Drehgebers zwischenspeichern
83
        b_zw = RB1;             // "
84
                      
85
        if (a_zw != a_akt)      //Sobald im zwischenspeicher ein anderer Wert als im a_akt speicher
86
        {                       //vorhanden ist. Wird zuerst a_akt in a_alt verschoben. Danach wird neuer Wert
87
            a_alt = a_akt;      //von a_zw in a_akt eingelesen
88
            a_akt = a_zw;
89
            flag = 1;
90
            //count = 2;
91
        }
92
 
93
        if (b_zw != b_akt)      //Gleiches Prinzip wie oben, nur für b
94
        {
95
            b_alt = b_akt;
96
            b_akt = b_zw;
97
            flag = 1;
98
            //count = 3;
99
        }
100
101
102
103
104
        if (b_akt == a_alt)     //wenn b_akt gleich a_alt zähler um 1 erhöhen
105
        {
106
            if (flag)
107
            {
108
                count++;
109
                flag = 0;
110
            }
111
        }
112
113
        if (b_akt != a_alt)     //wenn b_akt ungleich a_alt zähler um 1 reduzieren
114
        {
115
            if (flag)
116
            {
117
                count--;
118
                flag = 0;
119
            }
120
        }
121
    }

von MaWin (Gast)


Lesenswert?

Nun steht dort RB0 und RB1 nach RB4 und RB5, ist aber genau so falsch.
Warum nimmst du nicht den viel kürzeren code aus der dse faq?

von Tany (Gast)


Lesenswert?

>Warum sollte man denn etwas per Software halbgar unterdrücken oder
>"zurecht"frickeln, wenn es doch bereits eine solide Lösung gibt, welche
>ohne Tricks auskommt?

Hätte gern eine persönliche Antwort von dir, warum was untenstehende 
nicht funktionieren würde bzw. nicht solide wäre.

Ich kann mit beiden Variante umgehen /umsetzen. Bin kein Fanatiker im 
Gegensatz zu manchem hier im Forum.

PhaseA:
    ldi temp2,(0<<int_PhaseA)|(1<<int_PhaseB)
    sts PCMSK2, temp2
    sbrc enc_LastState,PhaseB
    rjmp vor
    sbrs enc_LastState,PhaseA
    rjmp HL
    dec puffer
    rjmp end_PhaseA
  HL:
    inc puffer
    rjmp end_phaseA
  vor:
    sbrs enc_LastState,PhaseA
    rjmp LH
    inc puffer
    rjmp end_phaseA
  LH:
    dec puffer
  end_PhaseA:
    save puffer
    ret
PhaseB:
    ldi temp2,(1<<int_PhaseA)|(0<<int_PhaseB)
    sts PCMSK2, temp2
    ret

von max2d (Gast)


Lesenswert?

> Nun steht dort RB0 und RB1 nach RB4 und RB5, ist aber genau so falsch.
Was ist denn daran falsch? Ich frage die PINs RB0 und RB1 immer bei 
einem Timer Interrupt ab, so wie ihr es vorgeschlagen habt.

> Warum nimmst du nicht den viel kürzeren code aus der dse faq?
Den Code verstehe ich nicht.

von MaWin (Gast)


Lesenswert?

max2d schrieb:
> Was ist denn daran falsch

Siehe
Beitrag "Re: C Programm für Drehimpulsgeber funktioniert nicht"

Welchen Sinn hat ein Forum, wenn dich die Antworten nicht interessierrn?

von max2d (Gast)


Lesenswert?

MaWin schrieb:

>
> Welchen Sinn hat ein Forum, wenn dich die Antworten nicht interessierrn?

Das Stimmt doch garnicht. Ihr habt zu mir gesagt ich soll nicht über die 
Flankeninterrupts auswerten, sondern über einen Timer.
Was ich jetzt ja mache!

Tut mir leid, aber mit euren Programmen kann ich nichts anfangen. Die 
sind total anders. Und dann auch noch ohne Kommentare

von Achim S. (Gast)


Lesenswert?

ich kenne deinen Controller nicht, aber ich lese folgendes aus den 
bisherigen Antworten:

mit

a_zw = RB0;             //Aktuellen Stand des Drehgebers 
zwischenspeichern

bekommst du nicht den aktuellen Stand des Drehgebers, sondern nur eine 
Konstante. Richtig abfragen müsstest du es mit

a_zw = PORTBbits.RB0;

Steht wie gesagt alles schon in den Antworten oben, du musst dich nur 
auf deren Inhalte konzentrieren statt auf deren Tonfall ;-)

von max2d (Gast)


Lesenswert?

Achim S. schrieb:
>
> a_zw = RB0;             //Aktuellen Stand des Drehgebers
> zwischenspeichern
>
> bekommst du nicht den aktuellen Stand des Drehgebers, sondern nur eine
> Konstante. Richtig abfragen müsstest du es mit
>
> a_zw = PORTBbits.RB0;
>

Stimmt nicht, es reicht RB0. Funktioniert einwandfrei zumindest in einer 
IF abfrage if (RB0) reicht also vollkommen.

von Achim S. (Gast)


Lesenswert?

max2d schrieb:
> Stimmt nicht, es reicht RB0.

wenn dem so ist, dann hättest du das vielleicht gleich nach Stampedes 
Beitrag klarstellen sollen.

Stampede schrieb:
> MaWin schrieb:
>> RB4 und RB5 sind doch Konstanten und nicht die Pins des Ports, oder ist
>> das beim PIC anders?
>
> So ist es. PORTBbits.RB4 wäre korrekt.

Dann hättest du dich nicht darüber ärgern müssen, dass MaWin dich 
mehrmals auf den selben, vermeintlichen Fehler hinweist.

Ob Stampede recht hat oder du kann ich nicht beurteilen: wie oben 
beschrieben (und in deinem Zitat dann weggelassen) weiß ich nicht, wie 
bei deinem Controller der Zugriff auf IO-Ports abläuft.

von max2d (Gast)


Lesenswert?

Ich war mir anfangs mit der PORT abfrage selber nicht so sicher.

Ich glaube eher, dass es ein logisches Problem ist.

von Achim S. (Gast)


Lesenswert?

max2d schrieb:
> Ich war mir anfangs mit der PORT abfrage selber nicht so sicher.

bin ich mir auch jetzt noch nicht. Wenn du mir dein define für RB0 
zeigst, könnte ich mich wahrscheinlich entscheiden, ob ich Stampedes 
oder deiner Schreibweise glaube.

max2d schrieb:
> Ich glaube eher, dass es ein logisches Problem ist.

Stimmt, logische Probleme hat dein Code auch noch zu genüge ;-) Du 
vergleichst z.B. den aktuellen Wert von Kanal A mit dem vorherigen Wert 
von Kanal B. Richtig wäre, dass du die beiden Bits von KanalA und KanalB 
in einen State zusammenfasst und vergleichst, ob ein Übergang von einem 
State zu einem anderen stattgefunden hat.

max2d schrieb:
> Tut mir leid, aber mit euren Programmen kann ich nichts anfangen.

Ich gebe dir recht, dass die Codebeispiele hier und bei dse-faq auf 
Effizienz ausgelegt sind, und nicht auf einfache Verständlichkeit. 
Deshalb hab ich dir zuliebe mal einen extra ausführlichen und extra 
wohlkommentierten Code zusammengetippt. Wenn du anhand dieses Codes die 
Idee besser verstehst, dann kannst du dich vielleicht auch mit den 
anderen (effizienteren) Code-Beispielen anfreunden.

Bis zur endgültigen Klärung verwendet mein Code die Syntax von Stampede 
für die Port-Abfrage ;-)
1
   char aktstate;  //aktueller Wert der beiden Kanäle
2
   char laststate; //Wert der beiden Kanäle bei der letzten Abfrage
3
   int counter;    //Zähler für Position
4
5
    
6
   //im Timer-Interrupt aufrufen
7
   aktstate = 0;
8
   if (PORTBbits.RB0) aktstate |=1; //speichere aktuellen Wert von Kanal A in Bit 0 von Aktstate
9
   if (PORTBbits.RB1) aktstate |=2; //speichere aktuellen Wert von Kanal B in Bit 1 von Aktstate
10
11
   if(aktstate != laststate) {  //falls es eine Änderung gab
12
      //entscheide je nach letztem Zustand, in welche Richtung die Änderung lief
13
      switch (laststate) {
14
      case 0:
15
         if (aktstate == 1) counter++;         //Übergang von 00 -> 01
16
         else if (aktstate == 2) counter--;    //Übergang von 00 -> 10
17
         break;
18
      case 1:
19
         if (aktstate == 3) counter++;         //Übergang von 01 -> 11
20
         else if (aktstate == 0) counter--;    //Übergang von 01 -> 00
21
         break;
22
      case 2:
23
         if (aktstate == 0) counter++;         //Übergang von 10 -> 00
24
         else if (aktstate == 3) counter--;   //Übergang von 10 -> 11
25
         break;
26
      case 3:
27
         if (aktstate == 2) counter++;         //Übergang von 11 -> 10
28
         else if (aktstate == 1) counter--;   //Übergang von 11 -> 01
29
         break;
30
      }
31
      laststate = aktstate; //übernimm neuen Zustand als laststate
32
   }

von Paul B. (paul_baumann)


Lesenswert?

@Achim
Das ist ein richtig gut verständliches Beispiel, selbst für einen
"Nicht-C-Programmierer" dank der Kommentare prima zu verwenden.

MfG Paul

von Achim S. (Gast)


Lesenswert?

Paul Baumann schrieb:
> selbst für einen
> "Nicht-C-Programmierer"

zu der Spezies zähle ich mich selbst eigentlich auch ;-)
(Beim Eintippen hatte ich zuerst diverse Brocken VHDL "beigemischt", 
weil mir das sehr viel präsenter ist als C-Syntax.)

Aber es freut mich, wenn der Code zum Verständnis hilft...

von m.n. (Gast)


Lesenswert?

Achim S. schrieb:
> Ich gebe dir recht, dass die Codebeispiele hier und bei dse-faq auf
> Effizienz ausgelegt sind, und nicht auf einfache Verständlichkeit.

Nachfolgender Code ist effizient und kommentiert, was doch kein 
Gegensatz sein muß.

temp = alter_zustand ^ neuer_zustand;       // aenderungen testen
alter_zustand = neuer_zustand;              // fuer naechsten Aufruf

if(temp & BIT(PHASE_A)) {                   // bei Aenderung von PHASE_A
  if(neuer_zustand == 0 || neuer_zustand == MASKE)
    temp = 1;
  else
    temp = -1;
} else {                                    // bei Aenderung von PHASE_B
  if(neuer_zustand == BIT(PHASE_A) || neuer_zustand == BIT(PHASE_B))
    temp = 1;
  else
    temp = -1;
}
count += temp;                              // Zaehler anpassen

Der Aufruf dieses Codes erfolgt per PCINT und ist in Gänze hier zu 
sehen: Beitrag "Schrittmotor als Drehgeber mit Dynamik, AVR"
Die Routine macht eine 4-fach Flankenauswertung, wie dies üblich ist.

von max2d (Gast)


Lesenswert?

Also, ich habe deinen Code mal auf meinen µC gespielt. Wenn ich am 
Drehgeber drehe zählt er manchmal richtig hoch.
Manchmal kann ich drehen, und es passiert garnichts.
Und manchmal Springt er mehrere Werte bei nur einer Umdrehung hoch.

von Achim S. (Gast)


Lesenswert?

Was genau ist denn jetzt "dein Code"? Der von m.n. oder der von mir?

Nur für den Fall, dass es sich um meinen Code handeln sollte:
- hast du sicher gestellt ob PORTBbits.RB0 oder einfach RB0 richtig ist? 
Welche Variante verwendest du jetzt und wie sieht nochmal dein define 
für RB0 aus?
- in welchen Zeitabständen wird dein Timerinterrupt aufgerufen? 
Vermutest du aufgrund der Programmierung, dass die Wiederholrate deines 
Timer-Interrupts richtig ist oder hast du das mal mit einem toggelnden 
Pin nachgemessen?

von max2d (Gast)


Lesenswert?

Achim S. schrieb:
> Was genau ist denn jetzt "dein Code"? Der von m.n. oder der von mir?

Deiner (Achim S.)

> Nur für den Fall, dass es sich um meinen Code handeln sollte:
> - hast du sicher gestellt ob PORTBbits.RB0 oder einfach RB0 richtig ist?

Ja, hab beides ausprobiert. Funktioniert beides.

> Welche Variante verwendest du jetzt und wie sieht nochmal dein define
> für RB0 aus?
Ich habe keinen define für RB0. Ich setze nur den Pin als Ausgang und 
kann dann den Port mit == abfragen oder mit = beschreiben.

> - in welchen Zeitabständen wird dein Timerinterrupt aufgerufen?
Das ist eine gute Frage. Ich habe den timer1 verwendet und die beiden 
Register mit 260 vorgeladen.

> Vermutest du aufgrund der Programmierung, dass die Wiederholrate deines
> Timer-Interrupts richtig ist oder hast du das mal mit einem toggelnden
> Pin nachgemessen?
Das Timerinterrupt muss passen, habe damit mal PINs abgefragt und dann 
auf der 7-Segment ausgeben lassen

von Achim S. (Gast)


Lesenswert?

max2d schrieb:
>> Was genau ist denn jetzt "dein Code"? Der von m.n. oder der von mir?
>
> Deiner (Achim S.)

na, das ist ja bitter ;-)

Kannst du uns mal deine konkrete timer-ISR zeigen und ggf. die 
Deklaration der Variablen und die Ausgabe der Ergebnisse auf den Port? 
(nicht dass vielleicht irgendwo ein volatile fehlt...)

max2d schrieb:
>> - hast du sicher gestellt ob PORTBbits.RB0 oder einfach RB0 richtig ist?
>
> Ja, hab beides ausprobiert. Funktioniert beides.

es wundert mich, dass beides das selbe Ergebnis liefern soll. Das define 
für RB0 dürfte in irgendeiner header-Datei stecken,die pic16f887.h oder 
ähnlich heißt. Kannst du mal in deinem Projekt nach der Datei suchen? 
Oder kennt deine Entwicklungsumgebung ein "Find in Files", so dass du 
mal eben schnell nach jedem Auftreten von RB0 suchen kannst?

max2d schrieb:
>> - in welchen Zeitabständen wird dein Timerinterrupt aufgerufen?
> Das ist eine gute Frage. Ich habe den timer1 verwendet und die beiden
> Register mit 260 vorgeladen.

Tja, wäre das mein Lieblingscontroller und würde ich deinen 
Initialisierungscode kennen, dann wüsste ich jetzt wie schnell der Timer 
läuft. Da beides nicht der Fall ist schlage ich mal vor: toggle einfach 
in der Timer-ISR einen Ausgang und schau nach, mit welcher Frequenz der 
hin und her wackelt. Am betsen gehts mit nem Oszi. Wenn nicht vorhanden 
dann vielleicht mit einem Multimeter, das Frequenzen messen kann.



PS: in der großen weiten Welt des Internet habe ich grade folgende Seite 
gefunden:
http://blog.irwellsprings.com/getting-started-with-pic-microcontrollers-the-header-file/
Darin steht im Abschnitt "The main header file" wie du zu den relevanten 
header-files findest, in denen die Infos zu deb IO-Ports definiert sind 
(zumindest falls du die selbe Entwicklungsumgebung benutzt):
"Let’s examine this in detail, and follow the header file “trail” to 
find out how it does this. To do this, highlight  <xc.h> right click and 
select Navigate->Go to Declaration"

von max2d (Gast)


Lesenswert?

Hier der Code, ist alles was ich habe:
1
#include <htc.h>
2
__CONFIG (LVP_OFF & WDTE_OFF);              //Low Voltage Programming OFF
3
                                            // Watch dog timer off
4
5
6
7
8
void anzeige (void);
9
10
11
char aktstate;
12
char laststate;
13
int counter;
14
15
void main (void)
16
{
17
18
    T1CON = 0b01000001;
19
    GIE    = 1;
20
    PEIE   = 1;
21
    TMR1IE = 1;
22
    TMR1L = 200;
23
    TMR1H = 200;
24
25
    TRISD = 0;
26
27
    TRISB1= 1;
28
    TRISB0 = 1;
29
    ANSELH= 0;
30
31
    while (1)
32
    {
33
        anzeige ();
34
    }
35
}
36
37
38
void anzeige (void)
39
{
40
        if (counter == 0)         //7-Segment: 00
41
        {
42
            PORTD = 0b00000000;
43
        }
44
45
        if (counter == 1)         //7-Sement: 11
46
        {
47
            PORTD = 0b00010001;
48
        }
49
50
        if (counter ==2)
51
        {
52
            PORTD = 0b00100010;
53
        }
54
55
        if (counter == 3)
56
        {
57
            PORTD = 0b00110011;
58
        }
59
60
        if (counter == 4)
61
        {
62
            PORTD = 0b01000100;
63
        }
64
65
        if (counter == 5)
66
        {
67
            PORTD = 0b01010101;
68
        }
69
}
70
71
72
void interrupt timer (void)
73
{
74
    if (TMR1IF)
75
    {
76
        TMR1L = 260;
77
        TMR1H = 260;
78
        TMR1IF= 0;
79
        aktstate = 0;
80
81
       
82
83
        if (RB0)
84
        {
85
            aktstate |= 1;
86
        }
87
        if (RB1)
88
        {
89
            aktstate |= 2;
90
        }
91
92
        if (aktstate != laststate)
93
        {
94
            switch (laststate)
95
            {
96
                case 0:
97
                    if (aktstate == 1) counter++;
98
                    else if (aktstate == 2) counter--;
99
                    break;
100
                case 1:
101
                    if (aktstate == 3) counter++;
102
                    else if (aktstate == 0) counter--;
103
                    break;
104
                case 2:
105
                    if (aktstate == 0) counter++;
106
                    else if (aktstate == 3) counter--;
107
                    break;
108
                case 3:
109
                    if (aktstate == 2) counter++;
110
                    else if (aktstate ==1) counter--;
111
                    break;
112
113
            }
114
            laststate = aktstate;
115
        }
116
    }
117
}

Ich habe auch mal in meiner Libary (htc.h)nachgeschaut ob ich was mit 
den PORTs finde. Leider sind in der htc.h noch soooo viele Verweise 
drin, dass ich da ne weile dran sitzen würde.

Die Interrupt Frequenz vom Timer kann ich mit meinem Oszi nicht mehr 
richtig messen. Ich sehe aber dass sich was tut.

von Peter II (Gast)


Lesenswert?

mache mal Counter volatile

volatile int counter;

und die Anzeige sollte nur einmal auf Counter zugreifen, also vorher in 
eine neue Variabel kopieren oder gleich ein Switch verwenden:


void anzeige (void)
{
   int tmp = Counter;
        if (tmp == 0)         //7-Segment: 00
        {
...

von Achim S. (Gast)


Lesenswert?

Peter II hats schon geschrieben: counter muss volatile deklariert 
werden, sonst kriegt "anzeige" gar nicht mit, wenn sich in der 
Interruptroutine etwas an "counter" geändert hat.

Außerdem zeigst du nur die counter-Werte 0..5 an. Wenn aus irgend 
welchen Gründen der Counter ins negative läuft (z.B. weil die Kanäle 
anders angeschlossen sind, als du denkst), kriegst du von allen weiteren 
Änderungen nichts mehr mit. Deshalb: greif den Vorschlag von Peter II 
auf, aber mach ein

        temp = counter & 7;

daraus und zeige auf der Siebensegement alle temp-Werte von 0-7 an. Dann 
kannst du keine Änderungen mehr verpassen.

max2d schrieb:
> Die Interrupt Frequenz vom Timer kann ich mit meinem Oszi nicht mehr
> richtig messen.

Was heißt das: zu schnell oder zu langsam für die Messung mit dem Oszi?

Ich weiß schon, dass das lästig und anfangs anstrengend ist, aber du 
musst einen Weg finden, den Counter auf eine definierte Überlauffrequenz 
einzustellen. Dass "sich da was tut" reicht nicht. Arbeite dich durchs 
Datenblatt oder suche dir eine leichter verdauliche Tutoriumsseite bis 
du es schaffst, den Timer auf ~1kHz einzstellen.

Und schon mal ein Tip vorneweg:

        TMR1L = 260;
        TMR1H = 260;

ist ziemlich sicher Unsinn, weil jedes dieser Register nur 8 Bit groß 
sein dürfte (also maximal den Wert 255 aufnehmen kann).

von max2d (Gast)


Lesenswert?

Also, ich habe counter jetzt als volatile deklariert, und tmp = counter 
&7 gesetzt.

Den Timer konnte ich jetzt so einstellen, dass er mit einer Frequenz von 
ca. 2kHz läuft.
Wenn ich den Timer einen PIN toggeln lasse, liegt das Signal 
komischerweise nur wenige Sekunden an. Nach ca. 8 Sekunden beginnt er 
wieder zu toggeln. warum?!

von Achim S. (Gast)


Lesenswert?

na prima, das ist doch schon mal ein Fortschritt.

max2d schrieb:
> Wenn ich den Timer einen PIN toggeln lasse, liegt das Signal
> komischerweise nur wenige Sekunden an. Nach ca. 8 Sekunden beginnt er
> wieder zu toggeln. warum?!

Das klingt in der Tat seltsam. Der Grund dürfte entweder in deiner 
Hardware oder deiner Software oder in deiner Messung liegen ;-)

Denkbare Kandidaten wären:
- irgendwas mit dem Watchdog (obwohl dein Codeschnipsel nahelegt, dass 
der nicht aktiv ist)
- irgendwas in deinem aktuellen Code führt dazu, dass sich das Programm 
nach einiger Zeit aufhängt
- ein externes Problem (vielleicht schaltet dein Netzteil immer mal 
wieder die Versorgung weg, vielleicht bekommt der Controller keinen 
stabilen Takt oder der Takt ist zu schnell, ...)
- ein nicht korrekt beschalteter Reset-Pin, der durch die Gegend floatet 
und ab und zu den Controller in reset hält
- vielleicht ist es auch nur ein Messartefakt (könnte vorkommen, wenn du 
das Oszi z.B.  im Roll-Mode mit einer niedrigen Abtastrate betreibst, so 
dass es zufällig manchmal nur "zwischen den Pulsen" misst und du die 
Pulse nicht erkennst)

Das sind mögliche Gründe, die mir spontan einfallen, es gibt sicher auch 
noch andere Möglichkeiten. Aber arbeite erst mal daran, dass dein 
Controller und dein Timer-Interrupt stabil laufen, danach gehts dann 
weiter mit der Auswertung des Drehgebers...

von max2d (Gast)


Lesenswert?

Den Watchdog Timer habe ich deaktiviert.
Am Netzteil liegt es glaube ich weniger, ist so das teuerste was ich 
hier gefunden habe.
Den Reset PIN habe ich auch richtig beschalten.
Ich glaube es muss am Code selber liegen. An der Quarz Frequenz liegt es 
glaube ich nicht. Ich habe den internen Quarz mal auf die niedrigste 
Frequenz gestellt, mit dem gleichen Ergebniss.

Hier mal mein Code:
1
#include <htc.h>
2
__CONFIG (LVP_OFF & WDTE_OFF);              //Low Voltage Programming OFF
3
                                            // Watch dog timer off
4
5
void anzeige (void);
6
7
char aktstate;
8
char laststate;
9
volatile int counter;
10
11
void main (void)
12
{
13
    OSCTUNE = 0b01111;                     //Oszillatorfreq.: 8MHz
14
    T1CON = 0b01000001;                    //Timer: 2kHz
15
    GIE    = 1;
16
    PEIE   = 1;
17
    TMR1IE = 1;
18
    TMR1L = 0;
19
    TMR1H = 0;
20
    
21
    TMR1L = 253;
22
    TMR1H = 253;
23
24
    TRISD = 0;
25
26
    TRISB1= 1;
27
    TRISB0 = 1;
28
    ANSELH= 0;
29
30
    while (1)
31
    {
32
        anzeige ();
33
    }
34
}
35
36
37
void anzeige (void)
38
{
39
    int tmp = counter &7;
40
    
41
        if (tmp == 0)         //7-Segment: 00
42
        {
43
            PORTD = 0b00000000;
44
        }
45
46
        if (tmp == 1)         //7-Sement: 11
47
        {
48
            PORTD = 0b00010001;
49
        }
50
51
        if (tmp ==2)
52
        {
53
            PORTD = 0b00100010;
54
        }
55
56
        if (tmp == 3)
57
        {
58
            PORTD = 0b00110011;
59
        }
60
61
        if (tmp == 4)
62
        {
63
            PORTD = 0b01000100;
64
        }
65
66
        if (tmp == 5)
67
        {
68
            PORTD = 0b01010101;
69
        }
70
}
71
72
73
void interrupt timer (void)
74
{
75
    if (TMR1IF)
76
    {
77
        TMR1IF= 0;
78
        TMR1L = 0;
79
        TMR1H = 0;
80
        
81
       // aktstate = 0;
82
83
        PORTD =~ PORTD;                 //PORT D Toggeln
84
85
        TMR1L = 253;
86
        TMR1H = 253;
87
88
       /*if (RB0)
89
        {
90
            aktstate |= 1;
91
        }
92
        if (RB1)
93
        {
94
            aktstate |= 2;
95
        }
96
97
        if (aktstate != laststate)
98
        {
99
            switch (laststate)
100
            {
101
                case 0:
102
                    if (aktstate == 1) counter++;
103
                    else if (aktstate == 2) counter--;
104
                    break;
105
                case 1:
106
                    if (aktstate == 3) counter++;
107
                    else if (aktstate == 0) counter--;
108
                    break;
109
                case 2:
110
                    if (aktstate == 0) counter++;
111
                    else if (aktstate == 3) counter--;
112
                    break;
113
                case 3:
114
                    if (aktstate == 2) counter++;
115
                    else if (aktstate ==1) counter--;
116
                    break;
117
118
            }
119
            laststate = aktstate;
120
        }*/
121
    }
122
}

von ichbins (Gast)


Lesenswert?

Hallo,

in der Timer-ISR toggelst du PortD (geht das überhaupt mit einem 
kompletten Port?) aber in der main spielst du ebenso an PortD herum. 
Damit kriegst du keine ordentliche Messung hin - lass einen anderen 
Ausgangspin auf einem anderen Port, als Debug-Pin toggeln.

von ichbins (Gast)


Lesenswert?

ach - und noch etwas

bitte schalte die Codeanzeige bei gepostetem Queltext hier im Forum ein 
- das macht das lesen einfacher

von max2d (Gast)


Lesenswert?

edit:
Habe das Problem gefunden. Ich hatte das T1CON Register falsch 
beschrieben.
Nun habe ich es so beschrieben: T1CON = 0b00000001;

Wenn ich den Drehgeber jetzt ganz langsam um nur eine Raste nach rechts 
oder links drehe kann ich sehen wie die 7-Segment Anzeige von 0 auf 5 
hochzählt, allerdings in nur einer! umdrehung.
Kann es sein, dass ich Prelltechnische Probleme hab?
Ich habe die externe Entprellung nichtmer angeschlossen.

von Achim S. (Gast)


Lesenswert?

max2d schrieb:
> Nun habe ich es so beschrieben: T1CON = 0b00000001;

Und was steuert das eine Bit, das du jetzt geändert hast?


max2d schrieb:
> kann ich sehen wie die 7-Segment Anzeige von 0 auf 5
> hochzählt, allerdings in nur einer! umdrehung.

Bei einer vollen Umdrehung (360°) oder bei einer neuen Rastung (z.B. 
30°).

Wie viele Pulse soll dir dein Drehgeber denn bei einer Umdrehung 
liefern? Auch einfache Drehgeber haben typisch 16 oder mehr Positionen 
pro vollständiger Umdrehung. Es kann auch sein, dass du pro Rastung 
schon 4 Positionen erhältst.

Wenn du eine geringere Auflösung willst, dann ignoriere einfach die 
unteren Bits von Counter

   temp = (counter >> 1) & 7;

von max2d (Gast)


Lesenswert?

Jetzt hat sich hier lange nichts mehr getan, ich war im Urlaub.

Sobald ich den Drehgeber um nur eine Raste drehe springt die Anzeige auf 
55.

Jetzt habe ich mit tmp = (counter >>)&7; hinbekommen, dass bei einer 
Raste die Anzeige nur um +1 erhöht wird.

Nun habe ich aber das Problem, dass meine Anzeige garnicht bis 9 kommt. 
Woran könnte das liegen?

von Oliver S. (oliverso)


Lesenswert?

max2d schrieb:
>  tmp = (counter >>)&7;
...
> Nun habe ich aber das Problem, dass meine Anzeige garnicht bis 9 kommt.
> Woran könnte das liegen?


Hm. Mal nachdenken...

Oliver

von max2d (Gast)


Lesenswert?

ich habe keine Ahnung was der Befehl macht :-D

von max2d (Gast)


Lesenswert?

sry heißt:
tmp = (counter >> 2) &7;

von Achim S. (Gast)


Lesenswert?

max2d schrieb:
> Nun habe ich aber das Problem, dass meine Anzeige garnicht bis 9 kommt.
> Woran könnte das liegen?


Na ja, lass uns noch mal schauen, warum diese Zeile eingeführt wurde:


Achim S. schrieb:
> Außerdem zeigst du nur die counter-Werte 0..5 an. Wenn aus irgend
> welchen Gründen der Counter ins negative läuft (z.B. weil die Kanäle
> anders angeschlossen sind, als du denkst), kriegst du von allen weiteren
> Änderungen nichts mehr mit. Deshalb: greif den Vorschlag von Peter II
> auf, aber mach ein
>
>         temp = counter & 7;
>
> daraus und zeige auf der Siebensegement alle temp-Werte von 0-7 an. Dann
> kannst du keine Änderungen mehr verpassen.

Erklärt das deine Beobachtung?

max2d schrieb:
> ich habe keine Ahnung was der Befehl macht :-D

den findest du in jedem Grundlagenbuch zu C erklärt. Wenn du ernshaft 
programmieren willst, wirst du um das Lesen eines solchen Buchs nicht 
herum kommen.

von max2d (Gast)


Lesenswert?

Das ist mir klar, aber dazu müsste ich erst mal wissen wonach ich suchen 
muss. Wie heißt denn dieser Befehl?

von ich (Gast)


Lesenswert?

max2d schrieb:
> Wie heißt denn dieser Befehl?

Wenn du das hier meinst:
> sry heißt:
> tmp = (counter >> 2) &7;

Das ist eine Bitverschiebung um zwei Bits nach rechts und dann eine 
UND-Verknüpfung. Findest du das wirklich nirgends?

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
Noch kein Account? Hier anmelden.