mikrocontroller.net

Forum: Compiler & IDEs Compare A Match setzt immer 0


Autor: David Knochenhauer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

ich versuch schon seit Stunden ein einfaches Problem zu lösen.
Es wird die Drehzal eines Motors über den ICP und eine PID-Regelung 
geregelt.

Beim ICP Interrupt (steigende Flanke) wird der Timer auf 0 gesetzt und 
der Wert des ICR1 an die PID-Regelung übergeben. Das funktioniert soweit 
ganz gut.
Jetzt soll aber noch aus dem anliegenden Signal ein weiteres generiert 
werden. Dazu habe ich mir überlegt, das ich den Output Compare A Mode 
benutze und OCR1A auf ICR1<<1 (also die Hälfte)setze. So dass ich aus 
einem Signal mit asymetrischem Tastverhältnis ein symetrisches 
Rechtecksignal bekomme.

Controller ist ein AT43USB355. OC1A ist auf PD5

mal ein bisschen Code:
// Interrupt Routine ICP
static unsigned int ui_lastval=0;
unsigned int ui_actval=0;
  
  ui_actval = ICR1;
  
  TCNT1H = 0x00;  //Counter auf 0
  TCNT1L = 0x00;
    
  SetTrigger();  //Trigger auf High
      
  if (uc_OvrFlow)
  {
  ui_NipSpeed = 0xFFFF;
  uc_OvrFlow = FALSE;
  }
  else
  {
  ui_NipSpeed = ui_actval;  
    
  ui_NipLast = ui_lastval;
  ui_lastval = ui_actval;
  }
  
  OCR1AH = (ui_NipSpeed>>9) & 0xEF; //CompareRegister auf Belichtungszeit/2, Rücksetzen von Trigger dann autom.
  OCR1AL = (ui_NipSpeed>>1) & 0xFF;
  
  if (PIDFlag) PID_control(ui_NipSpeed);

Der Timer ist wie folgt konfiguriert (Bezeichner sind aus UsbWizard):
#define PORTD_EXIST      1
#define AG_DDRD  255
#define AG_PORTVALD  129

#define AG_TIMSK    0xC8 // Input Capture Int enable; NO Compare A Interrupt enable; Overflow Interrupt enable
#define AG_TICTRLA  0x80 // Clear OC1A Output Pin on Match
#define AG_TICTRLB  131 // CK/64; No Clear on Match; Rising Edge; Noise Canceller ON //war 195

Das Problem ist nun folgendes:
Mit den obigen Einstellungen ist PD5/OC1A immer low. Bei TICTRLA 0xC0 
(set on Match) immer high. Der Portpin ist richtig konfiguriert. Wenn 
ich den Output Compare abschalte und in die ISR ein "Toggle PD5" 
einbaue, geht es (allerdings mit halber Frequenz).

Danke für die Hilfe :-)

