Hallo zusammen,
ich möchte mit INT0 und INT1 die Impulse messen. Dafür habe ich diese
Interrumps so programmiert, dass ich auf die High Flanke auf INT0 wird
der Timer gestartet und bei Low Flanke auf INT1 wird der Timer gestopt.
void extern_interrumps_init()
{
//Interrumpt aufloesen beim High- und Low-Flanke
MCUCR |= (1<<ISC00) | (1<<ISC01) | (1<<ISC11);
GICR |= (1<<INT0); //High-Flanke
GICR |= (1<< INT1); //Low-Flanke
}
//Interrumps
SIGNAL (SIG_INTERRUPT0)
{
TCNT1=0; //timer auf Null setzen
TCCR1B |= (0<<CS12) | (0<<CS11) | (1<<CS10);
}
SIGNAL (SIG_INTERRUPT1)
{
//INT1 timer stop
TCCR1B = (0<<CS12) | (0<<CS11) | (0<<CS10)
value= TCNT1; // Wert lesen.
}
Nun möchte jetzt zuerst ein paar Rechnungen durchführen ohne
Unterbrechungen von INT0 und INT1, sonst bekomme ich Werte die nicht
zusammenpassen.
Meine Überlegung, dass ich Beide Interrumps sperre bis meine Rechnungen
fertig sind.
Leider weiss ich nicht, wie und wo ich diese Interrumps sperren bzw.
freigen kann.
Dankeim Voraus für jede Hilfe.
P.S. ich verwende Atmega16
PS: Es heißt Interrupt. nicht Interrumpt
lat: Interruptus .. die Unterbrechung
Du hast Glück
TCCR1B = (0<<CS12) | (0<<CS11) | (0<<CS10)
Das ist eigentlich nicht so ganz richtig. In Kurzform ist das
gleichbedeutend mit
TCCR1B |= 0;
Und das ist wahrscheinlich nicht die Operation, die du haben willst.
Einzelne Bits kann man nicht mit deiner Methode auf 0 setzen
TCCR1B &= ~( (1<<CS12) | (1<<CS11) | (1<<CS10) );
... so geht das
> Leider weiss ich nicht, wie und wo ich diese Interrumps> sperren bzw. freigen kann.
Wenn du keine anderen Interrupts mehr im System hast, die weiter laufen
müssen, kannst du einfach mittels cli() alle Interrupts sperren und
mittels sei() alle Interrupts auf einmal wieder freigeben.
Ansonsten bleibt dir natürlich immer noch der Weg, die beiden Interrupts
um die es hier geht, im GICR wieder durch setzen ihres Bites auf 0 zu
sperren.
hallo Karl Heinz,
danke für die kurze Erklärung.
wenn Ich Dich richtig verstanden habe und Du darfst mich natürlich
korrigieren, es ist am besten die Impulsedauer der Input Capture Einheit
zu messen. Nun mit welcher Taktfrequenz wird es alles gemessen? Kann ich
die Voll CPU-Frequenz nutzen?
Danke
tetef schrieb:
> hallo Karl Heinz,>> danke für die kurze Erklärung.> wenn Ich Dich richtig verstanden habe und Du darfst mich natürlich> korrigieren, es ist am besten die Impulsedauer der Input Capture Einheit> zu messen. Nun mit welcher Taktfrequenz wird es alles gemessen? Kann ich> die Voll CPU-Frequenz nutzen?
Kannst du.
Du musst nur auf mehr als einem Timerüberläuf acht geben.
Hi Karl Heinz,
Ich stosse mich mit einem kleinem Problem und zwar, ich versuche, wie Du
erwähnt hast, dass ich mit dem Input Capture arbeite um die Impulse zu
messen.
Nun ich soll nur die Zeitdauer der high-Flanken messen.
Ich habe:
1. Mein Signal an den Port ICP Port (PD6 Atmega16) angeschlossen.
2. Den Timer1 habe ich initialisiert.
3. Die Interrupts wurden initialisiert.
Leider bekomme ich nicht die exakte Messungen, warum? bin ich ehrlich
ratlos?
//Interrupts
ISR(SIG_INPUT_CAPTURE1)
{
//timer capture
phase0 = TCNT1;
}
Der Sinn eines INput Capture besteht nicht darin, dass man sich dann von
TCNT1 den aktuellen Zählerstand holt. Bei einem Input Capture kopiert
die Hardware den aktuellen Zählerstand beim Auftreten des Ereignisses
in ein spezielles Register
while(1) // Unendlich lang wiederholen
{
//wait until PD6 low
while(!(PIND & (1<<PD6)));
//timer value initialize, measurement will be started
TCNT1 = 0;
//wit until PD6 high
while(PIND & (1<<PD6));
Genau das brauchst du dann nämlich nicht tun!
Du wartest auf nichts mehr.
In der ISR nimmst du die Differenz zum Zählerstand, der im
vorhergehenden ISR Aufruf gesichert wurde. Da deine ISR bei jeder
Low-High Flanke aufgerufen wird, ist diese Differenz exakt die Anzahl
der Timerticks von einer steigenden Flanke zur nächsten.
1
volatileuint8_thaveValue;
2
uint16_tprevCount;
3
uint16_tticks;
4
5
//Interrupts
6
ISR(SIG_INPUT_CAPTURE1)
7
{
8
uint16_tnowCount=ICR1;
9
10
ticks=nowCount-prevCount;
11
haveValue=TRUE;
12
13
prevCount=nowCount;
14
}
in ticks steht das Messergebnis. Liegt ein weiterzuverarbeitendes
Ergebnis vor, so wird haveValue auf TRUE gesetzt, damit man in main auch
weiß, dass wieder etwas vorliegt, was verarbeitet werden möchte.
(Und benutze bitte die für ISR vorgesehenen Namen der Interrupt
Routinen)
Ich habe nicht verstanden.
Ein Iterrupt wird gerufen, wenn ein high-low Flanke vorkommt.
Aber ich möchte, die Zeit zwischen low-high und high-low Flanke messen.
Tetef El schrieb:
> Ich habe nicht verstanden.>> Ein Iterrupt wird gerufen, wenn ein high-low Flanke vorkommt.> Aber ich möchte, die Zeit zwischen low-high und high-low Flanke messen.
Du kannst auch innerhalb einer ISR die Art der Flankenerkennung
umschalten :-)
Ich habs jetzt nicht im Kopf, aber ich denke man kann die Erkennung auch
so konfigurieren, dass sie bei jeder Flanke auslöst. Ein Blick auf den
Input-Pin sagt dir dann ob es eine High-Low oder eine Low-High Flanke
war.
Es ist nicht das, was ich in main geschrieben habe. solange ich die low
Flanke habe warte ich. Danach kommt natürlich eine high Flanke, wird
kutz davor der Timer auf 0 gestezt. Bei der nächsten high-low Flanke
wird die Interrupt ausgelöst. Ich habe die Übertragung in ISR
geschrieben. Aber troztdem bekomme ich nicht die richtigen Daten.
//Interrupts
ISR(SIG_INPUT_CAPTURE1)
{
//timer capture
phase0 = ICR1;
uart_puti(phase0);
uart_putc('\n');
uart_putc(13);
}
int main(void)
{
DDRD &= ~(1<<PD6);
uart_init(1, 1);
input_capture_init() ;
sei();
while(1) // Unendlich lang wiederholen
{
//wait until PD6 low
while(!(PIND & (1<<PD6)));
//timer value initialize, measurement will be started
TCNT1 = 0;
//wit until PD6 high
while(PIND & (1<<PD6));
}
}
Tetef El schrieb:
> Es ist nicht das, was ich in main geschrieben habe. solange ich die low> Flanke habe warte ich.
Nochmal.
Wozu?
Die ISR (meine Version) teilt dir mit, wann ein Ergebnis vorliegt
hi Karl Heiz,
Ich gebe dir recht, wenn Du schreibst, ich soll die Hardware für mich
arbeiten.
Nun mit Deiner Methode werde ich die Frequenz messen, aber ich möchte
das Tastverhältnis messen. Wie lange ist mein High Flanke?
Tetef El schrieb:
> hi Karl Heiz,>> Ich gebe dir recht, wenn Du schreibst, ich soll die Hardware für mich> arbeiten.> Nun mit Deiner Methode werde ich die Frequenz messen, aber ich möchte> das Tastverhältnis messen. Wie lange ist mein High Flanke?
Dann musst du in der ISR die High-Flanke von der Low-Flanke trennen.
(Hab jetzt doch im Datenblatt vom Mega16 nachgesehen. Den Input Capture
kann man nur auf entweder Fallend oder Steigend einstellen, Beides
zusammen geht nicht. Aber man kann natürlich in der ISR die jeweilige
Richtung umschalten :-)
1
//Interrupts
2
ISR(SIG_INPUT_CAPTURE1)
3
{
4
uint16_tnowCount=ICR1;
5
6
if(TCCR1B&(1<<ICES1)){
7
lowDuty=nowCount-prevCount;// wir sind auf einer steigenden Flanke ->
8
// d.h. der low Duty wurde gemessen
9
TCCR1B&=~(1<<ICES1);// die nächste Flanke soll eine fallende sein
10
}
11
else{
12
highDuty=nowCount-prevCount;
13
TCCR1B|=(1<<ICES1);// die nächste Flanke soll eine steigende sein
Bezüglich des Umschaltens der Flanke gibt es in jedem Datenblatt
(zumindest jedem, in das ich bisher gesehen habe) einen Satz, der gerne
übersehen wird:
1
After a change of the edge, the Input Capture Flag (ICF1) must be
2
cleared by software (writing a logical one to the I/O bit location).
Stefan Ernst schrieb:
> Bezüglich des Umschaltens der Flanke gibt es in jedem Datenblatt> (zumindest jedem, in das ich bisher gesehen habe) einen Satz, der gerne> übersehen wird:>
1
After a change of the edge, the Input Capture Flag (ICF1) must be
2
> cleared by software (writing a logical one to the I/O bit
3
> location).
> (nur so als Hinweis)
Danke!
Hätt ich glatt übersehen :-)
Karl heinz Buchegger schrieb:
> Danke!> Hätt ich glatt übersehen :-)
Mir ist sowieso schleierhaft, warum diese Info nicht auch dort steht, wo
sie meiner Meinung nach hingehören würde, nämlich bei der
Detailbeschreibung von ICES. Vielleicht ist dieser Satz mitten in der
Input-Capture-Unit-Beschreibung ja auch nur ein Überbleibsel aus "alten
Tagen" und nicht mehr gültig. Ich habe auch schon Code gesehen, der das
nicht berücksichtigt hat, und laut Autor einwandfrei funktionieren soll.
Wäre ja nicht das erste Copy&Paste-Problem bei AVR-Datenblättern. ;-)
Tetef El schrieb:
> Wo sollte man die ICF1 löschen??
Nach der Modusumschaltung. Steht doch dort.
Die Modusumschaltung ist in der ISR, also wird man dort das Flag
löschen.
hallo Karl Heiny,
ich habe jetzt das Programm geschrieben dank Deiner Hilfe.
Wenn ich einen Sensor (eine Spule) über ein Metall ziehe, dass ein Riss
hat, dann entsteht ein Wirbelstrom. Die Darstellung der Wirbelstrom
erfolgs durch
die bechnung vom Real und Imag. Teil.Diese komplexen Werte werden
übertragen und dargestellt.
Die Problematik, die ich jetzt habe, ist, dass wenn ich mit dem Sensor
langsam über ein Metall ziehe, dann bekomme ich ein schöne Darstellung
(bild2), aber wenn ich schnell ziehe, bekomme ich ein schrecklische
Darstellung (bild2).
Ich frage mich, was mache ich falsch oder liegt das an meinem µC, weil
er langsam ist. ich Amplitude umwandeln und jedes Mal die Zeit messen
und berechnen.
P.S µC Atmega16 mit 16Mhz. Generatorfrequenz 20kHz.