Hallo zusammen,
ich verzeifle gerade daran mehrere Analogeingänge hintereinander mit der
Funktion aus dem Tutorial abzufragen. Auf meinem LCD-Display gibt er mir
in jeder Zeile die gleichen Werte aus.
Habt ihr eine Idee warum? Ich lese doch jedes Mal einen anderen Kanal
ein.
Über einen Tipp wäre ich Euch sehr dankbar.
Ich habe den gleichen Code auch zusätzlich als Datei angehängt.
Viele Grüße und noch einen schönen Sonntag wünscht Matthias.
#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>
#include "E:\Eigene Dateien\Dropbox\Atmel\AVR
Programme\1aVorlagen\lcd_tools_h.h"
/* ADC initialisieren */
void ADC_ini(void)
{
DDRA=0b00000000; //PORT muss Eingang sein
PORTA=0b10000000; //Port muss low seink, oder
uint16_t result=0;
ADMUX |= (1<<REFS0) ; // interne Spannung nutzen
ADCSRA = (1<<ADPS2) | (1<<ADPS0); // Frequenzvorteiler: setzen auf
32 (4 MHz / 32 = 125 kHz) und ADC aktivieren
ADCSRA |= (1<<ADEN); // ADC aktivieren
ADCSRA |= (1<<ADSC); // eine ADC-Wandlung und danach wird
das Bit wieder auf Null gesetz
while (ADCSRA & (1<<ADSC) )
result=ADCW;
//ADCSRA |= (1<<ADATE); //free running mode aktivieren
}
/* ADC Einzelmessung */
uint16_t ADC_Read( uint8_t channel )
{
// Kanal waehlen, ohne andere Bits zu beeinflußen
ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion"
while (ADCSRA & (1<<ADSC) ) {} // auf Abschluss der Konvertierung
warten
return ADCW; // ADC auslesen und zurückgeben
}
/* ADC Mehrfachmessung mit Mittelwertbbildung */
uint16_t ADC_Read_Avg( uint8_t channel, uint8_t average )
{
uint32_t result = 0;
uint8_t i = 0;
for (i=0; i < average; ++i )
result += ADC_Read( channel );
return (uint16_t)( result / average );
return ADCW;
}
int main(void)
{
uint16_t adcval;
lcd_ini();
ADC_ini();
lcd_writetext(1,1, "Kanal_0: ") ;
lcd_writetext(2,1, "Kanal_1") ;
lcd_writetext(3,1, "Kanal_2: ") ;
lcd_writetext(4,1, "Kanal_3") ;
while( 1 )
{
adcval = ADC_Read(0); lcd_writezahl(1,9, adcval);
adcval = ADC_Read(1); lcd_writezahl(2,9, adcval);
adcval = ADC_Read(2); lcd_writezahl(3,9, adcval);
adcval = ADC_Read(3); lcd_writezahl(4,9, adcval);
}
return 0;
}
Gast
#2374914
Bekommst du auch die gleichen Werte angezeigt, wenn du die Funktion ADC_Read_Avg nutzt? Funktionieren die LCD Funktionen sonst ohne Probleme? Stimmt der Wert des ADC in etwa, der angezeigt wird? Kannst du das nachvollziehen? Ist wahrscheinlich der Wert von Channel 0 oder?
1 | |
2 | |
Sind alle ADC Kanäle an PortA? Warum setzt du die Bits von PortA, sind doch Eingänge... Gruß Jens
Gast
#2374927
Nach der Kanalumschaltung solltest du der Analogelektronik eine Chance geben, sich auf die neue Spannung einzustellen, bevor die Wandlung gestartet wird.
Gast
#2374950
..oder nach der Messung den Kanal auslesen und anhand dessen zuordnen..
Gibt es dazu Faustregeln, wie lange die Elektronik braucht, um sich auf den neuen Kanal einzustellen? Ich habe momentan das gleiche Problem: Ich habe mir diese Schaltung hier nachgebaut http://yveslebrac.blogspot.com/2008/10/cheapest-dual-trace-scope-in-galaxy.html, schreibe die Firm- und Software dazu jedoch neu. Ich frage regelmäßig die beiden ADC-Eingänge ab und habe dabei festgestellt, dass die Messwerte ineinander "überbluten"; lege ich den einen Anschluss auf VCC und den anderen auf GND, erhalte ich nicht wie erwartet 255 und 0 als Messwerte (ich verwerte nur 8 Bit), sondern ungefähr Werte um 130 herum. Der Code für den ATTiny85 (mit vUSB) sieht folgendermaßen aus:
1 | |
2 | |
3 | |
Hier die eigentliche sample-Routine:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
Timergesteuert rufe ich dann irgendwann die Funktion zweimal auf:
1 | |
2 | |
3 | |
4 | |
Ohne das _delay_us(50) bluten die Messwert-Paare ineinander über, "50" ist jetzt einfach willkürlich gewählt - gibt es da konkrete Anweisungen, wie der Wert zu wählen ist? Wie würde sich der ADC im Freerunning-Mode verhalten?
Gast
#2375009
Ich mache sowas immer über die ISR. Dabei lass ich die erste ADC-Messung von einem Timer triggern. Nach erfolgter Messung wird der Wert in einem Array o.ä. abgespeichert und gleich die Messung für den nächsten Kanal gestartet.Das wird wiederholt bis alle Kanäle gemessen wurden.Pausen zwischen den Messungen gibt es nicht. Funktioniert tadellos. Grüße
Hallo zusammen,
danke für Eure Beteiligung, mir bei meinem Problem zu helfen.
Ich bin der Sache ein interessantes Stück näher gekommen.
Ich habe es jetzt geschafft den ADC im Free running modus zu betrieben
und mir von einem!!! ausgewählten Kanal die Werte ausgeben zu lassen.
Sobal ich aber mehr als einen Kanal nur im free running modus !!! wähle
und beide auf dem LCD ausgebe,
dann sind die beiden Werte vertauscht!!!
Kanal 1 zeigt dann den Wert von Kanal 2 an
Kanal 2 zeigt dann den Werrt von Kanal 1 an!!!!!
ich habe den Fehler ebend gefunden!!
Ich takte den Prozessor mit 4MHZ und mache im Augenblick nur diese
Mess-Testschleife!!
uint16_t ADC_Read_free_running_mode( uint8_t channel )
{
// Kanal waehlen, ohne andere Bits zu beeinflußen
ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
_delay_us(300);
return ADCW; // ADC auslesen und zurückgeben
}
ich mußte _delay_us(300); einfügen und dann klappte es!!!
In einem normalen Programm kann ihc vielleicht auf diese _delay routine
verzichten, weil der Prozessor noch andere sachen macht.
bin ich mit diesen 300us =0,3ms im free running mode immer noch
schneller als im single mode??
denn darum ging es mir Zeit zu gewinnen.
Viele Grüße,
Matthias.
Martin schrieb: > Nach der Kanalumschaltung solltest du der Analogelektronik eine Chance > geben, sich auf die neue Spannung einzustellen, bevor die Wandlung > gestartet wird. Hallo Martin, ja genau das war der Fehler. Habe nicht lang genug nach der Kanalumschaltung gewartet 300us Zeit haben gereicht, jetzt geht es.
Hallo ! hast du das Datenblatt zu deinem AVR gelesen ? Beim atMega88 steht das auf Seite 248 Table 23-1. "ADC Conversion Time" Dort steht dass nach jedem Kanalwechsel ein Dummyread der ersten ADC Wandlung gemacht werden muss. Ich habe gerade heute eine neue 64-Fach Oversample Version mit Trigger über Timer1 COMPB geschrieben. Das sieht dann bei mir so aus:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | |
31 | |
32 | |
33 | |
34 | |
35 | |
36 | |
37 | |
38 | |
39 | |
40 | |
41 | |
42 | |
43 | |
44 | |
45 | |
46 | |
47 | |
48 | |
49 | |
50 | |
51 | |
52 | |
53 | |
54 | |
Gast
#2375262
siehe mein Post weiter oben: Beitrag "Re: Analogmessung mehrerer Kanäle hinterteinander, überall gl. Werte?"
Hallo zusammen, dake für Eure Tipps. Ich habe leider erst wieder am Wochenende Zeit diese durch zuarbeiten. Ich melde mich dann ggf. nochmal bei Euch. Viele Grüße, Matthias.
Matthias Lipinsky schrieb: > ..oder nach der Messung den Kanal auslesen und anhand dessen zuordnen.. Hallo Matthias, wie kann ich denn bitte nach der Messung den Kanal auslesen? Ich bin gerade dabei mich wieder damit zu beschäftigen. Viele Grüße, Matthias.
Gast
#2386112
Matthias, schaust du auch mal in das Datenblatt? Das steht doch alles, z.B. für einen atMega88 auf Seite 254f, Register Description 23.8.1 ADMUX – ADC Multiplexer Selection Register ADMUX 0000 ADC0 0001 ADC1 : 0111 ADC7
Mitleser schrieb: > Matthias, > > schaust du auch mal in das Datenblatt? > > Das steht doch alles, z.B. für einen atMega88 auf Seite 254f, > > Register Description > 23.8.1 ADMUX – ADC Multiplexer Selection Register > > > *ADMUX* > > 0000 ADC0 > 0001 ADC1 > : > 0111 ADC7 Hi, grüß Dich, danke für Deine Hilfe. Ja ich schaue auch gerade seit einer Stunde ins Datenblatt und erarbeite mir die Analogmessung im Detail, was ich vorher nicht ganz so intensiv getan habe. anbei ein Bild von einem Teil meiner aktuellen Ausarbeitung zum Beweis. :-) ich weiß auch wie man andere Kanäle wählt, habe aber Deine Ausführung leider nicht verstanden wie Du nachträglich nach einer Messung einen Kanäl zuordnen willst. Darum ging es nur. Viele Grüße, Matthias.
Gast
#2386124
Hallo, du schriebst "wie kann ich denn bitte nach der Messung den Kanal auslesen?"
1 | |
Wenn im Datenblatt R/W steht, dann können Register auch gelesen werden. Falls das mal nicht geht, einfach eine statische Variable mit dem aktuellen ADC-Eingang belegen, dann hat man auch immer die Information parat. Man muss ja auch vorher den ADC-Eingang setzen, dabei muss das ADMUX Register verändert werden und ein "dummy readout" folgen !! Oben steht eine seht eine funktionierendes Beispiel aus einem Programm: Beitrag "Re: Analogmessung mehrerer Kanäle hinterteinander, überall gl. Werte?" .
Gast
#2386126
Hallo, du schriebst "wie kann ich denn bitte nach der Messung den Kanal auslesen?"
1 | |
Wenn im Datenblatt R/W steht, dann können Register auch gelesen werden. Falls das mal nicht geht, einfach eine statische Variable mit dem aktuellen ADC-Eingang belegen, dann hat man auch immer die Information parat. Man muss ja auch vorher den ADC-Eingang setzen, dabei muss das ADMUX Register verändert werden und ein "dummy readout" folgen !! Oben steht eine funktionierendes Beispiel aus einem Programm: Beitrag "Re: Analogmessung mehrerer Kanäle hinterteinander, überall gl. Werte?" .
Gast
#2386192
64 Byte zur Mittelwertbildung ? Und dann noch eine Division ? 0. Reset 1. in ISR: increment Wandlungszähler 2. in ISR: gucken Wandlungszähler=1 wenn nicht weiter bei 5 3. in ISR: gucken ob Wandlungszähler>Anzahl der gewünschten Mittelungen 4. in ISR: bei der 1. Wandlung Flag setzen und Wert A speichern 5. in ISR: Wert B speichern und auf Wert A addieren und um 1 nach rechts shiften (also geteilt durch 2) und in A speichern speichersparend und einfach
Hallo,
danke für Deine Hilfe.
Mein konkretes Problem sieht folgendermaßen aus, oder ist es gar kein
Problem und ich packe es nur falsch an???
ich möchte in einem Programm mehrere Kanäle nacheinander abfragen.
Die Temperaturabfrage ist nicht zeitkritisch und wird einmal in der
Sekunde durchgeführt.
Auch die Strommessung des DC Motors ist nicht zeitkritisch und wird 1x
die Sekunde ausgeführt
Ein anderer, dritter Kanal, soll die Motorpotiwerte eines 24V DC Motors
so oft wie möglich messen.
Meine funktionierende Routine für die Aufgabenstellung sieht so aus:
was mich daran stört schreibe ich dann weiter unten
uint16_t ADC_Read_free_running_mode( uint8_t channel )
{
static uint8_t channel_vorheriger, result;
if (channel_vorheriger!=channel)
//wenn ein neuer Kanal gewählt wurde, dann Kanal einstellen und
Testmessung
{
ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
// Kanal waehlen, ohne andere Bits zu beeinflußen
_delay_us(250);
// 250us Warten, damit die Elektronik sich darauf einstellen kann,
verlangsamt das Programm unnötig
result=ADCW;
//eine Messung machen die verworfen wird
}
channel_vorheriger=channel;
return ADCW; // ADC auslesen und zurückgeben
}
mich stört die Wartezeit von 250uS nach der Kanaleinstellung. Ich weiß,
das ich der Elektronik Zeit geben muss sich auf den neuen Kanal
einzustellen.
Kann ich das Programm technisch nicht aber anders lösen, ohne das das
Gesamte Programm steht und wartet????
Das Beispiel oben vom Kollegen verwendet einen festen Kanal, da tritt
das Problem nicht auf.
Ich muss nach der Kanaländerung Wartezeit einbauen, kann ich das aber
auch ohne DElay lösen???? Welche Möglichkeiten seht ihr da?
Ein Interruptflag gibt es im free running mode ja auch nicht wie ich
gelesen habe!!!
Selbst, wenn ich ein Timer für das Messen des Kanals alle 50ms aufsetze,
braucht die Elektronik nach der Kanaländerung Zeit und das delay würde
das Programm und somit die Geschwindigkeit der Programmausführung
verlangsamen.
Oder ich setze den Timer auf 25ms!! Beim ersten Aufruf der ISR setze ich
nur den Kanal und beim 2. Aufruf nach weiteren 25mS lese ich diesen aus.
Dann muss ich aber 3 Kanäle in die ISR einbauen, die sich zeitlich nicht
in die Quere kommen.
Temperaturmessung alle 1s und
Strommessung alle 1s
Ich hoffe, ich konnte mich verständlich ausdrücken.
Kann ich den Code hier noch besser darstellen? Bei Euch sah das immer
anders aus.
Viele Grüße,
Matthias.
Gast
#2386235
Hallo uwe Gast, ich sehe leider nicht, auch durch einen Beweis, dass deine Funktion, dem des "arithmetische Mittel" entspricht. http://upload.wikimedia.org/wikipedia/de/math/b/f/a/bfa76a2b6dffa3618b04ba0f90f42ed6.png Falls ich mich verlesen habe, kannst Du bitte die Summenfunktion hier hinschreiben und einen Rechnung für
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
durchrechnen ? .
Gast
#2386268
Hallo Matthias, Du musst auch die Wandlung mit der Änderung des ADC-Kannals syncronisieren. so auf die schnelle, ohne es zu testen.
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
Gast
#2386277
Hallo Matthias, ich habe noch noch einen kleinen Fehler drin:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
Im Handbuch steht [q] Bits 3:0 – MUX3:0: Analog Channel Selection Bits The value of these bits selects which analog inputs are connected to the ADC. See Table 23-3 for details. If these bits are changed during a conversion, the change will not go in effect until this conversion is complete (ADIF in ADCSRA is set). [/q]
Gast
#2386278
Hallo Matthias, ich habe noch noch einen kleinen Fehler drin:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
Im Handbuch steht [q] Bits 3:0 – MUX3:0: Analog Channel Selection Bits The value of these bits selects which analog inputs are connected to the ADC. See Table 23-3 for details. If these bits are changed during a conversion, the change will not go in effect until this conversion is complete (ADIF in ADCSRA is set). [/q]
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.
