Forum: Compiler & IDEs Schaltung in C zur Solarzellen nachführung


von Ole S. (blackbird09)


Lesenswert?

Hallo zusammen,
ein paar Freunde und ich haben vor ein RC-Boot auf Basis von Solarstrom 
zu bauen. Wir sind auch bereits relativ weit!
Die Solarzellen auf dem Boot sollen sich auf einer Plattform befinden, 
welche sich zur Sonne ausrichtet. Dazu wollen wir einen Servo mit Relais 
ansteuern, die wiederum vom ATmega8 geschaltet werden.
Der ATmega8 vergleich Werte aus Photowiderständen und ermittelt so wo 
die Sonne steht(Photowiderstände sind auf der Plattform, drehen sich 
also mit) und richtet die Plattform neu aus.

        ______4______
 >>>    |             |    Anordnug der Sensoren an der Plattform
 >>>   0|             |    ">>>" von der Richtung soll die Sonne die
 >>>    |             |3         Solarzellen anstrahlen.
 >>>   1|             |
 >>>    |_____________|
               2

Nun zu meiner Frage: Ist der Quellcode so richtig?
(Programmieren das erste mal ein AVR)
ADC richtige Einstelllung?
Pin ansteuerung, etc?

Code:
1
//----------------------------------------------------------------------
2
//Projekt 
3
//Titel     : Solar-Boot
4
//----------------------------------------------------------------------
5
// Funktion  : Überprüfung von Pins auf diff zu Vin und Ausgabe der Drehrichtung für den Motor
6
// Schaltung : PC0-PC4 an Fotowiederstand
7
//----------------------------------------------------------------------
8
// Prozessor : ATmega8
9
// Takt      : 16 MHz
10
// Sprache   : C
11
// Datum     : 21.12.2009
12
// Version   : 1.0
13
14
//----------------------------------------------------------------------
15
#define   F_CPU 16000000  // Taktfrequenz des myAVR-Boards
16
#include  <avr\io.h>    // AVR Register und Konstantendefinitionen
17
#include   <util\delay.h>  // Bibliothek mit Warteroutinen
18
#define TOLERANCE 50        //Spannungstoleranz bei welcher er aufhört weiterzudrehen (50 ~ 0,25V)
19
//----------------------------------------------------------------------
20
/*PINC1 = Front der Solarzellen muss Sonne abbekommen
21
  PINC0 = Front der Solarzellen muss Sonne abbekommen
22
  Belichtung zwischen PINC0 und PINC1 sollte ca. gleich sein
23
  PINC2-4 sind übrige Sensoren C4 links; C3 hinten ; C2 rechts
24
  PINB1 ist der Ausgang für den Motor wenn Bit=1 dann 5V */
25
void adcinit()
26
{
27
   ADMUX |= (0<<REFS1) | (1<<REFS0); // Referenzspannung = ACC
28
   ADCSRA = (1<<ADEN) | (1<<ADFR);         
29
}
30
//=========================================================================
31
void init(void)        // Unterprogramm für die Initalisierung
32
{
33
    DDRC=0x00;  // DDRC = 0 alle auf Eingang (ADC)
34
    DDRB=0x00;  // PINB0 auf BIt = 0
35
    
36
}
37
//======================================================================
38
int main()
39
{
40
   init();                    // Unterprogrammaufruf für Initialisierung
41
     while(true)
42
     {              // Schleifenanfang Mainloop
43
     if( PINC4 > PINC0)    // Wenn 4 Mehr belichtet wird, als 0, soll solange rechts gedreht werden, bis 1 = 0
44
       {
45
         PORTB = 0x2; //PortB1 = 5V (Rechts rum drehen)
46
         while (PINC0 > PINC1) //Solange warten, bis 0 und 1 identische Werte haben
47
            _delay_ms(50);     
48
         PORTB = 0;   
49
       }
50
    
51
     //-------------------------------------------------------------------------
52
       if ( PINC2 > PINC1)  // Überprüfung ob PINC2 mehr belichtet wird als PINC1
53
     {          
54
    
55
           PORTB=0x04; // PORTB2 = 5V links rum
56
           while (PINC1 > PINC0) //Solange warten, bis 1 und 0 identische Werte haben
57
                 _delay_ms(50);
58
           PORTB = 0;
59
           
60
       }
61
      
62
      //---------------------------------------------
63
      if (PINC3 > PINC1 || PINC3 > PINC0 || PINC3 > PINC2 || PINC3 > PINC4) //Wenn 3 (hinten) mehr beleuchtet wird, als einer der anderen Sensoren
64
      {
65
                
66
                PORTB = 0x2; //Rechts drehen, bis PINC1 = PINC0
67
                while(PINC0 > PINC1 || PINC3 > PINC4) //Weiterdrehen, bis 1 = 0 ist und/oder solange 3 > 4 ist
68
                  _delay_ms(50); 
69
                PORTB = 0;
70
      }
71
      
72
      //-----------------------------------------------------
73
      while (PINC1 > PINC0 + TOLERANCE || PIN1 < PINC0 - TOLERANCE) //Korrektur, falls die differenz zwischen 1 und 0 zu groß ist
74
      {
75
            if (PINC1 > PINC0)
76
               PORTB = 0x04; //links rum
77
             else
78
               PORTB = 0x02;   //rechts rum  
79
             _delay_ms(50);
80
      }
81
      PORTB = 0;
82
     }             // Schleifenende Mainloop
83
     return 0;
84
}
85
//======================================================================

