www.mikrocontroller.net

Forum: Compiler & IDEs ADC 0 und 1 springen


Autor: elomt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo

Ich habe ein atmega8 und habe ihn in c mit AVR Studio4 programmiert.

Er soll eine Spannung am ADC0 und ADC1 Port einlesen und in der zweiten 
Zeile eines LCD ausgeben. Dies funktioniert auch wenn ich nur einen Wert 
anzeigen lasse.

Sobalt ich beide Werte ( einen links einen rechts ) anzeigen lasse, 
wechseln sich die Werte im Sekunden Tackt. Also die Anzeige von ADC0 
zeigt dann für ca. ne Sekunde den Wert von ADC1 und umgekehrt an.

Woran könnte das liegen?

interne 5V
AREF mit Kondensator mit 100N auf GND
ADC0 Poti 0
ADC1 Poti 1

LCD Ausgabe:

Zeile1: Gestartet
Zeile2: 0000mV 0000mV

Vielen Dank Jens

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das liegt an Zeile 42 in Deinem Code. Ganz klarer Fall...

Autor: elomt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry habe den Code vergessen

MIST

Hier ist der Ausschnitt der für denn ADC und Die Ausgabe zuständig ist.

#include <avr/io.h>
#include <util/delay.h>
#include <stlib.h>
#include <lcd-routines.h>

unsigned short wertadc0;
unsigned short wertadc1;

...

// Hauptprogramm
void main()
{
...
Start:

    ADC0();
    mV();
    ADC1();
    mA();
    _delay_ms(300);
    goto Start;

while(1)
{
}
return 0;
}

void ADC0()
{
    ADMUX = 0b01000000;
    ADCSRA = 0b10000110;
    ADCSRA |=(1<<ADSC);
    while (!(ADCSRA & ( 1<<ADSC)));
    wertadc0 = ADCW;
}
void ADC1()
{
    ADMUX = 0b01000001;
    ADCSRA = 0b10000110;
    ADCSRA |=(1<<ADSC);
    while (!(ADCSRA & ( 1<<ADSC)));
    wertadc1 = ADCW;
}

void mV()
{
    unsigned char lcdnummer1 = 0x00;
    unsigned char lcdnummer2 = 0x00;
    unsigned char lcdnummer3 = 0x00;
    unsigned char lcdnummer4 = 0x00;

NO1:
    if ( wertadc0 >=1000)
    {
         wertadc0-=1000;
         lcdnummer1 ++;
         goto NO1;
    }
    lcdnummer1 |= 0x30;
NO2:
    if ( wertadc0 >=100)
    {
         wertadc0-=100;
         lcdnummer2 ++;
         goto NO1;
    }
    lcdnummer2 |= 0x30;
NO3:
    if ( wertadc0 >=10)
    {
         wertadc0-=10;
         lcdnummer3 ++;
         goto NO1;
    }
    lcdnummer3 |= 0x30;
NO4:
    if ( wertadc0 >=1)
    {
         wertadc0-=1;
         lcdnummer4 ++;
         goto NO1;
    }
    lcdnummer4 |= 0x30;

    set_cursor(0,2);
    lcd_data(lcdnummer1);
    set_cursor(1,2);
    lcd_data(lcdnummer2);
    set_cursor(2,2);
    lcd_data(lcdnummer3);
    set_cursor(3,2);
    lcd_data(lcdnummer4);
    set_cursor(4,2);
    lcd_string("mV");
}
void mA()
{
    unsigned char lcdnummer1 = 0x00;
    unsigned char lcdnummer2 = 0x00;
    unsigned char lcdnummer3 = 0x00;
    unsigned char lcdnummer4 = 0x00;

NO1:
    if ( wertadc1 >=1000)
    {
         wertadc1-=1000;
         lcdnummer1 ++;
         goto NO1;
    }
    lcdnummer1 |= 0x30;
NO2:
    if ( wertadc1 >=100)
    {
         wertadc1-=100;
         lcdnummer2 ++;
         goto NO1;
    }
    lcdnummer2 |= 0x30;
NO3:
    if ( wertadc1 >=10)
    {
         wertadc1-=10;
         lcdnummer3 ++;
         goto NO1;
    }
    lcdnummer3 |= 0x30;
NO4:
    if ( wertadc1 >=1)
    {
         wertadc1-=1;
         lcdnummer4 ++;
         goto NO1;
    }
    lcdnummer4 |= 0x30;

    set_cursor(8,2);
    lcd_data(lcdnummer1);
    set_cursor(9,2);
    lcd_data(lcdnummer2);
    set_cursor(10,2);
    lcd_data(lcdnummer3);
    set_cursor(11,2);
    lcd_data(lcdnummer4);
    set_cursor(12,2);
    lcd_string("mA");

}

