www.mikrocontroller.net

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


Autor: Christian Paulsen (elch2001)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Axel R. (axelr) Flattr this
Datum:

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

Beitrag "Re: Servoausgänge verUNDen"

Axelr.

Autor: Lothar Sammel (magic33)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
also in basic sieht das ungefähr so aus
'-------------------------------------------------------------------------------
'                          mega163 auf stk 500
'                 einlesen eines empfängerpulses via t1 interupt LCD 16x4
'                     INT1=D3  NOV 07
'-------------------------------------------------------------------------------
$regfile = "m163def.dat"
$crystal = 3686000
$baud = 19200


Config Portb = Output
Config Portd = Input

Config Timer1 = Timer , Prescale = 1

Config Int1 = Change                                        'config change int0

Config Lcd = 20 * 4                                         'LCD Display
Config Lcdpin = Pin , Db4 = Porta.4 , Db5 = Porta.5 , Db6 = Porta.0 , Db7 = Porta.1 , E = Porta.3 , Rs = Porta.2


Dim Wert As Word
Dim Error As Bit
Dim Reading As Bit

On Timer1 Rc_error
On Int1 Rc_read

Portb = &HFF

Wert = 20
Error = 0
Reading = 0
Initlcd
Waitms 10

Enable Int1

Enable Timer1

Stop Timer1
Enable Interrupts

Waitms 10




Do
' Disable Interrupts
  Locate 1 , 4 : Lcd "ok"
  Locate 3 , 2 : Lcd Wert
  If Error = 1 Then
   Locate 4 , 1 : Lcd "error"
   End If

  Waitms 20
 Cls

' Enable Interrupts
 'Wert = 20
  Toggle Portb.6
Waitms 20

Loop

End

Rc_read:
If Reading = 0 And Portd.3 = 1 Then
   Start Timer1
   Reading = 1
  Else
   Stop Timer1
   Wert = Timer1
   Timer1 = 0
   Reading = 0
End If
Error = 0

Return


Rc_error:
Error = 1
Reading = 0
Stop Timer1

Return