MfG
Blackbird

von Oliver (Gast)


Lesenswert?

1
 if( PINC4 > PINC0)

und alle weiteren tun nicht das, was du erwartest. Tutorial nochmals 
lesen, wie man Eingänge einliest.
1
PORTB = 0;

kommt mehrfach vor, aber niemals sinvoll. Ich würde dafür einen eigenen 
Vergleichsblock anlegen, der ausgeführt wird, wenn das Solarpanel 
richtig steht.

Auch ist der Ansatz, innerhalb der einzelnen Blöcke nochmals 
while-Schlefen zu haben, auch nicht perfekt. Schließlich hast du ja in 
main eine große Schleife.

Ich würde das mit nur drei Zuständen lösen: Rechtsrum, linksrum, stehen 
bleiben. Da drin dann nur die Ausgänge passend setzen, sonst nichts.

Als letztes bleibt noch die Frage, was du mit "Servo" meinst. Ein 
Modellbauservo lässt sich so nicht ansteuern, und dreht auch nicht 
endlos in eine Richtung.

Oliver

von Karl H. (kbuchegg)


Lesenswert?

Die Tatsache, dass da ein paar mal das Wort ADC vorkommt, lässt in mir 
den Verdacht aufkeimen, dass du die Photowiderstände mit dem ADC 
auslesen willst. Und das geht dann so schon überhaupt nicht.
Aber auch hier weiß das Tutorial Rat. Diesmal sogar in Form einer 
fertigen ADC-Auslesefunktion

von Ole S. (blackbird09)


Lesenswert?

Erstmal Danke für die Tips!
Dann müssen wir uns wohl nochmal ran setzen.
Sry Servo war der falsche Begriff, ich meine einen kleinen Motor.

MfG

Ole S.

von Purzel H. (hacky)


Lesenswert?

Wie will man denn Photowiderstaende auslesen, wenn nicht mit einem ADC ? 
Was auch immer an diesem ADC sonst noch klebt, ist nicht Bestandteil vom 
Code.

von David O. (soley)


Lesenswert?

Oliver schrieb:
> Tutorial nochmals
> lesen, wie man Eingänge einliest.

Es bringt mir nichts das Tutorial endlos oft zu lesen, wenn die 
Information, die ich benötige nicht drin steht.
Aber vielleicht kannst du mir ja die Frage beantworten, weil du dich 
recht gut auszukennen scheinst:
Die letzten 5 Bits vom ADMUX Register müssen auf den Kanal gestellt 
werden, an dem die Spannung gemessen werden soll... Im Tutorial steht 
leider nicht, was ich dort reinschreiben muss, um auf den Pin 0 vom Port 
C zuzugreifen, bzw auf die anderen Pins von C

Danke ^^

