mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Encoder auslesen, fehlerhafte Werte -> Vorschubregelung (PI)


Autor: yoshi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Guten Tag Leute

Für meinen Laminator, welcher verschieden breite Platinen mit der 
Toner-Transfermethode "bedrucken" soll, brauche ich eine 
Vorschubregelung, damit die Platine homogen "bedruckt" wird. Das habe 
ich mit einem Quadraturencoder (HEDL 5540) und einem Mikrocontroller 
realisiert, was soweit auch funktioniert.
Der uC (c8051f330, silabs) besitzt ein PCA Modul, welches eine Capture 
Funktion hat. Ich habe einen Ausgang des Encoders an den uC verbunden. 
Bei jeder pos. Flanke dieses Encodersignals wird ein Interrupt 
ausgelöst. Da wird jedesmal ein "Capture" des im Hintergrund laufenden 
Zählers gemacht. Danach wird die Zeitdifferenz des aktuelle und des 
vorhergehenden Interrupts berechnet, was mir die Zeit zwischen zwei pos. 
Flanken ergibt, also den Kehrwehrt der Drehfrequenz (im code 'rpm') 
meines Motors.
Das sieht so aus:
void isr_capture() interrupt 11
{
  PCA0CN &= ~0x02;
  rpm = pca0cpl - capture_old; 
  capture_old = pca0cpl;
}

Das scheint Ansich auch alles zu funktionieren, jedoch wenn ich diesen 
Wert per UART auf dem PC in einem Diagramm anzeigen lasse, habe ich ca 
alle 2-3 Sekunden Spikes, die manchmal den doppelten Wert anzeigen.
Und genau da liegt das Problem. Diese Werte machen meine Regelung 
verrückt.
Ich könnte die zwar filtern, aber lieber möchte ich die Ursache dieses 
Verhaltens ermitteln! Ich dachte zuerst, dass der Encoder zu viele 
Interrupts generiert und der uC nicht mehr mit Abarbeiten nachkommt. 
Jedoch sind diese Spikes nicht von der Drehzahl abhängig (soweit ich das 
beobachten konnte). Weiter dachte ich, dass es evt. ein Overflow sein 
könnte. Dies ist jedoch nur möglich, wenn sich die Werte an einer 
Bereichsgrenze aufhalten würden. Das ist leider auch nicht der Fall.
Des weiteren habe ich versucht, alles anderen Interrupts abzuschalten. 
Das half leider auch nichts. Hat sowas auch schon jemand gehabt? Gibt es 
sonst noch Sachen, die ich austesten / beachten sollte?
Den kompletten Code könnte ich nachrücken, falls erwünscht, jedoch denke 
ich, dass es etwas grundlegenderes ist, was ich noch nicht verstanden 
habe.

Viele Grüsse,
yoshi

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Welche Datentypen haben pca0cpl und capture_old

Overflows des Timers kannst du nur dann ignorieren, wenn
* diese Variablen unsigned sind
* nicht mehr als 1 Overflow von einem Capture zum nächsten Auftritt

