Hi, ich habe 2 ADC Messungen an meinem ATmega und will nun wissen, ob
diese nicht zu weit auseinander sind. Um eine Bedingung zu sparen
quadriere ich erst und ziehe dann wieder die Wurzel. Habe mit einem
Multimeter bereits nachgemessen und sie unterscheiden sich nicht mehr
als 0.5 V.
1
temp1=ADC_read(0);
2
temp2=ADC_read(1);
3
4
if(!(sqrt((temp1-temp2)*(temp1-temp2))<0.5))
5
ERR=1;
Jedes mal geht der Error flag auf 1. Ich bin wahrscheinlich Codeblind
geworden, ist irgendetwas an der Rechnung falsch?
Danke
C. S. schrieb:> Um eine Bedingung zu sparen> quadriere ich erst und ziehe dann wieder die Wurzel.
Um einen Groschen zu sparen, geb' ich mal schnell 'ne Mark aus. ;-)
Ansonsten musst du schon noch die Datentypen und die Werte
nennen, die du da bekommst. Ich tippe auf integer promotion +
sign extension Probleme.
C. S. schrieb:> Hi, ich habe 2 ADC Messungen an meinem ATmega und will nun wissen, ob> diese nicht zu weit auseinander sind. Um eine Bedingung zu sparen> quadriere ich erst und ziehe dann wieder die Wurzel.
Ha, ha
Tschuldige. Aber der ist gut.
Um einen simplen Vergleich zu sparen, brummst du deinem µC hunderte
Taktzyklen auf?
> Habe mit einem> Multimeter bereits nachgemessen und sie unterscheiden sich nicht mehr> als 0.5 V.>>
1
temp1=ADC_read(0);
2
>temp2=ADC_read(1);
3
>
4
>if(!(sqrt((temp1-temp2)*(temp1-temp2))<0.5))
5
>ERR=1;
6
>
> Jedes mal geht der Error flag auf 1. Ich bin wahrscheinlich Codeblind> geworden, ist irgendetwas an der Rechnung falsch?
Was genau bekommst du von ADC_read zurück?
Sind das Spannungen oder ADC Werte?
Warum schiesst du dir von hinten selbst durch die Brust ins Auge?
if ( ! (A < B) )
Wenn du ausdrücken willst das A größer/gleich B sein muss um einen
Fehler zu haben, dann schreib das auch so
if( A >= B )
Man kann sich nämlich durch zu kompliziert geschriebenen Code auch
selber austricksen :-)
So kann man eine Bereichsabfrage gestalten.
Die Idee: Die Differenz zwischen den Wert (und zwar deren Absolutwert)
muss kleiner als ein gewisses Epsilon sein (oder größer, je nachdem)
1
#include"stdlib.h"
2
3
intmain()
4
{
5
inta=5;
6
intb=7;
7
intEpsilon=2;
8
9
if(abs(a-b)>Espilon)
10
err=1;
11
}
Welche Betragsfunktion man nimmt, hängt von den beteilgten Datentypen
ab.
abs int
labs long
llabs long long
fabs double
also beide temp variablen sind als double initialisiert. Desweitern
führe ich in meiner ADC_read Funktion eine Berechnung durch, um von den
10 Bit auf eine Voltzahl zu kommen, die dann auch zurückgeliefert wird.
Ich möchte wirklich prüfen, ob die Differenz beider Spanung im Bereich
von +- 0.5V liegt.
C. S. schrieb:> also beide temp variablen sind als double initialisiert. Desweitern> führe ich in meiner ADC_read Funktion eine Berechnung durch, um von den> 10 Bit auf eine Voltzahl zu kommen, die dann auch zurückgeliefert wird.>> Ich möchte wirklich prüfen, ob die Differenz beider Spanung im Bereich> von +- 0.5V liegt.
Diese Prüfung macht man zwar anders, aber jetzt geht es um das Problem
in deinem Code.
Zeig doch mal mehr. Aus dem bischen kann man nichts ersehen.
Deine Berechnung stimmt?
Die Funtkionssignatur stimmt?
Hast du die Werte in temp1 und temp2 unabhängig voneinander getestet
(ausgeben lassen).
Wie groß sind die Spannungen, die du anlegst?
Du scheinst deine Spannungen auf 5V zurückzurechnen, hast aber die 2.56V
Referenzspannung aktiviert.
Hast du dir schon mal die beiden Werte einzeln angesehen?
(Ich hab deinen Code mal im Simulator durchgespielt. Bei mir wird ERR
nicht auf 1 gesetzt, wenn ich dem ADC Data Register in ADC_Read gleiche
Werte unterjuble.
Es liegt eine Spannung von 2,91 Volt am 1. Eingang und 2,89 am 2.
Eingang an.
Was bedeutet das mit der Referenzspannung?
Das komische ist nämlich, dass die Einzelspannungen auch korrekt
ausgelesen werden. Sprich wenn ich Beispielsweise prüfe:
C. S. schrieb:> Was bedeutet das mit der Referenzspannung?
Dein ADC liefert dir ja nicht die Spannung direkt.
Sondern er gibt dir eine Zahl zwischen 0 und 1023, die aussagt wie hoch
die gemessene Spannung im Vergleich zur Referezspannung ist.
Im Prinzip (wenn wir mal vom Zahlenwert absehen) sagt dir dein ADC:
Die Messspannung beträgt x Prozent von der Messspannung.
> Es liegt eine Spannung von 2,91 Volt am 1. Eingang und 2,89 am 2.> Eingang an.
Wenn du eine Referenzspannung von 2.56 Volt eingestellt hast, dann ist
das deutlich zu hoch.
Welchen Mega verwendest du eigentlich?
Ich hab beim Mega16 nachgesehen und da ist
(1<<REFS1) | (1<<REFS0)
die interne Referenz in Höhe von ca. 2.5 Volt
Ist deine Messspannung darüber, dann liefert der ADC ständig 1023
Eindringlicher Tip:
Ehe du weiter machst, schau dir die ADC Werte direkt an, so wie du sie
vom ADC bekommst. Es bringt nichts, schon mit falschen Werten in eine
Berechnungen zu gehen und sich dann zu wundern warum da nichts
vernünftiges rauskommt.
> temp1 = ADC_read(0)> if(!((temp1 > 2.3) & (temp1 <2.7)))> ERR=1;>> In diesem Fall wird die ErrorFlag nicht gesetzt.
Hast du keine besseren Möglichkeiten, dir die Werte anzusehen, als immer
nur diese indirekten Schlussfolgerungen über ein ERR Flag?
Irgendwo musst du doch Zahlenwerte ausgeben können. LCD, UART oder
dergleichen.
Wenn nicht, dann frage ich mich wozu du eigentlich die ADC Werte
überhaupt in Spannungen umrechnest. Rechne doch gleich alles mit ADC
Werten und rechne deine Grenzspannungen in ADC Einheiten um. Ist für den
µC viel einfacher und schneller zu rechnen als da mit Floating Point
rumzumachen.
Dein Wandler hat 10 Bit, er liefert als einen Wert von 0 bis 1023.
Welcher dieser Werte entspricht jetzt welcher angelegten Spannung?
Der ADC-Wert 0 gehört immer zur Spannung 0 Volt.
Der höchste Wert (1023) gehört zur Referenzspannung, die restlichen
Werte dazwischen verteilen sich linear.
Hast du eine Referenzspannung von 2.56 V, dann steht 1023 für
2.56 V, 511 für 1.28 V usw..
Ist die Referenzspannung dagegen 5 V, dann steht 1023 für
5 V und 511 für 2.5 V.
PS. ok wieder zu spät...
C. S. schrieb:> ausgelesen werden. Sprich wenn ich Beispielsweise prüfe:>>
1
>temp1=ADC_read(0)
2
>if(!((temp1>2.3)&(temp1<2.7)))
3
>ERR=1;
4
>
Mein Gott.
Du scheinst eine Vorliebe dafür zu haben, deine Abfragen möglichst
kryptisch so zu schreiben, dass man nur ja beim ersten Hinschauen bloss
nicht erkennen kann, was eigentlich die Absicht an dieser Stelle ist.
Ganz abgesehen davon, dass hier ein && angebrachter wäre als ein &
> Es liegt eine Spannung von 2,91 Volt am 1. Eingang und 2,89 am 2.> Eingang an.> ...> ausgelesen werden. Sprich wenn ich Beispielsweise prüfe:> temp1 = ADC_read(0)> if(!((temp1 > 2.3) & (temp1 <2.7)))> ERR=1;>> In diesem Fall wird die ErrorFlag nicht gesetzt.
Da dein Vergleich gleichbedeutend ist mit
if( ( temp1 <= 2.3 ) || ( temp1 >= 2.7 ) )
ERR = 1;
sollte aber ERR auf 1 gesetzt werden, wenn deine Spannung 2.91 bzw. 2.89
Volt beträgt. Denn die ist definitiv größer als 2.7
Alles in allem tauchen mir da jetzt bei den Analysen schon zuviele
Ungereimtheiten auf, dass ich vorschlage du postest deinen kompletten
Code.
Mitlerweile hab ich das Vertrauen verloren, so dass ich als Fehlerquelle
nichts mehr ausschliessen möchte. Noch nicht einmal eine falsche
Auswertung des ERR-Flags.
Wenn dein Code zu umfangreich ist, dann produziere eine abgespeckte
Version, die nur das notwendigste (ADC Abfrage samt Auswertung) enthält,
teste ob sie den gleichen Fehler enthält und poste diese abgespeckte
Version, wenn der Fehler noch da ist.
Und bitte: keine Code-Auszüge!
Ein komplettes, compilierbares Programm
Also ich nutze einen ATmega 324P20PU und ich lese gerade, dass ich nur
(1<<REFS0) brauche um AVCC als Referenzspannung einzustellen.
Karl heinz Buchegger schrieb:> Da dein Vergleich gleichbedeutend ist mit>>>> if( ( temp1 <= 2.3 ) || ( temp1 >= 2.7 ) )>> ERR = 1;>>>> sollte aber ERR auf 1 gesetzt werden, wenn deine Spannung 2.91 bzw. 2.89>> Volt beträgt. Denn die ist definitiv größer als 2.7
Sry das Überprüfungsbeispiel bezog sich auf eine andere Überprüfung wo
der Wert 2.5V beträgt.
Wobei ich glaube, dass ein logisches oder nicht die richtige lösung
wäre. Es soll ja beides erfüllt sein. Das mit dem einfachen & habe ich
wohl übersehen... :/
ich gebe noch bescheid, ich probiere jett erstmal aus.
C. S. schrieb:> Wobei ich glaube, dass ein logisches oder nicht die richtige lösung> wäre. Es soll ja beides erfüllt sein.
Boolesche Algebra. Die Bedingung wird negiert (es wird ja ein
Fehler-Flag in Abhängigkeit davon gesetzt), und dann wird aus UND
ein ODER.
Ich dachte das Ergebnis der Bedingung wird negiert und nicht die
Opratoren. Ich ging davon aus, dass die Logik vollzogen wird und am Ende
das Ergenis negiert wird.
Ich bin ca. 186 groß.
Damit stimmt die Aussage:
"Ich bin größer als 180 UND kleiner als 190".
Ebenfalls richtig ist:
"es stimmt nicht, daß ich kleiner als 179 bin ODER größer als 191"
Daß es dir schwerfällt, die Umkehrung von && nach || nachzuvollziehen,
ist keine Schande.
Da stutzen andere auch und fallen öfter rein.
Das zeigt um so mehr, wie wichtig es ist, im Quelltext möglichst
einfache Formulierungen zu verwenden und nicht alles von hinten durch
die Brust ins Auge zu zielen.
C. S. schrieb:> Wobei ich glaube, dass ein logisches oder nicht die richtige lösung> wäre.
Man kanns auch so sehen:
Du willst wissen, ob eine Spannung in einem bestimmmten Bereich ist
Dazu muss die Spannung größer als die Bereichsuntergrenze sein UND
die Spannung muss kleiner als die Bereichsobergrenze sein
Soweit so gut: Jetzt drehst du die Logik um.
Du willst nicht mehr wissen, ob sie im Bereich ist sondern das genaue
Gegenteil: Du willst wissen, ob sie ausserhalb ist.
Jetzt kannst du natürlich da ein NICHT davor schreiben.
Du kannst aber auch sagen:
Wenn meine Spannung kleiner als die Bereichsuntergrenze ist ODER
die Spannung größer als die Bereichsobergrenze
dann liegt sie ausserhalb des Bereichs!
> Es soll ja beides erfüllt sein.
Das geht in deinem Fall nicht.
Eine Spannung kann nicht gleichzeitig kleiner als eine Untergrenze UND
größer als eine Obergrenze sein.
Mal dir eine Zahlengerade auf
1
/ / / / / / * * * * * / / / / /
2
/ / / / / / * * * * */ / / / /
3
----+-----------+----------+---------
4
nicht nicht
5
erlaubt erlaubt erlaubt
dein Zahlenraum teilt sich in 3 Bereiche auf:
im * Teil liegen deine erlaubten Zahlen - das ergibt keinen Fehler
die beiden / Teile sind jeweils nicht erlaubte Bereiche - wenn deine
Spannung da drinnen liegt, dann willst du einen Fehler melden.
Deine Spannung (wenn sie ungültig ist) kann aber nur entweder im linken
Teil ODER im rechten / Teil liegen. In beiden gleichzeitig geht nicht.
> Das mit dem einfachen & habe ich> wohl übersehen... :/>> ich gebe noch bescheid, ich probiere jett erstmal aus.
Das war aber nicht das eigentliche Problem.
Dein eigentiches Problem ist immer noch unklar.
Ich persönlich finde es zwar anschaulicher, allerdings bläht das mein
ohnehin schon langes Programm nurnoch auf. Zumal dort noch eine
if-Abfrage hinzukommt.
C. S. schrieb:> Ich persönlich finde es zwar anschaulicher, allerdings bläht das mein> ohnehin schon langes Programm nurnoch auf. Zumal dort noch eine> if-Abfrage hinzukommt.
du machst dir sorgen wegen der Programm größe und verwendest double und
sqrt? Nicht die Anzahl der Zeilen machen ein Programm groß!
C. S. schrieb:> Ich persönlich finde es zwar anschaulicher, allerdings bläht das mein> ohnehin schon langes Programm nurnoch auf. Zumal dort noch eine> if-Abfrage hinzukommt.
Das ist .... ein richtiger Schenkelklopfer, wenn man sich die spärlichen
Programmausschnitte so ansieht.
You made my day
(PS:
1) Funktionen sind schon lange erfunden.
2) Jede Alternative zu double bzw. sqrt ist eine spitzenmässige
Alternative)
PS-2:
Wenn du dich dazu durchringen könntest, mal etwas größere Teile deines
Programms zu zeigen, dann könnt man dir auch gezielt zeigen, wie du
a) die Komplexität in der Schreibweise des C-Codes runterbringen
kannst
b) dein Programm soweit vereinfachen kannst, dass sich auch der
µC damit leichter tut.
c) dein Programm insbesondere wegen letzterem Punkt um einen Faktor x
beschleunigt wird.
Du könntest davon profitieren und das eine oder andere dabei lernen.
Aber wenn du nicht willst ....
Ich behaupte mal 90-95% deiner Programmgröße ist auf Fließkommazahlen,
Wurzel und Quadratfunktion zurückzuführen. D.h. du brauchst nicht
Abfragen sparen, da diese wirklich nur minimal Platz benötigen. Schau
lieber, dass du dein programm auf Festkomma umstellst und auf
Wurzelfunktionen verzichtest. Dann kannst du tausende If Abfragen ein
bauen und dein Programm wird in einem Bruchteil der Zeit ablaufen.
Daraus lässt sich bestimmt noch ein Einzeiler machen... ;)
Mir persöhnlich ist ein aufgeblähter Sourcecode mit Kommentaren und
gescheiter Formatierung viel lieber als den µC 1.000 takte rechnen zu
lassen.
Mein KISS verlangt nicht nach Numerik die eine Wurzel nähert,
noch eine Multiplikation mit sich selbst.
Weiss denkst Du wieviel Schleifendurchläufe alleine für die Wurzel nötig
sind ?
(in der auch wieder abfragen und multiplikationen stecken)
Ich kann leider kein Assembler, aber ich schätze mal :
-Werte laden
-Vergleich gröser kleiner 16 bit
-Subtraktion ausführen / Else Sprung mit Subtraktion
-Werte laden
-vergleich grösser kleiner 16bit
-Jump oder else Jump
Weisst Du wie man eine Wurzel Approximiert (jetzt musst Du eigentlich
noch eine Fehlerabschätzung machen ;) ?
Während dessen wird obiger Code geschätzt 100 bis 1000 mal ausgeführt.
(jedenfalls nach meinem Gefühl)
Aber Hauptsache Dein Problem ist behoben.
Oh. Ein PS hab ich noch vergessen.
Arithmetische Operationen kosten auch Rechen-Zeit. Die kriegst du nicht
umsonst.
Insbesondere kostet Floating Point Rechnerei auf einem AVR eine Menge
Zeit. Aber so richtig Zeit kosten dann "Spezialdinge" wie sqrt oder sin,
cos, log, pow, ....
#define TOLERANZ 0.5 // Wie gross ist meine Toleranz ?
2
3
uint8_tisEqual(doublea,doubleb)
4
{
5
doublet
6
7
if(a>b)
8
t=a-b;
9
else
10
t=b-a;
11
12
returnt<TOLERANZ;
13
}
14
15
....
16
17
intmain(void){
18
[...]
19
20
doubletemp1;
21
doubletemp2;
22
ADC_init();
23
24
[...]
25
temp1=ADC_read(0);
26
temp2=ADC_read(1);
27
28
if(!isEqual(temp1,temp2))
29
ERR=1;
30
31
[...]
32
33
}
schon alleine das hier wird die Abfrage um einen Faktor (grob geschätzt)
100 bis 200 beschleunigen. Von der besseren Lesbarkeit red ich erst mal
gar nicht.
Mir ist momentan eine Optimierung im Bezug auf Rechenzeit oder
Speicherplatz noch egal. Erstmal möchte ich mich auslassen und dann kann
ich, falls es eng wird immer noch optimieren ;). Ich lerne ja gerade
erst, wie ihr offenbar alle festgestellt habt ^^.
Ich werde mein Programm bald zur Verfügung stellen. Thx @ all
C. S. schrieb:> allerdings bläht das mein> ohnehin schon langes Programm nurnoch auf.C. S. schrieb:> Mir ist momentan eine Optimierung im Bezug auf Rechenzeit oder> Speicherplatz noch egal.
Was nun?
C. S. schrieb:> Mir ist momentan eine Optimierung im Bezug auf Rechenzeit oder> Speicherplatz noch egal.
Du hast es immer noch nicht.
Es geht erst in 2-ter Linie um Rechenzeit und Speicherplatz.
Du kannst deinen C-Code viel einfacher gstalten und gleichzeitig, quasi
als Nebeneffekt, den Prozessor entlasten!
> Erstmal möchte ich mich auslassen und dann kann> ich, falls es eng wird immer noch optimieren ;).
Was du machst, hat mit 'Optimierung beiseite lassen' nicht wirklich was
zu tun. Was du machst ist: Ich schreibe den schlimmst möglichen Code!
Wenn es ein Gegenteil zu 'optimieren' gibt, dann betreibst du das genau
jetzt. Und zwar ohne wirklichen Grund! Das kommt dann nämlich als
Sahenhäubchen noch mit oben drauf.
> Ich lerne ja gerade> erst, wie ihr offenbar alle festgestellt habt ^^.
Was denkst du wohl warum hier so viele auf dich einreden, wie auf eine
kranke Kuh?
> Ich werde mein Programm bald zur Verfügung stellen. Thx @ all
Tus gleich!
Wenn der Rest des Programms genauso aussieht, wie das bischen was du
gezeigt hast, dann besteht da Unmenge an Potential, wie man den im
C-Code(!) vereinfachen kann.
Karl heinz Buchegger schrieb:> Insbesondere kostet Floating Point Rechnerei auf einem AVR eine Menge> Zeit.
Ja...jein. Teilweise sind die recht gut optimiert. uint32_t zum
Bleistift rechnet sehr viel länger herum, ist zwar ein paar Stellen
genauer, dafür fehlt die Dynamik.
Ich tendiere auch dazu, solche Dinge erstmal in Gleitkomma zu
implementieren, weil man dann schneller feststellt, ob der Algorithmus
auch plausibel ist und sich keine Gedanken um Zahlenbereichsüberläufe
oder derlei Dinge machen muss. Man kann halt 2,89 V auch als 2.89 im
Programm darstellen und sich im Debugger genau so ansehen (die
nachgemessene (!) ADC-Referenzspannung ist dann oft ein #define im
Programm).
Ob ich das dann später noch in einen Festkommaalgorithmus überführe
(nachdem klar ist, dass der Algorithmus an sich "steht"), hängt
wesentlich von der Aufgabenstellung ab. Wenn der Controller sowieso
noch nichtmal zu 50 % voll ist (ein Austausch durch den nächst
kleineren aber nicht lohnt, wer lötet schon freiwillig ein TQFP
wieder aus, wenn's nicht sein muss?) und die Rechenzeit auch keine
wirkliche Rolle spielt, dann sehe ich meist keinen Grund für
irgendwelche post-mortem-Optimierungen.
Gut, ich wäre allerdings trotzdem nicht auf die Idee gekommen, zwei
if-Anweisungen durch eine umständliche Quadratwurzel zu ersetzen. ;-)
C. S. schrieb:> okay okay ich habs verstanden :(>> was liefert deine fuktion zurück, nur 1 oder 0 richtig??
Das was ein Vergleich eben ergibt.
Von daher: richtig
Wenn dir das noch zu kryptisch ist, kannst du es ja auch so schreiben
1
uint8_tisEqual(doublea,doubleb)
2
{
3
doublet
4
5
if(a>b)
6
t=a-b;
7
else
8
t=b-a;
9
10
if(t<TOLERANZ)
11
return1;
12
13
return0;
14
}
Der springende Punkt ist aber:
Nichts und niemand hindert dich daran, für solche Dinge dir selber
Funktionen zu schreiben. Das sieht auf den ersten Blick nach mehr Arbeit
aus, ist es aber nicht. Alleine die Klarheit, die sich bei der
Verwendung dadurch einstellt
1
if(!isEqual(temp1,temp2))
2
ERR=1;
ist diese Funktion schon wert. Selbst wenn man nicht weiß, wie isEqual
im Detail funktioniert, ist das hier
a) viel besser zu lesen als dein Phytagoras Ansatz. Das ist schon
fast ein vollständiger englischer Satz, den ich nur so zu lesen
brauche wie er da steht und ich erfasse das, was an dieser Stelle
passiert.
b) für den µC viel einfacher auszuwerten
Man schlägt hier 2 Fliegen mit einer Klappe.
Der C Code wird einfacher
Der Code den der µC ausführen muss, wird einfacher
Und deswegen amüsieren wir uns auch über deinen Wurzel Ansatz :-)
Um deine Routenplanung für die Fahrt von Wien nach Paris nicht zu
kompliziert werden zu lassen, fragst du nach einem guten Weg durch
Koppenhagen durch.
Der richtige Ansatz ist es aber, gar nicht erst nach Koppenhagen zu
fahren, sondern direkt in Wien auf die richtige Autobahn aufzufahren und
in Paris wieder runter.
Ja du hast absolut recht. Ich dachte halt nur, erst ne Funktion
schreiben, dann noch 3 double Variablen in der Funktion erzeugen, das
würde das gnaze komplizierter machen. Aber ich bin hier der Noob und ihr
die Profs. also habt ihr recht :D
Ich werd aus deinem Code nicht wirklich schlau, was das werden soll.
Aber am Anfang der Schleife ist zb der Teil hier
1
PORTC|=S0|S1|S2;// H | H | H = Y7
2
_delay_ms(50);
3
if(!(PINB&(1<<D_IN1)))
4
ERR=+1;
5
PORTC=0x00;//reset MUX
6
_delay_ms(50);
immer gleich. Nur die Zahlenwerte ändern sich. -> Kandidat füe eine
Funktion
1
voidPulse(uint8_tPins,uint8_tInputMask)
2
{
3
PORTC|=Pins;
4
_delay_ms(50);
5
6
if(!(PINB&IputMask))
7
ERR=+1;
8
9
PORTC=0x00;//reset MUX
10
_delay_ms(50);
11
}
weil ich es gerade sehe: Ist es Absicht, dass du da
ERR = +1;
geschrieben hast, oder solltest du eigentlich
ERR += 1;
schreiben? So wie du deine Schreibweise hast, ohne Leerzeichen
dazwischen kann so ein Fehler schon einmal unbemerkt bleiben. Mit
Leerzeichen ist aber klar, dass
ERR =+ 1;
eher ein Tippfehler ist.
Wie auch immer. Mit der Funktion vereinfacht sich dann der Anfang deiner
Hauptschleife enorm
1
while(1)
2
{
3
if(debounce(PINB,PB0))//PINB & (1<<D_IN0))//Falls Taster an PIN PB0 gedrueckt...
/************* D_IN1: 12V_L to 0V_L *************/
18
Pulse(S0|S1|S2,1<<D_IN1);// H | H | H = Y7
19
20
/************* D_IN2: 12V_L to 0V_L *************/
21
Pulse(S1|S2,1<<D_IN2);// L | H | H = Y6
22
23
/************* D_IN3: 12V_L to 0V_L *************/
24
Pulse(S0|S2,1<<D_IN3);// H | L | H = Y5
25
26
/************* D_IN4: 12V_L to 0V_L *************/
27
Pulse(S2,1<<D_IN4);// L | L | H = Y4
28
29
/************* D_IN5: 12V_L to 0V_L *************/
30
if(!(PINB&(1<<D_IN5)))
31
ERR+=1;
32
33
....
und schon hast du wieder einen ordentlichen Komplexitätsbrocken aus der
Hauptschleife raus. Ob der Name 'Pulse' für die Funktion vernünftig ist
oder nicht, kann ich nicht sagen, weil ich nicht durschaut habe, was du
da eigentlich machst. Im Zweifel musst du dir einen anderen Namen dafür
einfallen lassen.
Auch würde ich das 0-Setzen von ERR auf jeden Fall machen, ehe da
irgendwas an ERR rumfummelt und nicht hinten nach, wo man es gerne
übersieht.
1
[C]
2
while(1)
3
{
4
if(debounce(PINB,PB0))//PINB & (1<<D_IN0))//Falls Taster an PIN PB0 gedrueckt...
PORTD|=(1<<D_OUT1);// Durchgangsprüfung : relay: Z
12
13
Pulse(S0|S1|S2,1<<D_IN1);// D_IN1: 12V_L to 0V_L; H | H | H = Y7
14
Pulse(S1|S2,1<<D_IN2);// D_IN2: 12V_L to 0V_L; L | H | H = Y6
15
Pulse(S0|S2,1<<D_IN3);// D_IN3: 12V_L to 0V_L; H | L | H = Y5
16
Pulse(S2,1<<D_IN4);// D_IN4: 12V_L to 0V_L; L | L | H = Y4
17
18
/************* D_IN5: 12V_L to 0V_L *************/
19
if(!(PINB&(1<<D_IN5)))
20
ERR+=1;
und schon hat sich über eine Seite C-Code auf ein paar wenige Zeilen
eingedampft. Und zwar ohne das es unübersichtlich wird. Ganz im
Gegenteil (und 1 Fehler, die Behandlung von ERR in einem Fall, ist so
nebenbei auch noch korrigiert worden).
Vielen Dank. Ich habe mich an das Thema mit den Funktionen nicht
rangetraut, weil ich nicht wusste, welche Werte ich übergeben muss. Ich
wusste garnicht, dass man
1
S0|S1|S2
einfach in eine uint8_t Variable übergeben kann.
>Auch würde ich das 0-Setzen von ERR auf jeden Fall machen, ehe da>irgendwas an ERR rumfummelt und nicht hinten nach, wo man es gerne>übersieht.
Habe ich im Else Zweig wenn der Taster nicht gedrückt wird. Oder reicht
das nicht?
Karl heinz Buchegger schrieb:> Ob der Name 'Pulse' für die Funktion vernünftig ist> oder nicht, kann ich nicht sagen, weil ich nicht durschaut habe, was du> da eigentlich machst.
Damit ist der Name offenbar nicht vernünftig.
QED
C. S. schrieb:>>Auch würde ich das 0-Setzen von ERR auf jeden Fall machen, ehe da>>irgendwas an ERR rumfummelt und nicht hinten nach, wo man es gerne>>übersieht.>> Habe ich im Else Zweig wenn der Taster nicht gedrückt wird. Oder reicht> das nicht?
Doch.
Man muss aber danach suchen.
Zieh ich es vor, dann ist klar, dass die Logik lautet
1
nimm an das es keinen Fehler gibt (ERR = 0)
2
3
dann überprüf alle möglichen Dinge die fehlerhaft sein könnten (ERR += 1)
4
5
im Abschluss werte aus, ob irgendetwas fehlerhaft war (if( ERR > 0 ))
das ist eine logische Abfolge dessen, was mit der Variablen ERR
passieren kann und wie sie benutzt wird. Warum willst du das 0-setzen
von ERR irgendwo anders verstecken, wo man es erst einmal suchen muss
und sich die if-Hierarchie genau ansehen muss, um draufzukommen, wann
ERR eigentlich auf 0 gesetzt wird?
C. S. schrieb:> Vielen Dank. Ich habe mich an das Thema mit den Funktionen nicht> rangetraut, weil ich nicht wusste, welche Werte ich übergeben muss. Ich> wusste garnicht, dass man>>
1
>S0|S1|S2
2
>
>> einfach in eine uint8_t Variable übergeben kann.
Warum denn nicht. Wenn du mehere LED einschaltest, machst du ja auch
PORTC = ( 1<<LED1 ) | (1<<LED2);
du veroderst einzelne Ausdrücke um einen kompletten uint8_t Wert zu
erhalten, der genau die beiden Bits gesetzt hat. Der Ausdruck
( 1<<LED1 ) | (1<<LED2)
ergibt genau diesen uint8_t, mit dem man dann als Ganzes etwas macht: An
einen Port zuweisen oder aber auch an eine Funktion übergeben.
du hast ja auch keine Skrupel
j = irgendeine_Funktion( 2 + 3 );
aufzurufen und beim Aufruf einen Ausdruck anzugeben. Du erwartest hier
ja auch, dass die Funktion mit dem Wert 5 aufgerufen wird, das heisst
der Ausdruck vor dem Funktionsaufruf ausgewertet wird.
| ist auch nur eine 'arithmetische' Operation, so wie + - * / % es ebenfalls sind.
Er macht halt nur etwas anderes. Nämlich die Bits miteinander verodern, anstelle
von addieren. Aber ansonsten ist das doch konzeptionell völlig dasselbe.
C. S. schrieb:> Ja das ergibt alles schon Sinn nur man traut sich halt nicht :D.
Genau deshalb lautet auch die am öftesten hier gepostete Antwort:
Kauf dir ein C-Buch und übe ein bischen auf dem PC zumindest die ersten
paar Kapitel durch. :-)
Funktion, Funktionsargumente, Ausdrücke etc, also die einfachen Sachen,
die im C-Buch in den ersten paar Kapitel behandelt werden ... all diese
Dinge sollten schon so einigermassen sitzen, ehe man sein erstes
richtiges Projekt angeht.