von Frauenverdreher (Gast)


Lesenswert?

> Die letzten 5 Bits

4 Bits beim Atmega8

> vom ADMUX Register müssen auf den Kanal gestellt werden, an dem die
> Spannung gemessen werden soll... Im Tutorial steht leider nicht, was ich
> dort reinschreiben muss, um auf den Pin 0 vom Port C zuzugreifen, bzw
> auf die anderen Pins von C

Das wäre ziemlich leicht aus dem Datenblatt zu entnehmen gewesen. Aber 
ich kann das gerne für dich da nachlesen und vorkauen:

Die Pins PC0 bis PC5 werden ausgewählt, indem man in die MUX-Bits den 
entsprechenden Wert (0 bis 5) einträgt.

von Oliver (Gast)


Lesenswert?

>Oliver schrieb:
>> Tutorial nochmals
>> lesen, wie man Eingänge einliest.

>Es bringt mir nichts das Tutorial endlos oft zu lesen, wenn die
>Information, die ich benötige nicht drin steht.

Wenn du das falsche Tutorial endlos oft liest, bringt das natürlich 
nichts.

Hier mal der link zum richtigen:
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial

Und da steht das alles drin. Wie man Eingänge einliest, und auch, wie 
das mit dem ADC funktioniert.

Ich zitiere mal:
>Mit diesen 5 Bits wird der zu messende Kanal bestimmt. Wenn man einen einfachen 
>1-kanaligen ADC verwendet wird einfach die entsprechende Pinnummer des Ports in 
>die Bits 0...2 eingeschrieben.

Beim Mega8 stimmt das nicht ganz, da sind es nur 4 Bit, aber am Prinzip 
ändert sich nichts. So etwas steht dann in der Mutter aller 
Informationsquellen, dem Datenblatt zum Mega8. Das ist die ultimative 
Referenz, ohne darin nachzusehen, kann man einen AVR nicht 
programmieren.

Oliver

von David O. (soley)


Lesenswert?

Supi, solche Antworten sind doch gleich viel hilfreicher, als "Lies das 
Tutorial nochmal" ;-)

Und ich hab nicht das falsche gelesen :P

Und nachdem ich das Tutorial auch noch ein drittes mal gelesen habe und 
alle Ratschläge versucht hab zu beherzigen, poste ich hier nochmal die 
überarbeitete Version des Codes:
1
//----------------------------------------------------------------------
2
//Projekt Solaris
3
//Titel     : SOLAR-Boot
4
//----------------------------------------------------------------------
5
// Funktion  : Überprüfung von PORT D0-D5 auf Wiederstand und Ausgabe der Drehrichtung für den Motor
6
// Schaltung : PC0-PC5 an Fotowiederstand
7
//----------------------------------------------------------------------
8
// Prozessor : ATmega8
9
// Takt      : 16 MHz
10
// Sprache   : C
11
// Datum     : 07.12.2009
12
// Version   : 1.1
13
//----------------------------------------------------------------------
14
#define   F_CPU 16000000  // Taktfrequenz des myAVR-Boards
15
#include  <avr\io.h>    // AVR Register und Konstantendefinitionen
16
#include   <util\delay.h>  // Bibliothek mit Warteroutinen
17
#define TOLERANCE 50        //Spannungstoleranz bei welcher er aufhört weiterzudrehen (50 ~ 0,25V)
18
//----------------------------------------------------------------------
19
/*PINC1 = Front der Solarzellen muss Sonne abbekommen
20
  PINC0 = Front der Solarzellen muss Sonne abbekommen
21
  Belichtung zwischen PINC0 und PINC1 sollte ca. gleich sein
22
  PINC2-4 sind übrige Sensoren C4 links; C3 hinten ; C2 rechts
23
  PINB1 ist der Ausgang für den Motor wenn Bit=1 dann 5V */
