Forum: Mikrocontroller und Digitale Elektronik STM32 Quadrature Encoder - 4x Resolution - ich bekomm's nicht hin


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Florian F. (flof3000)


Bewertung
0 lesenswert
nicht lesenswert
Hallo Forum,

ich versuche einen Glassmasstab per STM32 auszulesen.
Der Glassmastab hat eine Auflösung von 1 um,
und sollte also auf 5 cm 50.000 Impulse liefern.
Er hat einen 0815 Quadratur-Encoder eingebaut.

Ich bekomme aber leider nur 25.000 Impulse im Counter gezählt,
obwohl ich dem STM32F103C8T6 (Bluepill...) sage er soll
beide Kanäle zählen und die Doku sagt, dass immer beide Flanken 
ausgewertet werden. Ich bekomme also keine '4x' Auflösung hin.

Bevor ich also heute Abend den Glassmasstab durch zwei Schalter ersetzt 
und das wirklich auf Flankenebene durchspiele,
dachte ich vielleicht sieht ja jemand den Fehler per Glaskugel.

Auswerte Schmema ist Standard:
Timer2 ist als Encoder definiert und zaehlt von 0..16000, und wird auf 
8000 gesetzt. Impulse zählen hier also hoch und runter (unsigned Wert, 
deswegen der Shift um 8000).
Timer1 kommt jede Millisekunde, addiert Timer2->CNT - 8000 zu einem long 
und setzt wieder auf 8000.
Die Schleife gibt dann alle Sekunden den long per Serieller 
Schnittstelle aus...

Gruss
FloF
1
#define ENCODER_ZERO_VALUE  8000
2
3
HardwareTimer timer(2);
4
HardwareTimer timer_tick(4);
5
6
long current_position = 0;
7
8
void my_timer_tick(void)
9
{
10
    current_position += (signed int) timer.getCount() - ENCODER_ZERO_VALUE;
11
    timer.setCount(ENCODER_ZERO_VALUE); //setzt ->CNT
12
}
13
14
void init_timer() 
15
{
16
17
    //war mal per Arduino HardwareTimer eingerichtet, zeigt aber das gleiche verhalten...
18
    timer_dev *t = TIMER2; 
19
    timer_reg_map r = t->regs;
20
    timer_pause(t);
21
    timer_set_mode(t, 0, TIMER_ENCODER);
22
    //straight from the reference manual...
23
    r.gen->CCMR1 |= TIMER_CCMR1_CC1S;
24
    r.gen->CCMR1 |= TIMER_CCMR1_CC2S;
25
    r.gen->CCER |= TIMER_CCER_CC1P;
26
    r.gen->CCMR1 &= ~TIMER_CCMR1_IC1F;
27
    r.gen->CCER |= TIMER_CCER_CC2P;
28
    r.gen->CCMR1 &= ~TIMER_CCMR1_IC2F;
29
    r.gen->SMCR |= TIMER_SMCR_SMS_ENCODER3; //trigger on both channels  - this is 0b11
30
    r.gen->CNT = ENCODER_ZERO_VALUE; //current value
31
    r.gen->ARR = 2 * ENCODER_ZERO_VALUE; //overflow at
32
    r.gen->PSC = 0;//prescaler =1 / no prescalleroff
33
    timer_resume(t);
34
35
    //second timer reads the encoder register at regular intervals
36
    timer_tick.setChannel1Mode(TIMER_OUTPUTCOMPARE);
37
    timer_tick.setPeriod(1000); // in microseconds
38
    timer_tick.setCompare1(1); // overflow might be small
39
    timer_tick.attachCompare1Interrupt(my_timer_tick);
40
    timer_tick.resume();
41
}
42
43
44
void setup(){
45
    pinMode(LED_PIN, OUTPUT);
46
  led_on();
47
    Serial.begin(9600); //not sure why I need both, but I need both and then can write with Serial.println...
48
    Serial1.begin(9600);
49
    pinMode(PA0, INPUT_PULLUP);
50
    pinMode(PA1, INPUT_PULLUP);
51
    init_timer();
52
}
53
54
55
void loop() {
56
    delay(1000);
57
    Serial.println(current_position);
58
}