Autor: elomt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Komisch jetzt springt er nicht mehr sondern vertauscht permanent denn 
Wert.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> while (!(ADCSRA & ( 1<<ADSC)));
Das ADSC wird gelöscht, wenn die Wandlung beendet ist! Da es eine 
Zeile weiter oben erst gesetzt wird, wird die Schleife direkt 
übersprungen. Warten auf das Wandlungsergebnis geht anders...

Und benutze bitte zum Schreiben der Steuerregister die Bitnamen! Dafür 
sind die da. Nicht nur für ADSC...

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
void Output( unsigned char Column, unsigned char Row,
             unsigned short Value, const char* Unit )
{
  char Text[20];

  sprintf( "%04u%s", Value, Unit );
  set_cursor( Column, Row );
  lcd_string( Text );
}

void mV()
{
  Output( 0, 2, wertadc0, "mV" );
}

void mA()
{
  Output( 8, 2, wertadc1, "mA" );
}

Zu deinem ADC Problem.

   while (!(ADCSRA & ( 1<<ADSC)));

Das ist falsch rum.

Nachdem du den ADC auf einen neuen Kanal stellst, solltest du die erste 
Messung verwerfen. Die ist normalerweise Müll. Es empfiehlt sich auch 
ein paar mal hintereinander zu messen und den Mittelwwert davon zu 
nehmen. Also so wie im Tutorial: Erste Messung verwerfen, dann zb 4 mal 
messen und Mittelwert davon.

Warum verwendest du eigentlich nicht die Funktion aus dem Tutorial?
http://www.mikrocontroller.net/articles/AVR-GCC-Tu...

void main()
{
...
Start:

    ADC0();
    mV();
    ADC1();
    mA();
    _delay_ms(300);
    goto Start;

while(1)
{
}
return 0;
}

Der goto da drinn ist Nonsense. Die Idee ist es eine Endlosschleife zu 
kreieren. Die ist im Prinzip ja auch schon da: while( 1 )
Nur müsstest du sie noch mit Leben füllen.
void main()
{
  ...

  while(1)
  {
    ADC0();
    mV();
    ADC1();
    mA();
    _delay_ms(300);
  }
  return 0;
}


Gewöhn dir goto gleich wieder ab (auch in deinen Umwandlungsfunktionen). 
Wenn du zum jetzigen Zeitpunkt einen goto benutzen willst, gibt es immer 
eine einfachere strukturierte Möglichkeit dasselbe zu erreichen. Wenn 
ich es (ohne grosse Probleme oder darüber Nachzudenken) schaffe eine 
Dreiviertel-Million Lines of Code Programm ohne goto zu schreiben, dann 
wirst du ja wohl die 80 Zeilen ohne goto machen können.

Autor: Benedikt K. (benedikt) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger wrote:

> Nachdem du den ADC auf einen neuen Kanal stellst, solltest du die erste
> Messung verwerfen. Die ist normalerweise Müll.

Kannst du diese Aussage belegen? Im Datenblatt steht nur, dass man nach 
dem Einschalten/Wechseln der Referenz die erste Messung verwerfen soll:
The first ADC conversion result after switching reference voltage source
may be inaccurate, and the user is advised to discard this result.