24
//======================================================================
25
uint16_t get_voltage(int kanal) //Spannung im Bereich von 0-5V mit einer 10Bit auflösung ausgeben
26
{
27
         uint16_t voltage = 0;
28
         ADMUX &= 0b11100000;       //Kanal löschen
29
         ADMUX |= kanal;            //Kanal einstellen
30
         ADCSRA &= 0b11101111;      //Ausgabebit löschen, falls es nicht gelöscht war
31
         ADCSRA |= 1 << 6;          //Bit setzten, um Messung zu beginnen
32
         While(!(ADCSRA & 1 << 4)); //Warten, bis die Berechnung abgeschlossen ist
33
         voltage = ADCL;            //Zuerst ADCL auslesen
34
         voltage += (ADCH << 8);    //Anschließend ADCH auslesen
35
         return voltage;            //Wert zurückliefern
36
}
37
int main()
38
{
39
    //DDR initialisieren:
40
    DDRC=0x00;  // DDRC = 0 alle auf Eingang (ADC)
41
    DDRB=0xff;  // PortB = Ausgang
42
    
43
    //ADC initialisieren:
44
    ADCSRA = ADCEN | 0b111;
45
    ADMUX = 1 << 6;  // AVCC = Referenzspannung (5V)
46
    
47
    //Variableninitialisierung
48
    uint16_t c0, c1, c2, c3, c4;
49
        
50
    //Hauptschleife
51
     while(true)
52
     {
53
       c0 = get_voltage(0);
54
       c1 = get_voltage(1);
55
       c2 = get_voltage(2);
56
       c3 = get_voltage(3);
57
       c4 = get_voltage(4);
58
      //--------------------------------------------------------          
59
    if(c4 > c5)    // Wenn 4 Mehr belichtet wird, als 0, soll solange rechts gedreht werden, bis 1 = 0
60
           PORTB = 1 << 1; //PortB1 = 5V (Rechts rum drehen)
61
      //-------------------------------------------------------------------------
62
      if (c2 > c1)  // Überprüfung ob PINC2 mehr belichtet wird als PINC1          
63
           PORTB= 1 << 2; // PORTB2 = 5V links rum
64
      //------------------------------------------------------
65
      if (c3 > c1 || c3 > c0 || c3 > c2 || c3 > c4) //Wenn 3 (hinten) mehr beleuchtet wird, als einer der anderen Sensoren          
66
           PORTB = 1 << 1; //PORTB1 = 5V (Rechts rum)
67
      //-----------------------------------------------------
68
      if (c1 > c0 + TOLERANCE || c1 < c0 - TOLERANCE) //Korrektur, falls die differenz zwischen 1 und 0 zu groß ist
69
      {
70
            if (c1 > c0)
71
               PORTB = 1 << 2; //links rum
72
             else
73
               PORTB = 1 << 1;   //rechts rum  
74
      }
75
      //-------------------------------------------------------
76
      if (c1 <= c0 + TOLERANCE && c1 >= c0 - TOLERANCE) // Falls die Werte zwischen den Frontsensoren in Ordnung sind, anhalten
77
          PORTB = 0;
78
     }
79
     //Ende fer Hauptschleife
80
     return 0;
81
}
82
//======================================================================

Und vielen Dank für eure Hilfe :)

von Simon K. (simon) Benutzerseite


Lesenswert?

Ein paar Klammern bei den if-Statements könnten nicht schaden.

von David O. (soley)


Lesenswert?

Zu viele Klammern machen den Code aber auch unübersichtlich, deshalb 
lasse ich sie immer weg, wenn es möglich ist ^^

von MaWin (Gast)


Lesenswert?

> Nun zu meiner Frage: Ist der Quellcode so richtig?

Der Motor braucht mit dem Verfahren mehr Strom,
als das Solarpanel aus der Sonne gewinnen kann.

Mehr Gelassenheit!

Auch diffuser Himmel bringt euch durcheinander.

Es reichen übrigens 2 Sensoren.

von Simon K. (simon) Benutzerseite


Lesenswert?

David O. schrieb:
> Zu viele Klammern machen den Code aber auch unübersichtlich, deshalb
> lasse ich sie immer weg, wenn es möglich ist ^^

LOL. Mit dem Argument habe ich nicht gerechnet.

Zu wenige Klammern machen aber auch Probleme, wenn man die Prioritäten 
der Opratoren nicht auswendig kann oder lernen möchte.

