Forum: Mikrocontroller und Digitale Elektronik ADC ISR startet nicht


von Peter M (Gast)


Lesenswert?

Hi
Mit Hilfe eines Timers sollte jedes Mal eine Wandlung des ADC gestartet
werden (in der ISR vom Timer0). Nach Fertigstellung der Wandlung sollte
der ADC in die ISR springen und dort einen Port-Pin auf 1 setzen
(LED).
Allerdings wird die LED nie gesetzt.

Hier noch mein (Test)-Programm:

#include <mega128.h>
#include <stdlib.h>
#include <stdio.h>

void init_ADC(void);
void init_Timer0(void);

unsigned char adc_wert;


void init_ADC() {

  ADMUX=0x60;    //AVCC, Left adjust, ADC0
      ADCSRA=0x89;            //Enable, Single Mode, Interrupt
aktivieren, Prescaler 2

  SFIOR=SFIOR&0x8F;
}

void init_Timer0() {
  ASSR=0x00;
  TCCR0=0x02;    //prescaler 8 ==> Timer Takt 1MHz
  TCNT0=0x05;    //Vorladewert
  OCR0=0x00;    //Kein Compare Mode, nur Überlauf

  // Timer(s)/Counter(s) Interrupt(s) initialization
  TIMSK=0x01;    //Overflow Interrupt aktiviert
  ETIMSK=0x00;
}




interrupt [ADC_INT] void ADC_isr (void)
{
PORTE.6=1;      //LED auf 1 setzen
adc_wert=ADCH;        //gewandelten WErt auf Variable speichern

}


interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
ADCSRA=0xD9;     //Wandlungs-Start ADC
TCNT0=0x05;      // Vorladewert nachladen

}

void main (void) {
init_ADC();
init_Timer0();
#asm("sei")       // Global enable interrupts
PORTE=0x00;       //PORT E 0-Zustand bei Init
DDRE=0xFF;    //PORT E alle Pins als Ausgang

  while(1) {   }


}

mfg Peter M.

von Peter M (Gast)


Lesenswert?

achja...M103C Fuse nicht gesetzt (also nicht im ATmega103
Kompatibilitätsmodus)
ATmega128 Takt = 8MHz

von johnny.m (Gast)


Lesenswert?

Und wie ist die LED angeschlossen?

Abgesehen davon solltest Du adc_wert mit dem Typqualifizierer volatile
versehen, da Du sonst nicht weißt, was der Linker der Variablen antut
(also volatile unsigned char adc_wert)

von Peter M (Gast)


Lesenswert?

Die LED hängt direkt an PORTE.6 mit einem Widerstand parallel (~470Ohm).
Interne PullUps sind deaktiviert und die LED funktioniert auch wenn ich
sie einfach so ansteuere.
Nur wenn das "zum-leuchten-bringen" in der ISR des ADC steht dann
gehts nicht (also Vermutung ADC ISR wird nie aufgerufen, Warum?).

Danke für den Tipp mit volatile

mfg Peter M.

von Sebastian (Gast)


Lesenswert?

@Die LED hängt direkt an PORTE.6 mit einem Widerstand parallel
@(~470Ohm).

Also eine den Vorwiderstand würde ich nicht parallel sonder seriell zum
Port anbringen.

Setze doch mal den "LED an"-Code mal in Deinen Timerinterrupt und
schau ob der funktioniert.....

Richtiges Debuggen muss man sich auch gut überlegen...

von johnny.m (Gast)


Lesenswert?

Hallo

Mit 'Wie ist die LED angeschlossen' meinte ich eigentlich, ob sie Low
Side oder High Side dranhängt. Aber mit nem Parallelwiderstand kann es
eigentlich gar nicht funktionieren (zumindest nicht lange, weil der
Portpin nach kurzer Zeit abrauchen dürfte).

