Forum: Mikrocontroller und Digitale Elektronik Bin neu hier! Wie kann man beim atmega8 speichern?


von Darko D. (darlo)


Lesenswert?

Hallo. Ich bin Gelegenheitslöter und kenne mich mit dem atmega8 nicht so 
gut aus. Ich hoffe ihr könnt mir weiterhelfen. Aber bitte auch so das 
ich das verstehe. Ich habe folgenden Quellcode selbst geschrieben:



1
//----------------------------------------------------------------------
2
#define   F_CPU 3686400  // Taktfrequenz des myAVR-Boards
3
#include  <avr\io.h>    // AVR Register und Konstantendefinitionen
4
//----------------------------------------------------------------------
5
void initPorts(void)        // Unterprogramm füpr die Initalisierung
6
{
7
  DDRB |= (1 << PB0);             // damit ist dann PB0 ein Ausgang
8
  DDRB |= (1 << PB1);             // damit ist dann PB1 ein Ausgang
9
  DDRB |= (1 << PB2);             // damit ist dann PB2 ein Ausgang
10
  DDRB |= (1 << PB6);             // damit ist dann PB6 ein Ausgang
11
  DDRB &= ~(1 << PB7);            // das mit der Schlange ist dann ein Eingang
12
13
  uint8_t bPortB;
14
15
  bPortB = PINB;
16
17
}
18
//----------------------------------------------------------------------
19
main (void)
20
{
21
  unsigned char a;                         // bei a=0 sind die vorderen Klappen geschlossen bei a = 1 sind sie offen
22
  unsigned char b;                           // bei b=0 sind die hinteren Klappen geschlossen bei b = 1 sind sie offen
23
  unsigned char c;    
24
  int k;  
25
26
  a=0;
27
  b=0;
28
  k=0;
29
30
  initPorts();
31
32
  do
33
34
  {
35
    k=0;
36
    do                                             
37
    {
38
      k=k+1;
39
      waitMs(20);
40
    }
41
    while (!(PINB & (1 << PB7))    )  ;
42
43
    if ( (k>=2) && (k<=9)  && (b==1) && (a==1)   )   
44
45
    {
46
      PORTB |= (1 << PB0); 
47
      PORTB |= (1 << PB1);
48
      PORTB |= (1 << PB2); 
49
      PORTB |= (1 << PB6);
50
      waitMs(150);                          
51
      PORTB &= ~(1 << PB0);
52
      PORTB &= ~(1 << PB1);
53
      PORTB &= ~(1 << PB2);
54
      PORTB &= ~(1 << PB6);
55
      a=0;
56
      b=0;
57
      k=0;
58
    }
59
60
    if ( (k>=2) && (k<=9)  && (a==1) && (b==0)  )   
61
62
    {
63
      PORTB |= (1 << PB0); 
64
      PORTB |= (1 << PB2);
65
66
      waitMs(150);                          
67
      PORTB &= ~(1 << PB0);
68
      PORTB &= ~(1 << PB2);
69
      a=0;
70
      k=0;
71
    }
72
73
    if ( (k>=2) && (k<=9)  && (a==0) && (b==1)  )   
74
75
    {
76
      PORTB |= (1 << PB1); 
77
      PORTB |= (1 << PB6);
78
79
      waitMs(150);                          
80
      PORTB &= ~(1 << PB1);
81
      PORTB &= ~(1 << PB6);
82
      b=0;
83
      k=0;
84
    }
85
86
    if ( (k >=10) && (k<=20)&& (a==0) && (b==0) )                          
87
    {
88
      PORTB |= (1 << PB0); 
89
      waitMs(150);                            
90
      PORTB &= ~(1 << PB0);
91
      k=0;
92
      a=1;
93
    }
94
95
    if ( (k >=10) && (k<=20)&& (a==1) && (b==1) )                           
96
    {
97
      PORTB |= (1 << PB1);
98
      PORTB |= (1 << PB6);
99
      waitMs(150);                            
100
      PORTB &= ~(1 << PB1);
101
      PORTB &= ~(1 << PB6);      
102
      k=0;
103
      b=0;
104
    }
105
106
    if ( (k>=21)  && (k<=100) && (a==0) && (b==0) )                                                    
107
108
    {
109
110
      PORTB |= (1 << PB0); 
111
      PORTB |= (1 << PB1);      
112
      waitMs(150);                          
113
      PORTB &= ~(1 << PB0);
114
      PORTB &= ~(1 << PB1);
115
      k=0;
116
      a=1;
117
      b=1;
118
    }
119
120
    if ( (k>=21)  && (k<=100) && (a==1) && (b==0) )                                                   
121
122
    {
123
124
      PORTB |= (1 << PB1);      
125
      waitMs(150);                         
126
      PORTB &= ~(1 << PB1);
127
      k=0;
128
      b=1;
129
    }
130
131
    if ( (k>=101)   && (a==0) && (b==0) )                                                 
132
133
    {
134
135
      PORTB |= (1 << PB1);      
136
      waitMs(150);                
137
      PORTB &= ~(1 << PB1);
138
      k=0;
139
      a=0;
140
      b=1;
141
    }
142
143
  }
144
145
  while(true)  ;        
146
147
}







