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:
unsignedchara;// bei a=0 sind die vorderen Klappen geschlossen bei a = 1 sind sie offen
22
unsignedcharb;// bei b=0 sind die hinteren Klappen geschlossen bei b = 1 sind sie offen
23
unsignedcharc;
24
intk;
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
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.
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.
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
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
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
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
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)...
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.
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...
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
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
elseif(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
elseif(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
elseif(Pulslaenge<10){
2
if(KlappeVorne==OFFEN){
3
4
****Hier<<<<<<<
5
6
if(KlappeHinten==OFFEN){
7
....
8
}
9
else{
10
....
11
}
12
13
****Oderhier<<<<<<
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.
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
elseif(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
voidschliesseBeide()
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
intmain()
30
{
31
....
32
33
34
do{
35
36
...
37
38
if(Pulslaenge<2)
39
;// zu kurz. Keine Aktion notwendig
40
41
elseif(Pulslaenge<10)
42
schliesseBeide();
43
44
elseif(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.