Hallo zusammen, ich habe ein frage bezüglich des AD Wandlers in einem Mikrocontroller ATMEga644p ich habe dort einen Lichtwiderstand angeschlossen. dieser schickt mir die Werte von 1-255 über den uart an meinen PC Funktioniert auch alles sehr gut, leider kommen bei mir immer nur ganz zahlen an. Ich hätte eigentlich erwartet dass auch Fließkommazahlen ankommen. 1,1....20,1 hab ich da vielleicht was falsches in den Datentypen gemacht? kann der Controller vielleicht gar keine Fließkommazahlen übermitteln? bin leider Anfänger und für jede Hilfe dankbar. hier der Code: #ifdef F_CPU #undef F_CPU #define F_CPU 16000000UL #endif #include <avr/io.h> #include <inttypes.h> #include <util/delay.h> #include <stdint.h> #include <stdio.h> // Diese Beispiel zeigt die Anwendung des ADC eines ATmega644 /* ADC initialisieren */ void ADC_Init(void) { // die Versorgungsspannung AVcc als Referenz wählen: //ADMUX = (1<<REFS0); // oder interne Referenzspannung als Referenz für den ADC wählen: ADMUX = (0<<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 } void USART_Init( unsigned int baud ) { /*Set baud rate*/ UBRR0H = (unsigned char)(baud>>8); UBRR0L = (unsigned char)baud; /* Enable receiver and transmitter*/ UCSR0B = (1<<RXEN0)|(1<<TXEN0); /* Set frame format: 8data, 2stop bit*/ UCSR0C = (1<<USBS0)|(3<<UCSZ00); } void USART_Transmit( unsigned char data ) { /* Wait for empty transmit buffer*/ while ( !( UCSR0A & (1<<UDRE0)) ); /* Put data into buffer, sends the data*/ UDR0 = data; } void uart_puts( char *s ) { /* while *s != '\0' so unequally "string-end characters (terminator) */ while (*s) { USART_Transmit(*s); s++; } } void main(void) { PORTB = (1<<PD0)|(1<<PD1); DDRB = (1<<DDD0)|(1<<DDD1); USART_Init(0x6); char String1[32] = {"Test "}; char String2[32] = {"Test "}; char String3[32] = {"Test "}; char String4[32] = {"Test "}; long ADCWert1; long ADCWert2; long ADCWert3; long ADCWert4; ADC_Init(); //ADCWert = 123; while(1) { ADCWert1 = ADC_Read(0b00001);//Seite 249 Datenblatt Kanal 1 ADCWert2 = ADC_Read(0b00010);//Seite 249 Datenblatt Kanal 2 ADCWert3 = ADC_Read(0b00000);//Seite 249 Datenblatt Kanal 0 ADCWert4 = ADC_Read(0b00011);//Seite 249 Datenblatt Kanal 3 sprintf(String1,"LDR1: %i g \n", ADCWert1); sprintf(String2,"LDR2: %i g \n", ADCWert2); sprintf(String3,"LDR3: %i g \n", ADCWert3); sprintf(String4,"LDR4: %i g \n", ADCWert4); uart_puts(String1); uart_puts(String2); uart_puts(String3); uart_puts(String4); //USART_Transmit(S); _delay_ms(100); } }
Susanne schrieb: > Funktioniert auch alles sehr gut, leider kommen bei mir immer nur ganz > zahlen an. Klingt richtig Susanne schrieb: > Ich hätte eigentlich erwartet dass auch Fließkommazahlen ankommen. Wo sollen die herkommen? Der ADC des Mega hat ein 10-Bit Ergebnis Register, in dem nur ganze Zahlen zwischen 0 und 1023 ausgegeben werden. Erst, wenn du diesen Wert mit einer Gleitkommazahl multiplizierst oder durch eine teilst, könnten Nachkommastellen hinzukommen. Um die höchstmögliche Auflösung des ADC zu nutzen, solltest du allerdings die Ergebnisse in 16-bit (words) Wertten darstellen und nicht nur als 8-Bit Bytes.
Susanne schrieb: > kann der Controller vielleicht gar keine Fließkommazahlen übermitteln? Der Controller macht genau das, was du ihm sagst. Ob das identisch mit dem ist, was du möchtest, hängt von der Umsetzung in Form des Programms ab. Was der Controller in seiner Hardware unterstützt, findest du im Datenblatt. Im Kapitel 23. ADC - Analog-to-digital converter unter 23.1 Features steht zum Beispiel, dass der ADC eine Auflösung von 10 Bit besitzt, was einer Anzahl von 2^10=1024 Stufen entspricht. Und mehr als diese 10 Bit rückt der ADC über das ADC DATA REGISTER nicht raus. Was du damit machst und wie du das skalierst, steht auf einem anderen Blatt. Mit einer Umwandlung der Form
1 | sprintf(String1,"LDR1: %i g \n", ADCWert1); |
für die Ausgabe wirst du allerdings bei "%i" nie etwas anderes als Ganzzahlen erhalten. Guck dir mal die Beschreibung der Funktion sprintf() und die Beschreibung für die Format-Anweisung an.
Susanne schrieb: > ich habe dort einen Lichtwiderstand angeschlossen. Wenn du nur einen Widerstand an einen ADC anschliesst wirst du kein vernünftiges Ergebnis bekommen, denn ein ADC kann keine Widerstände messen sondern nur Spannungen. Und solange kein Strom durch deinen Widerstand fliest wird dort nahe bei Null Volt gemessen.
Leider bin ich noch nicht auf die entsprechende Lösung gekommen. auch den Wert: "i" durch "n" ersetzen erbrachte nicht den gewünschten Erfolg. dann kommt nämlich ein ? an. vorher: sprintf(String1,"LDR1: %i g \n", ADCWert1); nachher: sprintf(String1,"LDR1: %n g \n", ADCWert1);
Susanne schrieb: > Leider bin ich noch nicht auf die entsprechende Lösung gekommen. > auch den Wert: "i" durch "n" ersetzen erbrachte nicht den gewünschten > Erfolg. Wieso sollte das auch was ändern? Deine Variable ADCWert1 hast du als long definiert. Wie kommst du jetzt darauf, dass das ein Gleitkommatyp ist? Ein Integer bleibt ein Integer und wird nicht zum Gleitkommatyp nur weil man in sprint die Formatierung für Gleitkommatypen benutzt. Ich werd ja auch nicht Einstein, nur weil ich mir einen Bart anklebe. Dann schaun wir uns noch an wie du ADCWert1 befüllst und stellen fest: Selbst wenn ADCWert1 als Gleitkommatyp definiert wäre würde das nichts bringen denn du befüllst ADCWert1 mit einem Integer. Ich empfehle dir daher unbedingt, dass du dir noch mal die Funktionsweise des ADCs betrachtest denn du hast anscheinend noch gar nicht verstanden, was genau dir der ADC liefert.
Arduinoquäler schrieb: > Susanne schrieb: >> ich habe dort einen Lichtwiderstand angeschlossen. > > Wenn du nur einen Widerstand an einen ADC anschliesst wirst > du kein vernünftiges Ergebnis bekommen, denn ein ADC kann > keine Widerstände messen sondern nur Spannungen. Und solange > kein Strom durch deinen Widerstand fliest wird dort nahe > bei Null Volt gemessen. Da steht Lichtwiderstand. Also nen Photowiderstand. WIE der jetzt angeschlossen wurde ist allerdings interessant.
Sascha_ schrieb: > Da steht Lichtwiderstand. Also nen Photowiderstand. Mein bevorzugter Lichtwiderstand heisst "Sonnenbrille".
Susanne schrieb: > ich habe dort einen Lichtwiderstand angeschlossen. > dieser schickt mir die Werte von 1-255 über den uart an meinen PC Susanne schrieb: > sprintf(String1,"LDR1: %i g \n", ADCWert1); Ich vermute mal das du einen LDR Fotowiderstand an den Eingang des ADCs angeschlossen hast. Bitte mal Typenbezeichnung oder Datenblatt des LDRs. Ein LDR änderst sein Widerstand etwa zwischen ( dunkel ) mehreren Megohm bis zu ( hell ) einigen hundert Ohm. Und das an einer recht unlinearen Kennlinie Um daraus eine Spannung zu machen, welche der ADC auswerten kann müsste zumindest über einen Widerstand von mehreren 10K bis mehrere 100K eine Spannung angelegt werden. ( Vorzugsweise die Spannung , die der ADC auch als Referenzspannung verwendet. Der ADV macht dann daraus einen 10Bit breites digitales Wort ( Integer ) welches der Eingangspannung proportional ist ( nicht der der Lichtstärke wegen des stark nichtlinearen Zusammenhanges des LDR ). Mit der Größe des Widerstandes kann man in gewissen Grenzen festlegen bei welcher Lichtstärke die größte Auflösung der Lichtänderung ist. Also wie groß man den Widerstand wählt hängt von dem Helligkeitsbereich ab den man messen will. Ralph Berres
Ich glaube da sollten wir nochmal einfacher anfangen... Da mangelt es massiv an Grundlagen zu Datentypen, Ausgabe von Daten ("%i" zu tippen ergibt niemals float...), Verwendung des ADCs etc. Ich sehe hier noch zu viele Baustellen, würde das Projekt erstmal zurückstellen, Grundlagen aneignen und dann nochmal probieren.
Ralph B. schrieb: > Ich vermute mal das du einen LDR Fotowiderstand an den Eingang des ADCs > angeschlossen hast. > .......... Alles Quatsch. Sascha hast doch den vollen Durchblick: Sascha_ schrieb: > Da steht Lichtwiderstand. Also nen Photowiderstand. Damit ist doch alles gesagt.
Ralph B. schrieb: > Um daraus eine Spannung zu machen, welche der ADC auswerten kann müsste > zumindest über einen Widerstand von mehreren 10K bis mehrere 100K eine > Spannung angelegt werden. ( Vorzugsweise die Spannung , die der ADC auch > als Referenzspannung verwendet. > Deine Ausführungen in Ehren, aber das alles will unsere "Susanne" gar nicht hören bzw lesen. Sie will einfach nur aus einem Integer ein Float machen, so einfach ist das ....
Susanne schrieb: > ich habe dort einen Lichtwiderstand angeschlossen. > dieser schickt mir die Werte von 1-255 über den uart an meinen PC > > Funktioniert auch alles sehr gut, leider kommen bei mir immer nur ganz > zahlen an. > Ich hätte eigentlich erwartet dass auch Fließkommazahlen ankommen. > 1,1....20,1 Tja, den Spruch "Es gibt nichts Gutes, es sei denn, man tut es" kennst du hoffentlich. Also fang an, deine Aufgabe selbst zu lösen. Du willst eine Textausgabe per serieller Schnittstelle haben? Dann mußt du dies organisieren. Dein ADC liefert dir nur geordnete Bitmuster. Jaja, keine Zahlen, sondern geordnete Bitmuster. Alle ADC's machen das so. Es gibt ein LSB (also der Benjamin) und ein MSB (das größte) und einige Bits dazwischen, jeweils mit einer Staffelung der Wertigkeit um den Faktor 2. Aber du willst vermutlich eine Maßzahl haben, also 20.1 für 20.1 Volt (oder Grad Celsius oder weiß der Geier). Also mußt du dein Bitmuster vom ADC eben geeignet skalieren und dann in eine zugehörige Textausgabe wandeln. Jaja, klingt kompliziert, ja? Aber da muß man durch, zwecks grundlegenden Verständnisses. Überflieger, die nur copy&paste können, haben wir schon genug. Man kann das Ergebnis des ADC als simple Integerzahl ansehen, die bei dir eben von 0 bis 1023 geht (wenn du beide Teile richtig aus dem ADC ausgelesen hast). Kann, nicht muss. Nun kannst du diese Zahl ins Gleitkommaformat wandeln lassen, such dir dafür die geeignete Funktion aus, zumeist reicht eine simple Zuweisung aus. Anschließend kannst du die gewonnene Gleitkommazahl mit einer selbst erfundenen Gleitkommazahl multiplizieren und dann mußt du sie nur noch in eine Folge von Textzeichen wandeln. Sowas ist bei fast jedem Compiler mit dabei, aber es kostet einen Haufen Speicherplatz. Für spezielle Fälle geht es auch sehr viel simpler, also äußere dich mal über die konkreten Umstände. W.S.
W.S. schrieb: > also äußere dich mal über die konkreten Umstände. Das war schon viel mehr als zuviel des Guten. Susanne ist wohl längst untergetaucht ob des Überangebots an Wissen .....
Hallo zusammen, sorry, hätte nicht gedacht, dass doch noch ernsthafte hilfe kommt. wenn ich ehrlich bin weiß ich nicht wo anfangen. Ich weiß aber schonmal an was es liegt. vielleicht kann mir jemand die Lösung sagen dann kann ich anhand deren mich in die Thematik einarbeiten. Schließlich ist noch kein Meister vom Himmel gefallen.
ist ganz einfach... Du machst einfach aus
1 | sprintf(String1,"LDR1: %i g \n", ADCWert1); |
1 | sprintf(String1,"LDR1: %f g \n", ADCWert1*1.0); |
und schon hast du deine Gleitkommazahlen.
Susanne schrieb: > Schließlich ist noch kein Meister vom Himmel gefallen. Ja, Lernfaule dagegen schon viele. Susanne schrieb: > vielleicht kann mir jemand die Lösung sagen Mit oder ohne Silbertablett?
Susanne schrieb: > vielleicht kann mir jemand die Lösung sagen dann kann ich anhand deren > mich in die Thematik einarbeiten. Schließlich ist noch kein Meister vom > Himmel gefallen. Erkläre mir doch mal bitte was es dir hilft Gleitkommazahlen zu bekommen. Der 10 Bit ADC liefert nun mal exakt 1023 feste Werte. ( Dazwischen gibt es nichts ). Das sind meines Erachtens Integerwerte. Wenn du daraus Gleitkommazahlen machen willst gewinnst du nicht mehr Auflösung. Ralph Berres
Ralph B. schrieb: > Der 10 Bit ADC liefert nun mal exakt 1023 feste Werte. Sorry, 1024 (0...1023)! SCNR
Hallo, ich habe das mal so gemacht 32xADC wert gelesen (long) und addiert. Wert durch 32 in ein float geschrieben (musste wegen genauigkeit sein). einen UNION datentyp erstellt mit 4xchar und einen float. float in UNION.FLOAT geschrieben und 4xchar über UART an PC. Auf PC seite die 4 char auch in UNION.CHAR1..4 und zur Darstellung das float genommen. ms
sprintf(String1,"LDR1: %f g \n", ADCWert1*1.0); Das habe ich schon probiert, leider kommt dann auf meiner Konsole der Wert:"?" an irgendwas ist komisch, ich weiß nur noch nicht was...
Hallo Susanne teste das mal #include <stdio.h> #include <math.h> int main(void) { char buffer[80]; sprintf(buffer, "An approximation of Pi is %f\n", M_PI); puts(buffer); return 0; } ms
oder das float tmp_1; char string[20]; tmp_1 = (1.271 * ADCW); //ADC Wert multiplizieren dtostrf(tmp_1,1,3,string); der ADC-Wert wird immer ganzzahlig sein. Bei meinen Sensoren gibt es immer ein Datenblatt mit Werten zur umrechnung in einen anderen Einheit (Volt in bar) Meist ist das eine einfache geradengleichung(y=m*x+b) daraus ergeben sich automatisch Fließkommawert ms
was bedeutet das ganeu? "double to String Fließkommazahl" dtostrf temperatursensor1 was bedeutet aber das 1,3? Ausgabe als String. dtostrf(tmp_1,1,3,string);
Susanne schrieb: > was bedeutet das ganeu? Es reicht .... ich beschliesse: ----- das ist ein Troll Thread ----- So dämlich kann man sich nicht anstellen. Bitte füttert den Troll nicht noch weiter.
Susanne schrieb: > was bedeutet aber das 1,3? Das Problem hatten wir doch "neulich" gerade: Beitrag "dtostrf funktion allgemein"
Hallo Susanne, http://www.atmel.com/webdoc/AVRLibcReferenceManual/group__avr__stdlib_1ga060c998e77fb5fc0d3168b3ce8771d42.html 1. ADC ist immer Ganzzahlig. 2. Diese Zahl musst Du umrechnen in Lux,Lummen oder was auch immer. 3. das Ergebnis must du in ASCII umwandeln mit dtostrf oder sprintf Hast Du einen JTAG? Bei meiner Ausbildung habe ich immer die Simulation vom AVR-Studio verwendet (sichwort Breakpoint). Ich könnte Dir die Lösung anbieten aber das ist nicht das Ziel. ms
Susanne schrieb: > Ich weiß aber nicht für was das 1,3 steht. W.A. hatte den Link doch schon genannt: Beitrag "Re: dtostrf funktion allgemein" Muss man Dir den Text von Karl Heinz noch vorlesen? Da steht alles drin, sogar mit Beispiel. In dem Beispiel steht allerdings 7,2 und nicht 1,3. Das sollte doch hoffentlich nicht das Problem sein...
Hallo Susanne, Ich mache das immer so sobald was nicht so func wie ich das will. 1.BinTerm runterladen und Parameter einstellen. 2.In Main einen definierten Text in einer endlos loop schicken Kommt der Text i.O. am PC an ist die Peripherie in Ordnung. danach mit einer funktion rumspielen (dtostrf) und selber schluesse daraus ziehen.Das vergisst du nie. ms
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.