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.
Ach du Schande... Ja, das hab ich gestern Abend noch gemacht. Danke dir :)
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 | int main() |
2 | {
|
3 | uint16_t adc_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 | return 0; |
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
:
Wiederhergestellt durch User
Ja, hatte mich wohl doch zu früh gefreut. Die Genauigkeit stimmt glaub noch ned ganz. Jop, hab mal alles angehängt.
Hast du auf dem PC ein spezielles Programm laufen, oder warum verschickst du Zahlenwerte
1 | void RS_send(unsigned char c) |
2 | {
|
3 | while (!(UCSRA & (1<<UDRE))) {} // warten bis Senden moeglich |
4 | |
5 | UDR = c; |
6 | }
|
7 | |
8 | unsigned char RS_receive() |
9 | {
|
10 | while(!(UCSRA & (1<<RXC))) {} //warten bis zeichen verfügbar |
11 | |
12 | return UDR; |
13 | }
|
14 | |
15 | void RS_send_word(uint16_t word) |
16 | {
|
17 | uint8_t h, 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.
1 | void RS_send_string( const char* str ) |
2 | {
|
3 | while( *str ) |
4 | RS_send( *str++ ); |
5 | }
|
6 | |
7 | void RS_send_uint( uint16_t value ) |
8 | {
|
9 | char text[6]; |
10 | utoa( value, text, 10 ); |
11 | RS_send_string( text ); |
12 | }
|
Und dann
1 | #include <avr/io.h> |
2 | #include <util/delay.h> |
3 | #include <rs232.h> |
4 | #include <ADC.h> |
5 | |
6 | int main() |
7 | {
|
8 | uint16_t adc_wert; |
9 | |
10 | RS_init(); |
11 | ADC_init(5000); |
12 | PORTA= 0x00; |
13 | |
14 | while(1) |
15 | {
|
16 | switch( RS_receive() ) |
17 | {
|
18 | case 'a': |
19 | {
|
20 | adc_wert = ADC_read(0); |
21 | RS_send_string( "ADC Raw Value (" ); |
22 | RS_send_uint( 0 ); |
23 | RS_send_string( "): " ); |
24 | RS_send_uint( adc_wert ); |
25 | RS_send_string( "\n" ); |
26 | break; |
27 | }
|
28 | |
29 | case 'u': |
30 | {
|
31 | adc_wert = ADC_read_voltage(0); |
32 | RS_send_string( "ADC Voltage Value (" ); |
33 | RS_send_uint( 0 ); |
34 | RS_Send_string( "): " ); |
35 | RS_send_uint( adc_wert ); |
36 | RS_send_string( " mV\n" ); |
37 | }
|
38 | }
|
39 | }
|
40 | |
41 | return 0; |
42 | }
|
dann kann man auf einem hundsordinären Textterminal dann auch was lesen, ohne erst mal 2 Stunden Kopfrechnen zu müssen, wobei man sich 12 mal vertut.
Michael Stoffels schrieb: > Die Genauigkeit stimmt glaub > noch ned ganz. ??? Soll das etwa heißen, du bekommst tatsächlich was anderes als 0 heraus?
1 | unsigned char u_ref; |
2 | ...
|
3 | return adc*(u_ref/1024); |
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.
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.