Forum: Compiler & IDEs ADC-MUX verdreher ATmega8535


von Hendrik S. (gustaf3459)


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

von Gast (Gast)


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.

von Karl H. (kbuchegg)


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.
1
   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
1
uint16_t analog (void)
2
{
3
  uint16_t wert;
4
5
  ADCSRA = 0xC5;        //ADEN , ADSC und Pescaler auf 5 (32)
6
  loop_until_bit_is_set (ADCSRA, ADSC);
7
  wert = ADCW;
8
  _delay_ms(1);
9
10
  return wert;
11
}

Dann kannst du sie so benutzen
1
//*Prüfe Position und speicher Werte in Akku & Wert*/
2
3
  lcd_cursor(0,1);
4
  lcd_string("     Suche     ");
5
6
  ADMUX = 0x02;    //Linke Solarzelle???!!!!????
7
  hilf1 = analog();
8
9
  ADMUX = 0x06;    //Rechte Zelle???!!!????
10
  hilf2 = analog();

Gibst du zusätzlich der analog() Funktion auch noch den Kanal mit
1
uint16_t analog ( uint8_t channel )
2
{
3
  uint16_t wert;
4
5
  ADMUX = channel; 
6
  ADCSRA = 0xC5;        //ADEN , ADSC und Pescaler auf 5 (32)
7
  loop_until_bit_is_set (ADCSRA, ADSC);
8
  wert = ADCW;
9
  _delay_ms(1);
10
11
  return wert;
12
}
dann vereinfachen sich die Aufrufe zu
1
//*Prüfe Position und speicher Werte in Akku & Wert*/
2
3
  lcd_cursor(0,1);
4
  lcd_string("     Suche     ");
5
6
  hilf1 = analog( 0x02 );
7
  hilf2 = analog( 0x06 );

macht man sich dann für die magischen Konstanen 0x02 und 0x06 ein paar 
#define
1
#define ZELLE_LINKS  0x02
2
#define ZELLE_RECHTS 0x06
3
4
//*Prüfe Position und speicher Werte in Akku & Wert*/
5
6
  lcd_cursor(0,1);
7
  lcd_string("     Suche     ");
8
9
  hilf1 = analog( ZELLE_LINKS );
10
  hilf2 = analog( ZELLE_RECHTS );

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

von Hendrik S. (gustaf3459)


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

von Peter D. (peda)


Lesenswert?

Hendrik S. schrieb:
1
> void analog (void)
2
> {
3
>   ADCSRA = 0xC5;        //ADEN , ADSC und Pescaler auf 5 (32)
4
>   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"
1
>   wert=ADCW;
2
>   _delay_ms(1);

Was soll das, ist Dir die CPU zu schnell?


Peter

von Karl H. (kbuchegg)


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
1
uint16_t analog (void)
2
{
3
  uint16_t wert;
4
5
  ADCSRA = 0xC5;        //ADEN , ADSC und Pescaler auf 5 (32)
6
  loop_while_bit_is_set (ADCSRA, ADSC);
7
  wert = ADCW;
8
  _delay_ms(1);
9
10
  return wert;
11
}

Dann kannst du sie so benutzen
1
//*Prüfe Position und speicher Werte in Akku & Wert*/
2
3
  lcd_cursor(0,1);
4
  lcd_string("     Suche     ");
5
6
  ADMUX = 0x02;    //Linke Solarzelle???!!!!????
7
  hilf1 = analog();
8
9
  ADMUX = 0x06;    //Rechte Zelle???!!!????
10
  hilf2 = analog();

Gibst du zusätzlich der analog() Funktion auch noch den Kanal mit
1
uint16_t analog ( uint8_t channel )
2
{
3
  uint16_t wert;
4
5
  ADMUX = channel; 
6
  ADCSRA = 0xC5;        //ADEN , ADSC und Pescaler auf 5 (32)
7
  loop_while_bit_is_set (ADCSRA, ADSC);
8
  wert = ADCW;
9
  _delay_ms(1);
10
11
  return wert;
12
}
dann vereinfachen sich die Aufrufe zu
1
//*Prüfe Position und speicher Werte in Akku & Wert*/
2
3
  lcd_cursor(0,1);
4
  lcd_string("     Suche     ");
5
6
  hilf1 = analog( 0x02 );
7
  hilf2 = analog( 0x06 );

macht man sich dann für die magischen Konstanen 0x02 und 0x06 ein paar 
#define
1
#define ZELLE_LINKS  0x02
2
#define ZELLE_RECHTS 0x06
3
4
//*Prüfe Position und speicher Werte in Akku & Wert*/
5
6
  lcd_cursor(0,1);
7
  lcd_string("     Suche     ");
8
9
  hilf1 = analog( ZELLE_LINKS );
10
  hilf2 = analog( ZELLE_RECHTS );

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

von Hendrik S. (gustaf3459)


Lesenswert?

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

von Simon K. (simon) Benutzerseite


Lesenswert?

Dein Fehler ist hier:

Peter Dannegger schrieb:
> Hendrik S. schrieb:
>
1
>> void analog (void)
2
>> {
3
>>   ADCSRA = 0xC5;        //ADEN , ADSC und Pescaler auf 5 (32)
4
>>   loop_until_bit_is_set (ADCSRA, ADSC);
5
>
>
> 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"

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
Noch kein Account? Hier anmelden.