Bei mir funktioniert der Wechsel des Kanals nämlich auch problemlos.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Benedikt K. wrote:
> Karl heinz Buchegger wrote:
>
>> Nachdem du den ADC auf einen neuen Kanal stellst, solltest du die erste
>> Messung verwerfen. Die ist normalerweise Müll.
>
> Kannst du diese Aussage belegen? Im Datenblatt steht nur, dass man nach
> dem Einschalten/Wechseln der Referenz die erste Messung verwerfen soll:
> The first ADC conversion result after switching reference voltage source
> may be inaccurate, and the user is advised to discard this result.
>
> Bei mir funktioniert der Wechsel des Kanals nämlich auch problemlos.

Wenn das so im Datenblatt steht, dann hast hast du da wohl recht und ich 
war überereifrig.

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Nachdem du den ADC auf einen neuen Kanal stellst, solltest du die erste
>Messung verwerfen. Die ist normalerweise Müll.

Nachdem daß ja immer wieder postuliert wird, und auch im Beispiel-Code 
des Tutorials so steht, kann mir mal jemand sagen, wo genau das im 
Datenblatt steht? Ich finde das einfach nicht.

Oliver

Autor: Ralf Schwarz (spacedog) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das Problem liegt im Ablauf des Umschaltens des Multiplexers. Wenn du 
den Befehl gibst, den Kanal zu Wechseln, wird dieser Befehl 
logischerweise erst nach Ablauf der letzten Wandlung ausgeführt. Nach 
Ablauf der Wandlung wird aber auch, das Flag gesetzt, dass neue Daten 
bereitstehen. Somit hast du also nachdem du den Multiplexer umgeschaltet 
hast, noch ein Wandlungsergebnis vom vorher ausgewählten Kanal. Deshalb 
verwerfen viele Entwickler einfach das erste Wandlungsergebnis nach dem 
Kanalwechsel. Wenn man es aber geschickt aufgleist, geht es natürlich 
auch ohne verwerfen von Daten. Man kann nämlich auch einfach den Befehl 
zum Umschalten des Mux einfach vor der letzten Wandlung des 
vorhergehenden Kanals absetzen. Klar soweit?

Autor: elomt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Karl Heijnz

dein Code:

void Output( unsigned char Column, unsigned char Row,
             unsigned short Value, const char* Unit )
{
  char Text[20];

  sprintf( "%04u%s", Value, Unit );
  set_cursor( Column, Row );
  lcd_string( Text );
}

void mV()
{
  Output( 0, 2, wertadc0, "mV" );
}

void mA()
{
  Output( 8, 2, wertadc1, "mA" );
}

