PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Atmega8 ADC \ eeprom



live5
12.08.2014, 08:59
Hi,

nach stunden des Probierens und suchen hier meine Fragen....
Ich möchte am Analog eingang einen Strom messen, und diesen Wert ins eeporm speichern damit ich ihn nach dem einschalten wieder habe, das Ganze wird an einer 12V 3Ah Batterie angeschloßen.

Zum Testen hab ich Versucht and den PC0 einen Widerstand hängen und den auf die 5V vom µC gehängt, aber nach einen Spannungswert hat es mir nicht ausgesehen.. (hab es um den Wert zu sehen in den eeprom gepseichert)

1) wie könnte ich den adc wert sonst ausgeben ohne lcd display bzw. eeprom ?

2) Soweit ich das richtig nachgelesen habe bekomme ich vom analog eingang aber nur einen Spannungs wert und damit ich ich auf meinen Strom komme müsste das dann so aussehen
u = ADC*5.0;
i = u/r;

3) Daher das eeprom auf ca. 100.000 cyclen brenzt ist, wird es nicht sinnvoll sein den Wert immer zu beschreiben.
Meine Idee wäre so eine art dauerplus damit der µC immer unter spannung (Ruhemodus oder so) ist und der Wert im RAM somit erhalten bleibt aber geht das ohne das die Baterie gleich leer ist ?



#include <avr/io.h>
#include <util/delay.h>
#include <avr/eeprom.h>

uint16_t eeLastValueAddr EEMEM = 1;
uint16_t lastValue = 0;

int main()
{
// Set PORTD as Output
DDRD = (1<<PD7)| (1<<PD6)|(1<<PD5) | (1<<PD4) | (1<<PD3) | (1<<PD2)| (1<<PD1)| (1<<PD0);

// Set PortB (PB0,PB1) as Input
PORTB |= (1<<PB0);
PORTB |= (1<<PB1);

// Set Reference to AVCC and input to ADC0
ADMUX = (1<<REFS0);

// Enable ADC, set prescaler to 16
// Fadc=Fcpu/prescaler=1000000/16=62.5kHz
// Fadc should be between 50kHz and 200kHz
ADCSRA = (1<<ADFR)|(1<<ADEN)|(1<<ADPS2);

// Start the first conversion
ADCSRA |= (1<<ADSC);

while (1)
{
if (!(PINB & (1<<PB0)) && !(PINB & (1<<PB0)))
{
//Ruecksetzung des Wertes
lastValue = 0;
eeprom_write_word (&eeLastValueAddr, lastValue);
}
if ((PINB & (1<<PB0)))
{
//Analog Wert lesen und in eeprom schreiben
lastValue = ADC;
eeprom_write_word(&eeLastValueAddr, lastValue);
Set_LED();
}

//Wartezeit fuer Taster abfrage
_delay_ms(100);
}
}

void Set_LED()
{
switch (lastValue)
{
case > 700:
PORTD = 0b00000000;
break;

case > 600:
PORTD = 0b10000000;
break;

case > 500:
PORTD = 0b11000000;
break;

case > 400:
PORTD = 0b11100000;
break;

case > 300:
PORTD = 0b11110000;
break;

case > 200:
PORTD = 0b11111000;
break;

case > 100:
PORTD = 0b11111100;
break;

case >50:
PORTD = 0b11111110;
break;

case 0:
PORTD = 0b11111111;
break;
}
}

PICture
12.08.2014, 09:48
Hallo!


Meine Idee wäre so eine art dauerplus damit der µC immer unter spannung (Ruhemodus oder so) ist und der Wert im RAM somit erhalten bleibt aber geht das ohne das die Baterie gleich leer ist ?

Eine Baterrie wird nach eine Zeit t = C / I leer, wobei C seine Kapazität (hier 3 Ah) und I laufender Stromverbrauch ist. Beispielweise, wenn deine Schaltung 1 mA aus der 3 Ah Batterie ständig "saugt", dann wird die Batterie theoretisch nach 3000 Stunden, also ca. 4 Monaten leer.

Besserwessi
12.08.2014, 10:02
Die µC-Schaltung kann man schon sehr sparsam machen. Mit Sleepmodes und sparsamen Regler sind Werte Deutlich unter 1mA, so um 10 µA drin. Es reicht auch nur für die Zeit zu Puffern (per Elko), die der µC zum schreiben der Daten in EEPROM braucht. Das sind eher nur ein paar Millisekunden.
Die ausgabe zu Testzwecken geht etwa per UART an den PC (RS232).

live5
12.08.2014, 10:18
ok,danke...

eine frage hätte ich noch zum set_sleep_mode...

