Forum: Mikrocontroller und Digitale Elektronik Interrupt mit den CodeWizzard von Codevision


von Helge Böhr (Gast)


Lesenswert?

Hallo.

Ich wollte gerne interrupt-gesteuert eine LED an PortA zum leuchten
bringen, genauer gesagt mit Hilfe des Analog Komarators. Ich benutze
den MEGA32 und ich programmier in C, bzw. ich will mal gern in C
programmieren können ...
Der Code Wizzard in Codevision spuckt mir schon mal folgende Zeilen
hierfür aus:

#include <mega32.h>

// Analog Comparator interrupt service routine

interrupt [ANA_COMP] void ana_comp_isr(void)
{
// Place your code here
}

void main(void){

PORTA=0x00;
DDRA =0xFF;

.
.
.

// Analog Comparator initialization
// Analog Comparator: On
// Interrupt on Falling Output Edge
// Analog Comparator Input Capture by Timer/Counter 1: Off
// Analog Comparator Output: On

ACSR=0x0A;
SFIOR=0x00;

#asm("sei")

while (1)
 {
//Place your code here
 };
}

Ich lege also eine feste Spannung an AIN0 an, und wenn die sich
veränderende Spannung an AIN1 kleiner ist als das Potential an AIN0,
dann ist der "Analog Comparator Output" gesetzt und der Interrupt
setzt ein.
Was muss ich nun bei den beiden "Place your code here" Feldern bei
der Interrupt Funktion und bei der main Schleife eingeben, damit die
LED leuchtet, wenn der Interrupt ausgelöst wird ?

Danke schon im Vorraus für die Bemühungen.

Helge

von crazy horse (Gast)


Lesenswert?

bei main muss nicht zwangsläufig was rein, das ist das Hauptprogramm in
einer Endlosschleife, in deinem Fall tut es eben nichts ausser endlos
im Kreis zu laufen :-)
In die Interruptroutine schreibst du das, was der Interrupt tun soll.
In deinem Fall wäre das sowas wie:
PORTA.0=1;    //LED an

Das ist nicht ganz C-conform, geht, soweit ich weiss, nur bei CV, ist
aber sehr angenehm.

Besser lesbar:
#define LED1_out PORTA.0
.
.
.
LED1_out=1;

Das Programm macht dann aber nichts weiter, als beim 1.
Komperator-Interupt die LED einzuschalten, und nichts anderes,
wahrscheinlich nicht sehr sinnvoll für einen Mega32 :-)

von Helge Böhr (Gast)


Lesenswert?

Hallo.

Danke erstmal für die schnelle Antwort.

Natürlich will ich auf höheres hinaus, das soll erstmal der Anfang
sein. Ziel ist es ein Signal von ein entsprechend geleveltes Signal von
einem NTC aufzunehmen (also eigentlich von 16 NTC's, aber halt
gemultiplext) und dann auf 16 LED's auszugeben. Es soll also eine
Endlosschleife 16 mal durchlaufen werden und wenn der Wert an den
Komparator einen Schwellenwert erreicht, soll die entsprechende LED
leuchten. In der Schleife müsste also eine Variable bis 16 hochgezählt
werden um den externen MUX anzusteuern. Schaltet der MUX den ersten von
den 16 NTC's durch soll bei einen Interrupt dann die erste LED
entsprechend leuchten und so weiter. Das soll dann bei später erhöhter
Anzahl non NTC's so eine Art niedrig pixelige Wärmebildkamera werden.

Ich kenne mich nur noch nicht so gut aus um diese Schleife zu
programmieren, aber müsste ja eigentlich nicht so schwer sein, bin halt
noch blutiger Anfänger.

Die Schleife müsste ich dann in das "Place your Code here"-Feld bei
der Interruptfunktion schreiben, oder ?

von johnny.m (Gast)


Lesenswert?

