Autor |
|
|
|
BID = 851078
Offroad GTI Urgestein
Beiträge: 12741 Wohnort: Cottbus
|
|
Hallo,
habe mal wieder ein kleines Problem mit einem C-Programm.
Es wird über den ADC des ATMEGA32 im 10Bit-Modus eine Spannung eingelesen. Dies funktioniert auch schon, und wird auch korrekt auf dem LCD ausgegeben.
Jetzt wollte ich den Wert des ADC-Registers in die entsprechende Spannung umrechnen, dies funktioniert seltsamerweise aber nicht.
Auf dem LCD erscheint immer nur eine ein- bzw. zweistellige Zahl.
Code : |
#include <avr/io.h>
#include <stdlib.h>
#include <avr/interrupt.h>
#define F_CPU 1e6
#include <avr/delay.h>
#include "lcd-routines.h"
char adcWert[10];
char Spannung[10];
int main ()
{
//Initialisierung LCD
lcd_init();
set_cursor( 1, 1 );
lcd_string("ADC Wert:" );
set_cursor( 1, 2 );
lcd_string("Spannung:" );
sei();
//Initialisierung ADC
ADCSRA |= 1<<ADPS2;
ADMUX |= (1<<MUX0) | (1<<MUX1); //MUX auf ADC3
ADMUX |= 1<<REFS0; //AVCC als Referenz
ADCSRA |= 1<<ADIE;
ADCSRA |= 1<<ADEN;
//Erste Wandlung
ADCSRA |= 1<<ADSC;
while(1);
{
}
}
ISR(ADC_vect)
{
//H und L Bits des ADC-Registers zu einer 16Bit Zahl zusammenfassen
uint8_t LowBits=ADCL;
uint16_t ZehnBitWert=ADCH<<8|LowBits;
//Umrechnung des ADC-Werts in die entsprechende Spannung [mV]
uint32_t Umrechnung=(ZehnBitWert*5000)/1024;
//Zahlenwerte in Strings fürs LCD umwandeln
itoa(ZehnBitWert, adcWert, 10);
itoa(Umrechnung,Spannung,10);
//Werte auf LCD ausgeben
set_cursor( 10, 1 );
lcd_string( adcWert );
lcd_string( " Bit " );
set_cursor( 10, 2 );
lcd_string( Spannung );
lcd_string( "mV " );
//ADC-Wandlung vornehmen
ADCSRA |= 1<<ADSC;
}
|
|
Weiß jemand diesbezüglich einen Rat?
_________________
Theoretisch gibt es zwischen Theorie und Praxis keinen Unterschied. Praktisch gibt es ihn aber. |
|
BID = 851080
DonComi Inventar
Beiträge: 8605 Wohnort: Amerika
|
|
Mal mit ultoa() versuchen?
Immerhin nutzt du ja für die Spannung in Millivolt einen unsigned long.
_________________
|
|
BID = 851088
Offroad GTI Urgestein
Beiträge: 12741 Wohnort: Cottbus
|
Guter Hinweis, ultoa hatte ich aber auch schon versucht - ebenfalls erfolglos
Edit:
Die Variable Umrechnung wird pro ZehnBitWert um 5 erhöht und läuft bei >60 über und startet dann wieder bei 1.
Hilft das irgendwie weiter?
[ Diese Nachricht wurde geändert von: Offroad GTI am 6 Okt 2012 22:52 ]
|
BID = 851091
perl Ehrenmitglied
Beiträge: 11110,1 Wohnort: Rheinbach
|
Zitat :
| (ZehnBitWert*5000)/1024 |
Sollte da nicht 1023 stehen, damit du bei 5V auch 5000 angezeigt bekommst?
|
BID = 851118
Brizz Stammposter
Beiträge: 386 Wohnort: Rheine
|
Der Fehler liegt hier:
uint32_t Umrechnung=(ZehnBitWert*5000)/1024;
Der Zehn Bit-Wert ist als 16-Bit-Wert deklariert. Der wird mit 5000 multipliziert, dabei geht das meiste verloren. Das „kaputte“ Produkt wird durch 1024 dividiert. Dann der ganz „kaputte“ Quotient in eine Vorzeichenlose 32-Bit-Zahl gewandelt.
Deklariere eine 32-Bit-Zahl und weise der 5000 zu. Führe damit die Multiplikation und danach die Division durch, dann erhälst Du das erwartete Ergebnis.
|
BID = 851141
Offroad GTI Urgestein
Beiträge: 12741 Wohnort: Cottbus
|
Danke, genau da lag der Fehler.
Ich habe jetzt (einfach) ZehnBitWert auch als 32Bit Integer deklariert, und erhalte das gewünschte Ergebnis.
Hätte diese Variante
Zitat :
| Deklariere eine 32-Bit-Zahl und weise der 5000 zu. Führe damit die Multiplikation und danach die Division durch |
einen Vorteil?
@Perl: Ja, da sollte 1023 stehen, ist ebenfalls geändert.
_________________
Theoretisch gibt es zwischen Theorie und Praxis keinen Unterschied. Praktisch gibt es ihn aber.
|
BID = 851162
Brizz Stammposter
Beiträge: 386 Wohnort: Rheine
|
@Offroad GTI
Die 5000 auf eine Variable zu schieben, hat keinen Vorteil. Es ging nur darum, dass die Multiplikation und auch die nachfolgende Division mit 32-Bit-Integern durchgeführt wird .
Der C-Compiler prüft immer die Operanden einer arithmetischen Funktion, und ruft letzlich die Funktionen auf, welche durch den Operanden mit den meisten Bit erforderlich ist. Es gibt für char, integer, long usw. auch unterschiedliche Algorithmen.
Es gilt die Hierachie:
char
integer
long integer
long long integer
float
double
long double
Am wenigsten Speicher würde das Programm wie folgt gebrauchen:
uint32_t Umrechnung = ZehnBitWert;
Umrechnung *= 5000;
Umrechnung /= 1024;
Dann kannst Du den ZehnBitWert auch als 16-Bit-Variabel lassen, weil die Konvertierung bei der Zuweisung auf Umrechnung stattfände.
|
BID = 851171
DonComi Inventar
Beiträge: 8605 Wohnort: Amerika
|
Oder du castest:
uint32_t Umrechnung=(((uint32_t)(ZehnBitWert))*5000)/1023;
_________________
|
BID = 851193
Brizz Stammposter
Beiträge: 386 Wohnort: Rheine
|
Es geht auch:
uint32_t Umrechnung=(ZehnBitWert*5000L)/1023;
|
BID = 851203
Offroad GTI Urgestein
Beiträge: 12741 Wohnort: Cottbus
|
Danke noch mal euch beiden.
Zitat :
| Am wenigsten Speicher würde das Programm wie folgt gebrauchen:
uint32_t Umrechnung = ZehnBitWert;
Umrechnung *= 5000;
Umrechnung /= 1024; |
Dem ist aber nicht so. Diese Variante benötigt ein paar Byte (um genau zu sein 24) mehr Speicher, als die Variante mit ZehnBitWert als long int.
Diese Variante
Zitat :
| uint32_t Umrechnung=(((uint32_t)(ZehnBitWert))*5000)/1023; |
ist am sparsamsten (-4Byte)
Wohingegen diese
Zitat :
| uint32_t Umrechnung=(ZehnBitWert*5000L)/1023; |
geradezu verschwenderisch ist (+50Byte)
Diese Problematik kann somit als gelöst angesehen werden.
_________________
Theoretisch gibt es zwischen Theorie und Praxis keinen Unterschied. Praktisch gibt es ihn aber.
|
BID = 851204
perl Ehrenmitglied
Beiträge: 11110,1 Wohnort: Rheinbach
|
Einfacher gehts natürlich, wenn man den Prozessor mit etwas erhöhter Spannung von 5,115V betreibt, oder einen entsprechenden Eingangsspannungsteiler verwendet.
Dann enspricht jedes Digit genau 5mV, man kommt problemlos mit 16 Bit aus, weil man nur mit 5 zu multiplizieren braucht *), und man kann sich die häßliche platz- und rechenzeitraubende Division schenken.
Als besonderes Schmankerl kann man dann auch geringe Überspannungen bis hin zu jenen 5,115V anzeigen.
*) P.S.:
Der Assembler Programmierer macht das mit zweimal linksschieben und einer addition.
Dürfte ungefähr 15 Takte dauern und vielleicht 10 Instruktionen brauchen.
[ Diese Nachricht wurde geändert von: perl am 7 Okt 2012 22:37 ]
|
BID = 851295
Offroad GTI Urgestein
Beiträge: 12741 Wohnort: Cottbus
|
Zitat :
| wenn man den Prozessor mit etwas erhöhter Spannung von 5,115V betreibt |
Das wäre ja ganz schön verwegen
Man könnte auch eine 1,024V Refernezspannung erzeugen, und brächte gar nichts mehr rechnen. Hätte natürlich den Nachteil, dass ein präziser Spannungsteiler nebst Puffer-OPV benötigt wird.
Da aber eine Berechnung (mit Division und Umwandlung in ASCII) nur 20Byte (von 32k Gesamtspeicher) benötigt, werde ich es so lassen.
_________________
Theoretisch gibt es zwischen Theorie und Praxis keinen Unterschied. Praktisch gibt es ihn aber.
|
BID = 851298
perl Ehrenmitglied
Beiträge: 11110,1 Wohnort: Rheinbach
|
Zitat :
| Man könnte auch eine 1,024V Refernezspannung erzeugen, und brächte gar nichts mehr rechnen |
Und der ADC zählt dann plötzlich bis 5000?
Wunderlich.
Zitat :
| Das wäre ja ganz schön verwegen |
Das ist nicht verwegen, denn man wird ohnehin eine Abgleichmöglichkeit schaffen müssen, weil die 5V Versorgung üblicherweise nicht sehr genau ist.
Die Alternative, erwähnte ich bereits: Einen Eingangsspannungsteiler verwenden, der dafür sorgt, dass von 5V nur 4,888V am Eingang des ADC erscheinen.
P.S.:
Zitat :
| Da aber eine Berechnung (mit Division und Umwandlung in ASCII) nur 20Byte (von 32k Gesamtspeicher) benötigt |
Zeig mir mal den zugehörigen Maschinencode!
[ Diese Nachricht wurde geändert von: perl am 8 Okt 2012 17:44 ]
|
BID = 851310
Offroad GTI Urgestein
Beiträge: 12741 Wohnort: Cottbus
|
Zitat :
| Und der ADC zählt dann plötzlich bis 5000? |
Nein, so meinte ich das nicht. Er zählt natürlich weiterhin nur bis 1023.
Zitat :
| Zeig mir mal den zugehörigen Maschinencode! |
Was kann da denn rausgelesen werden?
Code : |
:100000000C942A000C9447000C9447000C94470071
:100010000C9447000C9447000C9447000C94470044
:100020000C9447000C9447000C9447000C94470034
:100030000C9447000C9447000C9447000C94470024
:100040000C9465000C9447000C9447000C944700F6
:100050000C94470011241FBECFE5D8E0DEBFCDBF12
:1000600010E0A0E6B0E0EAE2F5E002C005900D92F3
:10007000A238B107D9F710E0A2E8B0E001C01D92A4
:10008000AE3BB107E1F70E9449000C9493020C9437
:1000900000000E946E0181E061E00E94B90180E6EB
:1000A00090E00E94D40181E062E00E94B9018AE6FA
:1000B00090E00E94D4017894329A87B1836087B926
:1000C0003E9A339A379A369AFFCF1F920F920FB605
:1000D0000F921124CF92DF92EF92FF920F931F9312
:1000E0002F933F934F935F936F937F938F939F9340
:1000F000AF93BF93CF93DF93EF93FF9324B135B1C9
:10010000932F80E0C22FD0E0C82BD92BBE0180E016
:1001100090E028E833E140E050E00E94E8012FEF52
:1001200033E040E050E00E9407028901F42EE52E02
:100130008CE8C82E80E0D82ECE01B6014AE050E00F
:100140000E942902C2E8D0E0B8018F2D9E2DAE0199
:100150002AE030E00E944A02B8018F2D9E2D40EA2D
:1001600050E02AE030E00E944A02B8018F2D9E2D17
:100170004AEA50E02AE030E00E944A02B8018F2D9E
:100180009E2D44EB50E02AE030E00E944A02B80184
:100190008F2D9E2D46E950E02AE030E00E944A0271
:1001A0008AE061E00E94B901C6010E94D40184E79F
:1001B00090E00E94D4018AE062E00E94B901CE0181
:1001C0000E94D4018CE790E00E94D401369AFF91FE
:1001D000EF91DF91CF91BF91AF919F918F917F91DF
:1001E0006F915F914F913F912F911F910F91FF90D0
:1001F000EF90DF90CF900F900FBE0F901F9018954B
:10020000C59A0000C5980895DF93CF930F92CDB79C
:10021000DEB7C498C098C198C298C398982F929599
:100220009F7090FDC09A91FDC19A92FDC29A93FD74
:10023000C39A89830E940001C098C198C298C3984C
:1002400089818F7080FDC09A81FDC19A82FDC29A1A
:1002500083FDC39A0E94000188E18A95F1F700C0EE
:100260000F90CF91DF910895DF93CF930F92CDB789
:10027000DEB7C49AC098C198C298C398982F929537
:100280009F7090FDC09A91FDC19A92FDC29A93FD14
:10029000C39A89830E940001C098C198C298C398EC
:1002A00089818F7080FDC09A81FDC19A82FDC29ABA
:1002B00083FDC39A0E94000188E18A95F1F700C08E
:1002C0000F90CF91DF91089581E00E94040181EEAB
:1002D00094E00197F1F700C000000895B89AB99A28
:1002E000BA9ABB9ABD9ABC9A85EA9EE00197F1F74B
:1002F00000C00000C09AC19AC298C398C4980E94D6
:10030000000181EE94E00197F1F700C000000E9427
:10031000000189EF90E00197F1F700C000000E9412
:10032000000189EF90E00197F1F700C00000C0984C
:10033000C19AC298C3980E94000189EF90E001978A
:10034000F1F700C0000088E20E9404018CE00E94E6
:10035000040186E00E9404010E946401089582E085
:100360000E94040181EE94E00197F1F700C00000C3
:100370000895623069F0633018F4613089F405C083
:10038000633049F0643061F409C0982F915808C077
:10039000982F915405C0982F9D5602C0982F9D52BA
:1003A000892F0E9404010895EF92FF92CF93DF936B
:1003B000E82EE7017E01F92EE70102C00E94340118
:1003C00089918823D9F7DF91CF91FF90EF9008951D
:1003D000629FD001739FF001829FE00DF11D649F29
:1003E000E00DF11D929FF00D839FF00D749FF00DB5
:1003F000659FF00D9927729FB00DE11DF91F639F56
:10040000B00DE11DF91FBD01CF0111240895A1E236
:100410001A2EAA1BBB1BFD010DC0AA1FBB1FEE1F7E
:10042000FF1FA217B307E407F50720F0A21BB30BC9
:10043000E40BF50B661F771F881F991F1A9469F745
:1004400060957095809590959B01AC01BD01CF01A1
:100450000895FB019F01E8944230C4F04532B4F4A2
:100460004A3029F497FB1EF4909581959F4F642F95
:1004700077270E947F02805D8A330CF0895D81932B
:10048000CB010097A1F716F45DE251931082C901E8
:100490000C946F02FA01CF93FF93EF932230CCF0CC
:1004A0002532BCF4C22F2C2F332744275527FF9326
:1004B000EF930E940702EF91FF91605D6A330CF0A9
:1004C000695D6193B901CA016050704080409040FD
:1004D00051F710828F919F91CF910C946F02DC01A4
:1004E000FC01672F71917723E1F7329704C07C916B
:1004F0006D9370836291AE17BF07C8F30895AA1B6E
:10050000BB1B51E107C0AA1FBB1FA617B70710F0FE
:10051000A61BB70B881F991F5A95A9F78095909530
:0A052000BC01CD010895F894FFCF4F
:10052A0041444320576572743A005370616E6E7588
:10053A006E673A002042697420202000206D562000
:02054A000000AF
:00000001FF
|
|
_________________
Theoretisch gibt es zwischen Theorie und Praxis keinen Unterschied. Praktisch gibt es ihn aber.
|
BID = 851314
perl Ehrenmitglied
Beiträge: 11110,1 Wohnort: Rheinbach
|
Zitat :
| Was kann da denn rausgelesen werden? |
Na, die Maschinenbefehle.
Übersichtlicher als das obige, wahrscheinlich auch noch mit Prüfsummen aufgefüllte Binärformat, ist die Assembler-Darstellung.
Da das ja nur 20 Byte sind, wie du schreibst, sollte das ein sehr handliches Listing sein.
Wahrscheinlich wirst du mir aber nur ein paar Zubringerbefehle und Unterprogrammaufrufe präsentieren.
Die geschätzt 800 Bytes des zugehörigen Maschinenprogramms hat der Compiler wahrscheinlich woanders versteckt.
|