www.mikrocontroller.net

Forum: Compiler & IDEs ADC-MUX verdreher ATmega8535


Autor: Hendrik S. (gustaf3459)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Leute,

Ich benutze einen ATmega8535 um eine Solarzelle automatisch nach der
Sonne auszurichten (und weiter adwandlungen zur stromerfassung etc.) 
Hierzu habe ich 2 kleinere solarzellen , die rücken an rücken 
zusammengeklebt und antiparallel verschaltet wurde rechtwinklig an der 
solarzelle befestigt.
durch eine kleine diodenschaltung bekommen dann 2 pins (PA3 und PA4) die
ausgewerteten analogen signale und der controller soll nun nur noch
beide signale analog einlesen, vergleichen und daraufhin entsprechend
die motoren ansteuern. zudem wurde ein ldr installiert (PA6), der die
ausrichtung abschaltet, sobald der himmel bewölkt ist.

so, jetzt zu meinem problem... ich bin C-neueinsteiger und habe mich
daran begeben, das programm (assembler und funktionsfähig!) in c
umzuschreiben.

wie im programm möchte ich die pins separat einlesen und auswerten,
jedoch stimmen die MUX-werte des ports nicht mehr... das habe ich auch
auf ner testplatine probiert und bei 2 programmierten wandlungen
verdreht es auch schon die werte...

hierzu erstmal ein programmausschnitt indem ich durch rumprobieren den
mux so gesetzt habe, dass es soweit funktioniert.

die funtionen sind soweit funktionsfähig und sollten eig. nichts zu
sagen haben ^^




#include <avr/io.h>    // µC Register einbinden
#include <stdint.h>    // Zahlenwerte (int) einbinden
#define F_CPU 4000000    // Quarztakt bestimmen
#include <util/delay.h>    // Verzögerung einbinden
#include "includeLCD.c"    // Include-Datei für folgende LCD-Befehle

uint16_t wert=0;
uint16_t hilf1=0;
uint16_t hilf2=0;
uint16_t hell=0;
uint8_t x=0;
uint8_t y=0;


void analog (void)
{
  ADCSRA = 0xC5;        //ADEN , ADSC und Pescaler auf 5 (32)
  loop_until_bit_is_set (ADCSRA, ADSC);
  wert=ADCW;
  _delay_ms(1);
}



//*Prüfe Position und speicher Werte in Akku & Wert*/

  lcd_cursor(0,1);
  lcd_string("     Suche     ");

  ADMUX = 0x02;    //Linke Solarzelle???!!!!????
  analog();
  hilf1=wert;

  ADMUX = 0x06;    //Rechte Zelle???!!!????
  analog();
  hilf2=wert;


//*Werte Position aus*/

  if(hilf1==hilf2)
  {
    if (y==1)
    {
      stop_li();
    }
    if (y==2)
    {
      stop_re();
    }
    y=0;

  }
  else
  {

    if(hilf1<hilf2)    //Links ausrichten
    {
      y=1;
      links();
    }
    else        //Rechts ausrichten
    {
      y=2;
      rechts();
    }
  }

//*Prüfe ob Hell genug für Auswertung*/

  ADMUX = 0x03;                   //!!!!!????!!!!!!
  analog();
  hell=wert;

  while (hell < 0x00FF)
  {
    lcd_cursor(0,1);
    lcd_string("    Wolken     ");
    lcd_cursor(0,2);
    lcd_string("                ");
    PORTC &= ~((1<<motor_li)|(1<<motor_re));
    ADMUX= 0x06;             //!!!!!????!!!!!
    analog();
    hell=wert;
  }


normalerweise sollte rechts: ADMUX = 0x02;
links    ADMUX = 0x03;
ldr      ADMUX = 0x06;


wie kommen diese komischen dreher zusammen ?? falls der ausschnitt nicht
reicht häng ich mein bisher zusammengebasteltes programm in assembler
und c an.
ich hoffe ihr könnt mir helfen =)

danke schonmal

gruß hendrik

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was funktioniert denn jetzt nicht?

Im Datenblatt steht doch die eindeutige Zuordnung des ADMUX Registers.

Und versuche mal eindeutige Variablennamen zu benutzen, x,y hilf, wert 
könnte man sicher schöner machen.

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

Bewertung
0 lesenswert
nicht lesenswert
Um Fehlschaltungen und sonstige Logikfehler auszuschliessen, würde ich 
hergehen und mir einfach mal die Werte vom ADC am LCD ausgeben lassen.
Der deiner Meinung nach richtige Wert müsste sich verändern, wenn du mit 
der Hand die jeweilige Solarzelle/LDR abschattest.
   if(hilf1==hilf2)

Das ist sehr optimistisch.
Selbst wenn sich eine Spannung nicht verändert, liefert ein ADC bei 2 
Messungen normalerweise keine identischen Werte. Eine Abweichung von 1 
bis 2 binären Digits ist normal, solange man nicht einen hohen Aufwand 
zur Rauschunterdrückung und Stabilisierung der Referenzspannung treibt.

PS: Was spricht gegen Verwendung von zb. "ZelleLinks" "ZelleRechts" 
"Ldr" als Variablennamen anstelle von so nichtssagenden Namen wie x, y, 
hilf, test etc.

Schreibst du deine Funktion so
uint16_t analog (void)
{
  uint16_t wert;

  ADCSRA = 0xC5;        //ADEN , ADSC und Pescaler auf 5 (32)
  loop_until_bit_is_set (ADCSRA, ADSC);
  wert = ADCW;
  _delay_ms(1);

  return wert;
}