So aber das Problem ist, wenn ich bei meinem Auto die Zündung aus mache, 
wird der Mikrocontroller spannungslos geschaltet und dann spinnt die 
Schaltung. Die Ports PB1 und PB2 Steuern Relais und die wiederum Motore.
Wie kann ich den Mikrocontroller den letzten Zustand immer speichern 
lassen? Das geht doch bestimmt! Das wäre sehr nett wenn ihr mir da 
weiterhelfen könntet!! Danke!!!! Gruß Darko

: Bearbeitet durch User
von Dennis H. (c-logic) Benutzerseite


Lesenswert?

EEPROM wäre eine Lösung
Eine mehr oder minder aufwendige Schaltung ist notwendig die den 
Controller für den Spannungsabfall genug Leistung zum Beschreiben 
selbiger läßt und ihn bei einem Gewissen Spannungslevel zum Speichern 
motiviert.

EEPROM haben die AVR's meist an Board.

Eine Andere Lösung ist ein externer Speicher der Batteriegepuffert ist.
Allerdings ist da das Problem das die Spannung beim Schreiben des 
"Datenpacketes" abfällt und der Controller die Arbeit nicht beenden 
kann.

Oder Batteriegepufferter Controller der bei Spannungsabfall in 
Tiefschlaf geht.

: Bearbeitet durch User
von Stefan S. (sschultewolter)


Lesenswert?

Ich hoffe du versorgt deinem Atmega sauber bei der fiesen KFZ-Spannung.

Schau dir mal das an
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#EEPROM

Das Stichwort ist EEPROM.

Wenn du die Zündung startet, wird dein Atmega neugestartet und frag dann 
die vorher gespeicherten Eeprom Werte ab. Sobald ein Relais seinen 
Status wechselt, speicherst du den neuen Wert an diese Stelle.

von Darko D. (darlo)


Lesenswert?

Hallo. Danke für die Antwort! Wie mache ich das denn mit dem EEPROM? Ich 
weiß nicht ob der atmega8 einen EEPROM hat. Und woher bekomme ich denn 
die Schaltung? LG Darko

von Darko D. (darlo)


Lesenswert?

Ok, das habe ich verstanden. Sobald sich in der Schaltung was wechselt, 
ändere ich das im EEPROM. Die Spannung wird auf 4,98V durch einen 
festspannungsregler geregelt. Daher ist das mit der spannung kein 
problem. Warum die fies ist habe ich nicht verstanden?? Weil die von 12 
auf 13,8V steigt? Was schreibe ich denn jetzt in den Quellcode, dass er 
die Werte speichern soll? LG

von Joachim B. (jar)


Lesenswert?

Darko Dragojevic schrieb:
> Ich
> weiß nicht ob der atmega8 einen EEPROM hat.

wie wäre es mit nachsehen?
http://www.atmel.com/devices/atmega8.aspx?tab=parameters

und dann findet man:
EEPROM (Bytes): 512

von nur mal so (Gast)


Lesenswert?


von Dennis H. (c-logic) Benutzerseite


Lesenswert?

Darko Dragojevic schrieb:
> Ok, das habe ich verstanden. Sobald sich in der Schaltung was wechselt,
> ändere ich das im EEPROM. Die Spannung wird auf 4,98V durch einen
> festspannungsregler geregelt. Daher ist das mit der spannung kein
> problem. Warum die fies ist habe ich nicht verstanden?? Weil die von 12
> auf 13,8V steigt? Was schreibe ich denn jetzt in den Quellcode, dass er
> die Werte speichern soll? LG

Das mit dem Schreiben bei einem Wechsel ist etwas kritisch.
Die Schreib-Zyklen in EEPROM sind begrenzt auf 10000-100000 pro Byte.

