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:
1
// Interrupt Routine ICP
2
staticunsignedintui_lastval=0;
3
unsignedintui_actval=0;
4
5
ui_actval=ICR1;
6
7
TCNT1H=0x00;//Counter auf 0
8
TCNT1L=0x00;
9
10
SetTrigger();//Trigger auf High
11
12
if(uc_OvrFlow)
13
{
14
ui_NipSpeed=0xFFFF;
15
uc_OvrFlow=FALSE;
16
}
17
else
18
{
19
ui_NipSpeed=ui_actval;
20
21
ui_NipLast=ui_lastval;
22
ui_lastval=ui_actval;
23
}
24
25
OCR1AH=(ui_NipSpeed>>9)&0xEF;//CompareRegister auf Belichtungszeit/2, Rücksetzen von Trigger dann autom.
26
OCR1AL=(ui_NipSpeed>>1)&0xFF;
27
28
if(PIDFlag)PID_control(ui_NipSpeed);
Der Timer ist wie folgt konfiguriert (Bezeichner sind aus UsbWizard):
1
#define PORTD_EXIST 1
2
#define AG_DDRD 255
3
#define AG_PORTVALD 129
4
5
#define AG_TIMSK 0xC8 // Input Capture Int enable; NO Compare A Interrupt enable; Overflow Interrupt enable
6
#define AG_TICTRLA 0x80 // Clear OC1A Output Pin on Match
7
#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 :-)
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ß
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)
> 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.
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.
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.
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?
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.
1
#define SetTrigger() PORTD |= BIT5
2
#define ClearTrigger() PORTD &= ~BIT5
3
#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.
> 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... ;-)
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.
Ä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?
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.
@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