Hallo, bisher hatte ich immer AREF pin mit AVCC verbunden, Kondensator an Masse und Drossel an VCC. Alles war wunderbar. Nun möchte ich aber zwischendurch mal die interne Ref. von 1,1V nutzen, um die Batteriespannung zu prüfen. Also habe ich AREF abgetrennt von AVCC, den Kondensator aber gelassen Vorher möchte ich aber wie bisher "wandeln" 1. Test also: Intern: AVCC mit AREF verbinden durch setzen von REFS0 in ADMUX. Aber keine vernünftige Wandlung kommt zustande -- warum? REFS1 REFS0 Voltage Reference Selection 0 0 AREF, Internal Vref turned off 0 1 AVCC with external capacitor at AREF pin 1 0 Reserved 1 1 Internal 1.1V Voltage Reference with external capacitor at AREF pin Danke für Hilfe ... bin erst nachmittags wieder da und kann dann reagieren
Jens wrote: > Aber keine vernünftige Wandlung kommt zustande > -- warum? Lange genug gewartet? Wenn du die Referenz umschaltest muss der Kondensator umgeladen werden.
Ja, habe ich ... selbst wenn ich das gleich von Anfang an mache, also so starte - geht es nicht ...
>bisher hatte ich immer AREF pin mit AVCC verbunden, Kondensator an Masse >und Drossel an VCC. ??? Also generell kommt an AREF ein Kondesator und ans andere Beinchen des Kondesators kommt GND! Dann sollte es auch mit der Internen referenz klappen...
Andreas Kaiser wrote: > Jens wrote: > >> Aber keine vernünftige Wandlung kommt zustande >> -- warum? > > Lange genug gewartet? Wenn du die Referenz umschaltest muss der > Kondensator umgeladen werden. hallo wie lang muss man warten um umzuschalten? habe ein ähnliches problem. mega8 1. vcc als referenz wenn die spannung kleiner als 2,56V ist soll er auf die interne umschalten 2. int 2.56 als referenz beides einzeln funktioniert, jedoch hintereinader funktionierts nicht (s.o.) wille jedoch recht schnelle werte haben und nicht sekunden warten. der code funktioniert, jedoch halt leider ungenau hat wer einen tipp??
1 | uint16_t wert = readADC(0); //adc0 wird ausgelesen |
2 | wert2=wert; //der int wert aus dem adc wird übergeben |
3 | wert2=wert2*5/1024; //der adc wert wird in aus 0-1024 in 0-5V umgerechnet |
4 | |
5 | |
6 | if(wert2>=2.56) |
7 | {
|
8 | |
9 | lcd_gotoxy(0,0); |
10 | char text[77]; //wird für die übergabe für sprintf benötigt |
11 | sprintf(text,"ADC0=%2.3fV %02d", wert2,hilfs); //ausgabe adc0 und akt.intervall via sprintf |
12 | lcd_puts(text); //text aus sprintf wird auf dem lcd ausgegeben |
13 | }
|
14 | else
|
15 | {
|
16 | wert3 = readADC256(0); |
17 | wert3=wert3; //der int wert aus dem adc wird übergeben |
18 | wert3=wert3*2.56/1024; |
19 | lcd_gotoxy(0,0); |
20 | char text[77]; //wird für die übergabe für sprintf benötigt |
21 | sprintf(text,"ADC0=%2.3fV %02d", wert3,hilfs); //ausgabe adc0 und akt.intervall via sprintf |
22 | lcd_puts(text); |
23 | }
|
>wie lang muss man warten um umzuschalten?
In einigen Datenblättern steht dazu:
"The first ADC conversion result after switching reference voltage
source
may be inaccurate, and the user is advised to discard this result."
Versuchs mal mit einem dummy-Read.
Oliver
Alex Alex wrote: > der code funktioniert, jedoch halt leider ungenau > [...] > wert2=wert2*5/1024; //der adc wert wird in aus 0-1024 in 0-5V Was für einen Datentyp hat wert2? Wie wäre es mal mit Code, der alles zeigt, was relevant ist? Und "schnell" und Gleitkommaoperationen auf einem AVR beißen sich ebenfalls... Festkommaarithmetik ist da meist sinnvoller.
wert2 und wert 3 sind natürlich double! danke, jedoch ein dummyread verwende ich schon! vielleicht mehr dummyreads hintereinander?! achja hab noch ein problem, wenn ich schon den code poste vielleicht kann mir auch da wer helfen. und zwar die erste zeile in meiner endlosschleife nach for lcd_gotoxy(0,0); wenn ich diesen befehl weg nehme und ihn meine schleife reinpack (die alle ca85µs durchlaufen wird) dann wird am lcd nichts angezeigt. danke & mfg
1 | /*************************************************************************
|
2 | Title: Augabe von ADC0 an das LCD (pfleury_lcd LCD library)
|
3 | Anzeige "akku wird geladen"/ "akku voll"
|
4 | Display wird mittels Timer0 aktualisiert
|
5 | LCD an PD1-PD7
|
6 | Author:
|
7 | File:
|
8 | Software: AVR-GCC 4.14
|
9 | Hardware: HD44780 compatible LCD text display
|
10 | Poti
|
11 |
|
12 | **************************************************************************/
|
13 | #include <stdlib.h> |
14 | #include <avr/io.h> |
15 | //#include <avr/pgmspace.h>
|
16 | #include "lcd.h" |
17 | #include <avr/signal.h> |
18 | |
19 | |
20 | uint8_t sek=0; //sek werden mit 0 initialisiert |
21 | uint8_t hilfs=0; //hilfswert mit dem das lcd aktualisiert wird |
22 | double wert2; //wird für kommaausgabe benötigt |
23 | double wert3; |
24 | |
25 | //char buffer[10];
|
26 | void timerconfig(); //prototyp: der timer0 wird konfiguriert s.u. |
27 | uint16_t readADC(uint8_t channel); //Prototyp: adc wird konfiguriert und ausgelsen |
28 | uint16_t readADC256(uint8_t channel); |
29 | |
30 | int main(void) //hauptprogramm |
31 | {
|
32 | |
33 | timerconfig(); //timer config aufruf für lcd aktualisierung |
34 | lcd_init(LCD_DISP_ON); // initialize display, cursor off |
35 | |
36 | for (;;) { //endlosschleife |
37 | |
38 | lcd_gotoxy(0,0); //zu anfangskoordinaten des lcd springen |
39 | |
40 | |
41 | if(sek!=hilfs) { //abfrage wird alle 0,1sek abgefragt |
42 | |
43 | |
44 | lcd_clrscr(); //lcd wird gelöscht |
45 | |
46 | uint16_t wert = readADC(0); //adc0 wird ausgelesen |
47 | wert2=wert; //der int wert aus dem adc wird übergeben |
48 | wert2=wert2*5/1024; //der adc wert wird in aus 0-1024 in 0-5V umgerechnet |
49 | |
50 | |
51 | if(wert2>=2.56) |
52 | {
|
53 | |
54 | lcd_gotoxy(0,0); |
55 | char text[77]; //wird für die übergabe für sprintf benötigt |
56 | sprintf(text,"ADC0=%2.3fV %02d", wert2,hilfs); //ausgabe adc0 und akt.intervall via sprintf |
57 | lcd_puts(text); //text aus sprintf wird auf dem lcd ausgegeben |
58 | }
|
59 | else
|
60 | {
|
61 | wert3 = readADC256(0); |
62 | wert3=wert3; //der int wert aus dem adc wird übergeben |
63 | wert3=wert3*2.56/1024; |
64 | lcd_gotoxy(0,0); |
65 | char text[77]; //wird für die übergabe für sprintf benötigt |
66 | sprintf(text,"ADC0=%2.3fV %02d", wert3,hilfs); //ausgabe adc0 und akt.intervall via sprintf |
67 | lcd_puts(text); |
68 | }
|
69 | |
70 | /*if (wert2<4.3) //hier wird die akkuspannung verglichen, Schwellwert kann hier eingestellt werden ab 4,3v wird akku voll angezeigt
|
71 | { lcd_gotoxy(1,1);
|
72 | wert2=readADC(1);
|
73 | wert2=wert2*5/1024;
|
74 | sprintf(text,"ladevorgang");
|
75 | lcd_puts(text);
|
76 | }
|
77 | else{
|
78 | lcd_gotoxy(1,1);
|
79 | wert2=readADC(1);
|
80 | wert2=wert2*5/1024;
|
81 | sprintf(text,"akku voll");
|
82 | lcd_puts(text);
|
83 | }*/
|
84 | |
85 | hilfs=sek; //wird gleichgesetzt damit die abfrage erst wieder in 85µs abgefragt wird |
86 | } //if schleife ende |
87 | } //endlosschleife ende |
88 | } //main ende |
89 | |
90 | |
91 | |
92 | |
93 | void timerconfig() { // timer config für 85µsek |
94 | |
95 | TIMSK |= (1<<TOIE0); //Timer 0 Timer/Counter0 Overflow Interrupt Enable |
96 | |
97 | TCCR0 |= (1<<CS00) | (1<<CS02); //256Teiler |
98 | sei (); // |
99 | }
|
100 | |
101 | |
102 | |
103 | |
104 | |
105 | uint16_t readADC(uint8_t channel) { |
106 | uint8_t i; |
107 | uint16_t result = 0; |
108 | |
109 | ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1)| (1<<ADPS0); //der adc wird aktiviert und auf 128 teilungsfaktor |
110 | ADMUX = channel; // Kanal des Multiplexers waehlen |
111 | ADMUX |= (1<<REFS0); // AVCC als Referenzspannung & hier braucht man volle 12bit! also adlar weg |
112 | |
113 | ADCSRA |= (1<<ADSC); // Den ADC initialisieren und einen sog. Dummyreadout machen |
114 | while(ADCSRA & (1<<ADSC)); // Jetzt 3x die analoge Spannung and Kanal channel auslesen |
115 | |
116 | for(i=0; i<3; i++) { // und dann Durchschnittswert ausrechnen. |
117 | |
118 | ADCSRA |= (1<<ADSC); // Eine Wandlung |
119 | while(ADCSRA & (1<<ADSC)); // Auf Ergebnis warten... |
120 | result += ADCW; // wird zu result addiert |
121 | }
|
122 | |
123 | ADCSRA &= ~(1<<ADEN); // ADC wieder deaktivieren |
124 | result /= 3; // result /3 um zu richtigen wert zu gelangen |
125 | |
126 | return result; // wird zurückggegeben |
127 | }
|
128 | |
129 | |
130 | uint16_t readADC256(uint8_t channel) { |
131 | uint8_t i; |
132 | uint16_t result = 0; |
133 | |
134 | ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1)| (1<<ADPS0); //der adc wird aktiviert und auf 128 teilungsfaktor |
135 | ADMUX = channel; // Kanal des Multiplexers waehlen |
136 | ADMUX |= (1<<REFS0)|(1<<REFS1);// 2,56 als referenz & hier braucht man volle 12bit! also adlar weg |
137 | |
138 | ADCSRA |= (1<<ADSC); // Den ADC initialisieren und einen sog. Dummyreadout machen |
139 | while(ADCSRA & (1<<ADSC)); // Jetzt 3x die analoge Spannung and Kanal channel auslesen |
140 | |
141 | for(i=0; i<3; i++) { // und dann Durchschnittswert ausrechnen. |
142 | |
143 | ADCSRA |= (1<<ADSC); // Eine Wandlung |
144 | while(ADCSRA & (1<<ADSC)); // Auf Ergebnis warten... |
145 | result += ADCW; // wird zu result addiert |
146 | }
|
147 | |
148 | ADCSRA &= ~(1<<ADEN); // ADC wieder deaktivieren |
149 | result /= 3; // result /3 um zu richtigen wert zu gelangen |
150 | |
151 | return result; // wird zurückggegeben |
152 | }
|
153 | |
154 | |
155 | |
156 | |
157 | ISR(TIMER0_OVF_vect) { |
158 | sek++; //"pseudo"sek (85µsek) wird erhöht |
159 | }
|
Alex Alex wrote: > wert2 und wert 3 sind natürlich double! Der AVR-GCC kann keine echten (64-Bit) doubles. Die werden wie floats behandelt. Abgesehen davon ist das, was Du da machst, ein klassischer Fall für Festkommaarithmetik. GLeitommaoperationen sind hier absolut überflüssig und führen nur zu Problemen. Außerdem machst Du eine Mittelwertbildung über drei Werte, was auch unsinnig ist, weil die Rückrechnung eine echte Division erfordert. Nimm eine Zweierpotenz, also z.B. 4 Messwerte. > if(sek!=hilfs) { //abfrage wird alle 0,1sek abgefragt Variablen, die in Interrupt Handlern und im Hauptprogramm verwendet werden, müssen volatile deklariert sein, sonst sind sie gefundenes Fressen für den Optimizer. Und sek ist hier nicht volatile! Übrigens hat Dein Problem nicht wirklich viel mit dem ursprünglichen Thema des Threads zu tun. Es war absolut unsinnig, einen so alten Thread dafür wieder rauszukramen!
danke für die tipps, werde ich mir am wochenende genauer anschauen. aber, kann ich die gleitkomma dann auch so angenehm über einen string ausgeben, habe da schon im vorfeld probleme mit dem komma geortet und war dann froh über die jetzige lösung. aja zum makefile ist auch eine lib dazugefügt damit überhapt die komma gehen, habe ich auch in diesem forum gefunden und auch desahlb gedacht, dass es so ok ist jedoch hat das programm wie ich schon gesagt hatte funktioniert, wenn ich nur mit 2,56ref oder gvcc adc gemessen habe! die große meßunignauigkeit hatte ich nur bei der kombination aus beiden adc referenzen, wenn ich sie hintereiander abfarge, so wie im programm oben gepostet. da ist mir noch eine frage eingefallen zu dem if(sek!=hilfs) macht man das so oder gibt es eine bessere lösung? wollte auch nicht mein ganzes programm in die isr schreiben. danke &mfg alex
Abgesehen von eventuellen Softwarefehlern sei mal wieder darauf hingewiesen, das an AREF nichts außer einem Kondensator angeschlossen wird. Es sei denn, es wird eine andere als die internen Referenzspannungen verwendet. Betrachtet man z.B. beim atmega8 /644 das Blockschaltbild des ADC, so erkennt man das AREF direkt mit dem Eingang des ADC verbunden ist. Bei Verwendung der intern wählbaren Quellen ist daher AREF als (hochohmiger) Ausgang zu betrachten.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.