von Typ (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Ganz naiv, Hardware passt?
Also kommen bei beiden Pins Flanken an?

von Florian F. (flof3000)


Bewertung
0 lesenswert
nicht lesenswert
Jup - wenn ich einen davon abziehe zählt er nur noch hoch oder runter - 
würde ich auch so erwarten, der andere ist ja dann Dauerhaft HIGH.

von FloF3000 (Gast)


Bewertung
0 lesenswert
nicht lesenswert
So, jetzt hab ich's mit Tastern ausprobiert:
Er zählt tatsächlich nur bei jeder 2. Flanke.

Also entweder verstehe ich den Modus nicht, oder?

von chris (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Unter Verwendung der Standard Peripheral Lib hab ich das mit genau 
diesem µC schonmal erfolgreich umgesetzt.
Anbei der Code dazu. Welche Register genau die Funktionen setzen kannst 
du in der entpsrechenden Source von ST nachschauen. (stm32f10x_tim.c)
Ich möchte dieses File aus Copyright-Gründen jetzt hier nicht hochladen.

Das Zurücksetzen des Encoder-Counters halt ich übrigens für keine gute 
Idee. Wenn zwischen Auslesen und Zurücksetzen ein Encoder-Puls 
reinkommt, verlierst du den. Ein sehr seltener Fall, aber irgendwann 
wird das passieren und du wunderst dich warum die Position nicht stimmt.
Lass den Counter stattdessen einfach die vollen 16bit laufen und bilde 
immer die Differenz zwischen den jeweiligen Zaehlerständen (Codebeispiel 
siehe unten). Ein Überlauf macht da nichts, da die Differenz trotzdem 
stimmt (so lange du öft genug aufrufst, dass nicht 2^16 Pulse zwischen 
zweimal Auslesen reinkommen).

1
static void timer2_encoder_init()
2
{
3
  GPIO_InitTypeDef GPIO_InitStructure;
4
5
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
6
7
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
8
9
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
10
11
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;   // Pullups enable
12
13
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
14
  GPIO_Init(GPIOA, &GPIO_InitStructure);
15
16
  TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Falling);
17
18
  TIM_Cmd(TIM2, ENABLE);
19
20
  // Zaehlerstand abrufen mit:
21
  // uint16_t counter = TIM_GetCounter(TIM2);
22
}
23
24
int32_t pos_aktuell = 0;
25
int32_t speed = 0;
26
27
int32_t pos_alt = 0;
28
29
30
int16_t encoder_aktuell = 0;
31
int16_t encoder_alt = 0;
32
33
34
static void encoder_update()
35
{
36
  encoder_alt = encoder_aktuell;
37
  encoder_aktuell = TIM_GetCounter(TIM2);
38
39
  int16_t delta;
40
  delta = encoder_aktuell - encoder_alt;
41
  pos_alt = pos_aktuell;
42
  pos_aktuell += delta;
43
44
  speed = pos_aktuell - pos_alt;
45
}


LG
Chris

von apollo2mond (Gast)


Bewertung
-3 lesenswert
nicht lesenswert
hi,
ich verstehe nicht warum dein auswertschema standard ist, für mich ist 
das eher "esoterisch".
standard ist für mich ein interrupt bei jeder flanke an den 2 pins und 
dann auswertung.
das sollte ohne zweifel auch immer funktionieren unter der voraussetzung 
die maschine ist schnell genug mit bezug zum timing des external events 
und das passt ja wohl hier!
das habe ich schon x-mal so implementiert mit 8-bit herzschlag und einer 
function die beide isr benutzen.

erleuchte mich mal bitte, weil ich neige bereits dazu an murcks zu 
denken.


dk4ug

von chris (Gast)


Bewertung
0 lesenswert
nicht lesenswert
apollo2mond schrieb:
> "esoterisch"

Die meisten (alle?) STM32 haben einen Quadratur-Decoder in Hardware.
Damit kann ohne CPU-Beteiligung Frequenzen bis hin zum CPU-Takt 
erfassen.
Da ist also nix esoterisch dran, sondern es ist - sofern die Hardware 
vorhanden ist - der Standardweg.
Soft-UART oder Soft-SPI implementiert man ja i.d.R. auch nur, wenn keine 
Hardware dazu vorhanden (oder frei) ist.

von apollo2mond (Gast)


Bewertung
0 lesenswert
nicht lesenswert
... vielleicht hilft es ja?!
meine isr function für die zwei pin change interrupts

int32_t readEncoder() {
  const int8_t encoderStates[16] = 
{0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
  static uint8_t lastState=3;
  static int32_t  position;
  int8_t state =  digitalRead(ENCODER_PINA) | 
(digitalRead(ENCODER_PINB)<<1);

  if (state != lastState) {
    position += encoderStates[state | (lastState << 2)];
    lastState = state; //remember previous state
    if (state == 3) encoderPosition = position >> 2;
  }
  return encoderPosition;
}

von Johannes S. (jojos)


Bewertung
0 lesenswert
nicht lesenswert
Florian F. schrieb:
> r.gen->CCMR1 |= TIMER_CCMR1_CC1S;
> r.gen->CCMR1 |= TIMER_CCMR1_CC2S;

sind diese Zeilen richtig? Laut manual sollte das so initialisiert 
werden:
• CC1S= ‘01’ (TIMx_CCMR1 register, TI1FP1 mapped on TI1)
• CC2S= ‘01’ (TIMx_CCMR2 register, TI2FP2 mapped on TI2)

von Walter T. (nicolas)


Bewertung
0 lesenswert
nicht lesenswert
Und nicht vergessen: PA0 und PA1 sind nicht 5V-tolerant.


Die Initialisierung von Chris sollte auf jeden Fall funktionieren. Ich 
nutze die gleiche.

von Florian F. (flof3000)


Bewertung
0 lesenswert
nicht lesenswert
apollo2mond schrieb:
> standard ist für mich ein interrupt bei jeder flanke an den 2 pins und
> dann auswertung.

Das scheint mir der wahre Pfusch, siehe
https://www.mikrocontroller.net/articles/Drehgeber#Auswertung_mit_Interrupt_durch_Pegelwechsel

@chris: vielen Dank, das wird mir sicherlich weiterhelfen! Und der Tipp 
mit dem Überlauf ist auch sehr gut.

von Wolfgang (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Florian F. schrieb:
> Bevor ich also heute Abend den Glassmasstab durch zwei Schalter ersetzt
> und das wirklich auf Flankenebene durchspiele, ...

Das wäre doch wohl das naheliegendste. Den Debugger kannst du dann 
gleich mitlaufen lassen.

> Ich bekomme aber leider nur 25.000 Impulse im Counter gezählt,...

Wieso "nur". Wenn immer 25.000 raus kommt, hast du immerhin nicht die 
Maximalgeschwindigkeit bei der Bewegung überschritten und der Fehler 
läßt sich reproduzieren - beste Bedingungen zum Debuggen.

Du bist sicher, dass du das Datenblatt deines Geber richtig 
interpretiert hast oder hast die 1µm Auflösung durch eine Messung 
verifiziert?

von apollo2mond (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
ok, der hw decoder macht sinn, wenn du die maschine entlassten 
musst/willst und ein anspruchvolles external timing hast. beides wäre 
hier nicht der fall.

interessantes beispiel, weil mein sw decoder funktioniert und braucht 
augenscheinlich weniger hw resourcen - ich denke, noch kompakter geht es 
nicht!? hat aber grenzen, wenn die interrupts nicht verarbeitet werden 
können ... und darum gibt es ja das eventsystem.

ich kenne halbwegs die stm32 familie und das event system, aber daraus 
folgt für mich nicht dein standard als ansage.

aber natürlich muss auch ein hw encoder funktionieren und rund laufen.
ich zieh mir mal jetzt die details der doku und lib rein ...


keep going

von apollo2mond (Gast)


Bewertung
-2 lesenswert
nicht lesenswert
...
Das scheint mir der wahre Pfusch, siehe
https://www.mikrocontroller.net/articles/Drehgeber...

gleich lockere starke worte?!

diesen guten beitrag kenne ich.

mein gewählter ansatz ist ok, wenn du das in dem  !bewusstsein! machst, 
das pendeln/prellen die maschine durch "unnötige" interrupts belastet, 
führt aber nie zu fehlerhaften werten und das ist der entscheidene 
punkt.

copy/past ohne verstehen/bewusstwerdung sehe ich als problematischer an, 
darum kenne ich immer gut die hw plattform und lese auch die details.

ich benutze für jede hw plattform einen emulator/debugger, um beobachten 
zu können was da abgeht.

die arduino plattform taugt nur zum quick and dirty start ... und 
printf's als debug tool verdient keine erwähnung.

ich freue mich schon auf die auflösung und lass mal nur aus interesse 
die stopuhr laufen, um zu realisieren wie lange wir brauchen.

parallel hole ich mal mein entwicklungssystem raus um auf registerebene 
deinen code durchzufahren ...

von Marco H. (damarco)


Bewertung
0 lesenswert
nicht lesenswert
Ihr müsst auch darauf achten das eure Positions Variable nicht 
überläuft! Dreht sich das Rad immer in die gleiche Richtung läuft die 
Variable über.

Das Zurücksetzen an sich macht schon Sinn wenn man sich auf die Position 
der letzten Auswertung bzw. Den Mechanischen Überlauf der Hardware 
bezieht.

Der Weg das Register zurückzusetzen ist in der Tat wage, man kann aber 
das overflow Bit in der Hardware auswerten und die Absolute Position 
berechnen.

von Walter T. (nicolas)


Bewertung
0 lesenswert
nicht lesenswert
Marco H. schrieb:
> Ihr müsst auch darauf achten das eure Positions Variable nicht
> überläuft!

Die Positionsvariable ist unsigned 16 Bit. Ein Überlauf macht ihr 
überhaupt nichts, weil man ohnehin immer mit Differenzen arbeitet. Die 
ist dann 16 Bit vorzeichenbehaftet.

Bei meinem Projektchen läuft die Positionsvariable alle 0,8 Sekunden 
über und fühlt sich Pudelwohl dabei.

von Florian F. (flof3000)


Bewertung
1 lesenswert
nicht lesenswert
apollo2mond schrieb:
> gleich lockere starke worte?!

Wer die Methode aus dem Reference Manual als 'esoterisch' und 'Murks' 
bezeichnet darf auch mal ein "Pfusch" für seine Variante, vor der im 
Wiki explizit gewarnt wird, einstecken.
Glashaus und in den Wald rufen und und so.

apollo2mond schrieb:
> ok, der hw decoder macht sinn, wenn du die maschine entlassten
> musst/willst und ein anspruchvolles external timing hast. beides wäre
> hier nicht der fall.

Mit Verlaub - Du kannst nicht beurteilen, was sonst noch so außerhalb 
des obigen Minimalbeispiels anliegt.

----

Dein Ansatz hat neben dem Interrupts-lasten-die-CPU-vollständig aus noch 
ein Problem: Seine Fehlerfreiheit kommt daher, dass er nur jede 2. 
Flanke zählt (2X Auflösung).
Gefragt war aber gerade 4X.

4X geht nicht ohne Jitter von +-1, wie man auch in Abbildung 93, Seite 
330 des STM32F103 Reference Manuals sehen kann. Aber das stört mich hier 
nicht.

Die Hardwarelösung des STM32 ist ja nichts anderes als deine 
State-Maschine, aber eben ohne das Worst Case Problem.

------

Mein Debuggen per Schalter hat eine interessante Sache geliefert, die 
nicht zur Tabelle 81 im Reference Manual passen möchte:
Und zwar zählt er mir immer nur die 2. rising und die 2. falling Edge
Taster gegen GND, Pullup an, A=1,B=1:
drücke A  -> A=0, B=1 -> keine Veränderung.
drücke B  -> A=0, B=0 -> +1
A los     -> A=1, B=0 -> keine Veränderung
B los     -> A=1, B=1 -> +1
und umgekehrt
drücke B  -> A=1, B=0 -> keine Veränderung
drücke A  -> A=0, B=0 -> -1
B los     -> A=0, B=1 -> keine Veränderung
A los     -> A=1, B=1 -> -1

Das passt aber weder zu 'Counting on TI1' (oder TI2) only, noch zu 
'counting on TI1 and TI2'. Im ersteren Fall sollte er bei rising & 
falling nur von A oder nur von B zählen, und im zweiten bei jeder 
Veränderung.

Also entweder 'input filter', oder 'prescaler', oder die Addition 
versaut. Oder hab ich was übersehen?

von Chris D. (myfairtux) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Marco H. schrieb:
> Ihr müsst auch darauf achten das eure Positions Variable nicht
> überläuft! Dreht sich das Rad immer in die gleiche Richtung läuft die
> Variable über.
>
> Das Zurücksetzen an sich macht schon Sinn wenn man sich auf die Position
> der letzten Auswertung bzw. Den Mechanischen Überlauf der Hardware
> bezieht.
>
> Der Weg das Register zurückzusetzen ist in der Tat wage, man kann aber
> das overflow Bit in der Hardware auswerten und die Absolute Position
> berechnen.

Man benötigt kein Rücksetzen, wenn sichergestellt ist, dass man den 
Zähler so abfragt, dass maximal die halbe Zählerbreite hochgezählt 
werden konnte, hier also 32767 Impulse. Erfolgt das Auslesen vorher, so 
kann man immer entscheiden, ob der Zähler herauf- oder heruntergezählt 
wurde. Die ausgelesene Position speichert man ab und das Spiel beginnt 
von neuem.

So kann auch kein Impuls verloren gehen (eben weil der Zähler nur 
ausgelesen wird).

Die zyklische Abfrage selbst kann dann idealerweise in einem 
Timerinterrupt stattfinden, also bspw. alle 1ms. Das führt zu einer 
maximalen Zählfrequenz von 32767*1000 > 32MHz! - ohne großartige 
Controllerbelastung.

Im Moment sehe ich Deinen Fehler auch noch nicht. Hier mein 
(funktionierender) Code für Timer 3 eines STM32F0DISCOVERY:
1
  RCC_APB1PeriphClockCmd (RCC_APB1Periph_TIM3, ENABLE);
2
3
  // Initialisiere Pins für Encoderanschluss
4
  GPIO_InitTypeDef GPIO_InitStructure;
5
6
  // Den Pins die alternative Funktion zuordnen
7
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
8
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
9
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
10
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
11
    
12
  GPIO_InitStructure.GPIO_Pin = ENCODER_A_PIN;
13
  GPIO_Init (ENCODER_A_PORT, &GPIO_InitStructure);
14
  GPIO_InitStructure.GPIO_Pin = ENCODER_B_PIN;
15
  GPIO_Init (ENCODER_B_PORT, &GPIO_InitStructure);
16
17
  // Verknüpfung mit Timer 3-Eingängen (TIM3_CH1 und TIM3_CH2)
18
  GPIO_PinAFConfig (ENCODER_A_PORT, ENCODER_A_AF, GPIO_AF_1);
19
  GPIO_PinAFConfig (ENCODER_B_PORT, ENCODER_B_AF, GPIO_AF_1);
20
21
  // Konfiguriere Quadratur-Encoder-Modus von Timer 3
22
  // Lege TI1 auf TI1FP1 und TI2 auf TI1FP2
23
  TIM3->CCMR1 |= TIM_CCMR1_CC1S_0 | TIM_CCMR1_CC2S_0;
24
  // Polarität der Eingänge: beide nichtinvertierend
25
  TIM3->CCER &= (uint16_t) (~(TIM_CCER_CC1P | TIM_CCER_CC2P));
26
  // Sowohl auf fallenden als auch steigenden Flanken zählen (SMS = 011)
27
  TIM3->SMCR |= TIM_SMCR_SMS_1 | TIM_SMCR_SMS_0;
28
  // Vorteiler :1
29
  TIM3->PSC = 0;
30
  // Setze Zähler und ebenso den alten Encoderwert auf "Mitte"
31
  old_encoder = 0x8000;
32
  TIM3->CNT = old_encoder;
33
  // Timer einschalten
34
  TIM3->CR1 |= TIM_CR1_CEN;

: Bearbeitet durch Moderator
von Walter T. (nicolas)


Bewertung
0 lesenswert
nicht lesenswert
Solange TIMx_SMCR = 0x3 und TIMx_ETPS = 0 steht, sollte da keine Flanke 
verloren gehen.

von Marco H. (damarco)


Bewertung
0 lesenswert
nicht lesenswert
Ja das kann man so machen, eine weitere Möglichkeit. Ich sagte ja man 
muss den Umstand aber im Auge haben.

von c-hater (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
Florian F. schrieb:

> 4X geht nicht ohne Jitter von +-1, wie man auch in Abbildung 93, Seite
> 330 des STM32F103 Reference Manuals sehen kann. Aber das stört mich hier
> nicht.

Da bauen die extra eine Hardware für diese Sache ein und dann kann die 
nicht einmal die Umwandlung des "Jitter" in eine 
1-Schritt-Umkehrhysterese leisten (zumindest optional)? Das würde 
immerhin nur sehr wenige zusätzliche Gatter kosten.

Wenn das wirklich so wäre (was ich kaum zu glauben vermag): eine 
absolute Frechheit...

von Walter T. (nicolas)


Bewertung
1 lesenswert
nicht lesenswert
c-hater schrieb:
> und dann kann die
> nicht einmal die Umwandlung des "Jitter" in eine
> 1-Schritt-Umkehrhysterese leisten (zumindest optional)? Das würde
> immerhin nur sehr wenige zusätzliche Gatter kosten.

Eine Umkehrhysterese? Dann würde ich  aber hysterisch. Die Funktion des 
Zählers ist sauber und wie erwartet: Bei jeder Flanke wird herauf- oder 
herabgezählt.

von apollo2mond (Gast)


Bewertung
0 lesenswert
nicht lesenswert
... weiter gehts, ich denke du must mal die dinge "sortieren"

- 4x encoder und jitter haben nichts miteinander zwingend zu tun!
- das beispiel im manual zeigt nur, das bei prellen/jitter (realer 
encoder) der zähler immer +-1 zählt und daher kein fehler ensteht
- ein idealer encoder wäre ohne jitter
- der stm32 encoder mode macht alles richtig und hat auch kein problem 
mit x4!
- dein schaltertest erscheint mir unpassend weil die schalter natürlich 
prellen und daher muss auch nicht immer +1/-1 gezählt werden, wie ja das 
beispiel dir zeigt
- die regelmäßigkeit der testergebnisse erklärt sich mir nicht
- somit bleibt offen, ob die sw überhaupt die baustelle ist!
- entprell die schalter mit d-ff oder schalte port lines direkt und 
wiederhol den test
- ich denke, das ergebnis wird sich ändern
- was dein glasstab da so macht solltest du mal mit dem oszi anschauen!

- nur am rand, meine encoderanwendung ist auch 4x

keep going!


- 1-Schritt-Umkehrhysterese ... immer diese spinner, nix gelernt dafür 
doof und glücklich!?

von apollo2mond (Gast)


Bewertung
0 lesenswert
nicht lesenswert
MERKER:

Manaual Seite 329 ...
Figure 93 gives an example of counter operation, showing count signal 
generation and direction control.

!!!
It also shows how input jitter is compensated where both edges are 
selected.
!!!
total logisch ... both edges selected

nur aus dem grund zählt auch meine sw ohne fehler, weil beide flanker 
ausgewertet werden.


... und könnte/wird auch erklären dein unstimmiges testergebnis,

schaun wir mal wie es weitergeht!

passend zum hw testen, sei die frage erlaubt:

ist der unterschied zwischen verifizieren und validieren oder 
falsifizieren geläufig?

von Wolfgang (Gast)


Bewertung
0 lesenswert
nicht lesenswert
apollo2mond schrieb:
> - ein idealer encoder wäre ohne jitter

Jitter ist doch völlig egal. Es spielt für die Funktion einen 
Dreh-Encoders überhaupt keine Rolle, ob eine Flanke etwas früh oder 
später kommt, solange die Reihenfolge eingehalten wird.
https://de.wikipedia.org/wiki/Jitter

Was meinst du mit "Jitter"?

von m.n. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Wolfgang schrieb:
> apollo2mond schrieb:
>> - ein idealer encoder wäre ohne jitter
>
> Jitter ist doch völlig egal.

Ich glaube, Du sprichst nicht den Urheber des Jitter-Problems an, denn

apollo2mond schrieb:
> - 4x encoder und jitter haben nichts miteinander zwingend zu tun!

Bei diesem Thema kann aus Hysterie schnell eine Hysterese werden, sowie 
andere Leute von Pfusch reden, nur weil sie sich bei jedem Interrupt in 
die Hose machen. Der µC würde überlastet und könne jederzeit 
explodieren!
Da wird dann "Pendeln, Prellen, Surren, Zirren" usw. erfunden, um eine 
vermeintliche Universallösung zu propagieren, die allein in 
Schneckenhausen funktionieren würde.

Wenn ich einen Hardwaredekoder auf dem Chip habe, wird natürlich dieser 
verwendet. Aber bei einem 1 µm Glasmaßstab reicht auch ein ATmega48 für 
Verfahrgeschwindigkeiten <= 200 - 400 mm/s. Gerade bei einem Lineargeber 
ist dank beidseitigen Anschlages die Interruptlast begrenzt.

Mich würde ja mal interessieren, um welchen Geber es sich überhaupt 
handelt (genaue Typenbezeichnung). Hat er ggf. nur 2 µm Auflösung?

von apollo2mond (Gast)


Bewertung
0 lesenswert
nicht lesenswert
... in der tat, den begriff jitter hätte ich hier auch nie selber 
gewählt!
ich denke, denverwendet st hier irreführend, weil kontaktprellen damit 
beschrieben wird.

ABER jitter bei encodern extistiert (je nach bauart)und ist auch ein 
echtes problem, weil daraus eine ungenauigkeit oder ein 
reproduzierbakeitsproblem für eine gesuchte/detektierte position folgen 
kann.

richtig, jitter in unserem diskutierten fall würden wir garnicht 
bemerken, ausser wir messen immmer die strecke nach, die mit der 
possitionsangabe korrespondiert


meine erfahrung ...
wann auch immer ich nur copy/past mache, egal ob hw oder sw, das endete 
immer in mehr arbeit als wenn ich es gleich richtig selber gemacht hätte 
und war nie eine abkürzung, aber dafür oft viel frust.


cyberhermit

von FloF3000 (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Es handelt sich um GCS898-K5, und ja, sie sind für 1um spezifiziert.

Schalter waren natürlich mit RC-Glied zur Vermeidung von Prellen dran.

Wenn ich einen Encoder über Pins simuliere (und entsprechend verbinde) 
zählt er immer noch falsch:
1
void step_left()
2
{
3
    digitalWrite(PA2, 0);
4
    delay(1);
5
    digitalWrite(PA3, 0);
6
    delay(1);
7
    digitalWrite(PA2, 1);
8
    delay(1);
9
    digitalWrite(PA3, 1);
10
    delay(1);
11
}
führt zu einem Count von 200, und nicht zu 400.


Aber: Mit STM32CubeMX geht es!

-> Entweder es ist doch ein Fehler in meiner Registerdefinition,
oder das STM32Duino Framework setzt irgendwo was was nachher stört.

Mal schaun, wann ich dazu komme das zu debuggen.

von Uwe Bonnes (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Setz Dich in den Debugger. Gebe den Timer aus "p /x *TIMx" und dekodiere 
die gesetzten Bits...

Beitrag #5185194 wurde von einem Moderator gelöscht.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.