mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Drehgeber auf extern Interuppt LPC ARM


Autor: Meyer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So nun noch mal, habe dies schon mal gepostet, aber unter einer anderen 
nicht mit zutreffenden Überschrift. Ich möchte über einen Drehgeber 
einen externen Interupt auslösen. Hier folgender Code:
int zaehler = 0;
#define VPBDIV_VAL  0x02                   /*Setze Hardwaretimer[Pclk] auf 30 Mhz */

__irq void eint0 (void) {

  IOCLR0 = 0x00000100;                    /* Turn LED On  (P0.8 = 0) */  
  ++zaehler;
  EXTINT = 0x00000003;
  VICVectAddr = 0x0000000;                            // Acknowledge Interrupt
}
void init_extern(void) 
{
   /*VPBDIV muss(!!) man auf 0 gesetz werden bevor man ein(!) Register
  beschreiben kann*/
  // Hardwaretimer auf Null setzen
  VPBDIV=0;
  //Register kontrolliert falls
  EXTMODE = (1<<3);
  // Hardwaretimer wird auf 30 Mhz gesetzt 
  VPBDIV=VPBDIV_VAL;
  // Hardwaretimer auf Null setzen
  VPBDIV=0;
  // Register kontrolliert welcher Pin eine Flanke auslöst
  EXTPOLAR = ~(1<<3);  //fallende Flanke
  // Hardwaretimer wird auf 30 Mhz gesetzt 
  VPBDIV=VPBDIV_VAL;
   // ein Register per Interrupt
  VICVectCntl2 = (0x20 | 0x20000) ;
  //Vector wird Slot 2 zugewiesen
  VICVectAddr2 = (unsigned)eint0;
   //Aktiviert Interrupt Eingänge
  VICIntEnable = ( 0x20000 );
}
******** Hauptprogramm  **********/
int main (void)
{
  IODIR1 = 0x00FF0000; 
  PINSEL1|=(1<<29);      //P0.30 als EINT3
   PINSEL1&=~(1<<28);
    IODIR0 = 0x00000100;                     
     
  init_extern();
/*Programm in einer Endlosschleife*/
while (1)
  {     
     
  }
So sieht meine Start-Code aus:
I_Bit           EQU     0x80   ; when I bit is set, IRQ is disabled
F_Bit           EQU     0x40   ; when F bit is set, FIQ is disabled

UND_Stack_Size  EQU     0x00000000
SVC_Stack_Size  EQU     0x00000020
ABT_Stack_Size  EQU     0x00000000
FIQ_Stack_Size  EQU     0x00000000
IRQ_Stack_Size  EQU     0x00000080
USR_Stack_Size  EQU     0x00000400
Ich weiß nicht mehr weiter es will nicht laufen. Benutze auch schon 
einen Pull_Down Widerstand um wirklich auf low-Level zu sein!

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Einen Drehgeber tastet man per Timerinterrupt ab, NICHT mit einem 
exterenen Interrupt. Warum das so ist steht im Artikel.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Meyer wrote:
> Ich weiß nicht mehr weiter es will nicht laufen. Benutze auch schon
> einen Pull_Down Widerstand um wirklich auf low-Level zu sein!

Und wie erzeugst Du "wirklich" High?
Zeig dochmal den Schaltplan zu Deinem Programm.


Peter

Autor: Hotte (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@falk Sehr schön aber wie stelle ich das auf einem ARM board dar. Dort 
habe ich keine Funktion wie sei() oder cli()?

@Dannegger Ich benutze ein Board der Frima Phytec mit einem LPC2294 und 
einem Patch-Feld (HD200) und zu Testzwecken gebe ich nun auch meinen 
Port EINT3 (Port30) eine Spannung von 3.3 Volt drauf um zu sehen ob 
irgendetwas kommt, befor ich meinen Inkrementellen Drehgeber anschließe.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hotte wrote:

> @Dannegger Ich benutze ein Board der Frima Phytec mit einem LPC2294 und
> einem Patch-Feld (HD200) und zu Testzwecken gebe ich nun auch meinen
> Port EINT3 (Port30) eine Spannung von 3.3 Volt drauf um zu sehen ob
> irgendetwas kommt, befor ich meinen Inkrementellen Drehgeber anschließe.

Damit kann ich absolut garnichts anfangen.
Du mußt schon den richtigen Schaltplan malen.
D.h. wie ist der Drehgeber und die LED konkret angeschlossen.


Peter

Autor: Hotte Meyer (marvinthevirus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Peter, sorry mein Scanner hat den Geist aufgegeben, habe nun den 
Schaltplan fotografiert. Kann ich dir denn auch zu mailen, da die Datei 
viel zu groß ist? Ich bedanke mich auch schon mal für deine Mühe! Als 
LED benutze ich den Port 0.8 der auch auf dem Board festverdrahtet ist 
und auch voll funktionesfähig ist. Am Port 30 habe ich einen 10 kohm 
Widerstand mit der Masse verbunden:

 pos. Flanke 3.3 Volt
  |
  |
  --------------Eingang MC
  |
  |
  R1 10k[Pulldown]
  |
  GND
Nun gebe ich ganz einfach gehalten mit einem Kabel das den Drehgeber 
simulieren soll 3.3 Volt auf den Port 30.

Autor: let (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Poste doch mal das vollständige Projekt. So kann das kein
Mensch nachvollziehen.

Es gibt so etwas wie cli()/sei() auf den ARM7 Controllern. Daran
soll es nicht scheitern. Im einfachsten Fall kannst du das interrupt
enable Flag für den Timer abschalten.
Ich versuche das jedoch zu vermeiden was mir bisher auch (fast)
immer gelungen ist. Ein Blick in das Listfile und in ein C-Buch
zum Thema 'volatile' zeigt das viele dieser cli()/sei() Orgien
unnötig sind. Das sei() ist in einer Abfrageroutine sogar gefährlich.
Ohne Timer wirst du das Prellen des Encoders aber kaum in den Griff
kriegen. Du könntest natürlich auch mit delays arbeiten aber
Abfragezeiten für einen Encoder im Bereich von ms sind bereits
auf langsameren Controllern unpraktisch. Bei Zyklenzeiten von
~20ns ist ein delay() in der Hauptschleife geradezu unverantwortlich.

Autor: Hotte Meyer (marvinthevirus)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
So ich glaube dass mit dem externen Interrupt lasse ich liebe, wei ich 
mir den Rat von Herrn Brunner zu Herzen genommen habe. Ich habe jetzt 
versucht das Code-Beispiel Drehgeber von Herrn Dannegger auf einen 
LPC2294 umzuschreiben. Könnte sich jeder mal den Code anschauen ob ich 
irgendwo einen Fehler gemacht habe, wäre verdammt nett von Euch.

Außerdem habe ich noch Verständnisprobleme mit dem Code:
if (enc_diff & 1)         // bit 0 = value (1)
{
enc_last = enc_new;       //speicher new als nächten Wert
enc_delta += (enc_diff & 2)-1; // bit 1 = direction (+/-)
}

Kann mir jemand mal ganz genau erklären, was ich mit dieser if-Anweisung 
genau mach!

Autor: Hotte Meyer (marvinthevirus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@let hab gerade vergessen zu fragen, wie bekomme ich die funktionen bei 
einem LPC2294 denn?

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hotte Meyer wrote:
> LED benutze ich den Port 0.8 der auch auf dem Board festverdrahtet ist
> und auch voll funktionesfähig ist.

So, dann müßte man nur noch wissen, ob die LED gegen VCC oder GND 
geschaltet ist.

Hint:
Kontakte werden üblicher Weise gegen GND geschaltet, weil man dann den 
internen Pullup des MCs aktivieren kann.
LEDs werden üblicher Weise gegen VCC geschaltet.
Kontakte und LEDs sind also in der Regel Low-aktiv.

Ich hab nicht viel Erfahrung mit dem LPC. Ich hab da nicht so den 
richtigen Antrieb, einfache Sachen, die ein 8-Bitter spielend schafft, 
mit nem 32-Bit-Boliden zu machen.


Versuche mal schrittweise vorzugehen:
- LED schalten
- LED über Delayschleife blinken
- LED über Timer blinken
- LED über Timerinterrupt blinken
- LED über Eingangspin schalten
- LED über externen Interrupt schalten.

Danach solltest Du wissen, wo es klemmt.


Peter

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
let wrote:
> Es gibt so etwas wie cli()/sei() auf den ARM7 Controllern.

Leider nicht.
Die Applikation kann nicht global Interrupts sperren (privilegierte 
Instruktion).
Es ist daher beim ARM-7 einfacher und schneller, nur den Timerinterrupt 
selber zu sperren.


Peter

Autor: let (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn das Programm im User Mode läuft kann man das CPSR Register
nicht verändern. Aber solange man kein spezielles OS benutzt
das den User Mode für seine Prozesse erfordert kann man die
Anwendung auch gleich im System Mode ausführen.

Ich sehe aber keinen Grund dafür weshalb man alle Interrupts
sperren sollte nur um den Timer-Interrupt zu unterdrücken/verzögern.

@Hotte Meyer:
Eine cli()/sei() Implementierung findest in den Blinky Beispielen von
WinARM.

Du könntest auch mal versuchen was dabei herauskommt wenn du
den Code
long encode_read1 (void)
{
  long val;

  val = enc_delta;
  enc_delta = 0;
  return val;
}
in diesen
long encode_read1 (void)
{
  static long prev;
  long val, tmp;

  tmp = enc_delta;
  val = tmp - prev;
  prev = tmp;

  return val;
}
abänderst.

Dann kann dir ruhig ein Interrupt dazwischenfunken, es wird nur einmal
in einem Zyklus auf enc_delta zugegriffen.
Ich habe das gerade mal durch den Compiler gejagt und kann keine
Race Condition erkennen.

Autor: Hotte Meyer (marvinthevirus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke Euch allen. Ich werde das gleich mal ausprobieren, mlede mich 
bestimmt morgen wieder;-)

Autor: Meyer (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Habe den Code geändert, doch in der Funktion long encode_read1 (void) 
wird mir immer Null an mein Hauptprogramm übergeben und ich weiß nicht 
warum. Kann mir vielleicht jemand sagen wo mein Fehler liegt?

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Meyer wrote:
> Habe den Code geändert, doch in der Funktion long encode_read1 (void)
> wird mir immer Null an mein Hauptprogramm übergeben und ich weiß nicht
> warum. Kann mir vielleicht jemand sagen wo mein Fehler liegt?
#define PHASE_A     0x00000800    // Port 11
#define PHASE_B    0x00002000    // Port 13

Zahlen sind keine Porteingänge, sondern nur Zahlen.
Und diese beiden Zahlen sind immer wahr.

Hast Du auch beide Pullups aktiviert oder Pullups angeschlossen?


Peter

Autor: Hotte Meyer (marvinthevirus)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Erst einmal Danke an alle dir mir geholfen haben. Es läuft endlich mit 
vollster Zufriedenheit. Besonderen Dank an Herrn Dannegger der die 
Code-Vorlage bereit gestellt hat.
Meine letzten beiden Fehler waren 1. Zuweisung der Ports und 2. Abruf 
der Ports. Manchmal sieht man den Wald vor lauter Bäumen nicht.
Für alle die es interressiert hab ich meinen Code noch mal hochgeladen.

Schönen Abend noch, die nächsten Probleme kommen bestimmt. ;-)

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.