Hallo, Ich möchte gerne eine Pulseweite mit dem ICP Pin auslesen. Ich benutze WINAVR und programmiere in C. Doch ich verstehe die Funktion des ICP Pins nicht. Ich kann ja über die Register einstellen, ob auf positive oder negative Flanke reagiert werden soll. Und auch in der ISR dieses wieder auf die Andere Flanke zurück stellen. Doch was muss ich alles beachten, damit dies überhaupt möglich ist ? Muss ich den Timer 1 laufen lassen ? Muss ich mich an die Anweisungen halten das ICR Register von unten auszulesen oder macht der Compiler es automatisch, wenn ich das Register in einen Intager Kopiere. Ich bin mitlerweile dabei willkürlich alles auszuprobieren, doch es klappt nix. Mein Letzter Erfolg war, das die ISR einmal ausgeführt wurde. Mehr leider nicht. Währe spitze, wenn mir einer sagen könnte, wie ich alle Register setzen muss, die dafür zuständig sind oder mir sogar erklärt, wie der ICP Pin funktioniert. Mich ärgert es, dass ich immernoch nicht in der Lage bin das Datenblatt 100% zu verstehen. Danke schonmal im Vorraus.
Christian Paulsen wrote: > Hallo, > Ich möchte gerne eine Pulseweite mit dem ICP Pin auslesen. > Ich benutze WINAVR und programmiere in C. > Doch ich verstehe die Funktion des ICP Pins nicht. Datenblatt und AVR-Tutorial / AVR-GCC-Tutorial schon durchgearbeitet? > Ich kann ja über die Register einstellen, ob auf positive oder negative > Flanke reagiert werden soll. Ja, das kannst Du... > Und auch in der ISR dieses wieder auf die Andere Flanke zurück stellen. > Doch was muss ich alles beachten, damit dies überhaupt möglich ist ? Eigentlich gar nichts. > Muss ich den Timer 1 laufen lassen ? Wenn was Sinnvolles rauskommen soll, ja! > Muss ich mich an die Anweisungen halten das ICR Register von unten > auszulesen oder macht der Compiler es automatisch, wenn ich das Register > in einen Intager Kopiere. Wenn Du ICR1L und ICR1H nicht separat ausliest, sondern das 16-Bit-Register ICR1 benutzt, dann nimmt Dir der Compiler die Sache mit der Reihenfolge ab. > Ich bin mitlerweile dabei willkürlich alles auszuprobieren, doch es > klappt nix. Mein Letzter Erfolg war, das die ISR einmal ausgeführt > wurde. Mehr leider nicht. Dann hast Du vermutlich irgendwas falsch gemacht... > Währe spitze, wenn mir einer sagen könnte, wie ich alle Register setzen > muss, die dafür zuständig sind oder mir sogar erklärt, wie der ICP Pin > funktioniert. Ganz kurz und knapp: Wenn am ICP-Pin eine Flanke (je nach Einstellung positiv, negativ oder beide) auftritt ("Capture-Ereignis"), wird der Inhalt des Zählregisters (TCNT1) in das ICR1 übernommen. Das ICP-Interrupt-Flag wird gesetzt und (wenn aktiv) der Interrupt-Handler wird ausgeführt. Bei der nächsten Flanke dann wieder das gleiche Spielchen. Dass da immer der selbe Wert rauskommt, wenn der Timer nicht läuft (siehe Frage weiter oben), ist hoffentlich klar... > Mich ärgert es, dass ich immernoch nicht in der Lage bin das Datenblatt > 100% zu verstehen. Aha, Datenblatt hast Du also schon versucht...
Johannes M. wrote: > [...] Wenn am ICP-Pin eine Flanke (je nach Einstellung > positiv, negativ oder beide) auftritt [...] Sorry, geht natürlich nur entweder oder, und nicht beide...
Beschleunigungssensor ADXL oder Fernsteuerempfänger? Wenn Fernsteuerempfänger, dann könnte das evtl. helfen: Beitrag "Re: Servoausgänge verUNDen" Axelr.
also in basic sieht das ungefähr so aus
1 | '------------------------------------------------------------------------------- |
2 | ' mega163 auf stk 500 |
3 | ' einlesen eines empfängerpulses via t1 interupt LCD 16x4 |
4 | ' INT1=D3 NOV 07 |
5 | '------------------------------------------------------------------------------- |
6 | $regfile = "m163def.dat" |
7 | $crystal = 3686000 |
8 | $baud = 19200 |
9 | |
10 | |
11 | Config Portb = Output |
12 | Config Portd = Input |
13 | |
14 | Config Timer1 = Timer , Prescale = 1 |
15 | |
16 | Config Int1 = Change 'config change int0 |
17 | |
18 | Config Lcd = 20 * 4 'LCD Display |
19 | Config Lcdpin = Pin , Db4 = Porta.4 , Db5 = Porta.5 , Db6 = Porta.0 , Db7 = Porta.1 , E = Porta.3 , Rs = Porta.2 |
20 | |
21 | |
22 | Dim Wert As Word |
23 | Dim Error As Bit |
24 | Dim Reading As Bit |
25 | |
26 | On Timer1 Rc_error |
27 | On Int1 Rc_read |
28 | |
29 | Portb = &HFF |
30 | |
31 | Wert = 20 |
32 | Error = 0 |
33 | Reading = 0 |
34 | Initlcd
|
35 | Waitms 10 |
36 | |
37 | Enable Int1 |
38 | |
39 | Enable Timer1 |
40 | |
41 | Stop Timer1 |
42 | Enable Interrupts |
43 | |
44 | Waitms 10 |
45 | |
46 | |
47 | |
48 | |
49 | Do
|
50 | ' Disable Interrupts |
51 | Locate 1 , 4 : Lcd "ok" |
52 | Locate 3 , 2 : Lcd Wert |
53 | If Error = 1 Then |
54 | Locate 4 , 1 : Lcd "error" |
55 | End If |
56 | |
57 | Waitms 20 |
58 | Cls
|
59 | |
60 | ' Enable Interrupts |
61 | 'Wert = 20 |
62 | Toggle Portb.6 |
63 | Waitms 20 |
64 | |
65 | Loop
|
66 | |
67 | End
|
68 | |
69 | Rc_read: |
70 | If Reading = 0 And Portd.3 = 1 Then |
71 | Start Timer1 |
72 | Reading = 1 |
73 | Else
|
74 | Stop Timer1 |
75 | Wert = Timer1 |
76 | Timer1 = 0 |
77 | Reading = 0 |
78 | End If |
79 | Error = 0 |
80 | |
81 | Return
|
82 | |
83 | |
84 | Rc_error: |
85 | Error = 1 |
86 | Reading = 0 |
87 | Stop Timer1 |
88 | |
89 | Return
|
Hallo, vielen Dank für die Antworten. Ja genau, da ganze soll für eine RC Anlage sein. Ich möchte mir einen Fahrtenregler für meinen Hubschrauber Programmieren. Bis jetz wird nur beim Start des Controllers in die ISR gewechselt, danach spinnt der controller rum und macht irgend ein Quatsch. Habe warscheinlich Programmierfehler ohne Ende in meinem Programm. Ich lasse mir einfach jedes mal etwas auf einem Display anzeigen, wenn der Controller einmal in einer ISR war. Ich werd mal in dem Servo Code Beispiel stöbern. Vielleicht verstehe ich meinen Fehler ja dann. Wenn nicht, dann werde ich mal mein Programmausschnitt Posten. Vielen Dank noch mal.
Hallo nochmal. Also irgendwie bin ich immer noch nicht weiter. Ich benutze immoment einen MEGA 32. Ich möchte wissen, wie lange eine Flanke dauert. Bei der steigenden Flanke lese ich mit der ISR Routine des ICP PINs den Timerwert aus, schalte in der Routine um auf fallende Flanke und lass mir die Differenz auslesen und in eine Variable ausgeben. Im Hauptprogramm lasse ich mir den wert der Variablen durch 256 Teilen und gebe es auf Leuchtdioden aus. Bis jetzt sind jedoch alle leuchtdioden dunkel, egal , was ich am ICP PIN tue. Im Debugger jedoch tut der controller was er soll. Änder ich etwas am PIN D6 geht der Controller (laut simulator) in die ISR Routine. So Hier ist mein C# Code. Kann mir vielleicht jemand helfen ? :-(
1 | #include<avr/interrupt.h> |
2 | #include<avr/io.h> |
3 | #include "C:\Archiv\libary\mega32\Header\rs232.h" |
4 | #include "C:\Archiv\libary\mega32\Header\delay.h" |
5 | #include "C:\Archiv\libary\mega32\Header\umwandeln.h" |
6 | void ICP_init(void); |
7 | |
8 | int Buffer_ICR3=0; |
9 | volatile int Buffer_ICR1=0; |
10 | volatile int Buffer_ICR2=0; |
11 | volatile int x=0; |
12 | |
13 | ISR(TIMER1_CAPT_vect) |
14 | {
|
15 | |
16 | |
17 | |
18 | |
19 | //Edge Detektor auf negative Flanke einstellen
|
20 | //if (x==0)
|
21 | // {
|
22 | // Buffer_ICR1=ICR1;
|
23 | // TCCR1B &=(0<<ICES1);
|
24 | |
25 | // }
|
26 | //Edge Detektor auf positive Flanke einstellen
|
27 | // if (x!=0)
|
28 | // {
|
29 | // Buffer_ICR2=ICR1;
|
30 | // Buffer_ICR=Buffer_ICR2-Buffer_ICR1;
|
31 | // TCCR1B |=(1<<ICES1);
|
32 | Buffer_ICR3=ICR1; |
33 | |
34 | // }
|
35 | // TIFR |= (1<<ICF1);
|
36 | |
37 | // x=!x;
|
38 | |
39 | }
|
40 | |
41 | int main() |
42 | {
|
43 | DDRD=0x00; |
44 | DDRA=0xff; |
45 | PORTA=0xff; |
46 | |
47 | //ICP aktivieren
|
48 | //Noise Canceler aktivieren
|
49 | TCCR1B |= (1<<ICNC1); |
50 | //aktivieren, dass TCNT1 in ICR1 geschrieben wird.
|
51 | TCCR1B |=(1<<WGM13); |
52 | //Edge Detektor auf positive Flanke einstellen
|
53 | TCCR1B |=(1<<ICES1); |
54 | //Edge Detektor auf negative Flanke einstellen
|
55 | //TCCR1B &=(0<<ICES1)
|
56 | //Input Capture Interrupt aktivieren
|
57 | TIMSK |= (1<<TICIE1); |
58 | //
|
59 | //TIMSK |= (1<<
|
60 | //Prescaller Timer 1
|
61 | TCCR1B |= (0<<CS12)|(1<<CS11)|(0<<CS10); |
62 | sei(); |
63 | while (1) |
64 | {
|
65 | PORTA=(Buffer_ICR3); |
66 | |
67 | }
|
68 | return 0; |
69 | }
|
70 | |
71 | |
72 | void ICP_init(void) |
73 | {
|
74 | //ICP aktivieren
|
75 | //Noise Canceler aktivieren
|
76 | TCCR1B |= (1<<ICNC1); |
77 | //aktivieren, dass TCNT1 in ICR1 geschrieben wird.
|
78 | //TCCR1B |=(1<<WGM13);
|
79 | //Edge Detektor auf positive Flanke einstellen
|
80 | TCCR1B |=(1<<ICES1); |
81 | //Edge Detektor auf negative Flanke einstellen
|
82 | //TCCR1B &=(0<<ICES1)
|
83 | //Input Capture Interrupt aktivieren
|
84 | TIMSK |= (1<<TICIE1) ; |
85 | //
|
86 | //TIMSK |= (1<<
|
87 | //Prescaller Timer 1
|
88 | TCCR1B |= (0<<CS12)|(0<<CS11)|(1<<CS10); // clk/256 |
89 | sei(); |
90 | }
|
Achja.. der timer bleibt laut dem Simulator auch nach einem auslesen des ICR1 Registers stehen :-(
@ Christian, ja du darfst das WGM13-Bit nicht setzen ! Sascha
Hallo, wieder eine C-Übung für mich (sonst nur ASM)? int Buffer_ICR3=0; ... PORTA=(Buffer_ICR3); da nicht volatile dürfte der Compiler bei eingeschaltetet Optimierung da folgerichtig ein PORTA=0; draus machen. Ohne volatile weiß er ja nicht, daß die ISR den Wert ändert. Ansonste: in welchem Mode hasz Du den Timer? Das ist doch irgendein PWM-Mode oder? Normalmode (und in der ISR auf 0) oder CTC (und Differenz berechnen) sollte sinnvoll sein. Gruß aus Berlin Michael
Hallo Michael, Also der Timer läuft normal hoch, und wird beim auftreten einer Flanke an dem ICP PIN gespeichert. ich habe keinen Speziellen Modus ausgewählt. müsste also normal Modus sein. Bis dann. Ich werde mal das ändern mit dem volatile und wgm 13. Wenn das mit dem WGM 13 stimmt, hab ich das falsch verstanden im Handbuch... Danke erstmal ich guck mal.
Hallo nochmal. Ich hab den WGM13 krams mal weg gelassen. Der Timer stopt nach dem ausführen des Interrupts und zählt nicht weiter. Ich hab echt keine Ahnung warum.
1 | #include<avr/interrupt.h> |
2 | #include<avr/io.h> |
3 | #include "C:\Archiv\libary\mega32\Header\rs232.h" |
4 | #include "C:\Archiv\libary\mega32\Header\delay.h" |
5 | #include "C:\Archiv\libary\mega32\Header\umwandeln.h" |
6 | void ICP_init(void); |
7 | |
8 | volatile int Buffer_ICR3=0; |
9 | volatile int Buffer_ICR1=0; |
10 | volatile int Buffer_ICR2=0; |
11 | volatile int x=0; |
12 | |
13 | ISR(TIMER1_CAPT_vect) |
14 | {
|
15 | |
16 | |
17 | |
18 | |
19 | // Edge Detektor auf negative Flanke einstellen
|
20 | if (x==0) |
21 | {
|
22 | Buffer_ICR1=ICR1; |
23 | TCCR1B &=(0<<ICES1); |
24 | Buffer_ICR3=ICR1H; |
25 | }
|
26 | //Edge Detektor auf positive Flanke einstellen
|
27 | if (x!=0) |
28 | {
|
29 | // Buffer_ICR2=ICR1;
|
30 | //// Buffer_ICR3=Buffer_ICR2-Buffer_ICR1;
|
31 | TCCR1B |=(1<<ICES1); |
32 | Buffer_ICR3=ICR1L; |
33 | |
34 | }
|
35 | // TIFR |= (1<<ICF1);
|
36 | |
37 | x=!x; |
38 | |
39 | }
|
40 | |
41 | int main() |
42 | {
|
43 | DDRD=0x00; |
44 | DDRA=0xff; |
45 | PORTA=0xff; |
46 | |
47 | //ICP aktivieren
|
48 | //Noise Canceler aktivieren
|
49 | TCCR1B |= (1<<ICNC1); |
50 | //aktivieren, dass TCNT1 in ICR1 geschrieben wird.
|
51 | //TCCR1B |=(1<<WGM13);
|
52 | //Edge Detektor auf positive Flanke einstellen
|
53 | TCCR1B |=(1<<ICES1); |
54 | //Edge Detektor auf negative Flanke einstellen
|
55 | //TCCR1B &=(0<<ICES1)
|
56 | //Input Capture Interrupt aktivieren
|
57 | TIMSK |= (1<<TICIE1); |
58 | //
|
59 | //TIMSK |= (1<<
|
60 | //Prescaller Timer 1
|
61 | TCCR1B |= (0<<CS12)|(1<<CS11)|(0<<CS10); |
62 | sei(); |
63 | while (1) |
64 | {
|
65 | PORTA=(Buffer_ICR3); |
66 | |
67 | }
|
68 | return 0; |
69 | }
|
70 | |
71 | |
72 | void ICP_init(void) |
73 | {
|
74 | //ICP aktivieren
|
75 | //Noise Canceler aktivieren
|
76 | TCCR1B |= (1<<ICNC1); |
77 | //aktivieren, dass TCNT1 in ICR1 geschrieben wird.
|
78 | //TCCR1B |=(1<<WGM13);
|
79 | //Edge Detektor auf positive Flanke einstellen
|
80 | TCCR1B |=(1<<ICES1); |
81 | //Edge Detektor auf negative Flanke einstellen
|
82 | //TCCR1B &=(0<<ICES1)
|
83 | //Input Capture Interrupt aktivieren
|
84 | TIMSK |= (1<<TICIE1) ; |
85 | //
|
86 | //TIMSK |= (1<<
|
87 | //Prescaller Timer 1
|
88 | TCCR1B |= (0<<CS12)|(0<<CS11)|(1<<CS10); // clk/256 |
89 | sei(); |
90 | }
|
>TCCR1B &=(0<<ICES1);
eine 0 um eine gewisse Anzahl von Stellen zu verschieben bringt nichts!
Wenn dann muß das so heißen:
TCCR1B &= ~(1<<ICES1);
Irgendwo (im Tutorium?!) sollte das beschrieben sein.
Hallo, Du solltest Dir die Betriebsarten des Timers und die Bedeutung von WGM13...10 im Datenblatt nochmal genau anschauen und prüfen, was Du für Deinen Zweck eigentlich brauchst. Mit WGM13...10 = 0 läuft der Timer im Normalmode (Mode 0 der Tabelle). Er beginnt zu zählen, wenn der Vorteiler (CS12...10) so gesetzt wird, daß er einen Takt bekommt, zählt bis Top (0xFFFF), setzt das TOV1-Flag und bleibt dort so stehen. Wenn Du einen anderen Ablauf brauchst, dann such den passenden Mode raus und programmiere diesen... Gruß aus Berlin Michael
@Michael U. Im Normalmode wird das Overflowflag beim Wechsel 0xFFFF zu 0x0000 gesetzt. Der Timer läuft aber brav weiter. Das ist ja auch Sinn und Zweck der Übung. Wie sollte ich eine genaue Messung machen können, wenn der Timer stehen bleiben würde? Gruß Matthias
Hallo,
@Matthias Kölling: hast Du natürlich völlig Recht damit, ich habe mich
irgendwie durch die Aussage:
>Der Timer stopt nach dem ausführen des Interrupts und zählt nicht
weiter.
von Christian Paulsen irritieren lassen.
Gruß aus Berlin
Michael
@Christian Versuch erst erst mal nur mit einer Flanke zu arbeiten. Dann müsstest Du ja immer 20ms messen. Das Wechseln der Flanke im Interrupt würde ich nicht über eine Toggle-Variable machen sondern über das Lesen des Portpins. Wenn aus unerfindlichen Gründen Dir eine Flanke durch die Lappen geht, bist Du mit der Variablen plötzlich asynchron. Wenn Du den Portpin liest, synchronisiert Du Dich automatisch wieder auf. Gruß Matthias
Hallo, Danke für eure Hilfe. Ich Habe den Fehler gefunden ! Es lag nicht an den Registern. Es lag einfach an meinem unverständnis für C. Guckt euch mal die Zeile: TCCR1B &=(0<<ICES1); an. Kein Wunder, das der Timer stoppt. Mit dieser Zeile setze ich nicht nur die Flanke auf null, sndern auch alles andere, was im Register steht. Mein PWM Einlesen klappt jetzt wunderbar. Die Zeile muss heißen: TCCR1B ~&=(1<<ICES1); :-) Schöne Grüße Christian
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.