Bitte besorge Dir erst mal ein C-Buch und lies Dir das AVR-GCC-Tutorial
auf dieser Seite durch. Letzteres bezieht sich zwar nicht auf
CodeVision, aber die µC-Programmierung in C ist dort recht ausführlich
beschrieben. CodeVision hat zwar einige Erweiterungen ggü. ANSI-C, die
der GCC-C-Compiler nicht bietet (z.B. Bitvariablen und
Bitaddressierung) und ist in der Syntax z.B. bei der Deklaration von
Interrupt-Handlern anders, aber der Code lässt sich i.A. mit einigen
kleinen Änderungen relativ leicht portieren. Und es ist einfacher,
GCC-C-Code nach CodeVision zu portieren als umgekehrt, da CodeVision
auch die ANSI-konformen Bitmanipulationen versteht, GCC-C aber nicht
die vereinfachten Schreibweisen von CodeVision.

Zu Deiner eigentlichen Frage: Interrupt Handler sollten grundsätzlich
nur so viel Code enthalten, wie unbedingt nötig. Dort sollten wirklich
nur die zeitkritischsten Aktionen ausgeführt werden und vor allem keine
Schleifen (BTW: Eine Schleife, die 16 mal durchlaufen wird, würde ich
nicht als Endlosschleife bezeichnen, es sei denn, Du hast sehr
pessimistische Vorstellungen von der Ewigkeit...;-), da während der
Ausführung des Interrupt Handlers das komplette System blockiert ist.
Und das Programm soll ja vielleicht noch erweitert werden...

Die übliche Vorgehensweise ist, im Interrupt Handler ein Flag (also
eine Variable oder ein Bit in einer Variablen) zu setzen und dieses im
Hauptprogramm abzufragen. Auf die Weise gibts i.d.R. keine Aufhänger
oder Verluste. Das Setzen des Flags käme dann an die Stelle im
Interrupt Handler, wo steht 'Place your code here'.

Aber wie gesagt, erst die Grundlagen und Schritt für Schritt
heranarbeiten.

Gruß

Johnny

von Helge Böhr (Gast)


Lesenswert?

Hallo.

Danke für die ausführliche Antwort.

Das mit den C-Lehrbuch wäre sicherlich sinnvoll für mich. Kannst du mir
vielleicht eins empfehlen ? Ich werd aus den Lehrbüchern, die ich bis
jetzt so durchforstet habe nich schlau. Das Tutorial ist ja super
ausführlich, aber ich hatte da halt immer Probleme mit der Anwendung
der Codes in Codevision, weil ja die öfter mal etwas anders sind, und
ich nicht weiß warum das dann nicht geht.
Zu der Schleife: Die soll halt intern bis 16 zählen, und dann wieder
von Vorne beginnen. Die Fachsprache ist mir noch ziemlich fremd.

Ich weiß auch gar nicht, wie nan das am einfachsten macht. Da kommt
also ein Interrupt; dieser darf aber nicht irgendeine xy LED zu
leuchten bringen, sondern nur die, die dem xy NTC-Sensor entspricht,
der wiederrum vom externen Multiplexer angesteuert wird. Ich bräuchte
also noch so eine Art Bedingung die da heißt: Falls ein Interrupt
vorliegt UND der entsprechende NTC-Sensor gerade vom Multiplexer
angesteuert wird, dann darf die LED leuchten.

Mein Ziel ist es erstmal 16 LED's, denen 16 NTC-Sensoren
gegenüberliegen, zum leuchten zu bringen, wenn der entsprechende Sensor
warm wird.

Ich bräuchte also dann eine Schleife in main, die die ganze Zeit
nacheinander die Aufmerksamkeit auf die jeweilige LED lenkt, und dann,
falls ein Interrupt eintritt UND der entsprechende Sensor gerade
angesteuert wird, die LED zum leuchten bringt.

Denke ich da richtig ?
Aber wie setzte ich das Softwaremässig um ? Da hab ich halt noch keine
Ahnung.
Vielleicht weiß jemand schon mal was von einen ähnlichen Projekt ?

mfG
Helge

von Kai Markus Tegtmeier (Gast)


Lesenswert?

Hmm, so wie Du das jetzt beschreibst, wäre das meiner Meinung nach eher
ein Fall für den A/D-Wandler im AVR. Das geht soweit ich weiß
allerdings
nicht mit 16 Kanälen. Die Bausteine, die ich kenne, haben 8-Kanal-ADCs
drin, oder gibts da schon neuere Typen mit mehr Kanälen?

Wenn Du den ADC benutztest, könntest Du Dir die Sache mit den
Interrupts sparen. Einfach die NTCs, als Spannungsteiler geschaltet,
an den ADC hängen. Im Hauptprogramm reihum den ADC abfragen und bei
Erreichen oder Überschreiten des Schwellenwerts die LED anmachen...