funktioniert bei mir nicht es wirt auf dem LCD zweimal(
I'schwartzes kästchien schräges X ) ausgegeben.

Autor: elomt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Ralf Schwarz

ich setze doch erst den ADMUX und dann den ADCSRA und starte dann erst 
den ADC. Oder verstehe ich da was falsch?

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Ralf Schwarz
>Klar soweit?

Nö. Ein " ham' wer schon immer so gemacht" ist genauso hilfreich wie 
"viel hilft viel", das einmauern toter Katzen in Brückenfundamente, oder 
"schad' ja nix".

Etwas genauer: Die Anwendung hier sind einzelne Wandlungen, der ADC wird 
jedes mal neu gestartet, VREF wird nicht umgeschaltet. Ein 
Standard-Szenario für ADC-Betrieb ohne free-run.

Wo steht im Danteblatt, daß ein Umschalten des Kanals vor dem Start des 
ADC's zu einem ungültigem Wandlungsergebnius führt?

Oliver

Autor: Ralf Schwarz (spacedog) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Oliver: Sorry für meine unqualifizierte Aussage. Du hast natürlich 
Recht, der ADC läuft hier nicht im Free Running mode, somit hat mein 
Hinweis natürlich nichts mit dem Problem zu tun. Aber da viele (auch 
erfahrene) Leute sich schwer tun mit dem Timing des ADCs, hab ich hier 
mal meinen Senf dazugegeben und dümmer ist dabei sicher niemand 
geworden.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
elomt wrote:

> funktioniert bei mir nicht es wirt auf dem LCD zweimal(
> I'schwartzes kästchien schräges X ) ausgegeben.

My fault:

   sprintf( Text, "%04u%s", Value, Unit );
            ****

Mann muss dem sprintf schon auch sagen, wo der Ergebnistext hin soll :-)
Tschuldigung.

Autor: elomt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So
jetzt funktioniert alles habe :

while (!(ADCSRA & (1<<ADSC))); gegen while (ADCSRA & (1<<ADSC));
und die Ausgabe von Karl Heinz

Vielen Vielen Vielen Dank

Autor: elomt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
zu dem GOTO Befehl

Ich habe hier im Forum schon oft gelesen das der goto oldschool ist und 
nicht mehr genutzt werden soll. Andere sagen benutzt ihn ( ist einfach 
und funktioniert). Meine Frage ist nun was für Altanatieven gibt es 
denn?

Autor: P. S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
elomt wrote:

> Ich habe hier im Forum schon oft gelesen das der goto oldschool ist und
> nicht mehr genutzt werden soll. Andere sagen benutzt ihn ( ist einfach
> und funktioniert). Meine Frage ist nun was für Altanatieven gibt es
> denn?

Nichts dagegen goto zu benutzen, wo es einen Sinn ergibt. Aber wenn man 
eine Schleife implementiert, duerfte while() fast immer erste Wahl sein. 
Dein Code sieht eher aus wie Markoassembler mit den ganzen "von Hand" 
implementierten Schleifen. Im Uebrigen sind sind deine Spruenge in den 
mA und mV Funktionen hoechst zweifelhaft...

Autor: Benedikt K. (benedikt) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
elomt wrote:
> Ich habe hier im Forum schon oft gelesen das der goto oldschool ist und
> nicht mehr genutzt werden soll.

Prinzipiell richtig, da man schnell Fehler damit machen kann und das 
Programm unübersichtlich werden kann.

> Andere sagen benutzt ihn ( ist einfach und funktioniert).

Und hat einige Vorteile gegenüber anderen Lösungen. Generell verbieten 
ist also keine Lösung.

> Meine Frage ist nun was für Altanatieven gibt es
> denn?

In diesem Fall eine beliebige Endlosschleife:
Start:

    ADC0();
    mV();
    ADC1();
    mA();
    _delay_ms(300);
    goto Start;

Dies kann man wunderbar durch folgendes ersetzen:
  while (1)
  {
    ADC0();
    mV();
    ADC1();
    mA();
    _delay_ms(300);
  }

Die anderen gotos kann man auch durch ein while ersetzen. Dazu muss 
lediglich das if durch ein while ersetzt werden, wenn ich das richtig 
sehe.

Autor: elomt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry wenn ich nochmal was schreibe aber ich habe gerade gesehen das 
mein adc wert nicht unter 14 geht wenn ich gnd auf den adc port gebe. 
Weis einer woran das liegen könnte?

Autor: Benedikt K. (benedikt) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schlechte Masseanbindungvom GND Pin, ADC Pin auf Ausgang + High 
geschaltet usw.

Autor: elomt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
die GND's und der ADC liegen auf dem selben GND in der Schaltung

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dein Poti wird halt nicht exakt 0 Ohm erreichen können.

Autor: elomt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
mit einem Multimeter messe ich aber 0,000V am Port dann sollte der ADC 
doch auch 0 anzeigen.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Auch Multimeter messen Mist.
Aber 14 ist schon ein bischen viel.

Welchen Wert kriegst du, wenn du mal direkt GND an den Pin hängst?

Edit: Grade gesehen. Du hast ja schon Masse mal direkt an den Pin 
angeschlossen.

Zeig nochmal das Pgm, so wie es jetzt aussieht. Schaltbild wär auch 
nicht verkehrt, damit wir nicht aneinander vorbeireden.

Autor: elomt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
auch 14

Autor: elomt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo

Ich schreibe erstmal ein neues Programm da mein jetziges mit der ganzen 
LCD Menüführung zu umfangreich ist.

Vielen Dank noch mal für die guten tips.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.