Autor: Gock (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi!
Kann es sein:
Wenn Du die Zeitkonstante des ICP (der ja weiterhin auslöst) für OCR 
verdoppelst, weil DU die halbe Frequenz willst, dann wird OCR vom 
schnelleren ICP IRQ überschrieben, bevor es auslösen konnte.
Allerdings erkenne ich nicht, was uc_OvrFlow ist...
Gruß

Autor: David N-K (knochi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich verdoppel den Wert ja nicht, sondern halbiere ihn.
Das Signal wird gesetzt, wenn der Interrupt passiert und soll dann nach 
der Hälfte der Zeit (die aus der vorigen Umdrehung ermittelt wurde) 
zurückgesetzt werden. So ergibt sich dann ein gleichmässiges Rechteck.

Übrigens hatte ich das TCCR1B Register falsch gesetzt, hatte auf 
fallende statt auf steigende Flanke getriggert. Macht aber auch keinen 
Unterschied, hätte auch funktionieren sollen, da das Eingangsignal recht 
kurz high pegel hat und dann lange low ist. Änderung brachte aber auch 
nix.

uc_OvrFlow ist ein bool, der gesetzt wird, wenn der Zähler überläuft 
(was in der Regel nicht passiert, ist nur für den Anlauf gedacht um 
Überläufe zu vermeiden)

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Mit den obigen Einstellungen ist PD5/OC1A immer low. Bei TICTRLA 0xC0
> (set on Match) immer high.

Weder dem Codeschnipsel, noch deiner Beschreibung, ist zu entnehmen, wie 
und wo sich der Pegel auch wieder "zurückändern" soll.

Autor: David N-K (knochi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Na "zurückändern" soll der Pegel des OC1A Ausganges sich durch ein 
Output Compare Match.

Ich versuchs mal so:
Eingangssignal an ICP/PF3
 <-------T-------->
+---+              +---+
|   |              |   |
+   +--------------+   +-----
1                  1

gewünschtes Ausgangssignal an OC1A/PD5
 <---T/2-->
+----------+           +-----
|          |           |
+          +-----------+
1          2           1


Bei (1) kommt der Interrupt durch den ICP (Input Capture), der Zähler 
wird auf Null gesetzt und das OCR1A Register wird auf T/2 gesetzt.
Nach dem ICP Interrupt läuft der Zähler wieder von 0 los und wenn er den 
Wert von OCR1A erreicht setzt der Controller selbstätig OCR1A/PD5 auf 
"0" (Zeitpunkt (2))(Clear the OC1A output line (to zero)).
So hab ich jedenfalls den Mechanismus interpretiert, korrigiere mich 
bitte, falls ich falsch liegen sollte.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und du meinst, der Pegelwechsel zum Zeitpunkt 1 passiert von alleine?

Autor: David N-K (knochi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Narf...
Der Pegelwechsel (low-high) am Zeitpunkt "1" erfolgt durch das Makro 
SetTrigger() (siehe Kommentar). Der Pegelwechsel (high-low) zum 
Zeitpunkt "2" sollte durch den Output Compare Mechanismus erfolgen.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
David Knochenhauer wrote:

> Der Pegelwechsel (low-high) am Zeitpunkt "1" erfolgt durch das Makro
> SetTrigger() (siehe Kommentar).

Aha, der OC1A-Output-Pin heißt bei dir "Trigger", kann ich ja nicht 
wissen. Wo ist der Code zu SetTrigger?

Autor: David N-K (knochi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eigentlich hatte ich gehofft hier Hilfe zu bekommen und nicht vorgeführt 
zu werden, wie ein kleiner Schuljunge. Mir ist durchaus bewusst das 
meine Schilderungen, nunja etwas undurchsichtig waren.
Das ist aber sicher kein Grund, solch einen Ton anzuschlagen.

Der Code zu SetTrigger, setzt ganz normal den Portpin und funktioniert 
auch.
#define SetTrigger()  PORTD |= BIT5
#define ClearTrigger()  PORTD &= ~BIT5
#define ToggleTrigger()  PORTD ^= BIT5

PIDFlag ist übrigens ein bool und dient dazu die Regelung ein oder aus 
zu schalten. Ist für die gewünschte Funktion aber nicht von Bedeutung.

Autor: Micha (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Eigentlich hatte ich gehofft hier Hilfe zu bekommen und nicht vorgeführt
> zu werden, wie ein kleiner Schuljunge.
Dann solltest du aber auch die zum Helfen benötigten Informationen 
posten, sprich: eine kompilierbare Minimalversion des Programmes, die 
das Problem enthält.

> Das ist aber sicher kein Grund, solch einen Ton anzuschlagen.
Ob dein Ton soviel besser ist... ;-)

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
David Knochenhauer wrote:

> Das ist aber sicher kein Grund, solch einen Ton anzuschlagen.

Welcher Ton denn bitte?
Dein "siehe Kommentar" kann man durchaus interpretieren als "es steht 
doch da, du musst nur richtig hinschauen". Darauf habe ich geantwortet.

Autor: David N-K (knochi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Äh Leute...
Wollen wir uns jetzt mit dem Problem beschäftigen oder weiter zwischen 
den Zeilen irgendwelche Anschuldigungen rein interpretieren?

Ich dachte halt, das vieleicht jemand in dem Codeschnipsel einen 
Flüchtigkeitsfehler entdeckt, der mir endgangen ist. Das Ganze ist ja 
nun kein Hexenwerk. Eine minimal kompilierbare Version zu posten ist 
relativ schwierig, da es sich um einen USB-Controller AT43USB355 handelt 
und das mitgeliefert Codegerüst (ja das muss man nutzen, da dieses auf 
vorkompilierte Programmteile zurückgreift) recht umfangreich ist.

Ich wollte eigentlich nur wissen, was ich übersehen haben könnte beim 
einstellen des Timer1 Compare A Match.

Können wir jetzt auf einer normalen Ebene kommunizieren oder muss ich 
woanders Hilfe suchen?

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
David Knochenhauer wrote:
> Äh Leute...
> Wollen wir uns jetzt mit dem Problem beschäftigen oder weiter zwischen
> den Zeilen irgendwelche Anschuldigungen rein interpretieren?
> ...
> Können wir jetzt auf einer normalen Ebene kommunizieren oder muss ich
> woanders Hilfe suchen?

Sorry, aber du hast schließlich angefangen, dich über den Ton zu 
beschweren. Da werde ich ja wohl noch drauf reagieren dürfen.

Autor: Jörg G. (joergderxte)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@OP:Für mich sieht das so aus, als ob du zwei Sachen (Interrupts?) 
laufen lassen willst , die BEIDE den Timer1 löschen ?
Wie soll das denn funktionieren?
Versuch's doch mal anders (falls die Frequenzen niedrig genug sind):
 - Die ICR1 ISR lässt den Timer in Ruhe und berechnet die Differenz 
zum vorherigen ICR1-Wert (Musst du natürlich speichern)
 - Der OC1A output wird auf "Toggle on compare match" eingestellt
 - in der OC1A-ISR wird der Halbe Sollwert (ist das ICR1/2 ?) auf das 
OC1A Register addiert (nicht wundern, das GEHT).

Und poste Code, kurz&kompilierbar, wie schon mehrfach erwähnt.

hth, Jörg

Autor: David N-K (knochi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hmm den Timer1 löscht eigentlich nur die Input Capture Routine.

Kann es sein, das immer bei einem Capture Interrupt auch der Compare A 
Match auslöst?

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.