Autor: Christian Paulsen (elch2001)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Christian Paulsen (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 ? :-(
#include<avr/interrupt.h>
#include<avr/io.h>
#include "C:\Archiv\libary\mega32\Header\rs232.h"
#include "C:\Archiv\libary\mega32\Header\delay.h"
#include "C:\Archiv\libary\mega32\Header\umwandeln.h"
void ICP_init(void);

int Buffer_ICR3=0;
volatile int Buffer_ICR1=0;
volatile int Buffer_ICR2=0;
volatile int x=0;

ISR(TIMER1_CAPT_vect)
  {
  
    
  
  
    //Edge Detektor auf negative Flanke einstellen
    //if (x==0)
  //  {  
    //  Buffer_ICR1=ICR1;
  //    TCCR1B &=(0<<ICES1);
      
  //  }
    //Edge Detektor auf positive Flanke einstellen
  //  if (x!=0)
  //  {
    //  Buffer_ICR2=ICR1;
    //  Buffer_ICR=Buffer_ICR2-Buffer_ICR1;
    //  TCCR1B |=(1<<ICES1);
    Buffer_ICR3=ICR1;
      
  //  }
//  TIFR |= (1<<ICF1);

//  x=!x;

  }

int main()
{
DDRD=0x00;
DDRA=0xff;
PORTA=0xff;

//ICP aktivieren
//Noise Canceler aktivieren
TCCR1B |= (1<<ICNC1);
//aktivieren, dass TCNT1 in ICR1 geschrieben wird.
TCCR1B |=(1<<WGM13);
//Edge Detektor auf positive Flanke einstellen
TCCR1B |=(1<<ICES1);
//Edge Detektor auf negative Flanke einstellen
//TCCR1B &=(0<<ICES1)
//Input Capture Interrupt aktivieren
TIMSK |= (1<<TICIE1);
//
//TIMSK |= (1<<
//Prescaller Timer 1
TCCR1B |= (0<<CS12)|(1<<CS11)|(0<<CS10);
sei();
while (1)
{
  PORTA=(Buffer_ICR3);

}
return 0;
}


void ICP_init(void)
{
  //ICP aktivieren
//Noise Canceler aktivieren
TCCR1B |= (1<<ICNC1);
//aktivieren, dass TCNT1 in ICR1 geschrieben wird.
//TCCR1B |=(1<<WGM13);
//Edge Detektor auf positive Flanke einstellen
TCCR1B |=(1<<ICES1);
//Edge Detektor auf negative Flanke einstellen
//TCCR1B &=(0<<ICES1)
//Input Capture Interrupt aktivieren
TIMSK |= (1<<TICIE1) ;
//
//TIMSK |= (1<<
//Prescaller Timer 1
TCCR1B |= (0<<CS12)|(0<<CS11)|(1<<CS10); // clk/256
sei();
}

Autor: Christian Paulsen (Gast)
Datum:

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

Autor: sascha (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Christian,

ja du darfst das WGM13-Bit nicht setzen !

Sascha

Autor: Michael U. (amiga)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Christian Paulsen (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Christian Paulsen (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.
#include<avr/interrupt.h>
#include<avr/io.h>
#include "C:\Archiv\libary\mega32\Header\rs232.h"
#include "C:\Archiv\libary\mega32\Header\delay.h"
#include "C:\Archiv\libary\mega32\Header\umwandeln.h"
void ICP_init(void);

volatile int Buffer_ICR3=0;
volatile int Buffer_ICR1=0;
volatile int Buffer_ICR2=0;
volatile int x=0;

ISR(TIMER1_CAPT_vect)
  {
  
    
  
  
  //  Edge Detektor auf negative Flanke einstellen
    if (x==0)
    {  
      Buffer_ICR1=ICR1;
      TCCR1B &=(0<<ICES1);
      Buffer_ICR3=ICR1H;
    }
    //Edge Detektor auf positive Flanke einstellen
    if (x!=0)
    {
    //  Buffer_ICR2=ICR1;
    ////  Buffer_ICR3=Buffer_ICR2-Buffer_ICR1;
      TCCR1B |=(1<<ICES1);
    Buffer_ICR3=ICR1L;
      
    }
//  TIFR |= (1<<ICF1);
  
  x=!x;

  }

int main()
{
DDRD=0x00;
DDRA=0xff;
PORTA=0xff;

//ICP aktivieren
//Noise Canceler aktivieren
TCCR1B |= (1<<ICNC1);
//aktivieren, dass TCNT1 in ICR1 geschrieben wird.
//TCCR1B |=(1<<WGM13);
//Edge Detektor auf positive Flanke einstellen
TCCR1B |=(1<<ICES1);
//Edge Detektor auf negative Flanke einstellen
//TCCR1B &=(0<<ICES1)
//Input Capture Interrupt aktivieren
TIMSK |= (1<<TICIE1);
//
//TIMSK |= (1<<
//Prescaller Timer 1
TCCR1B |= (0<<CS12)|(1<<CS11)|(0<<CS10);
sei();
while (1)
{
  PORTA=(Buffer_ICR3);

}
return 0;
}


void ICP_init(void)
{
  //ICP aktivieren
//Noise Canceler aktivieren
TCCR1B |= (1<<ICNC1);
//aktivieren, dass TCNT1 in ICR1 geschrieben wird.
//TCCR1B |=(1<<WGM13);
//Edge Detektor auf positive Flanke einstellen
TCCR1B |=(1<<ICES1);
//Edge Detektor auf negative Flanke einstellen
//TCCR1B &=(0<<ICES1)
//Input Capture Interrupt aktivieren
TIMSK |= (1<<TICIE1) ;
//
//TIMSK |= (1<<
//Prescaller Timer 1
TCCR1B |= (0<<CS12)|(0<<CS11)|(1<<CS10); // clk/256
sei();
}

Autor: Rahul Der trollige (rahul)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Michael U. (amiga)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Matthias Kölling (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Michael U. (amiga)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Matthias Kölling (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Christian Paulsen (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Roberto (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
TCCR1B &= ~(1<<ICES1);
:-)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.