Im Code kann ich auch nach mehrmaligem Durchsehen keinen Fehler finden,
der darauf hindeutet, dass der Interrupt nicht ausgelöst wird. Die
Steuerregister sind anscheinend korrekt initialisiert. Du solltest Dir
aber vielleicht noch eine andere Schreibweise angewöhnen, damit nicht
jeder erst im Datenblatt nachsehen muss, was Du da überhaupt machst
(Die Steuerbits haben Namen:-). Also versuchs mal mit dem Hinweis von
Sebastian. Das ist sicher nicht verkehrt.

Gruß

Johnny

von Peter M (Gast)


Lesenswert?

Hab jetzt mal umgelötet und den Widerstand in Serie gehängt (PORT
"lebt" immer noch).

Wenn der "LED-an" code in der Timer ISR steht, dann leuchtet sie,
aber in der ADC ISR nicht.

Muss ich noch irgendwas mit Interruptvektor oder so was anpassen (so
weit ich weiß braucht man das ja in C nicht, aber schön langsam bin ich
mit meinem Latein am Ende)

@johnny: habs normalerweise nicht so mit den kommentaren :), werds mir
aber merken

Grüße, Peter M.

von johnny.m (Gast)


Lesenswert?

Hallo

Es ging ja nicht um die Kommentare, die waren so weit i.O. Aber in der
Header-Datei sind für jedes Bit Namen definiert, die man auch im
Programm benutzen kann und sollte.

Die Vektortabelle brauchst Du in C tatsächlich nicht zu initialisieren.
Das macht der Compiler selbst.

Fehler sehe ich in Deinem Code immer noch nicht. Was mir noch
aifgefallen ist (ganz nebenbei) ist, dass Du den ADC mit 4 MHz quälst.
Ich glaube kaum, dass Du selbst wenn Du nur 8 Bit Auflösung brauchst,
mit dem Takt noch ein brauchbares Ergebnis bekommst. Mit wesentlich
mehr als 1 MHz würde ich den nicht betreiben. OK, aber damit ist das
Erleuchtungsproblem noch nicht gelöst...

Hast Du mal versucht, den ADC mit Auto Trigger zu starten? Ich habe
gesehen, dass Du das SFIOR ja bereits korrekt initialisiert hast.
Ansonsten könntest Du mal schauen, ob das ADC-Flag überhaupt gesetzt
wird (Interrupt deaktivieren und im HP das ADIF abfragen).

Gruß

Johnny

von Karl H. (kbuchegg)


Lesenswert?

> @johnny: habs normalerweise nicht so mit den kommentaren :),

Es geht nicht um Kommentare
Es geht darum, dass du anstelle von