Also dann würde ich z.B PC1 die AVCC (5V) messen und wenn diese unter 4.5V abfällt könnte ich ihn in den set_sleep_mode(SLEEP_MODE_PWR_DOWN) setzen.
Wenn am INT0 wieder 5V anliegen sollte der Interrup reagieren und ihn wieder starten.

Ist das so richtig oder habe ich einen denkfehler ?

Valen
12.08.2014, 21:17
Du möchtest AVcc an PC1 messen. Aber gegen welcher Referenzspannung wird das passieren? Was wird den ADC-Wert 1023 definieren?


Zurück zu deinem ersten Beitrag. Dort sagst du, du hast ein Widerstand zwischen PC0 und 5 Volt geschaltet. Und davon möchtest du ein Spannung messen, und daraus ein Strom berechnen. Was bedeutet diese Strom für dich? Was ist den Zweck? Leider geht das messen einer Spannung nicht auf diese weise. Ein Pin das als Eingang geschaltet wird ist hochohmig. Da fliest kaum Strom rein. Den Widerstand wird den Spannung an den Pin nur zu 5 Volt hoch ziehen. Und immer ein Wert in die nahe von 1023 bekommen.Wenn du ein Spannung messen möchtest, nimmst du ein Spannungsteiler aus 2 Widerstanden zwischen GND und 5 Volt. Dann den Mittelpunkt der beiden Widerstanden messen. Den Ratio der Widerstanden ist abhängig von dein Anwendung.


Den AVR Mikrocontroller haben oft ein internen Spannungsreferenz, den man auch als Mess-eingang wählen kann. Als Referenz für den ADC wert 1023 kannst du aber auch aVcc wählen, was oft quasi gleich an Vcc angeschaltet ist. Und damit ist es möglich den Bordspannung zu messen, aber in ein invertierte Weg.

live5
13.08.2014, 07:42
Ziel wäre es einen Drucksensor anzuschließen und dessen wert einzulesen (ergibt 4-20mA aus)
Ich habe mich jetzt nur mal auf das einlesen des ADC konzentriert, bei mir wären 5V = 1023

Mein aktuelles Problem ist das der ADC wert > 205 und < 409 ist und das Immer sogar wenn nichts angeschlossen ist ?
Ich konnte den Fehler noch nicht finden, daher ich noch kein Poti habe verwende ich verschiedene widerstände.



#include <avr/io.h>
#include <util/delay.h>
#include <avr/eeprom.h>

uint16_t lastValue = 0;
uint16_t ADC_Read(uint8_t channel);

int main()
{
// Set PORTD as Output
DDRD = (1<<PD7)| (1<<PD6)|(1<<PD5) | (1<<PD4) | (1<<PD3) | (1<<PD2)| (1<<PD1)| (1<<PD0);
PORTD |= ((1 << PD7) | (1 << PD6) |(1<<PD5) | (1<<PD4) | (1<<PD3) | (1<<PD2)| (1<<PD1)| (1<<PD0));

ADC_init();

while (1)
{
//0V = 0
//1V = 205
//2V = 409
//3V = 614
//4V = 816
//5V = 1023
//Vgemessen=lastValue*5/1024;

lastValue = ADC_Read(0);
if (lastValue = 0) {
PORTD = 0b11111111;
}
else if (lastValue > 205) {
PORTD = 0b11111110;
}
else if (lastValue < 409) {
PORTD = 0b11111100;
}
else if (lastValue > 614) {
PORTD = 0b11111000;
}
else if (lastValue > 816) {
PORTD = 0b11110000;
}
else if (lastValue > 1023) {
PORTD = 0b11100000;
}
}
}

/* ADC initialisieren */
void ADC_init(void) {
// die Versorgungsspannung AVcc als Refernz wählen:
ADMUX = (1<<REFS0);
// oder interne Referenzspannung als Referenz für den ADC wählen:
//ADMUX = (1<<REFS1) | (1<<REFS0);
// Bit ADFR ("free running") in ADCSRA steht beim Einschalten
// schon auf 0, also single conversion
ADCSRA = (1<<ADPS1) | (1<<ADPS0); // Frequenzvorteiler
ADCSRA |= (1<<ADEN); // ADC aktivieren

/* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */


ADCSRA |= (1<<ADSC); // eine ADC-Wandlung
while (ADCSRA & (1<<ADSC) ) { // auf Abschluss der Konvertierung warten
}

/* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
Wandlung nicht übernommen. */
(void) ADCW;
}