Stefan S. hatte ja da schonmal mit der Zaunsreihe gewunken wegen 
EEPROM-Programmieren ...
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#EEPROM

von Darko D. (darlo)


Lesenswert?

Puuuuuhhhhh :-)

Ich schreibe einfach in den Quellcode folgendes rein:


IF (PORTB change)
    {
   save EEPROM
    }


ich glaube kaum, dass das klappt :-)

Ne, war natürlich n Spaß. ich werde mich da morgen in die beiden Links 
einlesen und hoffe, dass ich mich noch mal melden darf wenn ich das gar 
nicht verstehen sollte.

Gruß Darko

von Max H. (hartl192)


Lesenswert?

Darko Dragojevic schrieb:
> Warum die fies ist habe ich nicht verstanden?? Weil die von 12
> auf 13,8V steigt?
Das alleine ist kein Problem, hier findest du Genaueres: 
http://www.dse-faq.elektronik-kompendium.de/dse-faq.htm#F.23

von Dennis H. (c-logic) Benutzerseite


Lesenswert?

Darko Dragojevic schrieb:
>
> IF (PORTB change)
>     {
>    save EEPROM
>     }
>


Wieviele Schreibzyklen erwartest du dann so Pro Stunde ?

von Darko D. (darlo)


Lesenswert?

