Hallo,
ich möchte einen ADC für den Atmega 128 programmieren (er soll die
Spannungswerte die er intern misst auf dem Computer über den UART1
ausgeben)
Das Problem ist, dass der Prozessor zwar Werte aus gibt, diese aber
Zeichen aus der Ascii- Tabelle ausgibt.
Hier ist mal ein Ausschnitt aus dem Quellcode meines Programmes:
1
/* Init ADC*/
2
3
ADMUX|=(1<<REFS1);
4
ADMUX|=(1<<ADLAR);
5
ADMUX|=(1<<MUX3);// mit gain 10x
6
// ADLAR |= (1 << ADC1);
7
8
ADCSRA|=(1<<ADEN);
9
ADCSRA|=(1<<ADSC);
10
ADCSRA|=(1<<ADPS1);
11
ADCSRA|=(1<<ADPS2);
12
13
// for(x = 0; x < 5; x++){
14
while(ADCSRA&(1<<ADSC))//warten bis ADSC Bit gelöscht wird
15
{
16
;
17
}
18
19
spannung=ADCW;
20
21
// warte bis TX bereit
22
while(!(UCSR1A&(1<<UDRE1)))
23
;
24
25
UDR1=spannung;
Im Anhang befinde sich die Ausgabe des HyperTerminals.
Zwei Möglichkeiten:
1. Terminalprogramm benutzen, das Binärwerte anzeigen kann (etwa HTerm).
2. Auf dem uC die Werte vor dem Versenden durch utoa schicken.
Ok das Programm funktioniert soweit das ich einen Wert im Hyperterminal
ausgegeben bekomme( für angelegte Spannung 1,9V z.b. 0644).
Jetzt wäre es natürlich schöner den Wert z.b als 1,9 auszugeben.
Die dafür nötige Rechnung ist nach Vin umgestellt:
(ADC * Vref) / 1024 = Vin
Vref ist laut Datenblatt 2,56V gemessen habe ich allerdings 3,11V und
die Rechnung stimmt auch nur mit 3,03V daher nehme ich diesen Wert.
nehmen wir den Wert von 1,9V = 0644
(644 * 3,03) / 1024 = 1,9055859375
soweit so gut, jetzt noch den Wert in ein float speichern.
Aber wie kann ich den Wert jetzt ausgeben?
Wieder in ein Array speichern und ausgeben wäre ziemlich umständlich da
ich nie weiß wieviele Nachkommstellen der Wert hat.
Hier noch der Code:
1
/* Einbeziehen von Header- Dateien*/
2
#include<avr/io.h>
3
4
#include<inttypes.h>
5
#include<stdlib.h>
6
#ifndef F_CPU
7
8
#include<string.h>
9
#include<stdio.h>
10
11
#define F_CPU 8000000UL //Taktfrequenz Atmega
12
13
#endif
14
15
16
//-----------------------------------------------
17
18
19
/*Init Variables*/
20
floatspannung;
21
floatZ_array;
22
floatV_mess;
23
intcounter;
24
unsignedchararray[4];// Array für den Spannungswert der aus maximal 4 Zeichen besteht (0-1023)
25
// anlegen.
26
intzerlegen(void)
27
{
28
29
30
memset(array,'\0',sizeof(array));
31
spannung=ADCW;//ADCW-Wert in die Wariable Spannung aufnehmen
Wenn du das in deinem Eröffnungsposting gezeigt hätte, hätte ich nichts
gesagt. Aber nach dem Hinweis auf itoa bzw. dem Link in die FAQ ist die
Funktion zerlegen() ja wohl ein Hohn auf alle die dir geholfen haben.
Fang mal damit an, dir eine Funktion zu schreiben, die 1 Zeichen
ausgibt. Und zwar nach den Regeln der Kunst und nicht nur indem auf gut
Glück ein Zeichen an UDR1 zugewiesen wird.
Dann machst du eine Funktion, die einen String ausgeben kann. Da kommt
dir jetzt die eben geschrieben Funktion für Einzelzeichen zu gute.
Und dann schreibst du dir eine Funktion die einen int ausgeben kann.
Dazu benutzt du eine Umwandlungsfunktion, die dir den Zahlenwert in
einen String umwandelt und gibst diesen mit der String-Ausgabefunktion
aus.
Das alles lässt sich in 3 Funktionen abbilden, von denen keine einzige
mehr als 4 Zeilen Code umfasst und universell einsetzbar ist.
Man kann dein Problem natürlich auch mit Floating Point lösen. Man muss
es aber nicht. Das Stichwort heisst Fixpunktarithmetik. Ob du
Geldbeträge als Kommazahlen in Euro zusammenzählst oder ob du das mit
ganzen Zahlen in Cent machst, kommt aufs gleiche raus. Wenn du die
Centbeträge hast und zwischen die 2.te und 3.te Stelle bei der Ausgabe
ein , einschmuggelst, dann merkt kein Benutzer, dass du in Wirklichkeit
nicht mit Kommazahlen gerechnet hast
1,20 € 120 Cent
+ 3,40 € 340 Cent
+ 5,60 € 560 Cent
------ ----------
10,20 e 1020 Cent
|
| Zur Anzeige ein , zwischen Stelle 2
| und Stelle 3
v
10,20
> Wieder in ein Array speichern und ausgeben wäre ziemlich umständlich> da ich nie weiß wieviele Nachkommstellen der Wert hat.
Er hat soviele Stellen wie du gewillt bist auszugeben.
> nehmen wir den Wert von 1,9V = 0644> (644 * 3,03) / 1024 = 1,9055859375
Das ist ziemlich sinnlos.
Dein ADC löst in 1024 Stufen aus, kann daher eine Spannung auf
1/1024*Referenzspannung = 0.0029 Volt (also rund 0.003V) auflösen.
Es ist daher völlig sinnlos, die Ausgabe auf 10 Nachkommastellen zu
machen. Alles nach der 3ten Nachkommastelle ist sowieso gelogen. Und ob
die Tausendstel stimmen, ist mehr als fraglich. Man hat ja schliesslich
auch Messfehler, die im Ergebnis auftauchen.
Nur weil ein Taschenrechner auf 10 Stellen nach dem Komma rechnen kann,
heist das noch lange nicht, dass so ein Ergebnis auch Sinn macht. Das
ist wie mit den Meinungsforschern, die vor einer Wahl ihre Prognose am
liebsten auf 2 Nachkommastellen veröffentlichen, basierend auf einer
Befragung von 100 Leuten :-) Wenn von den 100 nur 1 anders antwortet,
ändert sich das Ergebnis um einen ganzen Prozentpunkt, aber sie geben
ihre Hochrechnung auf 2 Nachkommastellen an :-)
>> Vref ist laut Datenblatt 2,56V gemessen habe ich allerdings 3,11V und
die Rechnung stimmt auch nur mit 3,03V daher nehme ich diesen Wert.
Hast du dir mal überlegt wo dieser Fehler nun begründet ist ?
AD Wandler haben Offset, Gain, AREF Fehler um mal bei den linearen
Fehlern zu bleiben. Den Offset solltest du dir mal genauer anschauen und
auch bestimmen können.
Aller Anfang ist schwer aber nehm mal den Tipp von Karl Heinz an.
Schreib dir mal das Ganze in ein paar Funktionen. Eine gebe ich dir vor
aber du erklärst sie mir dann :-)
1
voidAdcValOut(uint16_tAdcValue)
2
{
3
uint8_tAdcValArray[5];// Integer Array
4
uint8_tm=4;// Schleifenzähler für Ausgabe
5
6
do{
7
AdcValArray[m]='0'+AdcValue%10;// Berechnung der Stellen
Ich denke ich hab im Hinblick auf meine momentanen Kentnisse etwas zu
sehr nach den Sternen gegriffen.
Ich werde mich jetzt erstmal noch etwas genauer mit den einzelnen Teilen
des späteren Programms auseinandersetzen.(sprich: Ausgaben über den
UART)
Ich komme dann später auf den Thread zurück wenn ich mich gewappnet
genug fühle^^
Vielen Dank an alle die mir geholfen haben, aber ich denke, dass ich mit
dem Programm im ganzen erst wieder etwas später beschäftigen.
Mangosniper schrieb:
> Ich denke ich hab im Hinblick auf meine momentanen Kentnisse etwas zu> sehr nach den Sternen gegriffen.
Das ist nicht schlimm.
Das passiert vielen, dass sie die Schwierigkeit der Programmierung
unterschätzen. Massiv unterschätzen.
Wichtig ist nur, dass du auf den Boden der Tatsachen zurückkommst und
das Zeugs von der Pieke auf lernst. Wir alle hier wissen, dass das am
Anfang nicht einfach ist. Es gibt einfach zu vieles, das gleichzeitig
berücksichtigt werden muss. Am besten lernt mal alles gleichzeitig. Aber
das geht nun mal nicht.