Hallo alle zusammen,
ich möchte gerne eine digitale Temperaturdiffernzschaltung aufbauen und
dazu einen ATmega32, bzw. seinen ADC verwenden.
Zu Testzwecken, habe ich ADC0 direkt über mein Labornetzgerät gespeist
und den Controller an 5V gehängt. Die Beschaltung habe ich im Anhang.
Den ADC habe ich wie folgt eingestellt:
ADMUX = (1<<REFS0);
ADCSRA = (1<<ADPS1) | (1<<ADPS2);
Bedauerlicherweise liefert mir der ADC keine sonderlich guten Werte.
Hier eine kleine Messreihe:
anliegende Spannung | ADC-Wert
---------------------------------------
0V | 33020 / 32932
1V | 32988 / 177774
2V | 289 / 465
3V | 706 / 674
4V | 963 / 899
5V | 963 / 899
An AREF liegen 5,04V an. Genauso wie an AVCC und VCC. Die Schwankungen
bei den ADC-Werten würde ich auf das Netzteil schieben. Aber kann mir
Jemand sagen, wieso der ADC Werte über 1023 ausgibt und bei ~963 am
Anschlag zu sein scheint?
mfg
Michi
Hi
>ADMUX = (1<<REFS0);>ADCSRA = (1<<ADPS1) | (1<<ADPS2);
Ist das die ganze Initialisierung?
Wenn ja, brauchst du dich nicht wundern. Der ADC ist nicht
eingeschaltet.
MfG
Michael Stoffels schrieb:> Aber kann mir> Jemand sagen, wieso der ADC Werte über 1023 ausgibt und bei ~963 am> Anschlag zu sein scheint?
Klar, du hast riesen Mist programmiert. Wenn man aus einem 10 Bit ADC
Werte über 1023 rausholt, dann sollte man einfach mal sein Programm
debuggen anstatt einen Thread aufzumachen. Und wenn man schon, debugging
via Forum machen will, dann sollte man wenigstens den Code anhängen.
Irgendeine arme Seele (Karlheinz meistens) wird sich schon erbarmen und
dir den Fehler suchen. Du kannst ja solange bisschen in der Sonne
chillen.
Michael Stoffels schrieb:> bei den ADC-Werten würde ich auf das Netzteil schieben. Aber kann mir> Jemand sagen, wieso der ADC Werte über 1023 ausgibt und bei ~963 am
Liegt am Programm
aus dem Datenblatt (Table 122, Seite 294):
VREF Reference Voltage 2.0 to AVCC-0.5
AREF sollte (um mind. 0.5V) kleiner als AVCC sein! Besser du benutzt die
interne Referenz und einen Spannungsteiler davor...
Nein, das war nicht die ganze Initialisierung, sondern nur die
Konfiguration der Register. Den Code habe ich aus dem gcc tutorial für
ADC kopiert. Also ist anhängen überflüssig ->
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Analoge_Ein-_und_Ausgabe
Trotzdem häng ichs mal an. (habs n bischen verändert)
Und ja, ich hab mich auch mit dem Text drüber beschäftigt ;-)
@mario: Ja, das probier ich mal aus
EDIT: hab nen kleinen Fehler gefunden. Ich geb die Register in der
flaschen Reihenfolge aus.
Michael Stoffels schrieb:> Ich geb die Register in der> flaschen Reihenfolge aus.
Außerdem schreibst du ihren Inhalt mittels nicht initialisierter Pointer
weiß Gott wohin.
Die Frage ist, warum gist du überhaupt irgendwelche Register aus?
> (habs n bischen verändert)
Darf man fragen wozu?
Was war an der Original-Routine so schlimm, dass du da was verändern
musst?
wäre ein
1
intmain()
2
{
3
uint16_tadc_wert;
4
5
RS_init();
6
ADC_init();
7
PORTA=0x00;
8
9
while(1)
10
{
11
switch(RS_receive())
12
{
13
case'a':{
14
adc_wert=ADC_read(0);
15
RS_send_integer(adc_wert);
16
break;
17
}
18
}
19
}
20
21
return0;
22
}
wirklich so schlimm gewesen?
Gut, du müsstest dir für die UART eine Sende-Funktion machen, die einen
uint16_t ausgeben kann(*), aber das soll ja erstens nicht so wahnsinnig
schwer und auf der anderen Seite auch nicht so wahnsinnig unnötig sein.
Denn eine derartige Routine kann man immer wieder mal brauchen.
(*) wobei. Deinen Ausgabewerten nach zu urteilen kann die vorhandene
Funktion RS_send das sogar.
Ja, es ist vllt. wirklich schlauer mir nen int zurückgeben zu lassen und
den dann zu zerlegen. Ich war mir nur nicht sicher, ob der mega32 n ADCW
register hat. In nem anderen Tutorial stand nähmlich, dass die
einfacheren Controller das nicht hätten. Gut, ich hätt vllt. im
Datenblatt nachschauen können. Ich änder das heut Abend mal ab.
RS_send verschickt nur unsigned chars. RS_send_int werd ich wohl noch
implementieren. Vielen Dank für die Anregung.
Jetzt is mir das Wetter aber doch zu schön ;)
Michael Stoffels schrieb:> Ja, es ist vllt. wirklich schlauer mir nen int zurückgeben zu lassen und> den dann zu zerlegen.
Mach es dir zur Regel zunächst mit den Datentypen zu arbeiten, die am
natürlichsten sind.
Für einen 16 Bit Wert ist das ein uin16_t.
> Ich war mir nur nicht sicher, ob der mega32 n ADCW> register hat.
Hat er auch nicht.
Aber der C-Compiler erlaubt es dir so zu tun als ob.
Der Compiler zerlegt das dann richtig bzw. setzt umgekehrt die
Einzelregister wieder zusammen.
Ja, ich hab erst vor Kurzem mit µC-Programmierung angefangen. Vorher
habe ich nur mit Delphi und C für den PC programmiert und da ist das
nicht sooo kritisch. War auch nicht sehr hardwarenah. Auf jeden Fall
dake für die Tipps. Meinst Du, dass das das Problem löst?
mfg
So, ich habe es jetzt so umgeändert, wie Du es mir empfohlen hast.
Leider hat sich an den Werten nicht viel geändert. Jetzt möchte ich
nochmal gernen den Punkt mit AREF aufgreifen. Obwohl ich, meines
Erachtens nach, schon die interne Referenzspannung (von AVCC) verwende
und AREF über 100nF auf GND gesetzt habe, liegen an AREF, genau wie an
AVCC und VCC, 5,04V an. Was soll ich dagegen machen? Weil die Spannung
kommt vom Controller und sollte doch eig min. 0.5V kleiner als AVCC
sein. Wäre es vllt. hier sonnvoll eine externe Referenzspannung (durch
Spannungsteiler aus Betreibsspannung erzeugt), zu verwenden?
Hi
>Was soll ich dagegen machen? Weil die Spannung>kommt vom Controller und sollte doch eig min. 0.5V kleiner als AVCC>sein.
Gar nichts. Wenn das ein Problem wäre würde Atmel keine Referenzspannung
VCC über die Vref-Bits anbieten.
Außerdem steht im aktuellen Datenblatt
VREF Reference Voltage 2.0 - AVCC V
Also nichts mit VCC-0,5V.
MfG Spess
So, ich habs ENDLICH hinbekommen! :D
Hatte wiedermal nen fehler beim auseinanderziehen des words zum senden.
Bitmanipulation muss ich wohl noch n bissl üben ;)
Vielen Dank für die Hilfe
mfg
Michi
Michael Stoffels schrieb:> So, ich habe es jetzt so umgeändert, wie Du es mir empfohlen hast.> Leider hat sich an den Werten nicht viel geändert.> Was soll ich .... machen?
Dein Programm herzeigen.
Und zwar komplett, inklusive der USART Funktionen.
Denn
> 1V | 32988 / 177774
die 177-tausend machen mich stutzig
Hast du auf dem PC ein spezielles Programm laufen, oder warum
verschickst du Zahlenwerte
1
voidRS_send(unsignedcharc)
2
{
3
while(!(UCSRA&(1<<UDRE))){}// warten bis Senden moeglich
4
5
UDR=c;
6
}
7
8
unsignedcharRS_receive()
9
{
10
while(!(UCSRA&(1<<RXC))){}//warten bis zeichen verfügbar
11
12
returnUDR;
13
}
14
15
voidRS_send_word(uint16_tword)
16
{
17
uint8_th,l;
18
19
RS_send(word>>8);
20
RS_send(word&0xff);
21
}
in Byteform?
Wenn da ein Terminal ist, dann lass dir doch um Himmels Willen vom µC
eine Textform der Daten schicken! Ist doch für dich viel einfacher, als
wenn du laufend Bytes analysieren musst. Deine Computer sollen für DICH
arbeiten und nicht du ihren Job auch noch übernehmen.
Danke, auf das mit dem Text bin ich nicht gekommen. Habs immer mit dem
Taschenrechner von Windows aus der binären Darstellung rausgerechnet.
Ich arbeite mit hTerm. Jetzt muss ich nurnoch die Berechnung der
Spannung ändern. Ich werds wohl in µV rechnen, damit ich keine floats
brauch. Die hinteren 3 Stellen werden dann mit u-= u%1000 abgeschnitten.
Ich sagte ICH GLAUBE, dass die Genauigkeit nicht stimmt. Jetzt hab ich
die Betriebspannung auf exakt 5,00V eingestellt und die Genauigkeit
stimmt. (zumindest bei der manuellen Berechnung aus dem ADC-Wert). Mit
Genauiglkeit habe ich nicht die Auflösung, sondern die Tatsache gemeint,
dass die errechnete Spannung von der Gemessenen zu stark abwich.
Michael Stoffels schrieb:> Danke, auf das mit dem Text bin ich nicht gekommen. Habs immer mit dem> Taschenrechner von Windows aus der binären Darstellung rausgerechnet.
Wir sind Programmierer. Und als solche notorisch faul. Ehe wir selber
uns die Fingern mit einem Taschenrechner schmutzig machen, lassen wir
ein Programm die Dinge ausrechnen oder so aufbereiten, dass WIR
möglichst wenig Arbeit haben. Frei nach dem Motto: lieber einmal und
dann dafür aber ordentlich.
> Ich arbeite mit hTerm. Jetzt muss ich nurnoch die Berechnung der> Spannung ändern. Ich werds wohl in µV rechnen, damit ich keine floats> brauch. Die hinteren 3 Stellen werden dann mit u-= u%1000 abgeschnitten.
Dann rechne dir doch mal aus, wievielen Millivolt es entspricht, wenn
der ADC Wert um 1 schwankt. Noch genauer brauchst du ganz offensichtlich
nicht rechnen.
> Ich sagte ICH GLAUBE, dass die Genauigkeit nicht stimmt.
Stefan hat aber trotzdem recht (und ich habs übersehen).
Deine 5000 werden in einem unsigned char nicht so recht reinpassen.
Ich geb dir einen Tip. Wir verwenden hier nicht umsonst als Datentypen
uint8_t oder uint16_t oder int16_t oder.... Denn dann kann man am
Datentyp sofort ablesen, wieviele Bits der hat und damit auch ohne groß
Überlegen, welches die größte/kleinste speicherbare Zahl da drinnen ist.