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
Es heisst Interrupt und nicht Interrumpt. Und zum Deaktivieren: GIMSK
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.
Und noch ein PS. Periodenlängen misst man am Besten mit der Input Capture Einheit vom Timer 1. Genau dafür ist die nämlich gebaut worden.
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 | volatile uint8_t haveValue; |
2 | uint16_t prevCount; |
3 | uint16_t ticks; |
4 | |
5 | //Interrupts
|
6 | ISR(SIG_INPUT_CAPTURE1) |
7 | {
|
8 | uint16_t nowCount = 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
1 | volatile uint8_t haveValue; |
2 | uint16_t prevCount; |
3 | uint16_t ticks; |
4 | |
5 | //Interrupts
|
6 | ISR(SIG_INPUT_CAPTURE1) |
7 | {
|
8 | uint16_t nowCount = ICR1; |
9 | |
10 | ticks = nowCount - prevCount; |
11 | haveValue = TRUE; |
12 | |
13 | prevCount = nowCount; |
14 | }
|
15 | |
16 | ....
|
17 | |
18 | int main() |
19 | {
|
20 | ...
|
21 | |
22 | while( 1 ) { |
23 | |
24 | ...
|
25 | |
26 | if( haveValue ) { // es gibt ein Ergebnis |
27 | // das Ergebnis steht in ticks
|
28 | haveValue = FALSE; |
29 | mach was mit ticks |
30 | }
|
31 | }
|
Lass doch die Hardware für dich arbeiten!
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_t nowCount = 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 |
14 | }
|
15 | |
16 | haveValue = TRUE; |
17 | prevCount = nowCount; |
18 | }
|
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). |
(nur so als Hinweis)
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.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.