Forum: Mikrocontroller und Digitale Elektronik Brauche Hilfe beim Mega8 ICP Pin, Um eine PWM Einzulesen


von Christian P. (elch2001)


Lesenswert?

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.

von Johannes M. (johnny-m)


Lesenswert?

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...

von Johannes M. (johnny-m)


Lesenswert?

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...

von Axel R. (Gast)


Lesenswert?

Beschleunigungssensor ADXL oder Fernsteuerempfänger?
Wenn Fernsteuerempfänger, dann könnte das evtl. helfen:

Beitrag "Re: Servoausgänge verUNDen"

Axelr.

von Lothar S. (magic33)


Lesenswert?

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

von Christian P. (elch2001)


Lesenswert?

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.

von Christian Paulsen (Gast)


Lesenswert?

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
}

von Christian Paulsen (Gast)


Lesenswert?

Achja.. der timer bleibt laut dem Simulator auch nach einem auslesen des 
ICR1 Registers stehen :-(

von sascha (Gast)


Lesenswert?

@ Christian,

ja du darfst das WGM13-Bit nicht setzen !

Sascha

von Michael U. (amiga)


Lesenswert?

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

von Christian Paulsen (Gast)


Lesenswert?

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.

von Christian Paulsen (Gast)


Lesenswert?

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
}

von Rahul D. (rahul)


Lesenswert?

>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.

von Michael U. (amiga)


Lesenswert?

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

von Matthias Kölling (Gast)


Lesenswert?

@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

von Michael U. (amiga)


Lesenswert?

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

von Matthias Kölling (Gast)


Lesenswert?

@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

von Christian Paulsen (Gast)


Lesenswert?

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

von Roberto (Gast)


Lesenswert?

TCCR1B &= ~(1<<ICES1);
:-)

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
Noch kein Account? Hier anmelden.