Autor: hlhjghj (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kann es sein, dass Du den Zaehler ueberlaufen laesst und die seltsamen 
Werte immer dann auftauchen, wenn die Differenz "ueber den Ueberlauf 
hinweg" berechnet wird?

Waere so mein erster Gedanke.

Gast

Autor: yoshi (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger

Es sind beides 16bit unsigned Typen. Es passiert meines Erachtens nicht 
mehr als 1 Overflow.

Ich habe ein Bild angehängt. Das linke Diagramm zeigt denn gemessenen 
Wert des Encoders. Also die Zeit zwischen zwei pos. Flanken.
Im Rechten Diagramm sieht man den PWM-Wert. Man sieht deutlich, dass er 
versucht diesen Spike auszuregeln.

Das komische ist ja, dass mehrer Messwerte nacheinander sehr valide 
scheinen, nur diese vereinzelten Spikes stören das Bild.

Grüsse,
yoshi

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Fangen wir mal damit an, dass du ein wenig mehr als nur diesen 
Winzigausschnit deines Programms zeigst.

Ich tippe irgendwo auf eine leichtfertige Berechnung, bei der du aus den 
unsigned Typen zwischendurch irgendwo signed Werte kriegst. Mach dein 
Diagramm größer und ich wette deine Spitze geht bis 65536 - ~4000

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  yoshi (Gast)

>Bei jeder pos. Flanke dieses Encodersignals wird ein Interrupt
>ausgelöst. Da wird jedesmal ein "Capture" des im Hintergrund laufenden
>Zählers gemacht. Danach wird die Zeitdifferenz des aktuelle und des
>vorhergehenden Interrupts berechnet, was mir die Zeit zwischen zwei pos.
>Flanken ergibt, also den Kehrwehrt der Drehfrequenz (im code 'rpm')

MÖÖP! Falsch. Einen Drehgeber wertet man mit einer Abtastung im 
festen Intervall aus, siehe Artikel.

MfG
Falk

Autor: yoshi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Karl heinz Buchegger:
Komischerweise sind bei gleichbleibender Drehgeschwindigkeit die Spikes 
nicht immer gleich hoch.
Ich werde, wenn ich zuhause bin, den Code soweit abspecken, dass er sich 
nurnoch auf das Problem beschränkt und ich ihn hier zeigen kann ;-)

@Falk:
Da sich der Encoder nur sehr langsam dreht, habe ich gedacht, wäre es 
sinnvoller wenn die Zeit zwischen zwei Flanke gemessen wird (um auf 
etwas höhere Werte zu kommen). Wenn ich bloss die Encoder Incs zählen 
würde, wären diese Werte viel zu klein um die für die Regelung verwenden 
zu können. Darum habe ich nicht die dort vorgeschlagenen Methoden 
verwendet.
Liege ich da falsch?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
yoshi schrieb:

> Liege ich da falsch?

Kommt drauf an.

Ist dein Encoder prellfrei?

(Die Richtung willst du ja nicht feststellen. Sehe ich das richtig?
Im Grunde verwendest du den Encoder nur als vorhandenen Ersatz für eine 
Lochscheibe mit Lichtschranke)

Autor: yoshi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Karl heinz Buchegger:
Ja, es ist einen optischen Encoder (besitzt sogar eine Lochscheibe mit 
Lichtschranke).

Genau, ich will bloss ein Mass für die Drehgeschwindigkeit erhalten.


Grüsse,
yoshi

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
yoshi schrieb:

> Genau, ich will bloss ein Mass für die Drehgeschwindigkeit erhalten.

:-)
Dann nennen wir das ganze nicht 'Drehencoder auswerten' sondern 
'Frequenz der Unterbrechungen der Lichtschranke' feststellen und alles 
ist paletti :-)

Also:
Ohne Programm ist das jetzt schwer zu sagen. Schau dir noch mal alle 
Datentypen an. Schau dir alle Berechnungen an. Schau dir an, ob 
Berechnungen überlaufen können, etc. ...

Autor: yoshi (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Habe nun das Programm mal stark vereinfacht.
Die Datentypen sollten stimmen.

Hier der Code:
#include <c8051f330.h>
#include "drehzahlregler.h"

sfr16 pca0cpl = 0xe9;
unsigned int capture_old, rpm;

// main program
void main (void){
  Init_Device();

  rpm = 0;
  set_motor_speed(30);

  // main loop
  while(1){
  }
}  


void isr_capture() interrupt 11
{
  PCA0CN &= ~0x02;
  rpm = pca0cpl - capture_old; 
  capture_old = pca0cpl;

  SBUF0 = rpm >> 8;
  while(!TI0);
    TI0 = 0;
  SBUF0 = rpm;
  while(!TI0);
    TI0 = 0;
}

void set_motor_speed(unsigned char speed)
{
  PCA0CPH0 = 0xff - speed;
}


void PCA_Init()
{
    PCA0CN    = 0x40;
    PCA0MD    &= ~0x40;
    PCA0MD    = 0x08;
    PCA0CPM0  = 0x42;
    PCA0CPM1  = 0x21;
}

void Timer_Init()
{
    TCON      = 0x45;
    TMOD      = 0x20;
    CKCON     = 0x08;
    TL1       = 0xBA;
    TH1       = 0xA9;
    TMR2CN    = 0x04;
    TMR2RLL   = 0x7E;
    TMR2RLH   = 0xF9;
    TMR2L     = 0x7E;
    TMR2H     = 0xF9;
}

void UART_Init()
{
    SCON0     = 0x10;
}

void Port_IO_Init()
{
    P0MDIN    = 0xF3;
    P0MDOUT   = 0x50;
    P0SKIP    = 0x0F;
    XBR0      = 0x01;
    XBR1      = 0x42;
}

void Oscillator_Init()
{
    int i = 0;
    OSCXCN    = 0x67;
    for (i = 0; i < 3000; i++);  // Wait 1ms for initialization
    while ((OSCXCN & 0x80) == 0);
    CLKSEL    = 0x01;
    OSCICN    = 0x00;
}

void Interrupts_Init()
{
    IE        = 0x80; 
    IP        = 0x10;
  EIP1    = 0x10;
    EIE1      = 0x10;
    IT01CF    = 0x98;
}

void Init_Device(void)
{
    PCA_Init();
    Timer_Init();
    UART_Init();
    Port_IO_Init();
    Oscillator_Init();
    Interrupts_Init();
}

Autor: yoshi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Habs nun raus, der Encoder war defekt :(
;-)
Trotzdem vielen Dank,
yoshi

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]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [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.