Achso, ich wusste nicht, dass die KFZ Spannung sooo schlimm ist :-(
Ich habe n LM 317 genommen und ihn auf 4,98 V eingestellt.
Ich kann euch ja sagen was ich mit dieser Schaltung machen möchte. Die 
Schaltung soll Klappen in der Auspuffanlage ändern. Es kann sein, dass 
ich ne Woche nicht schalte, und dann kann es sein, dass ich pro Tag 5 
mal schalte. Also sagen wir höchstens 50 Änderungen in der Woche (so 
ganz grob)...

von Peter D. (peda)


Lesenswert?

Mit eeprom_update_byte() kann man beliebig oft speichern, geschrieben 
wird erst, wenn sich der Wert auch geändert hat.

Du solltest Deinen Code unbedingt kommentieren, sonst weißt Du bald 
selber nicht mehr, wie er funktioniert.

Der Code könnte deutlich einfacher, lesbarer und wartbarer werden, wenn 
Du eine bewährte Entprellroutine für den Taster benutzt. Wie Du bisher 
entprellst, erschließt sich einem Betrachter nicht.

Die vielen &&-Verknüpfungen könnte man bestimmt mit einer Statemaschine 
deutlich lesbarer schreiben. Eine Variable kann ja mehr als 2 Zustände 
repräsentieren und den möglichen Zuständen kann man als Enum selbst 
erklärende Namen geben.
Dann sieht man auch schnell, ob es ungelöste Zustände gibt, wo sich das 
Programm aufhängen könnte. Die kann man dann im Default-Zweig in einen 
definierten Zustand überführen.

: Bearbeitet durch User
von Darko D. (darlo)


Lesenswert?

Guten morgen :-)
Also ich hatte mich auch damals in einem KFZ Forum angemeldet und da 
habe ich definitiv nicht so viele Hilfestellungen bekommen. Ich muss 
aber sagen, dass ich nicht sooo viel Ahnung im programmieren habe und es 
bestimmt möglich ist den ganzen Quellcode in 5 Zeilen deutlich lesbarer 
zu bekommen. Ich weiß aber nicht wie das geht :(

Mit weniger && verknüpfungen habe ich das nicht hinbekommen :(


Ich habe ungefähr 15 Stunden für diesen Quellcode gebraucht :( Ja ich 
bin sehr ehrgeizig, aber dieser ist die neue Version und ist sehr sehr 
übersichtlich im vergleich zu den alten version :)

Und was ist eine Entprellroutine?

ich entprelle nie... muss man das? Es funktioniert so alles 
einwandfrei...

von Darko D. (darlo)


Lesenswert?

Eigentlich ist der Sinn dahinter gar nicht so komplex. wenn ich die 
einzig vorhandene Taste lange drücke, werden beide Relais angesteuert, 
wenn ich sie kürzer drücke, wird nur 1 relais angesteuert und wenn ich 
sie ganz kurz drücke, werden die beiden relais angesteuert plus noch 
zwei. Mehr technik steckt da eig. nicht hinter.

Das Hauptproblem ist nur gewesen, dass wenn ich die taste 2 mal lange 
drücke, dass die relais nicht 2 mal angesteuert werden, weil mehr als 
aufmachen kann der motor nicht... es gibt ja nicht doppelt auf :-)

Gruß aus Cuxhaven

von Karl H. (kbuchegg)


Lesenswert?

Darko Dragojevic schrieb:
> Guten morgen :-)
> Also ich hatte mich auch damals in einem KFZ Forum angemeldet und da
> habe ich definitiv nicht so viele Hilfestellungen bekommen. Ich muss
> aber sagen, dass ich nicht sooo viel Ahnung im programmieren habe und es
> bestimmt möglich ist den ganzen Quellcode in 5 Zeilen deutlich lesbarer
> zu bekommen. Ich weiß aber nicht wie das geht :(

Fang erst mal an, vernünftige Variablennamen zu benutzen.
a, b und k sind keine vernünftige Namen.

Wenn a für den Zustand der vorderen Klappe steht, dann nenn die Variable 
auch zum Beispiel KlappeVorne.

>
> Mit weniger && verknüpfungen habe ich das nicht hinbekommen :(

aus
1
   if( k >= 2 && k <= 9 && a == 0 && b == 0 )
2
     ....
3
4
   if( k >= 2 && k <= 9 && a == 1 && b == 0 )
5
     ...

kannst du zum Beispiel schon mal den in beiden Fällen gleichen Teil der 
Überprüfung von k herausziehen (was soll dieses k eigentlich sein? 
Wieder: nimm vernünftige Variablennamen, so dass der Name beschreibt, 
welchen Zweck diese Variabel hat; was in ihr drinnen steht!)
1
  if( k >= 2 && k <= 9 ) {
2
3
    if( a == 0 && b == 0 ) {
4
      ...
5
    }
6
7
    if( a == 1 && b == 0 ) {
8
      ...
9
    }
10
  }

bei deinen 'a'-Fällen kannst du wieder dasselbe machen. Zusammen mit 
einer vernünftigen Benamung der Variablen bleibt dann zum Beispiel das 
hier übrig
1
#define OFFEN        1
2
#define GESCHLOSSEN  0
3
4
...
5
6
7
     if( Pulslaenge < 2 )
8
       ; // zu kurz. Keine Aktion notwendig
9
10
     else if( Pulslaenge < 10 ) {
11
       if( KlappeVorne == OFFEN ) {
12
         if( KlappeHinten == OFFEN ) {
13
           ....
14
         }
15
         else {
16
           ....
17
         }
18
       }
19
20
       else {
21
         if( KlappeHinten == OFFEN ) {
22
           ...
23
         }
24
         else {
25
           ...
26
         }
27
       }
28
     }
29
30
     else if( Pulslaenge < 21 ) {
31
       ...

Durch die Verwendung von sprechenden Bezeichnungen liest sich der ganze 
Code viel einfacher.
Zieh gleichen Code zusammen. Wenn in diesem Beispiel Dinge gemacht 
werden müssen, die nur davon abhängen dass die KlappeVorne offen ist, 
nicht aber vom Zustand der KlappeHinten abhängen, dann ziehst du das an 
eine der beiden Stellen
1
     else if( Pulslaenge < 10 ) {
2
       if( KlappeVorne == OFFEN ) {
3
4
         **** Hier <<<<<<<
5
6
         if( KlappeHinten == OFFEN ) {
7
           ....
8
         }
9
         else {
10
           ....
11
         }
12
13
         **** Oder hier  <<<<<<
14
       }

denn Code an dieser Stelle wird auf jeden Fall ausgeführt, wenn die 
KlappeVorne offen ist. Was du aber nicht tust, das ist, dass du den Code 
in den beiden Fällen für die Klappe hinten wieder duplizierst. Es sei 
denn, da ist eine bestimmte Reihenfolge notwendig, die durch die hintere 
Klappe modifiziert wird.


Verwende else bzw. else if um anzudeuten, dass es um den gegenteiligen 
Fall geht. Deine Klappe kann nur 2 Zustände haben. Entweder sie ist 
offen oder sie ist zu. Wenn sie nicht offen ist, dann ist völlig klar, 
dass sie zu sein muss
1
     if( Klappe == OFFEN )
2
       Hier wissen wir, dass die Klappe offen ist. Definitiv!
3
4
     else
5
       Hier wissen wir, dass die Klappe zu sein muss. Denn sie ist ja nicht offen
6
       D.h. das braucht nicht mehr getestet werden. Wenn die Klappe offen waere
7
       dann wäre das Programm nicht hier gelandet, sondern im Zweig darueber

> ich entprelle nie... muss man das?

Das kommt drauf an, was es mit diesem ominösen k eigentlich auf sich 
hat.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz schrieb:

> denn Code an dieser Stelle wird auf jeden Fall ausgeführt, wenn die
> KlappeVorne offen ist. Was du aber nicht tust, das ist, dass du den Code
> in den beiden Fällen für die Klappe hinten wieder duplizierst. Es sei
> denn, da ist eine bestimmte Reihenfolge notwendig, die durch die hintere
> Klappe modifiziert wird.

Deine ganze Fälle für k zwischen 2 und 9 lassen sich, wenn ich das 
richtig gesehen habe, so zusammenfassen
1
...
2
3
    else if( Pulslaenge < 10 ) {
4
5
      if( KlappeVorne == OFFEN ) {
6
        PORTB |= (1 << PB0); 
7
        PORTB |= (1 << PB2);
8
      }
9
10
      if( KlappeHinten == OFFEN ) {
11
        PORTB |= (1 << PB1); 
12
        PORTB |= (1 << PB6);
13
      }
14
15
      waitMs(150);                          
16
17
      if( KlappeVorne == OFFEN ) {
18
        PORTB &= ~(1 << PB0);
19
        PORTB &= ~(1 << PB2);
20
      }
21
22
      if( KlappeHinten == OFFEN ) {
23
        PORTB &= ~(1 << PB1);
24
        PORTB &= ~(1 << PB6);
25
      }
26
27
      KlappeVorne = GESCHLOSSEN;
28
      KlappeHinten = GESCHLOSSEN;
29
    }
30
31
...

Bei den anderen Pulszeiten wird das wieder ein wenig anders gehen. Aber 
der Trick ist nicht, da alle Varianten jeweils in einem eigenen if mit 
lauter && zu verknüpfen, sonden sich je nach Situation die immer 
gleichen Teile zu identifizieren und rauszuziehen.

Das Wichtigste allerdings dürfte erst mal eine ordentliche Benamung der 
Variablen sein. Denn in 2 WOchen kommst du garantiert durcheinander, 
wenn du das Programm überarbeiten musst und dann nur noch a und b 
siehst. UNter a bzw. b kann man sich eben so schlecht was vorstellen.

Wenn dir das immer noch zu unübersichtlich ist, dann lagere es in eine 
Funktion aus
1
void schliesseBeide()
2
{
3
  if( KlappeVorne == OFFEN ) {
4
    PORTB |= (1 << PB0); 
5
    PORTB |= (1 << PB2);
6
  }
7
8
  if( KlappeHinten == OFFEN ) {
9
    PORTB |= (1 << PB1); 
10
    PORTB |= (1 << PB6);
11
  }
12
13
  waitMs(150);                          
14
15
  if( KlappeVorne == OFFEN ) {
16
    PORTB &= ~(1 << PB0);
17
    PORTB &= ~(1 << PB2);
18
  }
19
20
  if( KlappeHinten == OFFEN ) {
21
    PORTB &= ~(1 << PB1);
22
    PORTB &= ~(1 << PB6);
23
  }
24
25
  KlappeVorne = GESCHLOSSEN;
26
  KlappeHinten = GESCHLOSSEN;
27
}
28
29
int main()
30
{
31
  ....
32
33
34
  do {
35
36
    ...
37
38
     if( Pulslaenge < 2 )
39
       ; // zu kurz. Keine Aktion notwendig
40
   
41
    else if( Pulslaenge < 10 )
42
      schliesseBeide();
43
44
    else if( Pulslaenge < 21 )
45
      ....
46
...

dann hast du eine Einheit, eine Funktion, die eine ganz bestimmte 
Aufgabe erfüllt, nämlich beide Klappen zu schliessen, sofern sie nicht 
schon geschlossen sind. Das wiederrum ist etwas, was dir die 
Hauptschleife in main vereinfacht, weil du dich nicht mehr um Details 
kümmern musst, sondern dort einfach nur noch steht: wenn diese gemessene 
Länge (das k bei dir) im Zahlenbereich 2 bis 9 liegt, dann werden beide 
Klappen geschlossen. Wie immer das auch geht, das interessiert dich an 
dieser Stelle nicht, denn die Funktion schliesseBeide() weiss ja wie das 
geht. An der Stelle hast du also den Kopf frei, welche prinzipielle 
Aktion abhängig von der gemessenen Laenge durchzuführen ist. Die Details 
zu diesen Aktionen wissen dann die Funktionen.

: Bearbeitet durch User
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.