Hallo allerseits,
ich soll ein kleines Programm zum Auslesen des ADC im free running mode
schreiben. An den Pins PC1,PC4 und PC5 befinden sich Dioden, die in
Abhängigkeit des ADC-Wertes leuchten sollen.
Hier mein Code
1
#define F_CPU 7372800UL
2
3
4
#include<avr/io.h>
5
#include<avr/signature.h>
6
#include<avr/interrupt.h>
7
#include<avr/sleep.h>
8
9
staticuint16_tADCresult;// beinhaltet den Inhalt des ADC Registers
10
11
// Interrupt Handler
12
13
ISR(ADC_vect){
14
15
//ADC Register auslesen
16
ADCresult=ADC;
17
18
//LEDs in Abhängigkeit des Wertes von ADCresult gemäß vorgegebener Tabelle setzen
19
if((ADCresult>=0)&&(ADCresult<128)){
20
PORTC&=~(1<<PC1);
21
PORTC&=~(1<<PC4);
22
PORTC&=~(1<<PC5);
23
}
24
elseif((ADCresult>127)&&(ADCresult<512)){
25
PORTC&=~(1<<PC1);
26
PORTC&=~(1<<PC4);
27
PORTC|=(1<<PC5);
28
}
29
elseif((ADCresult>511)&&(ADCresult<769)){
30
PORTC&=~(1<<PC1);
31
PORTC|=(1<<PC4);
32
PORTC|=(1<<PC5);
33
}
34
elseif((ADCresult>768)&&(ADCresult<1024)){
35
PORTC|=(1<<PC1);
36
PORTC|=(1<<PC4);
37
PORTC|=(1<<PC5);
38
}
39
40
}
41
42
43
/* FUNKTIONEN */
44
voidadu(void)
45
{
46
cli();
47
48
//Referenzspannung Uref=2.56V, Single Ended Input ADC0, da MUX0...MUX5=0
49
ADMUX|=(1<<REFS1)|(1<<REFS0);
50
// ADC wird aktiviert, Auto-Triggerung wird aktiviert, ADU-Frequenz wird auf f_clk/32 gesetzt
Da ich als Referenzspannung 2,56V gewählt habe, müssten alle LEDs bei
einer Eingangsspannung von 4V am PIN ADC0 leuchten. Nur funktioniert es
leider nicht und ich stize schon 2 Stunden daran, durch das Datenblatt
das Problem zu lösen. Leider sehe ich meinen Fehler nicht.
Würde mich sehr darüber freuen, wenn ihr mir Tipps geben würdet.
MfG Tom
Hallo,
ich denke Du hast einiges nicht verstanden:
Referenzspannung Uref=2.56V und 4V Eingangsspannung, das kann den ADC
Eingang nicht verkraften ohne weitere Vorsichtsmaßnahmen.
Warum taktest Du den ADC so schnell ?
Das passt auch nicht zusammen, da fehlt ein Modifizierer von ADCresult,
er fängt mit V an.
1
staticuint16_tADCresult;// beinhaltet den Inhalt des ADC Registers
Hallo Uwe,
der Takt war in der Aufgabenstellung gegeben.
Was ist ein Modifizierer? Bei den Tutorial zu AVR-GCC Tutorials bin ich
leider nie darauf gestoßen.
Habe bisher in Java/Matlab/Labview progammiert und komme hin C leider
nicht so ganz zurecht.
Uwe S. schrieb:> Referenzspannung Uref=2.56V und 4V Eingangsspannung, das kann den ADC> Eingang nicht verkraften ohne weitere Vorsichtsmaßnahmen.
wenn der Prozessor mit 4 oder mehr V betrieben wird ist das kein Problem
Peter Dannegger schrieb:> Welches Target?> JTAG disabled?
Wir verwenden Atmel Studio 4 und laden mithilf evon Nodetool die .hex
Dateien auf den Microcontroller. Von einem Target und JTAG habe ich nie
was mitbekommen.
Hallo,
Walter S. schrieb:> wenn der Prozessor mit 4 oder mehr V betrieben wird ist das kein Problem
es geht nicht um Vcc, sondern er schrieb am ADC Eingang liegen 4V an.
Siehe seinen ersten Beitrag.
Und dass ist laut Datenblatt nicht ok !
Uwe S. schrieb:> Hallo,>> Walter S. schrieb:>> wenn der Prozessor mit 4 oder mehr V betrieben wird ist das kein Problem>> es geht nicht um Vcc, sondern er schrieb am ADC Eingang liegen 4V an.>> Siehe seinen ersten Beitrag.>> Und dass ist laut Datenblatt nicht ok !
Für alle I/Os gilt max. Vcc+0,5. Für den ADC gilt Vref als max was er
messen kann, aber die Schutzdioden greifen nach wie vor erst bei
Vcc+0,5. Bei >= Vref hat man halt nur Fullhouse
1
[...] Single ended channels that exceed VREF will result in codes close to 0x3FF
Tom schrieb:> Von einem Target und JTAG habe ich nie> was mitbekommen.
mit Target ist der Prozessor gemeint den du verwendest,
ein Schaltplan wäre auch hilfreich
Uwe S. schrieb:> Das passt auch nicht zusammen, da fehlt ein Modifizierer von ADCresult,> er fängt mit V an.
wenn du damit volatile meinst:
das braucht's hier nicht da ADCresult nur im Interrupt verwendet wird
Bei nächsten mal werde ich mir auf jeden Fall mehr Gedanken darüber
machen, welche Spannungen ich auf die Pins einspeisen kann. Ich dachte,
dass alle Spannungen bis Vcc erlaubt sind.
Kann bzw. möchte mir keiner beim Code helfen?
Ich habe mir das Kapitel über den ADC noch einmal durchgelesen. Leider
weiß ich immer noch nicht, was ich falsch mache -.-
Tom schrieb:> Ich dachte,> dass alle Spannungen bis Vcc erlaubt sind.
Das ist auch so. Wenn du mehr als VREF auswerten willst, ist der ADC
halt auf Anschlag.
Untersuch doch bitte mal das MAP File, ob deine ISR überhaupt kompiliert
wird, oder ob sie weg optimiert wird (es ist ja nirgends im Programm ein
Aufruf).
'static' muss deine Variable nicht sein, mach sie aber entgegen Walters
Ratschlag doch bitte mal 'volatile', damit wird der Compiler
'gezwungen', die ISR zu kompilieren.
Noch was:
Matthias Sch. schrieb:> Untersuch doch bitte mal das MAP File, ob deine ISR überhaupt kompiliert> wird, oder ob sie weg optimiert wird (es ist ja nirgends im Programm ein> Aufruf).
den Compiler der die ISR wegoptimiert würde ich in die Tonne treten,
aber bitte bitte Tom:
SCHALTPLAN!
Tom schrieb:> Von einem Target und JTAG habe ich nie> was mitbekommen.
Target ist die exakte Bezeichnung Deines ungenannten MCs.
Z.B. ein ATtiny1634 und ein AT90CAN128 unterscheiden sich erheblich.
Für JTAG ist bei einigen AVR-Derivaten per default PORTC reserviert,
d.h. erstmal nicht als IO zugänglich.
Wir verwenden einen Sensorknoten, der vom Fachgebiet mit verschiedenen
Anschlüssen erweitert wurde. Den Schaltplan besitze ich nicht.
Auf dem Sensorknoten wird der Atmega 1281 verwendet.
Matthias Sch. schrieb:> 'static' muss deine Variable nicht sein, mach sie aber entgegen Walters> Ratschlag doch bitte mal 'volatile', damit wird der Compiler
Leider hat diese Veränderungen nichts bewirkt.
Matthias Sch. schrieb:> Untersuch doch bitte mal das MAP File, ob deine ISR überhaupt kompiliert> wird, oder ob sie weg optimiert wird (es ist ja nirgends im Programm ein> Aufruf).
Nach dem kompilieren erhalte ich eine .c und .aws Datei, im
Default-Ordner befinden sich Dateien vom Typen .eep .elf .hex .lss .p +
Makefile +Linker Address Map.
Taste Dich systematisch vor:
1. Schritt:
Versuche erstmal, die LEDs fix an und aus zu machen. Funktioniert das?
Dann kannst Du die LEDs/Ports als Ursache ausschließen.
2. Schritt:
Lasse eine LED im ADC-Interrupt togglen. Toggelt sie? Dann läuft der
ADC.
3. Schritt:
...
Tom schrieb:> sei() ;>> while(1){}> return 0;> }
Fehlt da wirklich das Semikolon hinter while(1){}?
Ganz nebenbei läuft der ADC mit 230,4 KHz außerhalb der Spezifikationen
für 10Bit. Mach mal den Prescaler größer.
Hallo Ingo,
Ingo Less schrieb:> Fehlt da wirklich das Semikolon hinter while(1){}?
Nein alles tutti so.
> Ganz nebenbei läuft der ADC mit 230,4 KHz außerhalb der Spezifikationen> für 10Bit. Mach mal den Prescaler größer.
Ja das weis er und interessiert ihn nicht:
Beitrag "Re: Free running mode ADC"
Man sieht schon wohin die Reise geht, es gibt keinen Schaltplan und Tom
ist erst am Anfang seiner Reise mit den Atmel AVR µC. Da werden noch
viele Fehler gemacht, aus denen man viel lernen kann.
Wenn ich keinen Schaltplan würde ich mir einen Zeichen und wenn er noch
nicht mal den Namen des AVR µC kennt, dann wäre das Lesen des
Datenblatts die erste Pflichtaufgabe.
Matthias Sch. schrieb:> mach sie aber entgegen Walters> Ratschlag doch bitte mal 'volatile', damit wird der Compiler> 'gezwungen', die ISR zu kompilieren.
Nein wieso?
Wenn der Compiler beweisen kann dass ein bestimmter Pfad, in dem der
Variablenzugriff erfolgt niemals erreicht werden kann so darf er den
Zugriff wegoptimieren.
Volatile hin oder her.
Das nur am Rande. Hat mit dem Problem des TE nichts zu tun.
DJ Tobsen schrieb:> 1. Schritt:> Versuche erstmal, die LEDs fix an und aus zu machen. Funktioniert das?> Dann kannst Du die LEDs/Ports als Ursache ausschließen.>> 2. Schritt:> Lasse eine LED im ADC-Interrupt togglen. Toggelt sie? Dann läuft der> ADC.>> 3. Schritt:> ...
Danke für den Tipp. Ich habe alle drei LED's getestet und mit dem
folgenden Code lande ich im Interrupt und das LED toggelt:
1
#define F_CPU 4000000UL
2
#include<avr/io.h>
3
#include<avr/signature.h>
4
#include<avr/interrupt.h>
5
#include<avr/sleep.h>
6
#include<util/delay.h>
7
//volatile uint16_t ADCresult; // beinhaltet den Inhalt des ADC Registers
8
9
10
// Interrupt Handler
11
12
ISR(ADC_vect){
13
_delay_ms(100);
14
if(PORTC&(1<<PC5))
15
PORTC&=~(1<<PC5);
16
else
17
PORTC|=(1<<PC5);
18
19
20
21
/*
22
//ADC Register auslesen
23
ADCresult = ADC;
24
25
//LEDs in Abhängigkeit des Wertes von ADCresult gemäß vorgegebener Tabelle setzen
26
if(ADCresult<12){
27
PORTC &= ~(1<<PC1);
28
PORTC &= ~(1<<PC4);
29
PORTC &= ~(1<<PC5);
30
}
31
if((ADCresult>127) && (ADCresult<512)){
32
PORTC &= ~(1<<PC1);
33
PORTC &= ~(1<<PC4);
34
PORTC |= (1<<PC5);
35
}
36
if((ADCresult>511) && (ADCresult<769)){
37
PORTC &= ~(1<<PC1);
38
PORTC |= (1<<PC4);
39
PORTC |= (1<<PC5);
40
}
41
if(ADCresult>768){
42
PORTC |= (1<<PC1);
43
PORTC |= (1<<PC4);
44
PORTC |= (1<<PC5);
45
}
46
*/
47
48
}
49
50
51
/* FUNKTIONEN */
52
voidadu(void)
53
{
54
cli();
55
56
ADCSRA|=(1<<ADEN)|(1<<ADIE);
57
ADCSRA|=(1<<ADATE);
58
ADMUX|=(1<<REFS1)|(1<<REFS0);
59
ADCSRA|=(1<<ADPS2)|(1<<ADPS0);
60
ADCSRA|=(1<<ADSC);
61
/*
62
//Referenzspannung Uref=2.56V, Single Ended Input ADC0, da MUX0...MUX5=0
63
ADMUX|=(1<<REFS1) | (1<<REFS0);
64
// ADC wird aktiviert, Auto-Triggerung wird aktiviert, ADU-Frequenz wird auf f_clk/32 gesetzt
Habe f_clk auf 4 MHz eingestellt und erhalte nun für f_ADU=125 kHz.
Leider funktioniert mein Code imme noch nicht.
Uwe S. schrieb:> Man sieht schon wohin die Reise geht, es gibt keinen Schaltplan und Tom> ist erst am Anfang seiner Reise mit den Atmel AVR µC. Da werden noch> viele Fehler gemacht, aus denen man viel lernen kann.>> Wenn ich keinen Schaltplan würde ich mir einen Zeichen und wenn er noch> nicht mal den Namen des AVR µC kennt, dann wäre das Lesen des> Datenblatts die erste Pflichtaufgabe.
Als Neuling werde ich viele Fehler machen. Das stimmt.
Den verwendeten MC habe ich angegeben und mir das Datenblatt auch
durchgelesen!
ändert nicht die µC Frequenz, sondern muss mit der externen Beschaltung
synchronisiert werden !
Also Quarz dran, die Fusebits richtig eingestellt und dann diesen Wert
in das Makefile eingetragen.
Eine Interrupt-Service-Routine soll so schnell als möglich abgearbeitet
werden. Also was soll ein Delay dort?
Liegt der Fehler wirklich an der Frequenz des MC?
Ich habe mir den Code von Kommilitonen angeschaut, die funktionieren
ohne eine Änderung an der Frequenz des Mcs vorzunehmen.
Ich habe auch geschaut, ob ich alle relevanten Bits setze. Leider fällt
mir kein Unterschied auf.
Tom,
wie willst Du feststellen können, wie die eingestellt µC Frequenz ist ?
Z.B. Toggle eine LED alle 500ms und messe mit einem Oszi an diesem Pin
die Zeit, damit erhälst Du Gewissheit.
Kompilierst du überhaupt für den richten uC? Eventuell ist das Target ja
versehentlich verstellt worden... Grundfunktionen wie Ports toggeln sind
vielleicht kompatibel, aber der ADC-Zugriff vielleicht nicht...
bla schrieb:> Kompilierst du überhaupt für den richten uC? Eventuell ist das Target ja> versehentlich verstellt worden... Grundfunktionen wie Ports toggeln sind> vielleicht kompatibel, aber der ADC-Zugriff vielleicht nicht...
Danke für den Tipp der möglichen Fehlerquelle.
Habe zur Sicherheit ein neues Projekt erstellt:
AVR GCC -> AVR Simulator -> ATmega1281... save, build
Unter Nodetool habe ich ohnehin nur eine Auswahl_ COM11...->
ATmega1281/...
Ich werde mich anscheinend nicht mit der C-Programmierung anfreunden.
Uwe S. schrieb:> Tom,> Kann es sein, dass Du gar keine reale Hardware hast ?> Und die Programmschnipsel nur virtuell testen möchtest?
Doch ich habe eine reale Hardware vor mir liegen^^
Was ich komisch finde, ist, dass beim Debuggen das Programm beim ersten
Durchlaufen der Interrupt-Routine stehen bleibt.
Beim Debuggen des Codes für das Toggeln der LED im Interrupt ist er
permanent weitergelaufen
Tom schrieb:> Was ich komisch finde, ist, dass beim Debuggen das Programm beim ersten> Durchlaufen der Interrupt-Routine stehen bleibt.
Na, das ist doch ein Ansatz.
-> Datenblatt -> ADCSRA -> hier steht auch, wie so eine Wandlng
vonstatten geht.
Ralf G. schrieb:> -> Datenblatt -> ADCSRA -> hier steht auch, wie so eine Wandlng> vonstatten geht.
Laut Datenblatt muss ich also ADCSRA in der Interrupt-Routine noch ein
mal setzen. Danke für den Hinweis. Jetzt läuft das Programm permanent
nur die LED's leuchten nicht so, wie sie sollten. Ich werde verrückt^^
Hallo Tom,
ich habe Dir nach der Vorlage des ersten Posts, was Port-Pins und
Taktfrequenz angeht, ein (Test-)Programm geschrieben.
Es macht das selbe wie in Deiner Vorlage, bis auf die ADC-Messungen,
dort bilde ich eine Mittelwert über 8 aufeinander folgende Messungen.
Desweiteren habe ich über das Digital Input Disable Register 0 den
digitalen Eingang von ADC0 abgeschaltet.
1
DIDR0|=(1<<ADC0D);
Wichtig: die Eingangsspannung an ADC0 darf max 2.56V betrangen, da dies
dein erster Beitrag so vorgibt.
*ADMUX – ADC Multiplexer Selection Register*
/1 1 Internal 2.56V Voltage Reference with external capacitor at AREF
pin/
Das Setzen der LED erfolgt nun in der Hauptprogramm-Schleife über ein
Event-Flag. Dieses Event-Flag wird in der ADC Interrupt-Routine gesetzt.
Bitte berichte.
F_CPU := 7372800
Device := atmega1281
ADC-Channel := 0
LED1 := PORTC.1
LED2 := PORTC.4
LED3 := PORTC.5
LED_OFF := 0
LED_ON := 1
Ich bin immer ein Verfechter des definierten Setzens von Registern. Also
nicht verlassen auf Defaultwerte. Wenn etwas Input sein soll, dann auch
das entsprechende Bit löschen, auch wenn es laut Default schon so ist.
Genauso mit den ganzen ADC-Registern.
Ich lese es schon nicht gerne, wenn der erste Zugriff auf ein Register
mit z.B. |= oder &= passiert. Weil man dann immer irgendwas voraussetzt.
Einfach klare Verhältnisse schaffen!
Warum nicht ganz einfach mal den ADC-Wert per UART ausgeben.
Man muß schon etwas nachdenken bei der Fehlersuche, statt im Nebel zu
stochern.
Offensichtliche Programmfehler hat bisher keiner gefunden, mehr können
wir nicht prüfen.
Uwe S. schrieb:> Wichtig: die Eingangsspannung an ADC0 darf max 2.56V betrangen
Nö.
Es wird nur bis U_ref*1023/1024 gemessen, alles darüber wird als 1023
ausgegeben.
Danke Peter,
für die Klarstellung. Ich bezog mich bei diesem Beitrag auf die max.
Eingangsspannung für den Messbereich des ADC.
Peter Dannegger schrieb:> Uwe S. schrieb:>> Wichtig: die Eingangsspannung an ADC0 darf max 2.56V betrangen>> Nö.> Es wird nur bis U_ref*1023/1024 gemessen, alles darüber wird als 1023> ausgegeben.