/* 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
}

28892

Hubert.G
13.08.2014, 09:21
Nur ein Hinweis.
Du kannst Probleme bekommen wenn du AREF mit AVCC verbindest. An AREF gehört ein 100n Kondensator nach GND.
Wenn du, wie in deinem Fall einmal die interne Referenz verwenden willst, fließt ein Ausgleichsstrom in AREF.

oberallgeier
13.08.2014, 09:53
... aktuelles Problem ... ADC wert > 205 und < 409 ... Immer sogar wenn nichts angeschlossen ist ...


...
/* 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
}
Wenn das Ergebnis gleich ist - egal ob am ADC eine Spannung anliegt oder der Pinn in der Luft hängt - dann klingt das doch danach, dass der ADC "nichts" misst. Jedenfalls nichts Sinnvolles. Oder?

Rechne mal bitte: Dein Vorteiler ist clock/8. WENN Du den Controller mit 8 MHz fährst (ist ja nicht unüblich, Du gibst hier leider nix an) dann bekommst Du eine ADC-Frequenz von 1 MHz. Dieser Takt ist die Stoppuhr für die Abläufe des ADC - der zählt die Takte und bemisst damit seine Samplezeit, seine Wandlungszeit und so.

... By default, the successive approximation circuitry requires an input clock frequency between 50kHz and 200kHz to get maximum resolution. If a lower resolution than 10 bits is needed, the input clock frequency to the ADC can be higher than 200kHz to get a higher sample rate...Nun siehts also so aus, als sei Dein ADC-Takt zu hoch >>WENN<< meine Annahme mit den 8 MHz stimmt. Musst halt rechnen.

Verdächtig erscheint mir auch Dein Kanalwechsel bei Deiner ADC_Read-Funktion mit der unmittelbar folgenden Leseaktion. Lies Dir dazu mal das Datenblatt durch, Abschnitt Changing Channel oder so, dort ist ausgeführt wie glaubhaft der erste Wert nach dem Kanalwechsel ist. Und ein Kanalwechsel erfolgt (meines Wissens nach) auch dann, wenn durch den Befehl derselbe Kanal wie vorher ausgewählt wird . . .

Und Huberts Hinweis ist ja auch im Datenblatt (... Analog Input Circuitry ...) näher erläutert *gg*

live5
13.08.2014, 16:06
ja der Controller läuft mit 8Mhz...

Wenn ich das richtig verstehe das ist mein Teilungsfaktor falsch...
Nach dieser Rechnung müsste ich den Faktor 64 Nehmen und nich 8 ist das so korrekt von mir ?

TFmin=CLK/200kHz=8000000/200000=40
TFmax=CLK/50kHz=8000000/50000=160
ADCSRA = (1<<ADPS1) | (0<<ADPS0); // Teilungsfaktor (64)

HeXPloreR
13.08.2014, 16:28
Hallo,

zusätzlich, und nicht ganz unwichtig, finde ich es auch zu sagen das ein Analogsensor meist einen Spannungswert (V) aus gibt. Mir ist bisher kein Drucksesnor begegnet/bekannt der das nicht tut - mal abgesehen von I²C und PWM und so weiter, wo also der Sensor die Spannungswerte selbst vorverarbeitete und als "Datenpaket" verschickt. Bist Du denn sicher das dein Sensor mA(mpere) ausgibt? Welcher Sensor ist das genau? Oder sind es doch eher mV?

Um das Problem mit der ADC-Grundbeschaltung zu lösen würde ich mir persönlich den Schaltplan der RN-Control diesbezüglich rein tun. Diese ist aber dann definitiv nur für Spanungen (V) am ADC gedacht. Ob man dazu einen Shunt aufbauen muss damit man Ampere erhält .... hab ich mich noch nicht ausreichen damit beschäftigt deswegen bleibt diese Antwort von mir offen.

Blöd wäre es ja nur wenn der Sensor sowieso schon "wirklich" einen mA-Wert als verkappten "Spannungswert" liefert ... frage mich grade ob man an so einem Wert überhaupt dann noch was umrechnen muss, wenn es schon der gesuchte Wert ist?

Das Problem bei Deiner ersten Rechnung oben wird sein, das Du nur *5,0 rechnest. Dadurch ist eine 10 Bit-Wert schon mit dem kleinsten Messwert von 1 Bit auf 5. Und das sagt ja quasi garnichts aus ebensowenig wie 5115 bei max wert - es sei denn man rechnet sich das auch wieder umständlich um... dieser wert müsste also noch durch 1023 (10Bit) geteilt werden U = ADC-bit * Ref (5V) /1023-bit. Daraus kann man eine Konstante erstellen = Ref(5V)/1023 mit der dann der ADC-Wert nur noch multupliziert werden muss um die korrekte Spannung angegeben zu bekommen.

Hüstel: und der Sensor sollte natürlich im angegeben Spannungsbereich (etwa 3,3 - 5V) funktionieren.

Hüstel nochmal: Du solltest mal schauen ob in Deinem zweiten Programm Dein "Vgemessen" ggf nicht in einem Kommentar stehen sollte. Und ob es gut ist "LastValue" zu prüfen obwohl Du "Vgemessen" vergleichen möchtest, oder?
Wenn Du vermutlich eine Art Bargraph Anzeige realisieren möchtest dann sollte auch nicht nur der Wert für den 409er Vergleich auf kleiner (<) geprüft werden sondern Alle. Ggf machte es auch Sinn bei dieser Art des Vergleichs die Reihenfolge umzudrehen, also erst auf den größten ADC-Wert zuerst zu prüfen. Denn dann sind es weniger Vergleiche wenn man davon ausgeht das eher eine hohe Spannung anliegt als eine niedrige. 1023 als Vergleichswert könnte man vernachlässigen...


Viele Grüße
Jörg

live5
14.08.2014, 10:34
Ok, ich weiß nicht wie ich auf mA komme aber gemeint wäre so einer:
http://www.conrad.at/ce/de/product/182546/Drucksensor-IEE-CP18-FSR151AS-ca-10-g-10-kg?queryFromSuggest=true

Gibt es eigentlich eine möglich keit die Ports vom µC zu Testen bzw. den Controller selbst ich hab die vermutung das ich das ding zerstört habe, per PC kann ich noch programmer draufbrennen.

Valen
14.08.2014, 10:51
Ok, ich weiß nicht wie ich auf mA komme aber gemeint wäre so einer:
http://www.conrad.at/ce/de/product/182546/Drucksensor-IEE-CP18-FSR151AS-ca-10-g-10-kg?queryFromSuggest=true Dan brachst du sicher eine weitere Widerstand und den beiden als ein Spannungsteiler zu schalten.

live5
14.08.2014, 11:08
ja das hab ich auch schon gelesen zum Testen hab ich das ganze so aufgebaut, jetzt müsste ich eigenltich am PC0 ca 3.2V haben aber was mir eigentartig erscheint ist das meine LED leuchtet wenn ich das so verbinde^^
Als würde mein eingang durchschalten deshalb die Frage ob ich eventuell einen Funktionstest machen kann mit dem controller.

5V
|
|
|
|
----
| |
| |
| | R = 56 Ohm
| |
----
|
|
|
-----------|LED|---- PC0

Valen
14.08.2014, 11:37
Die pin hoch schalten. Oder als Eingang schalten. Und auch auf die polaritat der led achten. Wie man die pins in zbs C Schalten muss steht in dem Atmel datasheet der mikrocontroller

HeXPloreR
14.08.2014, 16:54
Vermutlich wird es nicht mehr lange dauern bis du deinem Armen8er gebraten hast wenn Du mit diesem spielchen so weiter machst auf blauen Dunst irgendwie Bauteile anzuschliessen.

Welche Grundlagen hast Du? - hast Du schon mal in RN-wissen (http://rn-wissen.de/wiki/index.php/Fototransistor)geschaut und dir bei den Anwendungsbeispielen (erster Schaltplan) einen Spannungsteiler angesehen?
Hast Du vielleicht noch einen zweiten Widerstand mit 56 Ohm....damit liese sich ein Spannungsteiler aufbauen an dem etwa die Hälfte Deiner 5V abfallen werden. Wenn Dein Programm dann korrekt arbeitet, könnte man darauf abfragen ob der gemessene Wert zb über 3V liegt wenn ja 0 Led an, wenn nicht dann LED aus.

Wenn man keine weiteren Widerstände außer die zwei unbedingt benötigten (und Poti hast du ja nicht) hat, dann programmiert man es im Programm so um das es dann eben auf diese feste Schwelle reagiert. Oder gibt die Daten wie schon angesprochen wurde auf einem PC-Terminal aus.

Die Test-LED sollte dazu aber nicht in den zu messenden ADC-Kanal mit eingebaut werden. Du wirst vermutlich auch keine abschliessenden Erkenntnis erlangen ob der ADC kaput ist, wenn Du ihn nicht als ADC schaltest. Immerhin hast Du einen Microcontroller vor Dir - also einen programmierbaren IC - mit noch mehr Beinchen die Die nutzen solltest.

Du solltest auch darauf achten nicht zu viel Ampere von der Led "ziehen" zu lassen.
Bei Deinem Aufbau mit den 56 Ohm bist du schon über die Maximal Grenze von 40mA drüber: I = U / R => (5V - LedSpaunng ca 2V) / 56 Ohm = 0,053A = 53mA. Besser würdest Du bei 10 - 15 mA liegen...