von Ole S. (blackbird09)


Lesenswert?

Hallo Zusammen,
leider funktioniert unser Code immer noch nicht.
Ich hoffe ihr könnt mal ein Blick auf ihn werfen und uns mögliche 
Fehlerursachen nennen. Problem ist, dass der ATMega8 nichts macht, wenn 
man eine Spannung an einen der Eingänge anlegt(es passiert nichts am 
Ausgang (links oder rechts drehen)).

Vielen Dank im Vorraus!
1
//----------------------------------------------------------------------
2
//Projekt Solaris
3
4
//----------------------------------------------------------------------
5
// Funktion  : Überprüfung von Pin C0-C4 auf Wiederstand und Ausgabe der Drehrichtung für den Motor
6
// Schaltung : PinC0-PinC4 an Fotowiederstand
7
//----------------------------------------------------------------------
8
// Prozessor : ATmega8
9
// Takt      : 16 MHz
10
// Sprache   : C
11
// Datum     : 23.02.2010
12
// Version   : 2.1
13
14
15
//----------------------------------------------------------------------
16
#define   F_CPU 16000000  // Taktfrequenz des myAVR-Boards
17
#include  <avr\io.h>    // AVR Register und Konstantendefinitionen
18
#include   <util\delay.h>  // Bibliothek mit Warteroutinen
19
#define TOLERANCE 50        //Spannungstoleranz bei welcher er aufhört weiterzudrehen (50 ~ 0,25V)
20
//----------------------------------------------------------------------
21
/*PINC1 = Front der Solarzellen muss Sonne abbekommen
22
PINC0 = Front der Solarzellen muss Sonne abbekommen
23
Belichtung zwischen PINC0 und PINC1 sollte ca. gleich sein
24
PINC2-4 sind übrige Sensoren C4 links; C3 hinten ; C2 rechts
25
PINB1 ist der Ausgang für den Motor wenn Bit=1 dann 5V */
26
//======================================================================
27
uint16_t get_voltage(int kanal) //Spannung im Bereich von 0-5V mit einer 10Bit auflösung ausgeben
28
{
29
  uint16_t voltage = 0;
30
  ADMUX &= 0b11100000;       //Kanal löschen
31
  ADMUX |= kanal;            //Kanal einstellen
32
  ADCSRA &= 0b11101111;      //Ausgabebit löschen, falls es nicht gelöscht war
33
  ADCSRA |= 1 << 6;          //Bit setzten, um Messung zu beginnen
34
  while(!(ADCSRA & 1 << 4)); //Warten, bis die Berechnung abgeschlossen ist 
35
  voltage = ADCL;            //Zuerst ADCL auslesen
36
  voltage += (ADCH << 8);    //Anschließend ADCH auslesen
37
  return voltage;            //Wert zurückliefern
38
}
39
int main()
40
{
41
  //DDR initialisieren:
42
  DDRC=0x00;  // DDRC = 0 alle auf Eingang (ADC)
43
  DDRB=0xff;  // PortB = Ausgang
44
45
  //ADC initialisieren:
46
  ADCSRA = ADEN | 0b111; 
47
  ADMUX = 1 << 6;  // AVCC = Referenzspannung (5V)
48
49
  //Variableninitialisierung
50
  uint16_t c0, c1, c2, c3, c4;
51
52
  //Hauptschleife
53
  while(true)
54
  {
55
    c0 = get_voltage(PINC0);
56
    c1 = get_voltage(PINC1);
57
    c2 = get_voltage(PINC2);
58
    c3 = get_voltage(PINC3);
59
    c4 = get_voltage(PINC4);
60
    //--------------------------------------------------------          
61
    if(c4 > c0)    // Wenn 4 Mehr belichtet wird, als 0, soll solange rechts gedreht werden, bis 1 = 0 
62
      PORTB = 1 << 1; //PortB1 = 5V (Rechts rum drehen)
63
    //-------------------------------------------------------------------------
64
    if (c2 > c1)  // Überprüfung ob PINC2 mehr belichtet wird als PINC1          
65
      PORTB= 1 << 2; // PORTB2 = 5V links rum
66
    //------------------------------------------------------
67
    if (c3 > c1 || c3 > c0 || c3 > c2 || c3 > c4) //Wenn 3 (hinten) mehr beleuchtet wird, als einer der anderen Sensoren          
68
      PORTB = 1 << 1; //PORTB1 = 5V (Rechts rum)
69
    //-----------------------------------------------------
70
    if (c1 > c0 + TOLERANCE || c1 < c0 - TOLERANCE) //Korrektur, falls die differenz zwischen 1 und 0 zu groß ist
71
    {
72
      if (c1 > c0)
73
        PORTB = 1 << 2; //links rum
74
      else
75
        PORTB = 1 << 1;   //rechts rum  
76
    }
77
    //-------------------------------------------------------
78
    if (c1 <= c0 + TOLERANCE && c1 >= c0 - TOLERANCE) // Falls die Werte zwischen den Frontsensoren in Ordnung sind, anhalten
79
      PORTB = 0;
80
  }
81
  //Ende fer Hauptschleife
82
  return 0;
83
}
84
//======================================================================
MfG