Greetz
kmt

von johnny.m (Gast)


Lesenswert?

Wenn es nur um eine Schwellwert-Erkennung geht (Ja-Nein-Entscheidung),
wovon ich bei einer (binären) Darstellung durch einzelne LEDs mal
ausgehe, braucht man den ADC eigentlich nicht. Aber wenn mans mit dem
Komparator macht, würde ich es auch nicht mit dem Interrupt lösen,
sonder den Komparator-Ausgang in der Zählschleife direkt abfragen.

#include <io.h>
#include <delay.h>
//...bla...
#define ACO ACSR.5
//...blabla...
void main(void)
{
    unsigned char ntc_mux; //Zählvariable f. ext. Mux
    //Initialisierung
    //...blablabla...
while(1)
{
    for(ntc_mux = 0; ntc_mux < 16; ntc_mux++)
    {
        PORTB &= 0xf0; //Mux Kanal setzen
        PORTB |= ntc_mux & 0x0f;
        delay_us(100); //kurz warten
        if(ntc_mux < 8)
        {
            if(ACO) //Wenn Komparator-Ausgang 1
                PORTD &= ~(1 << ntc_mux); //LED ein
            else    //Komparator-Ausgang 0
                PORTD |= 1 << ntc_mux; //LED aus
        }
        else
        {
            if(ACO) //Kommentar siehe oben
                PORTC &= ~(1 << (ntc_mux - 8));
            else
                PORTC |= 1 << (ntc_mux - 8);
        }
    }
}
}

Dabei ist der Mux an die 4 LSB von PortB angeschlossen. Die LEDs sind
an PortD (für Kanal 0 bis 7) und PortC (Kanal 8 bis 15) angeschlossen,
und zwar High-Side (mit Vorwiderstand gegen VCC; wenn Du die LEDs
andersrum anschließen willst, dann die Operationen zum Setzen und
Löschen vertauschen).

Das Codeschnipselchen nur als Denkanstoß. Gibt sicherlich viele andere
Lösungsmöglichkeiten für das Problem. Viel Spaß noch beim basteln.

Gruß

Johnny

von Helge Böhr (Gast)


Lesenswert?

Hallo.

Vielen Dank für den Code. Ich probier das so schnell es geht mal aus.
Gruß Helge

von Helge Böhr (Gast)


Lesenswert?

Hallo.

Wie verhält es ich eigentlich im Programmbeispiel mit der for-Schleife;
die Variable ntc_mux zählt bis 16 und dann ? Wie funktioniert das, dass
die Variable wieder auf Null zurückgesetzt wird und wieder von Vorne
die Schleife wieder und wieder durchläuft ?

Gruß Helge

von johnny.m (Gast)


Lesenswert?

Die Initialisierung 'ntc_mux = 0' steht doch in der
Schleifenanweisung... Und da die for-Schleife in einer Endlosschleife
immer wieder aufgerufen wird, wird ntc_mux auch bei jedem Durchlauf neu
initialisiert

von Helge Böhr (Gast)


Lesenswert?

Hallo.

Kann es sein, dass der Codevision Compiler die Operatorenschreibweise
mit |= und &= (Bitoperatoren, oder ?) nicht verarbeiten kann ?
Irgendwie funktioniert das Programm nämlich überhaupt nicht. Ich wollte
mit folgenden Codeabschnitt nur mal auf PORTB ein Rechtecksignal
anliegen lassen, aber auf meinem Oszi erscheint nur Gleichspannung.
Oder  kann es irgendwie sein, dass mein uralt-Oszi das gar nicht mehr
darstellen kann ?

#include <mega32.h>
#include <delay.h>
#define ACO ACSR.5

unsigned char ntc_mux; //Zählvariable f. ext. Mux

void main(void)
{


while(1)
{
for (ntc_mux=0; ntc_mux<16; ntc_mux++)
{
PORTB &=0xF0;
PORTB |= ntc_mux & 0xF0;
delay_us(100);
}
}
}

von Helge Böhr (Gast)


Lesenswert?

O.K.
Hat sich erledigt, ist wohl eher ein Problem meiner Verpeiltheit.

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.