Dann kannst du sie so benutzen
//*Prüfe Position und speicher Werte in Akku & Wert*/

  lcd_cursor(0,1);
  lcd_string("     Suche     ");

  ADMUX = 0x02;    //Linke Solarzelle???!!!!????
  hilf1 = analog();

  ADMUX = 0x06;    //Rechte Zelle???!!!????
  hilf2 = analog();

Gibst du zusätzlich der analog() Funktion auch noch den Kanal mit
uint16_t analog ( uint8_t channel )
{
  uint16_t wert;

  ADMUX = channel; 
  ADCSRA = 0xC5;        //ADEN , ADSC und Pescaler auf 5 (32)
  loop_until_bit_is_set (ADCSRA, ADSC);
  wert = ADCW;
  _delay_ms(1);

  return wert;
}
dann vereinfachen sich die Aufrufe zu
//*Prüfe Position und speicher Werte in Akku & Wert*/

  lcd_cursor(0,1);
  lcd_string("     Suche     ");

  hilf1 = analog( 0x02 );
  hilf2 = analog( 0x06 );

macht man sich dann für die magischen Konstanen 0x02 und 0x06 ein paar 
#define

#define ZELLE_LINKS  0x02
#define ZELLE_RECHTS 0x06

//*Prüfe Position und speicher Werte in Akku & Wert*/

  lcd_cursor(0,1);
  lcd_string("     Suche     ");

  hilf1 = analog( ZELLE_LINKS );
  hilf2 = analog( ZELLE_RECHTS );

dann wird das ganze Codestück selbsterklärend und leicht lesbar

Autor: Hendrik S. (gustaf3459)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
es funktioniert SO schon aber normalerweise sollten die MUX-werte , die 
nach der zuordnung im datenblatt vorgegeben sind auch zutreffen.
Wenn ich beispielweise am PA0 und PA1 etwas einlese, ist für PA1 ADMUX = 
0x00 und für PA0 ADMUX = 0x01 eintreffend... das verwirrt mich und muss 
an irgendetwas liegen. Die Muxwerte sind Durch ausporbieren rausgekommen 
und bei der auswertung unten im programm lese ich den selben pin einmal 
mit 0x03 und 0x06 ein o.O

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hendrik S. schrieb:
> void analog (void)
> {
>   ADCSRA = 0xC5;        //ADEN , ADSC und Pescaler auf 5 (32)
>   loop_until_bit_is_set (ADCSRA, ADSC);

Wenn der Name stimmt, dann macht diese Funktion nichts.
Und dadurch liest Du immer den Wert der vorherigen Wandlung aus.

Du brauchst ein "loop_while_bit_is_set"
>   wert=ADCW;
>   _delay_ms(1);

Was soll das, ist Dir die CPU zu schnell?


Peter

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

Bewertung
0 lesenswert
nicht lesenswert
PS: Was spricht gegen Verwendung von zb. "ZelleLinks" "ZelleRechts" 
"Ldr" als Variablennamen anstelle von so nichtssagenden Namen wie x, y, 
hilf, test etc.

Schreibst du deine Funktion so
uint16_t analog (void)
{
  uint16_t wert;

  ADCSRA = 0xC5;        //ADEN , ADSC und Pescaler auf 5 (32)
  loop_while_bit_is_set (ADCSRA, ADSC);
  wert = ADCW;
  _delay_ms(1);

  return wert;
}

Dann kannst du sie so benutzen
//*Prüfe Position und speicher Werte in Akku & Wert*/

  lcd_cursor(0,1);
  lcd_string("     Suche     ");

  ADMUX = 0x02;    //Linke Solarzelle???!!!!????
  hilf1 = analog();

  ADMUX = 0x06;    //Rechte Zelle???!!!????
  hilf2 = analog();

Gibst du zusätzlich der analog() Funktion auch noch den Kanal mit
uint16_t analog ( uint8_t channel )
{
  uint16_t wert;

  ADMUX = channel; 
  ADCSRA = 0xC5;        //ADEN , ADSC und Pescaler auf 5 (32)
  loop_while_bit_is_set (ADCSRA, ADSC);
  wert = ADCW;
  _delay_ms(1);

  return wert;
}
dann vereinfachen sich die Aufrufe zu
//*Prüfe Position und speicher Werte in Akku & Wert*/

  lcd_cursor(0,1);
  lcd_string("     Suche     ");

  hilf1 = analog( 0x02 );
  hilf2 = analog( 0x06 );

macht man sich dann für die magischen Konstanen 0x02 und 0x06 ein paar 
#define

#define ZELLE_LINKS  0x02
#define ZELLE_RECHTS 0x06

//*Prüfe Position und speicher Werte in Akku & Wert*/

  lcd_cursor(0,1);
  lcd_string("     Suche     ");

  hilf1 = analog( ZELLE_LINKS );
  hilf2 = analog( ZELLE_RECHTS );

dann wird das ganze Codestück selbsterklärend und leicht lesbar

Autor: Hendrik S. (gustaf3459)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
okay, danke =) eine andere schreibweise hat meinen fehler behoben, auch 
wenn ich kp hab , wo genau der fehler war...

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dein Fehler ist hier:

Peter Dannegger schrieb:
> Hendrik S. schrieb:
>
>> void analog (void)
>> {
>>   ADCSRA = 0xC5;        //ADEN , ADSC und Pescaler auf 5 (32)
>>   loop_until_bit_is_set (ADCSRA, ADSC);
> 
>
> Wenn der Name stimmt, dann macht diese Funktion nichts.
> Und dadurch liest Du immer den Wert der vorherigen Wandlung aus.
>
> Du brauchst ein "loop_while_bit_is_set"

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.