Blackbird

von Karl H. (kbuchegg)


Lesenswert?

>  ADCSRA = ADEN | 0b111;

Was soll denn das sein?

Tu dir selbst einen Gefallen und benutze die ADC Routine aus dem 
Tutorial so wie sie da drinnen steht. Die Referenz kannst du anpassen, 
aber den Rest lässt du erst mal so wie er ist.

Weiters künstelst du nicht mit dem Motor rum, sondern hängst dir erst 
mal einfach nur eine LED an einen Ausgang. An den ADC-Eingang (zuerst 
experimentierst du nur mit 1 ADC Eingang) hängst du ein Poti (so wie im 
Tut angegeben) und schreibst ein Programm, welches die LED einschaltet, 
wenn die Spannung am ADC (eingestellt mit dem Poti) über einem Grenzwert 
(den du im Programm fix vorgegeben hast) liegt. Durch Drehen des Potis 
links rum bzw. rechts rum kannst du die LED ein/aus schalten.

Das ist dein erstes Zwischenziel. Solange du das nicht erreicht hast, 
brauchst du nicht weiter machen.

Dein nächstes Zwischenziel ist es, den Grenzwert für den Vergleich über 
den 2.ten ADC Kanal einzustellen. D.h. du hast dann 2 Poti. Mit dem 
einen stellst du ein, welchen Wert das andere überschreiten muss, damit 
die LED leuchtet. Oder du steuerst 2 LED an, jede mit ihrem eigenen 
Poti. Im Grunde völlig egal, was du dir als Aufgabenstellung wählst - 
Ziel der Übung ist der Umgang mit 2 ADC-Eingangskanälen (die ADC Routine 
aus dem Tut hast du immer noch nicht angerührt - ausser der 
Referenzspannung - die ist immer noch so wie im Tut angegeben)

Und erst dann arbeitest du dich langsam an die Motoren ran. Immer 
Schritt für Schritt, nicht zu viele Änderungen auf einmal.

Tust du das nicht, dann gehts dir so wie es dir jetzt geht: Du stehst 
vor einem Code-Haufen der (natürlich) nicht funktioniert und hast keine 
Ahnung wo du mit der Fehlersuche anfangen sollst, weil du nichts in 
deinem Programm hast, das als bereits funktionierend und getestet 
abgehakt werden kann.


Und erst dann, wenn das alles so einigermassen läuft, gehst du her und 
mistest die Tut-ADC Routine aus, wie du das möchtest. Aber auch hier 
gehst du wieder nicht her und machst eine alles-in-einem-Aufwasch 
Rundumkur, sondern du arbeitest wieder in kleinen Schritten. Wenn in 
einem funktionierendem Programm eine kleine Veränderung gemacht wird und 
hinterher funktioniert es nicht mehr, dann hat man nur diese kleine 
Veränderung zu analysieren was da schief lief. Ändert man aber zuviel, 
dann weiß man nicht, welche der zig Änderungen für das 
Nichtfunktionieren verantwortlich 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
Noch kein Account? Hier anmelden.