Hallo,
also ich habe mir zur Übung einen Batterietester gebaut. Für mignon 1,5v
batterien.
Dieser soll mir an ADC0 über einen 2K Widerstand die Spannung einlesen.
Und je nach Zustand eine rote, gelbe oder grüne led an PC1, PC2 oder PC3
anschalten.
jetzt ist es aber so, das er mir zwischen den Farben (3 ports c) hin und
herspringt. Mal grün solange er will, dann mal rot, und in den seltesten
fällen orange.
ich habe auch batterien mit unterschiedlicher Ladung hier liegen, wenn
ich diese aber dran halte, ändert sich nichts. Berühre ich dann noch
zusätzlich mit der linken Hand an gnd, und mit der rechten Hand +, dann
geht es von rot nach grün, hände weg von grün nach rot (spannung der
batterie 1,5V. laut meinem Code sollte sie ja auf orange schalten.
nun meine Frage was habe ich hier nicht beachtet? Schaltung im bild oben
aufgezeichnet.
dazu habe ich folgenden code geschrieben.:
1
#define F_CPU 100000UL
2
#include<util/delay.h>
3
4
5
#include<avr/io.h>
6
#include<avr/interrupt.h>
7
8
#define newled PINC1
9
#define okled PINC2
10
#define oldled PINC3
11
12
#define analogvalue 0
13
#define leddeelay 2000
14
floatvoltage=0;
15
16
intmain(void)
17
18
{// Ein und Ausgänge konfigurieren
19
20
DDRC=(1<<PD1)|(1<<PD2)|(1<<PD3);
21
22
23
// Kanal waehlen kein bit = kanal ADC0, (1<<MUX1) = ADC1 usw...
24
ADMUX=(1<<REFS1)|(1<<ADLAR);// Refs0 u. Refs1 Referenzspannung // ADLAR bits linksbündig setzen
25
// AVCC with external capacitor at AREF pin to GND
26
27
ADCSRA=(1<<ADEN)|(1<<ADFR)|// ADEN bit startet den wandler, ADFR = Freerunningmode
Hi,
Delay in ner ISR ist nicht gut. Mach die Verarbeitung der LEDs in der
Main. In der ISR aktualisierst du einfach nur den ADC Wert.
Du kannst dir auch den Floatteil sparen wenn du die Grenzwerte einfach
als ADC Int ausrechnest.
Bei den LEDs ist es einfacher die einfach nur leuchten zu lassen ohne
das delay. Einfach die beiden anderen LEDs auf low setzen und der If
Abfrage fürchte Grenzwerte.
Gruß JackFrost
So, wie die Beschaltung des Potentiometers aussieht, liegt der ADC 0
immer auf Masse und das Poti geht zum Teufel, wenn der Schleifer oben
beim +5V-Anschluss ankommt.
MfG Paul
(Ob das Programm richtig ist, kann ich nicht sagen, weil ich C nicht
beherrsche und auch nicht beherrschen will.)
Ja, das mit den Delays in der ISR ist nicht schön ...
Hast Du Dir mal das Datenblatt angeschaut? Welche Referenzspannung soll
es denn sein?
Table 27-2 ADC Voltage Reference Selection
REFS[1:0] Voltage Reference Selection
00 AREF, Internal Vref turned off
01 AVCC with external capacitor at AREF pin
10 Reserved
11 Internal 2.56V Voltage Reference with external capacitor at AREF pin
"Reserved" heißt: Nicht nehmen :-)
Oh Mann - ich hatte nicht gesehen, dass Du es bist. Hartnäckig bist Du
ja - aber ohne Datenblatt-Studium (und vor allem C-Studium) wird das
schwierig werden.
Achso. Jetzt verstehe ich. Das soll kein missglückter Versuch einer Last
sein, sondern der TO will die Leerlaufspannung der Batterie messen. Na
dann....
ASM Superprofi schrieb:> Und der 2k R zu PC0 hat genau was für einen Sinn?
zum schutz des uc gegen zu hohen strom , wenn ich die batterie anklemme.
hrmpf schrieb:> Den hat der TO so von einem x-beliebigen Schaltplan abgemalt und weiß> selbst nicht, was das soll...
Das ist genau das was ich auf dem Breadboard auf gesteckt habe. Aus
einem vor mir liegenden Workshop Buch Projekt nr.3 . Nach lauflicht und
Ampelschaltung.
Dieter F. schrieb:> Hast Du Dir mal das Datenblatt angeschaut? Welche Referenzspannung soll> es denn sein?
ja hab ich. Beim Atmega8a steht REFS01 für AVCC with external capacitor
at AREF pin drinen das habe ich ja gesetzt. Das wollte ich auch.
werde das Ausserhalb der ISR testen. damit ich die delays raus bringe.
Dieter F. schrieb:> aber ohne Datenblatt-Studium (und vor allem C-Studium) wird das> schwierig werden.
Datenblatt habe ich wenig probleme. der ADC gibt mir ja einen wert aus
:-).
C studium, don`t panic :-) hab das buch (C programmieren von anfang an)
schon begonnen .
Huber M. schrieb:> ja hab ich. Beim Atmega8a steht REFS01 für AVCC with external capacitor> at AREF pin drinen das habe ich ja gesetzt. Das wollte ich auch.
Nö, Du musst schon richtig Lesen und Verstehen - REFS01 gibt es nicht:
Dieter F. schrieb:> REFS[1:0] Voltage Reference Selection> 01 AVCC with external capacitor at AREF pin
REFS1 = 1. Stelle
REFS0 = 2. Stelle
Also muss REFS0 auf 1 gesetzt werden.
Huber M. schrieb:> Datenblatt habe ich wenig probleme. der ADC gibt mir ja einen wert aus> :-).
Ja, irgendetwas ... :P
... prinzipiell kann ein "Batteriezustand" nur im belasteten Zustand
erfasst werden, weil ansonsten ein Spannungsmesser (wie bspw. der ADC
eines Controllers) extrem viel groesser als der Innenwiderstand der zu
messenden Zelle ist.
Im unbelasteten Zustand wird ansonsten (fast nur) die U0 der Zelle
gemessen.
Ich würde bspw. eine Mignonzelle kurzfristig mit ca. mindestens 100mA
belasten, was einem 150 Ohm Widerstand entspricht (bei Nennspannung der
Zelle).
Programm im Anhang, die Schwellen für "leer" , "mittel" und "voll" ...
kann man drüber streiten.
@ralf auf allefälle für mich interresant, aber ich werd mich erstmal an
mein buch halten.
Dieter F. schrieb:> Nö, Du musst schon richtig Lesen und Verstehen - REFS01 gibt es nicht:
da habe ich mich wohl verschrieben, es gibt natürlich nur das, was im
Einstellregister steht.
danke.
so jetzt habe ich das ganze nochmal übersichtlicher geschrieben. Und
ausserhalb der ISR.
Und jetzt glaube ich langsam das bei mir sachen nicht funktionieren die
bei jeden anderen einfach so funktionieren.
ich dachte mir, wenn ich den ADC- converter mit ISR richtig konfiguriert
habe, muss ich im zusammen spiel mit der #include <avr/interrupt.h> den
befehl sei; darunter setzen das er das ganze aktiviert.
dann compilier ich das ganze, danach kommt das dabei raus
Error 1 'sei' undeclared (first use in this function) C:\Dokumente
und Einstellungen\Huber\Eigene Dateien\Atmel
Studio\6.2\GccApplication34\GccApplication34\GccApplication34.c 31 2
GccApplication34
das kann doch jetzt fast nicht sein oder?
Huber M. schrieb:> // ISR für ADC-wert> ISR(ADC_vect)> {> ADC;> }
Was soll das bewirken?
Lese mal nach, was VOLATILE bzw. so definierte Variablen bewirken und
wozu man diese nutzt :-)
Mit sei; hast Du "verschlimmbessert" - das war im Eingangspost richtig.
Du solltest auch nochmal drüber nachdenken, wie schnell Dein ATMega8a so
ist und das mit Deiner Angabe in Übereinstimmung bringen ...
Dieter F. schrieb:> Was soll das bewirken?>> Lese mal nach, was VOLATILE bzw. so definierte Variablen bewirken und> wozu man diese nutzt :-)
Ok, das heisst in Groben zügen ich muss dem Compiler mitteilen, das sich
diese variable ausser halb der ISR, und umgekehrt verändern kann. das er
mir das nicht weg optimiert?
aber mir erschliesst sich jetzt nicht ganz daraus. Wie ich das richtig
deklariere/definiere. also volatile ist klar, muss ich ihm da noch einen
Startwert zuweisen zb. 0 ?
[]
#define F_CPU 1000000UL
#include <util/delay.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#define leddeelay 50
float voltage = 0 ;
volatile uint8_t ADC; // so frisst er mir das nämlich nicht
// ISR für ADC-wert
ISR(ADC_vect)
{
ADC = 0;
}
int main(void)[]
Möglich, dass dir das hier (auch) einen Strich durch die Rechnung macht?
Ist mir nur grade aufgefallen, hab deinen restlichen Code noch nicht
angeschaut.
Aber in deinem neuesten Post hast du das ja schon geändert..
Huber M. schrieb:> Ok, das heisst in Groben zügen ich muss dem Compiler mitteilen, das sich> diese variable ausser halb der ISR, und umgekehrt verändern kann. das er> mir das nicht weg optimiert?
Korrekt.
Huber M. schrieb:> also volatile ist klar, muss ich ihm da noch einen> Startwert zuweisen zb. 0 ?
Nein, das ist nicht notwendig.
Aber - es soll ein 16-Bit-Wert aus dem Doppel-Register ADC (ohne
Vorzeichen) übernommen werden (IN DER ISR), welchen Du dann in der
MAIN-Routine verwenden willst. Daher sollte diese Variable auch als
uint16_t deklariert werden.
Huber M. schrieb:
1
>volatileuint8_tADC;// so frisst er mir das nämlich nicht
Da hat er Recht, ADC ist ein fest vergebenes Doppel-Register (ADCH und
ADCL) - Du musst eine eigene Variable -z.B. ADC_WERT definieren und
verwenden (also den ADC-Wert in diese Variable übernehmen und dann in
MAIN damit rechnen).
Also ich weiss was du meinst
ADCH ADCL = ADC, deshalb uint_16 deshalb ADC wert = 0-
1023
00000000 00000000 gibt er aus
volatile uint16_t ADC; // oder ADCH & ADCL aber hier beisst es
gerade aus
// bringt mir immer noch fehler egal ob ich =
// davor setze oder nicht
#define ADC_wert = ADC;
16-Bit Register (ADC, ICR1, OCR1x, TCNT1, UBRR)[Bearbeiten]
Einige der Portregister in den AVR-Controllern sind 16 Bit breit. Im
Datenblatt sind diese Register üblicherweise mit dem Suffix "L"
(Low-Byte) und "H" (High-Byte) versehen. Die avr-libc definiert
zusätzlich die meisten dieser Variablen die Bezeichnung ohne "L" oder
"H". Auf diese Register kann dann direkt zugegriffen werden. Dies ist
zum Beispiel der Fall für Register wie ADC oder TCNT1.
Aus:
https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#16-Bit_Register_.28ADC.2C_ICR1.2C_OCR1x.2C_TCNT1.2C_UBRR.29
Bitte tue Allen einen Gefallen und arbeite das Tutorial durch.
Dieter F. schrieb:> Aus:> https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#16-Bit_Register_.28ADC.2C_ICR1.2C_OCR1x.2C_TCNT1.2C_UBRR.29>> Bitte tue Allen einen Gefallen und arbeite das Tutorial durch.
werd ich auf jeden fall auch noch machen.
Dieter F. schrieb:> Eigentlich wollte ich Dir keinen Code vorgeben ...
das verlange ich auch von keinem, das bringt mich nicht weiter. bin dir
aber dankbar für die tipps. Wo ich nachschlagen kann. Mit der letzten
Antwort hast du meinen nächste Frage schon beantwortet. Das ist genau
das, warum ich immer durcheinander komme. Da ich immer meinte hier zb.
ADC gibt mir schon einen wert von 0-1023 aus (zusammen gefasst aus
ADCH/ADCL). Und ich muss erst ADC einer Variable zuweisen.
das es ADCH und ADCL register gibt wusste ich alles. Aber nicht das ich
direkt darauf zugreifen kann. Und mit dem ADLAR bit kann ich links oder
rechtsbündig wählen. das hat mich total aus dem konzept gebracht. denn
woher soll unint_16 wissen das ich jetzt genau das ADC register meine,
wenn ich einfach ""volatile uint16_t ADC_wert;"" zuweise. das kann ich
mir ja jetzt nochmal durch arbeiten
also noch mal danke
Unabhängig von deinen Programmierproblemen:
hast du das beachtet was Paul zu dem Poti gesagt hat?
So beschaltet machst du einen Kurzschluss wenn du den Poti in eine
Endstellung drehst!
Die Verbindung vom Schleifer zur Masse muss weg!
Weiter wurde oben schon erwähnt, dass man die Batterie belasten muss um
ein aussagekräftiges Ergebnis zu bekommen. Mindestens 100, besser ca.
300mA bei Mignon Zellen.
Der beste Batterietester für Mignon und Micro Batterien sind bei mir
1-zellige Taschenlampen mit guten alten Glühfadenbirnchen.
Wenn die Batterie schwächelt, dann sieht man das sofort am funzeln der
Lampe.
Das findest Du gut beschrieben hier:
Die Ergebnisregister ADCL und ADCH[Bearbeiten]
Da das Ergebnis des ADC ein 10 Bit Wert ist, passt dieser Wert
naturgemäß nicht in ein einzelnes Register, das ja bekanntlich nur 8 Bit
breit ist. Daher wird das Ergebnis in 2 Register ADCL und ADCH abgelegt.
Standardmäßig (d.h. ADLAR = 0) werden von den 10 Ergebnisbits die
niederwertigsten 8 im Register ADCL abgelegt und die noch fehlenden 2
Bits im Register ADCH an den niederwertigsten Bitpositionen gespeichert.
ADCH ADCL
+---+---+---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+
| | | | | | | | | | | | | | | | | |
+---+---+---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+
9 8 7 6 5 4 3 2 1 0
Ist keine 10-bit Genauigkeit gefragt, kann diese Zuordnung aber auch
geändert werden: Durch Setzen des ADLAR Bits im ADMUX Register wird die
Ausgabe geändert zu:
ADCH ADCL
+---+---+---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+
| | | | | | | | | | | | | | | | | |
+---+---+---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+
9 8 7 6 5 4 3 2 1 0
Auf diese Weise kann das ADC Ergebnis direkt als 8 Bit Zahl
weiterverarbeitet werden: Die 8 höchstwertigen Bits stehen bereits
verarbeitungsfertig im Register ADCH zur Verfügung.
Beim Auslesen der ADC-Register ist zu beachten: Immer zuerst ADCL und
erst dann ADCH auslesen. Beim Zugriff auf ADCL wird das ADCH Register
gegenüber Veränderungen vom ADC gesperrt. Erst beim nächsten Auslesen
des ADCH-Registers wird diese Sperre wieder aufgehoben. Dadurch ist
sichergestellt, daß die Inhalte von ADCL und ADCH immer aus demselben
Wandlungsergebnis stammen, selbst wenn der ADC im Hintergrund
selbsttätig weiterwandelt. Das ADCH Register muss ausgelesen werden!
https://www.mikrocontroller.net/articles/AVR-Tutorial:_ADC#Die_Ergebnisregister_ADCL_und_ADCH
ADLAR setzt man i.d.R., wenn man sowieso nur mit 8 Bite Genauigkeit
rechnen will (weil z.B. der Wert etwas "wackelt"). Dann reicht natürlich
eine 8-Bit Variable uint8_t für die Übernahme des Wertes - in diesem
Fall direkt aus ADCH - aus.
Ralph S. schrieb:> Ich würde bspw. eine Mignonzelle kurzfristig mit ca. mindestens 100mA> belasten, was einem 150 Ohm Widerstand entspricht (bei Nennspannung der> Zelle).
Diese Aussage verstößt gegen das Ohmsche Gesetz.
Guten morgen;
Der Andere schrieb:> Unabhängig von deinen Programmierproblemen:>> hast du das beachtet was Paul zu dem Poti gesagt hat?> So beschaltet machst du einen Kurzschluss wenn du den Poti in eine> Endstellung drehst!> Die Verbindung vom Schleifer zur Masse muss weg!
ja habe ich, das habe ich peinlicherweise falsch gezeichnet.
Der Andere schrieb:> Weiter wurde oben schon erwähnt, dass man die Batterie belasten muss um> ein aussagekräftiges Ergebnis zu bekommen. Mindestens 100, besser ca.> 300mA bei Mignon Zellen.
ja das habe ich verstanden. Aber ich glaube, ich habe hier noch ein
grundliegendes Problem, mit der Beschaltung von ADC0 eingang. In meinem
Verständis. Zu nachfolgenden Code
Bild 1 , wie hier zu sehen ist habe ich das Poti als Spannungsteiler auf
ca. 0.4V eingestellt. Im bild leuchtet die Grüne Led, laut Code sollte
doch die Rote leuchten ?
Bild 2 hier habe ich es auf ca. 1.2V eingestellt, dann sollte doch die
orange Led leuchten? Habe ich hier beim Anschluss an den analogen
Eingang, oder doch im Code etwas nicht richtig verstanden?
Huber M. schrieb:> Und mit dem ADLAR bit kann ich links oder> rechtsbündig wählen. das hat mich total aus dem konzept gebracht. denn> woher soll unint_16 wissen das ich jetzt genau das ADC register meine,> wenn ich einfach ""volatile uint16_t ADC_wert;"" zuweise. das kann ich> mir ja jetzt nochmal durch arbeitenHuber M. schrieb:> // Kanal waehlen kein bit = kanal ADC0, (1<<MUX1) = ADC1 usw...>> ADMUX = (1<<REFS0)|(1<<ADLAR);
Scheinbar ist das noch nicht passiert.
-> Beitrag "Re: Fragen zu meinem Batterietester"
Huber M. schrieb:> Bild 2 hier habe ich es auf ca. 1.2V eingestellt, dann sollte doch die> orange Led leuchten? Habe ich hier beim Anschluss an den analogen> Eingang, oder doch im Code etwas nicht richtig verstanden?
Ich finde du solltest dazu übergehen dir mittels serieller
(RS232/USB) Schnittstelle einen besseren Einblick zu
verschaffen was im Controller vorgeht. Der dazugehörige Software-
aufwand ist minimal und du kannst damit weitaus mehr "debuggen",
insbesondere hier ADC Werte ausgeben und evtl. den Controller
mittels PC-Tastatur kommandieren/steuern.
Was du an Hardware brauchst ist sowas:
http://www.ebay.de/itm/RS232-USB-Adapter-Kabel-IC-PL2303HX-5V-TTL-Seriell-Pegel-fur-Arduino-/201482917436?hash=item2ee951563c:g:~kAAAOSw0RpXlbsA
(für dein Steckbrett ganz gut geeignet)
Arduinoquäler schrieb:> Ich finde du solltest dazu übergehen dir mittels serieller> (RS232/USB) Schnittstelle einen besseren Einblick zu> verschaffen was im Controller vorgeht.
Da gebe ich Dir Recht. Es ist immer noch schneller erledigt, sich
seriell eine Variable oder ein Zwischenergebnis auf den Rechner ausgeben
zu lassen, als etliche Stunden zu spekulieren, was los ist.
MfG Paul