void init_ADC() {

  ADMUX=0x60;    //AVCC, Left adjust, ADC0
      ADCSRA=0x89;            //Enable, Single Mode, Interrupt
aktivieren, Prescaler 2

  SFIOR=SFIOR&0x8F;

besser schreibst:

void init_ADC() {
  ADMUX = ( 1 << REFS0 ) | ( 1 << ADLAR );
  ADCSRA = ( 1 << ADEN ) | ( 1 << ADIE ) | ( 1 << ADPS0 );

  ...

Anstatt da jetzt jede der Hex-Zahlen auseinanderzunehmen, um
zu sehen welches Bit du eigentlich setzt, kann man das in
der alternativen Version wunderbar sehen. Das erspart zwar
nicht den Blick ins Datenblatt aber immerhin erspart man
sich die Bit-Pfriemelei.

Zum Beispiel sieht man in der 2. Version ganz deutlich, dass
das ADSC ( AD - Start Conversion ) Bit im ADCSRA nie gesetzt
wird. Bei ADCSRA=0x89 kann man das ohne Kopfrechnen nicht so
deutlich sehen.

von Rahul (Gast)


Lesenswert?

@Karl-Heinz: Guck mal in die Timer ISR, da wird es gesetzt. Ich dachte
auch, dass dort der Fehler liegt.
Makros zu verwenden erhöht wirklich die Lesbarkeit, und vergössert nur
den Quelltext, nicht das Assembler-File.

von Karl H. (kbuchegg)


Lesenswert?

> @Karl-Heinz: Guck mal in die Timer ISR, da wird es gesetzt. Ich
> dachte auch, dass dort der Fehler liegt.

Asche auf mein Haupt.
Alelrdings kann man das auch als Beispiel dafuer nehmen, dass
diese Makros die Lesbarkeit deutlich erhoehen. Ansonsten
koennte man das nur schwerlich uebersehen.

Jetzt bin ich allerdings auch mit meinem Latein am Ende :-)

von Rahul (Gast)


Lesenswert?

@Peter: Hast du den ADC schon mal im poll-Modus zum Laufen bekommen?
Jonny hat auch Recht, dass 1MHz etwas viel ist. Irgendwas um die 100kHz
(500-200kHz?) sollte man laut Datenblatt einstellen. Bin mir jetzt aber
nicht ganz sicher, ob das mit der Genauigkeit zusammenhing.

von johnny.m (Gast)


Lesenswert?

@Rahul:
50-200 kHz sind tatsächlich nur für (volle) 10 Bit Auflösung
erforderlich. Bei geringerer Auflösung kann man höher gehen, wobei im
Datenblatt glaub ich nicht drinsteht, WIE hoch. Aber ich gehe mal aus
Erfahrung davon aus, dass 4 MHz (ADC-Prescaler-Taktteilung durch 2,
anscheinend betreibt er den µC mit 8 MHz, geht jedenfalls aus dem
Kommentar bei der Timer-Init hervor) auch bei reduzierter Auflösung zu
viel sind. 1 MHz geht vielleicht sogar noch... Aber daran lag es eh
nicht.

Wie gesagt, versuchs mal mit Polling, also so was wie

while(!(ADCSRA & (1 << ADIF)));
PORTE.6 = 1;

Den Interrupt musste natürlich erst deaktivieren.

Gruß

Johnny

von Peter M (Gast)


Lesenswert?

im datenblatt steht nur das man nicht größer als 100kHz gehen soll wenn
man 10bit auflösung verwendet. bei geringerer auflösung steht das
höhere frequenzen möglich sind (ich verwende 8bit daher hohe frequenz)

ja mit dauerwandlung lief der ADC bereits!

>>Hast Du mal versucht, den ADC mit Auto Trigger zu starten?
kenn leider die funktion nicht. was ist das?

>>Ansonsten könntest Du mal schauen, ob das ADC-Flag überhaupt gesetzt
wird (Interrupt deaktivieren und im HP das ADIF abfragen).
werd ich mal probieren, danke.

@all: okay das mit meiner Hex-Code Zuweisung sollte ich wahrscheinlich
wirklich mal überdenken (ist halt schon gewohnheitssache)

von Peter M (Gast)


Lesenswert?

@johnny.m
ja mein Atmega128 hat 8MHz Takt (siehe 2.ter post)

von johnny.m (Gast)


Lesenswert?

Auto-Trigger: Steht im Datenblatt. Trotzdem kurz: Das ADSC-Bit (ADC
Start Conversion) kann nicht nur per Software sondern auch durch
bestimmte Hardware-Ereignisse (z.B. den Timer 0 Overflow) gesetzt
werden. Das SFIOR enthält die entsprechenden Bits (ADTS..) zur Auswahl
der Triggerquelle. Das Bit ADATE im ADCSRA aktiviert den Auto-Trigger.
Ist die elegantere Möglichkeit. Aber das dürfte auch nicht die Ursache
für Dein Problem sein.

Gruß

Johnny

von Sebastian (Gast)


Lesenswert?

Hallo,

ich habe dein Programm mittels AVR-Studio simuliert. Den Timer0 bekomme
ich nicht zum Laufen. Ich kenne den ATmega128 nicht, daher kenne ich die
zu setzenden Register nicht. Geh' erstmal sicher ob Dein Timer wirklich
funktioniert. Lass von mir aus die LED blinken....

Sebastian.

von Peter M (Gast)


Lesenswert?

>>SFIOR enthält die entsprechenden Bits (ADTS..) zur Auswahl
der Triggerquelle.

SFIOR:
Bit 7:   TSM,  timer/counter synchronisation modus
Bit 6-4: reserved
Bit 3:   ACME, analog comparator multiplexer enable
Bit 2:   PUD,  generelles PullUp Disable
BIt 1:   PSR0, wert für asynchron modus für timer
Bit 0:   PSR321, prescaler reset timer1, 2, 3

>>Das Bit ADATE im ADCSRA aktiviert den Auto-Trigger.

ADCSRA:
Bit 7: ADEN, ADC enable
Bit 6:ADSC, ADC start conversion
Bit 5:ADFR, free running, single conversion
Bit 4:ADIF, Interrupt flag
Bit 3:ADIE, ADC Interrupt enable
Bit 2-0: Prescaler Auswahl


Also bei mir gibts die Funktion nicht

von johnny.m (Gast)


Lesenswert?

Ups, dann ist da beim Mega128 was komplett anders. Die Funktion an sich
müsste es allerdings geben. Habe nur das Datenblatt vom Mega16 da. Kann
es jetzt nicht überprüfen (Über Modem dauert das downloaden so ewig...).
Kann mir aber net vorstellen, dass der 'dicke' Mega128 keine ADC Auto
Trigger Möglichkeit hat.

Sorry

Johnny

von johnny.m (Gast)


Lesenswert?

Verd****, hab grad nachgesehen, der Mega128 hat tatsächlich KEINEN ADC
Auto Trigger... Sorry für die Verwirrnis... Der Mega64 (mit dem ich im
Unterschied zum 128 schon gearbeitet hab), der ansonsten dem 128 recht
ähnlich ist hat das nämlich. Wundere mich ein wenig, dass der 128 das
nicht hat. Ist nämlich eine feine Sache...

Gruß

Johnny

von Rahul (Gast)


Lesenswert?

der 128er ist auch etwas älter...

von Sebastian (Gast)


Lesenswert?

Also ich hab' Dein Programm nochmals simuliert mit der neuesten Version
vom AVRStudio. Alles funktioniert so wie von Dir gewollt. Der ADC-ISR
wird auch angesprungen. Entweder ist Dein Atmega128 hin oder mit Deiner
Hardware stimmt was nicht. Gibt es beim Atmeg128 AVCC ?!

Sebastian

von Peter M (Gast)


Lesenswert?

@johnny.m: wenigstens bin ich kein fall von RTFM ;)

