Hallo,
ich habe ien C Programm geschrieben, welches 2 Spannungen mittel sdes
internen Komperator vergleicht.
Kompilieren klappt, aber könntet Ihr trotzdem mal drüberschauen?
Habe es mit der Hilfe von dem Tutorila erstellt.
1
#include<avr/io.h>
2
#include<stdint.h>
3
4
intmain(void)
5
{
6
ACSR&=~(1<<ACD)|(1<<ACBG);//ACE einschalten und externe Ref Spannung
Hallo,
gute Frage :-).
Wenn ACO also IST > SOLL.
Würde es gerne so machen, das wenn ACO = 1 (IST < SOLL) dann PB0
einschalten (grüne LED brennt), und wenn ACO = 0, dann PB1 einschalten
(rote LED).
Habe das mal programmiert:
1
#include<avr/io.h>
2
#include<stdint.h>
3
4
intmain(void)
5
{
6
ACSR&=~(1<<ACD)|(1<<ACBG);//ACE einschalten und externe Ref Spannung
Da gibt es 2 Fallen:
Operatorenreihenfolge
Der linke Teilausdruck muss nicht notwendigerweise 1 ergeben
(nach der Syntaxkorrektur)
Der C-Compiler sieht diesen Ausdruck als
1
ACSR&((1<<AC0)==1)
und das ist nicht ganz das was du haben willst. Du willst
1
(ACSR&(1<<AC0))==1
Generell: Lass diese Vergleiche mit == 1 oder != 1 überhaupt weg. Die
funktionieren nämlich meistens sowieso nicht, es sei denn AC0 ist
zufällig genau 1
1
if(ACSR&(1<<AC0))
macht das Gewünschst und du laufst nicht Gefahr, dass dir da die
Operatorenreihenfolge reinpfuscht. Die Umkehrung allerdings erfordert
eine Klammer mehr
1
if(!(ACSR&(1<<AC0)))
allenfalls, wenn du explizit sein möchtest, kannst du noch schreiben
1
if((ACSR&(1<<AC0))==0)// Bit nicht gesetzt
1
if((ACSR&(1<<AC0))!=0)// Bit gesetzt
aber hüte dich davor, anzunehmen dass bei gesetztem Bit der ganze linke
Ausdruck dann zu 1 wird! Das wird er nämlich nicht.
Nicht umsonst ist die C Definition für logisch wahr: alles was nicht 0
ist. Daher: derartige Auswertungen immer so formulieren, dass auf 0
Bezug genommen wird.
Einrückungen zu machen reicht nicht aus, um dem Compiler zu sagen, dass
die ersten 2 Zeilen zum "if" gehören und die anderen zum "else".
Richtig wäre Klammerung mit "{" und "}'":
1
if(ACSR&(1<<ACO)==1)//wenn IST < SOLL
2
{
3
PORTB|=(1<<PB0);//PORT B0 auf einschalten
4
PORTB&=~(1<<PB1);//und B1 auf 0
5
}
6
else//wenn IST > SOLL
7
{
8
PORTB|=(1<<PB1);//B1 einschalten
9
PORTB&=~(1<<PB0);//B0 ausschalten( auf 0)
10
}
> Habe das mal programmiert:
Was verstehst Du unter "programmieren"? Zumindest ein compilieren sollte
schon dazugehören, um festzustellen, ob wenigstens syntaktisch alles in
Ordnung ist. Deine Version kann eigentlich kein Compiler schlucken, weil
dieser das "if" zum "else" ohne Klammern gar nicht finden kann...
Gruß,
Frank
Hallo,
habe in einem C-Buch nachgeschaut.
Wenn ich nach dem if nur einen Befehl habe, dann brauche ich keine
Klammern, da ich aber zwei Zeilen habe, brauche ich bei if und auch bei
else klammern, oder nicht?
Wenn ich es bei AVR Studio durchlaufen lasse, dann bekomme ich weder
Fehler noch Warnungen, dann müsste es doch laut Compiler syntaktisch
richtig sein, oder?
Aber es geht ja auch um die Funktion. Würde es so wie ich es geschrieben
haben funktionieren, oder habe ich wasa grundlegendes falsch gemacht
oder vergessen?
LG
Hans Peter schrieb:
> Hallo,>> habe in einem C-Buch nachgeschaut.> Wenn ich nach dem if nur einen Befehl habe, dann brauche ich keine> Klammern, da ich aber zwei Zeilen habe, brauche ich bei if und auch bei> else klammern, oder nicht?
Ja
Und zwar deshalb, weil das hier
{
Anweisung
Anweisung
Anweisung
...
}
(also eine Abfolge von Anweisungen eingeshlossen in { }, ein sog. Block)
selbst wieder als eine Anweisung gilt.
Die Syntax vom if ist ganz einfach
if( Ausdruck )
Anweisung
Es kann also nur eine einzige Anweisung innerhalb des auszuführenden
Teils geben. Aber man kann ja einen Block benutzen um eine Abfolge von
Anweisungen als nur eine einzige Anweisung zu verkaufen.
> Wenn ich es bei AVR Studio durchlaufen lasse, dann bekomme ich weder> Fehler noch Warnungen, dann müsste es doch laut Compiler syntaktisch> richtig sein, oder?
Im letzten Fall nicht. Und zwar deshalb, weil die vollständige if-Syntax
lautet
if( Ausdruck )
Anweisung
else
Anweisung
(wobei der else Teil auch entfallen kann)
Bei dem was du geschrieben hast, hängt das else aber in der Luft.
Das wird der Compiler monieren.
> Aber es geht ja auch um die Funktion. Würde es so wie ich es geschrieben> haben funktionieren, oder habe ich wasa grundlegendes falsch gemacht> oder vergessen?
Siehe weiter oben
Hallo,
verstehe ich nicht so ganz.
Durch meine Klammern, bei if und bei else, sage ich Ihm, dass es ein
Block von Anweisungen ist, die werden doch dann beide abgearbeitet,
oder?
Warum hängt else in der Luft?
Wenn die if Bedingung nicht zutrifft, dann wechselt er doch in den else
Teil.
also wenn die Spannungen so sind, dann mache das ansonsten mach das.
Oder soll ich zwei If - Schleifen untereinander machen?
LG
ein beispiel:
if(D)
B=1;
C=1;
wenn du das so machst meckert kein compiler. nur mach der daraus das
hier:
if(D)
{
B=1;
}
C=1;
das heißt das C=1 nicht mehr in der if ist und immer(!) nach der if
abfrage ausgeführt wird.
der nimmt nur die erste zeile, die weiteren sind dann eigene befehle...
also bei einem oder mehr immer klammern setzen!
Hans Peter schrieb:
> Hallo,>> verstehe ich nicht so ganz.> Durch meine Klammern, bei if und bei else, sage ich Ihm, dass es ein> Block von Anweisungen ist, die werden doch dann beide abgearbeitet,> oder?
Du hast aber keine Klammern gemacht.
Zitat
1
if(ACSR&(1<<ACO)==1)//wenn IST < SOLL
2
PORTB|=(1<<PB0);//PORT B0 auf einschalten
3
PORTB&=~(1<<PB1);//und B1 auf 0
4
else//wenn IST > SOLL
5
PORTB|=(1<<PB1);//B1 einschalten
6
PORTB&=~(1<<PB0);//B0 ausschalten( auf 0)
Für den COmpiler ist das
1
if(ACSR&(1<<ACO)==1)//wenn IST < SOLL
2
PORTB|=(1<<PB0);//PORT B0 auf einschalten
3
4
PORTB&=~(1<<PB1);//und B1 auf 0
5
6
else//wenn IST > SOLL
7
PORTB|=(1<<PB1);//B1 einschalten
8
9
PORTB&=~(1<<PB0);//B0 ausschalten( auf 0)
Das ist ist daher mit dem
PORTB |= (1<<PB0); //PORT B0 auf einschalten
zu Ende. Das
PORTB &=~(1<<PB1); //und B1 auf 0
gehört schon nicht mehr dazu.
Aber: Zu welchem if gehört denn jetzt das else. Da ist kein if mehr zu
dem es gehören könnte. Denn das if war ja schon nach dem
PORTB |= (1<<PB0); //PORT B0 auf einschalten
zu Ende.
Hans Peter schrieb:
> Das ist mir klar, aber ich habe doch Klammern gesetzt, sowohl bei if und> auch bei else, oder?
Wo?
Schau dir doch noch einmal deinen Code an!
1
while(1)
2
{
3
if(ACSR&(1<<ACO)==1)//wenn IST < SOLL
4
PORTB|=(1<<PB0);//PORT B0 auf einschalten
5
PORTB&=~(1<<PB1);//und B1 auf 0
6
else//wenn IST > SOLL
7
PORTB|=(1<<PB1);//B1 einschalten
8
PORTB&=~(1<<PB0);//B0 ausschalten( auf 0)
9
}
Wo sind da die beiden Anweisungen die vom if abhängen sollen mit einer {
} geblockt worden?
Hans Peter schrieb:
> Also so?
Ja.
Aber wenn ich dir einen Formatiertip geben darf.
Lass die { } auf derselben Einrückungstiefe, wie die Anweisung
deretwegen du sie gemacht hast und rücke nach der { um 2 Zeichen ein und
beim } wieder um 2 Zeichen aus.
1
intmain(void)
2
{
3
ACSR&=~(1<<ACD)|(1<<ACBG);//ACE einschalten und externe Ref Spannung
4
DDRB|=(1<<DDB0)|(1<<DDB1);//DDRB als Ausgang
5
6
7
while(1)
8
{
9
if((ACSR&(1<<ACO))==1)//wenn IST < SOLL
10
{
11
PORTB|=(1<<PB0);//PORT B auf einschalten
12
PORTB&=~(1<<PB1);
13
}
14
else
15
{
16
PORTB|=(1<<PB1);
17
PORTB&=~(1<<PB0);
18
}
19
}
20
}
So ist es optisch einfacher, die zu einem } gehörende öffnende { zu
finden. Die { und } gehen dann nicht so leicht unter.
Hallo,
habe jetzt alles mal auf meinem Breadboard aufgebaut und zwei
verschiedene Spannungen drangelegt.
Die Spannung an AIN0 (SOLL) hat ca. 2,4V und die Spannung an AIN1 hat
1,8V.
Das heißt Soll>IST und somit soll er doch laut meinem Code den Ausgang
PB0 schalten, aber er setzt PB1 auf eins, es brennt die andere LED.
Wo ist der Denkfehler?
Ich habe da noch was, ich würde gerne den AD Wandler benutzen.
Also erstmal testen. Ich habe da an eine Schaltung gedacht, wo ich 8
LED´s ansteuere.
Die erste hat die Wertigkeit 2^0, 2^1 usw.
damit möchte ich dann die Zahl 256 darstellen, also 8 Bit.
Hat das jemand schon gemacht, oder habt Ihr eine andere Idee, wie ich
einen Einstieg in den AD Wandler bekomme (Tutorial habe ich schon
gelesen), ich hätte gerne ein Bsp. Programm, an dem ich noch testen
kann.
LG
Wollte dafür keinen neuen Beitrag schreiben, hoffe es ist O.K..
Das hier
ACSR &= ~(1<<ACD) | (1<<ACBG); //ACE einschalten und externe Ref
Spannung
macht nicht das was du denkst.
Ironischerweise ist der ADC von Haus schon so konfiguriert, dass er
genau das macht, was du eigentlich erreichen willst:
Er ist eingeschaltet und
er vergleicht die Pins AIN0 und AIN1 miteinander
Wenn du ihn also einfach nur in Ruhe gelassen hättest, hättest du das
gewünschte Ergebnis.
Mit obigen schaltest du den ADC so, dass die Referenzspannung die
interne Referenz ist.
~(1<<ACD) | (1<<ACBG)
wird vom Compiler geparst als
(~(1<<ACD)) | (1<<ACBG)
du bräuchtest aber:
~( (1<<ACD) | (1<<ACBG) )
Daher noch einmal der Aufruf: Wenn du dir über Opertorenreihenfolge
nicht sicher bist, dann verwende Klammern!
Hans Peter schrieb:
> einen Einstieg in den AD Wandler bekomme (Tutorial habe ich schon> gelesen)
und, wo ist dann das Problem.
Im Tutorial gibt es eine schöne Routine, die dir den Wert vom AD Wandler
holt. Was du dann mit dem Wert machst bleibt deiner Phantasie
überlassen.
Ja, aber es fängt ja schon beim Schaltungsaufbau an.
Verbessert mich bitte.
Also ich würde ein Poti an PA0 z.B. anschliessen.
5V auf das Poti und die Spannung die an PA0 ankommt über den AD Wandler
wandeln, mit 8 Bit aber, damit die Zahl nicht so riesig wird (wie ich
mit 8 Bit anstatt 10 wandle, ist mir aber auch noch nicht klar).
Dann kann ich ja sagen, 5V / 256 = 19,53 mV. Das sind ja dann meine
Schritte, denen ich Zahlenwerte zuweisen kann, das wird im Tutorial
genauso gemacht.
0-19,53mV = 0
19,53mV - 39,06mV = 1
usw.
Dann würde ich gerne aber diese Zahlen irgendwie da ich kein Display
habe über LED´s ausgeben. 2^0, 2^1, 2^2 usw.
Da hängt es aber auch schon. (Schaltungs und Programmiertechnisch)
LG
Hans Peter schrieb:
> Also ich würde ein Poti an PA0 z.B. anschliessen.> 5V auf das Poti
Für den Anfang:
ARef an das Poti.
Und das andere Ende des Potis kommt an GND
> und die Spannung die an PA0 ankommt über den AD Wandler
Der MIttenabgriff des Potis kommt an PA0
> wandeln, mit 8 Bit aber, damit die Zahl nicht so riesig wird (wie ich> mit 8 Bit anstatt 10 wandle, ist mir aber auch noch nicht klar).
Wandle mit 10 Bit. Was du hast, hast du. Die Zahl kleiner machen (zb
indem man durch 4 dividiert) kann man immer noch.
> Dann kann ich ja sagen, 5V / 256 = 19,53 mV. Das sind ja dann meine> Schritte, denen ich Zahlenwerte zuweisen kann, das wird im Tutorial> genauso gemacht.> 0-19,53mV = 0> 19,53mV - 39,06mV = 1> usw.
Gib für den Anfang einfach nur den Wert vom ADC (geteilt durch 4) an
deine 8 Leds aus. Ohne Umrechnung, ohne irgendwas. Einfach nur
PORTB = adc_wert / 4;
(adc_wert ist das Ergbnis welches dir die ADC-routine aus dem Tutorial
gegeben hat)
Hans Peter schrieb:
> Alles klar,>> dannist ja PA0 mein Eingang (AD-Wanlder Eingang) und die Ausgänge, die> sind ja egal, ob ich B oder C nehmen, oder?
Dort wo du LEDs drann hast
Hallo,
O.K., ist klar.
Habe jetzt mal aus dem Tutorial die ersten Zeieln übernommen und
abgeändert.
Komme aber trotzdem nicht so richig weiter.
Hier mal der Quelltext:
/* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
19
also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
20
ADCSRA|=(1<<ADSC);// eine ADC-Wandlung
21
22
while(ADCSRA&(1<<ADSC)){
23
;// auf Abschluss der Konvertierung warten
24
}
25
adc_wert=ADCW;// ADCW muss einmal gelesen werden,
26
// sonst wird Ergebnis der nächsten Wandlung
27
// nicht übernommen.
28
adc_wert=0;
29
for(i=0;i<4;i++)
30
{
31
ADCSRA|=(1<<ADSC);// eine Wandlung "single conversion"
32
while(ADCSRA&(1<<ADSC)){
33
;// auf Abschluss der Konvertierung warten
34
}
35
adc_wert+=ADCW;// Wandlungsergebnisse aufaddieren
36
}
37
ADCSRA&=~(1<<ADEN);// ADC deaktivieren (2)
38
39
PORTB=adc_wert/4;// Summe durch vier teilen = arithm. Mittelwert
40
41
42
}
Habe halt ziemlich viel aus dem Tutorial genommen, weis aber nicht, ob
es passt.
Jetzt muss ich doch irgendwie noch mehrere If abfragen reiinmachen,
damit ich bei bestimmten Werten, die verschiedenen Ausgänge ansteuern
kann, oder?
Gibt es da noch eine andere Lösung, wie ich das machen kann?
Ist ja ganz schöne Schreibarbeit.
Verstehe es auch nicht so ganz, warum ich den Mittelwert bilden soll,
wegen der Genauigkeit oder warum?
Ich habe mir jetzt hier auf einem Blatt mal angefangen die Werte
aufzuschreiben, 0V-...V = 0 usw.
Das sind ja ziemlich viele Werte, muss ich jetzt für jeden Wert den ich
ausgeben will, eine Zeile schreiben?
LG
Hans Peter schrieb:
> Hallo,>> O.K., ist klar.> Habe jetzt mal aus dem Tutorial die ersten Zeieln übernommen und> abgeändert.
Warum tust du das?
Im Tutorial ist eine fix und fertige Funktion. Die musst du für deine
ersten Schritte nur aus dem Tutorial per Cut&Paste in deinen Code
einsetzen und in main() einen Aufruf der Funktion in die Hauptschleife
einbauen.
Machst du dir selbst absichtlich das Leben schwer?
Zuerst nimmt man was man kriegen kann. Dann bringt man es zum Laufen.
Und erst dann fängt man an, die Funktionen zu modifizieren.
> Ist ja ganz schöne Schreibarbeit.
Was ist an ...
/* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
21
also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
22
ADCSRA|=(1<<ADSC);// eine ADC-Wandlung
23
while(ADCSRA&(1<<ADSC)){
24
;// auf Abschluss der Konvertierung warten
25
}
26
result=ADCW;// ADCW muss einmal gelesen werden,
27
// sonst wird Ergebnis der nächsten Wandlung
28
// nicht übernommen.
29
30
/* Eigentliche Messung - Mittelwert aus 4 aufeinanderfolgenden Wandlungen */
31
result=0;
32
for(i=0;i<4;i++)
33
{
34
ADCSRA|=(1<<ADSC);// eine Wandlung "single conversion"
35
while(ADCSRA&(1<<ADSC)){
36
;// auf Abschluss der Konvertierung warten
37
}
38
result+=ADCW;// Wandlungsergebnisse aufaddieren
39
}
40
ADCSRA&=~(1<<ADEN);// ADC deaktivieren (2)
41
42
result/=4;// Summe durch vier teilen = arithm. Mittelwert
43
44
returnresult;
45
}
46
47
intmain()
48
{
49
DDRB=0xFF;
50
51
while(1)
52
{
53
PORTB=ReadChannel(0)/4;
54
}
55
}
Mit Schreibarbeit habe ich das auswerten von dem Messwert gemeint.
Ich muss doch jetzt sagen, welchen Ausgang von PORTB ich ansteuern will,
oder?
Ich glaube ich denke in eine falsche Richtung oder zu umständlich.
Sorry
Hans Peter schrieb:
> Mit Schreibarbeit habe ich das auswerten von dem Messwert gemeint.> Ich muss doch jetzt sagen, welchen Ausgang von PORTB ich ansteuern will,> oder?
Für deine ersten Tests reicht es völlig dem PORTB als Ganzes ein neues
Bitmuster zu verpassen.
Genau das macht diese Zuweisung :-)
Hallo,
wollte noch mal fragen, mit dem anschliessen.
Ich gehe von der Spannungsquelle an das Poti und an den AREF.
Mit dem Poti GND gehe ich zum Pin 31, also der GND unter AREF.
Dann gehe ich mit den 5V an Pin 10 Vcc und Pin 11 GND.
Muss ich it dem GND vom POTI auch noch auf den GND von der
Spannungsquelle gehen, oder sind die GND von Pin31 mit dem Pin 11 intern
gebrückt?
MfG
Hans Peter schrieb:
> Hallo,>> wollte noch mal fragen, mit dem anschliessen.> Ich gehe von der Spannungsquelle an das Poti und an den AREF.
Nein.
Du gehst nicht an den ARef.
Du schaltest den Mega per Software so (das macht die ReadChanel), dass
der Mega seine Versorgungsspannung als Referenzspannung hernimmt. Diese
Referenzspannung stellt dir der Mega freundlicherweise am Pin ARef zur
Verfügung.
Du schaltest also ganz einfach nur das Poti an den ARef und der Mega
beaufschlagt das Poti mir der Spannung.
> Mit dem Poti GND gehe ich zum Pin 31, also der GND unter AREF.> Dann gehe ich mit den 5V an Pin 10 Vcc und Pin 11 GND.> Muss ich it dem GND vom POTI auch noch auf den GND von der> Spannungsquelle gehen, oder sind die GND von Pin31 mit dem Pin 11 intern> gebrückt?
Du machst dir das jetzt kompliziert (und ich hab jetzt keine Lust das
auseinanderzudröseln)
Stinknormale Prozessorbeschaltung, so dass er läuft: Alle GND mit GND
der Spannungsquelle verbunden. Alle Vcc, AVcc mit Vcc der
Spannungsquelle verbunden. BLockkondensatoren wie gehabt.
Also -> ganz normale Arbeitskonfiguration des Prozessors.
Dann nimmst du dein Poti.
Das eine Ende (der 3 Anschlüsse) kommt an GND, das andere Ende an ARef
und der mittlere Potianschluss an PA0.
Achte noch darauf, dass an ARef ein 100n Kondensator zur Abblockung der
vom Mega zur Verfügung gestellten Spannung ist, und schon kanns
losgehen.
Hallo,
habe es angeschlossen, und es leuchtet nix.
Ich kann das Poti drehen wie ich will, da tut sich nix.
Verschaltung:
Poti:
Plus vom Poti über 100n an AREF
Mittelabgriff an PA0
GND an GND vom mC (Pin 31)
ATmega
Vcc von der Sapnnungsquelle
GND mit GND der Spannungsquelle verbunden (PIN 11)
PB0 bis PB7 über Widerstände an LEDs,
LED´s
Anode mC
Kathode GND von Spannungsquelle.
LG
Da habe ich nix dran.
Wird Port A nicht durch den Mittelabgriff des Potis versorgt.
Ich habe mal angeschlossen und gemessen, am Ausgang von Port B habe ich
eine Spannung anliegen. Vom Ausgnag PB0 bis zum Widerstand auch noch,
aber auf der anderen Seite des Widerstandes ist 0 V.
Hat das was mit den internen Pull up Widerständen zu tun?
Kann das sein?
Hans Peter schrieb:
> Da habe ich nix dran.
Dann mal schnell.
> Wird Port A nicht durch den Mittelabgriff des Potis versorgt.
Nein.
AVcc liefert die Energie, damit der ADC überhaupt arbeiten kann.
Arbeiten bedeutet dann, dass der ADC die Spannung misst, die an einem
bestimmten Pin anliegt.
Das wäre wohl ein wenig fatal, wenn das Messgerät die zu messende Größe
dadurch beeinflusst, indem die Messgröße auch noch das Messgerät
versorgen muss.
> Hat das was mit den internen Pull up Widerständen zu tun?> Kann das sein?
Nein.
SChliess endlich Avcc an.
Und dann liest du das Assembler Tutorial von Anfang an durch. Auch wenn
du nicht Assembler programmierst, so finden sich darin viele Hinweise,
die auch für dich als C-Programmierer wichtig sind.
Und ich klinke mich jetzt aus.
Hallo,
AVCC ist angeschlossen, habe auch noch einen Fehler im Prog gehabt, habe
die interne Ref Spannung verwendet, was ja falsch ist, ich lege ja eine
externe an.
Ich habe bis zu 5V an PCB0 aber einen Strom von 20mA. Die LED macht nix,
nicht mal aufleuchten.
LG
Karl heinz Buchegger schrieb:
> Und ich klinke mich jetzt aus.
Respekt für deine Engelsgeduld.
@Hans Peter:
Is nicht böse gemeint, aber n bisschen mehr Eigeninitiative wär schon
angebracht gewesen.