@sebastian: ja das mit AVCC müsste passen

mfg Peter M

von Sebastian (Gast)


Lesenswert?

und läuft's mittlerweile???

von Peter M (Gast)


Lesenswert?

Problemstelle gefunden (ich hoffe ihr hängt mich jetzt nicht)

Hab im ganz oben angeführten Programm eben nur die relevanten Teile
eingefügt. Allerdings hab ich auch gleich die USART mitinitialisiert
(für spätere Verwendung) und ich dachte das wäre nicht wichtig für die
Lösung des ADC Problems.
Allerdings geht der ADC in die ISR wenn ich die USART NICHT
initialisiere.

Die Frage ist nur warum?

Meine USART INIT:
UCSR0A=0x00;    //Flag register der USART
UCSR0B=0xF8;    //RX Complete Interrupt Enable (IEN), TX Complete IEN,
Data Register Empty IEN, Receiver enable, Transmitter enable
UCSR0C=0x06;    //synchron, no parity, 1stop-bit, 8bit Datenlänge
UBRR0H=0x00;    //BAudrate 9600
UBRR0L=0x33;    //Baudrate 9600

Daten senden mach ich über den printf Befehl!
Sorry für die undurchsichtigen Hex-Werte für die Register, muss das
erst ändern!

von yeah (Gast)


Lesenswert?

kann es sein das deine USART-Schaltung nicht in Ordnung ist?

von Peter M (Gast)


Lesenswert?

Ja die USART-BEschaltung ist vollkommen in Ordnung und funktioniert auch
einwandfrei. Hab es mit HyperTerminal von Windows probiert!

mfg Peter M.

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.