Guten Morgen zusammen,
ich möchte gern meine externe lct_tools.c Datei so ändern, dass ich das
LCD_Display an beliebige Ports anschließen kann.
Im Augenblick sieht es so aus, dass diese Routine für PORTD programmiert
ist.
Ein umstecken des Display auf PORTB würde bedeuten die ganze Datei
umzuschreiben.
Ich habe einen Lösungsansatz. Haltet ihr den für so richtig.
Hier ein kleines Beispielprogramm.
int main(void)
{
DDRC=0x00; //als eingang setzen
PORTC=0xff; // Eingang auf High gesetzt
DDRD=0xff; //als Ausgang setzen
PORTD=0xff; //Ausgang auf High setzen LED leuchtet
#define Eingabeport PINC //hiermit kann ich an einer Stelle den PORT
ändern
#define WARTEBIT0 PC0 diese müssen aber jedes Mal auch dennoch
geändert werden, oder
#define WARTEBIT1 PC1
#define WARTEBIT2 PC2
#define WARTEBIT3 PC3
#define WARTEBIT4 PC4
#define WARTEBIT5 PC5
#define WARTEBIT6 PC6
#define WARTEBIT7 PC7
while(1)
{
alter Code, den man nicht flexibel ändern kann
/* while( (!(PINA & (1<<PA6)))==0 && (!(PINA & (1<<PA7)))==0 &&
(!(PINA & (1<<PA5)))==0 && (!(PINA & (1<<PA4)))==0 && (!(PINA &
(1<<PA3)))==0 && (!(PINA & (1<<PA2)))==0 && (!(PINA & (1<<PA1)))==0 &&
(!(PINA & (1<<PA0)))==0 );
_delay_ms(1000);
PORTD ^= ( 1 << PD6 );
_delay_ms(1000);
*/
neuer Code, den man relativ flexibel ändern kann
while( (!(Eingabeport & (1<<WARTEBIT0)))==0 && (!(Eingabeport &
(1<<WARTEBIT1)))==0 && (!(Eingabeport & (1<<WARTEBIT2)))==0 &&
(!(Eingabeport & (1<<WARTEBIT3)))==0 && (!(Eingabeport &
(1<<WARTEBIT4)))==0 && (!(Eingabeport & (1<<WARTEBIT5)))==0 &&
(!(Eingabeport & (1<<WARTEBIT6)))==0 && (!(Eingabeport &
(1<<WARTEBIT7)))==0 );
_delay_ms(1000);
PORTD ^= ( 1 << PD6 );
_delay_ms(1000);
}
}
Einen schönen Tag wünscht Matthias.
Julian Baugatz schrieb:> Wenn du nur den Port wechseln willst, dann mußt du nur den eingabeport> per define ändern.>> 1<<PC0 = 1<<0 = 1<<PD0
Hallo Julian,
danke für die Antwort.
achso 1<<PA6 muss ich dann nicht auch jedes Mal ersetzen. sondern ich
schreibe gleich 1<<6 das steht dann für in diesem Fall PA6
vielen Dank für Deinen Tipp.
Dann kann ich mich jetzt ran machen und die Routine umschreiben.
Einen schönen Tag wünsche ich noch.
Julian Baugatz schrieb:> Wenn du nur den Port wechseln willst, dann mußt du nur den eingabeport> per define ändern.>> 1<<PC0 = 1<<0 = 1<<PD0
Hallo,
bei dem folgenden Beispiel habe ich Deinen Tipp umgesetzt und er hat
funktioniert.
Die PORTrichtung muss ich dennoch jedes Mal umändern, wenn ich einen
anderen PORT über #define Eingabeport definiere, oder?
DDRB=0x00; muss ich dann dennoch in z.B. DDRA=0x00 ändern
Viele Grüße,
Matthias.
int main(void)
{
lcd_ini();
#define Eingabeport PINB
DDRB=0x00; //als Eingang
PORTB=0xff; // auf high gesetzt
lcd_gotoline(2);lcd_writezahl(result);
while(1)
{
if (!(Eingabeport &(1<<0))) //Wenn PIN low wird, dann erhöhe um 1
und gib das Ergebnis aus
{
result=result+1;
lcd_gotoline(2);lcd_writezahl(result);
}
}
Matthias H. schrieb:> schreibe gleich 1<<6 das steht dann für in diesem
Das ist doch eine Konstante, dann kannst du doch gleich 0x40 oder
0b01000000 schreiben. Der Kompiler sollte das aber eh erkennen und genau
das daraus machen. Warum vergleichst du alle Bits einzeln? Das geht auch
mit einem 10tel des Codes und übersichtlicher wird es dann auch.
M2 schrieb:> Matthias H. schrieb:>> schreibe gleich 1<<6 das steht dann für in diesem>> Das ist doch eine Konstante, dann kannst du doch gleich 0x40 oder> 0b01000000 schreiben. Der Kompiler sollte das aber eh erkennen und genau> das daraus machen. Warum vergleichst du alle Bits einzeln? Das geht auch> mit einem 10tel des Codes und übersichtlicher wird es dann auch.
Hallo,
danke für Deine Hilfe. Ja, ich war mir auhc unsicher, ob es so elegant
ist.
Leider verstehe ich nicht ganz was Du meinst, nicht das wir gleich
aneinander vorbei reden.
Was soll das (1<<0) den bewirken?
Prüfung, ob der PIN1 von z.B. PORT B gedrückt wurde. Und da ich alle
PINs( oder manchmal auch nur bestimmte) prüfen möchte,
frage ich alle so in einer Zeile ab. so wie hier.
while( (!(Eingabeport & (1<<0)))==0 && (!(Eingabeport & (1<<1)))==0 &&
(!(Eingabeport & (1<<2)))==0 && (!(Eingabeport & (1<<3)))==0 &&
(!(Eingabeport & (1<<4)))==0 && (!(Eingabeport & (1<<5)))==0 &&
(!(Eingabeport & (1<<6)))==0 && (!(Eingabeport & (1<<7)))==0);
das geht bestimmt noch besser, habe aber Deine Ausführungen nicht so
verstanden
Matthias H. schrieb:
> schreibe gleich 1<<6 das steht dann für in diesem
Das ist doch eine Konstante, dann kannst du doch gleich 0x40 oder
0b01000000 schreiben. Der Kompiler sollte das aber eh erkennen und genau
das daraus machen. Warum vergleichst du alle Bits einzeln? Das geht auch
mit einem 10tel des Codes und übersichtlicher wird es dann auch.
Kannst du das bitte nochmal ..
Viele Grüße,
MAtthias.
Matthias H. schrieb:> Was soll das (1<<0) den bewirken?>> Prüfung, ob der PIN1 von z.B. PORT B gedrückt wurde. Und da ich alle> PINs( oder manchmal auch nur bestimmte) prüfen möchte,> frage ich alle so in einer Zeile ab. so wie hier.
Das << bewirkt eine Bitverschiebung also werden bei 1<<0 alle Bit um
Null stellen nach links geschoben. Somit wird aus 1 (Binär 0b00000001)
genau 1^(Binär 0b00000001).
Bei 1<<4 werden alle Bits um 4 stellen nach links geschoben so wird aus
0b00000001 eben 0b00010000 und das entspricht Hexadezimal 0x10 oder
Dezimal 16.
> while( (!(Eingabeport & (1<<0)))==0 && (!(Eingabeport & (1<<1)))==0 &&>(!(Eingabeport & (1<<2)))==0 && (!(Eingabeport & (1<<3)))==0 &&>(!(Eingabeport & (1<<4)))==0 && (!(Eingabeport & (1<<5)))==0 &&>(!(Eingabeport & (1<<6)))==0 && (!(Eingabeport & (1<<7)))==0);
Wenn ich das richtig sehe, willst du hier wissen ob alle Bits vom
Eingabeport 0 sind. Bei mir sehe das so aus:
while(!Eingabeport)
oder wolltest du wissten ob alle Bits 1 sind dann so
while(Eingabeport == 0b11111111)
Hallo,
while(!Eingabeport)
oder wolltest du wissten ob alle Bits 1 sind dann so
while(Eingabeport == 0b11111111)
ja das wollte ich beides wissen.
ich habe das dank deines vorherigen Tipps so gelöst.
while(!(Eingabeport==0xff))
damit ist mir jetzt geholfen.
Viele Grüße und noch einen schönen Tag wünscht,
Matthias.
Nochmal zu deinem Code
>(!(Eingabeport & (1<<2)))==0
Kürzen wir das mal
(!(Eigabeport & 0b00000100))==0
(Eigabeport & 0b00000100)==1
PS: Schau dir auch mal die XOR Verknüpfungen an, damit bann man auch
schöne Bitvergleich erstellen. Versuche mal raus zu finden was dieser
Code macht:
while (!(Eigabeport ^ 0b01010100))
ok, mache ich heute noch.
habe ja auch ein C-Buch Mikrocomputertechnik mit Controllern der Atmel
AVR RISC-Familie
Da steht auhc einiges drüber drin.
So nebenbei gefragt, ich beschäftige mich ja gerade mit Tastern ein und
Ausgabe.
Ist es normal, dass sich der Atmega32 am PORTC nicht ganz normal
verhält?
Wenn ich die Datenrichtung auf high und ausgang setze, dann sind dennoch
nciht alle auf high,
genauso, wenn ich die auf Eingang setze, alle scheinen nicht zu
funktionieren.
hier eine konkrete messung
Alle auf low geschaltet, eingang oder Ausgang kann ich jetzt nciht mehr
sagen
PC2,3 ist auf high
PC4 schwankt,
PC5 ist auf high
Das ist doch merkwürdig. Hast Du eine Ahnung? Ich habe gehört man kann
den Atmel konfigurieren (Fuse) und somit die Pins ändern..
Ich kann mich jetzt erst später wieder melden. Würde mich aber dennoch
über eine Antwort freuen.
Viele Grüße,
Matthias.
Eventuell unqualifiziert da ich gerade nur oberflächlich ins Datenblatt
geschaut habe:
Im Kapitel "Alternate Functions of Port C" des Atmega32 Datenblatts
steht in Tabelle 29, dass PC7 bis PC4 scheinbar für JTAG genutzt werden,
wenn die Fuse JTAGEN gesetzt ist. Nachschauen ob das so ist, kannst du
einfach über das entsprechende Tab in AVR-Studio wenn du dich auf den
Controller (ich denke mal über die ISP-Schnittstelle) verbunden hast.
M2 schrieb:> Nochmal zu deinem Code>>>(!(Eingabeport & (1<<2)))==0>> Kürzen wir das mal>> (!(Eigabeport & 0b00000100))==
M2, dein Vorschlag die (1 << Pin) Schreibweise durch die Bitschreibweise
zu ersetzen ist kontraproduktiv.
Unmengen von Leute hier im Forum versuchen alles Mögliche um die Leute
möglichst zu dieser Shift-Schreibweise zu bringen.
Matthias: Deine Shift-Schreibweise ist schon in Ordnung. Dein Compiler
setzzt das schon richtig um. Bzw. er tut etwas noch viel besseres: Er
kennt diese Schreibweise und optimiert sie wenn möglich zu bestimmte
Bit-Setz bzw. Bit-Lösch Operationen, wenn dies geht.
> while(!(Eingabeport==0xff))>> damit ist mir jetzt geholfen.
Damit ist deine ganze schöne Flexibilität, um die es dir in erster Linie
ging, wieder beim Teufel
1
#define TASTER_PORT PORTC
2
#define TASTER_PIN PINC
3
#define TASTER_DDR DDRC
4
5
#define TASTE_LINKS PC0
6
#define TASTE_RECHTS PC1
7
#define TASTE_ENTER PC7
8
9
#define LED_PORT PORTC
10
#define LED_DDR DDRD
11
12
#define LED_ROT PC2
13
#define LED_GRUEN PC4
14
15
intmain()
16
{
17
TASTER_DDR&=~((1<<TASTE_LINKS)|// die Portbits für die Tasten
18
(1<<TASTE_RECHTS)|// auf Eingang stellen
19
(1<<TASTE_ENTER));// (sind sie an und für sich sowieso per Default)
20
21
TASTER_PORT|=(1<<TASTE_LINKS)|// Pullups für die Tasten einschalten
22
(1<<TASTE_RECHTS)|
23
(1<<TASTE_ENTER);
24
25
LED_DDR|=(1<<LED_ROT)|// die Ausgaenge für die LED
So kannst du nur in den #define festlegen, wo welche Taste bzw. LED
angeschlossen wird. Wobei hier noch davon ausgegangen wird, dass die
jeweilige Bauteilkategorie alle am selben Port angeschlossen ist. Wenn
man das noch feiner braucht, dann muss man noch mehr #define einführen,
zb für jede LED eine eigene Port/DDR Definition und im Code dann
entsprechend aufdröseln.
Mit noch ein paar #define mehr kann man zb die Vorgang des Bit-Setzens
bzw. Bit-löschens zb für LED hinter einem Makro verstecken, so dass sich
der Code in der Hauptschleife so liest
jetzt hat man einen lesbaren Code, der durch die #define zudem noch gut
an andere Gegebenheiten angepasst werden kann.
Bei Makros (#define) ist es meistens eine gute Idee, wenn man sich 2
Dinge hinschreibt:
* wie schaut der Code ursprünglich aus
* wie hätte ich gerne, dass der Code aussieht
Aus dem Vergleich der beiden folgt dann relativ unmittelbar, durch
welche Textersetzung Punkt 2 aus Punkt 1 erhalten werden kann. Und damit
hat man dann schon meist das Makro fast vollständig.
Das compilierbare Ziel
1
LED_PORT&=~(1<<LED_ROT);
kann man aus
1
LED_ON(LED_ROT);
erzeugen, indem man den Präprozessor anweist mittels
1
#define LED_ON(led) LED_PORT &= ~( 1 << led )
die entsprechende Textersetzung durchzuführen. Du schreibst das für dich
lesbare
1
LED_ON(LED_ROT);
und durch Anwenden aller Textersetzungen entsteht für den Compiler dann
der Code
1
PORTC&=(1<<PC2);
welches er in eine "Clear Bit 2 an PORTC"-Assembler-Instruktion
übersetzt.
Fridolin schrieb:> Eventuell unqualifiziert da ich gerade nur oberflächlich ins Datenblatt> geschaut habe:> Im Kapitel "Alternate Functions of Port C" des Atmega32 Datenblatts> steht in Tabelle 29, dass PC7 bis PC4 scheinbar für JTAG genutzt werden,> wenn die Fuse JTAGEN gesetzt ist. Nachschauen ob das so ist, kannst du> einfach über das entsprechende Tab in AVR-Studio wenn du dich auf den> Controller (ich denke mal über die ISP-Schnittstelle) verbunden hast.
Hallo Fridolin,
hat geklappt. Nachdem ich die Jtag Schnittstelle in den Fuses
deaktiviert habe, konnte ich die PORTC PINs problemlos benutzen.
viele Grüße,
Matthias.
Karl Heinz Buchegger schrieb:> M2, dein Vorschlag die (1 << Pin) Schreibweise durch die Bitschreibweise> zu ersetzen ist kontraproduktiv.>> Unmengen von Leute hier im Forum versuchen alles Mögliche um die Leute> möglichst zu dieser Shift-Schreibweise zu bringen.
Ich bin der Auffassung, Code muss übersichtlich sein. Und das ist die
1000fache 1<<x Schreibweise nicht (Zumindes bin ich der Meinung, du
kannst es ja anders sehen). Und dann die invertierung und der Vergleich
mit 0. Sicherlich kann man das 0xff noch anders ausdrücken mit
ergendwelchen Konstanten.
M2 schrieb:> while( (!(Eingabeport & (1<<WARTEBIT0)))==1 && (!(Eingabeport &> (1<<WARTEBIT1)))==0 && (!(Eingabeport & (1<<WARTEBIT2)))==0 &&> (!(Eingabeport & (1<<WARTEBIT3)))==0 && (!(Eingabeport &> (1<<WARTEBIT4)))==1 && (!(Eingabeport & (1<<WARTEBIT5)))==0 &&> (!(Eingabeport & (1<<WARTEBIT6)))==1 && (!(Eingabeport &> (1<<WARTEBIT7)))==0 );>> @Karl Heinz Buchegger>> (Code verändert)>> Sag mir mal in 1 Sekunde welchen Pegel Wartebit 5 haben soll
Formatier es ordentlich, dann sieht man das auch
1
while((!(Eingabeport&(1<<WARTEBIT0)))==1&&
2
(!(Eingabeport&(1<<WARTEBIT1)))==0&&
3
(!(Eingabeport&(1<<WARTEBIT2)))==0&&
4
(!(Eingabeport&(1<<WARTEBIT3)))==0&&
5
(!(Eingabeport&(1<<WARTEBIT4)))==1&&
6
(!(Eingabeport&(1<<WARTEBIT5)))==0&&
7
(!(Eingabeport&(1<<WARTEBIT6)))==1&&
8
(!(Eingabeport&(1<<WARTEBIT7)))==0)
9
;
abgesehen davon, dass deine Vergleiche mit den Konstanten
kontraproduktiv sind. In C ist weniger manchmal eben mehr. Aber das
weniger muss auch an der richtigen Stelle sitzen.
M2 schrieb:> Karl Heinz Buchegger schrieb:>> M2, dein Vorschlag die (1 << Pin) Schreibweise durch die Bitschreibweise>> zu ersetzen ist kontraproduktiv.>>>> Unmengen von Leute hier im Forum versuchen alles Mögliche um die Leute>> möglichst zu dieser Shift-Schreibweise zu bringen.>> Ich bin der Auffassung, Code muss übersichtlich sein.
Eben.
Und da ist die << Schreibweise allemal besser als eine Binärzahl. Von
Wartungsfreundlicher reden wir erst mal gar nicht.
Was ist leichter zu lesen bzw zu verstehen
1
LED_PORT&=~(1<<ALARM_LED);
2
3
bzw.
4
5
LED_ON(ALARM_LED);
oder
1
POTRD&=0b11111011;
Was ist leichter zu verändern, falls die LED in der nächsten
Programmversion umziehen muss, weil der Pin wegen seiner Sonderfunktion
für etwas anderes gebraucht wird?
M2 schrieb:> Achso und zeige mir mal den Assembler-Code dazu.
So oft kommt das nicht vor, dass man tatsächlich alle 8 Bit eines Ports
in einer Abfrage berücksichtigen muss. Und selbst wenn, kann man das
immer noch mit einer ganz anderen Schreibweise berücksichtigen
solange loopen, wie WARTEBIT1 und WARTEBIT4 und WARTEBIT5 auf 1 sind
(alle anderen Pins bleiben unberücksichtigt).
Braucht man: Solange warten wie von allen 8 Bits (also alle
berücksichtigt) die Pins WARTEBIT1, WARTEBIT4 und WARTEBIT5 auf 1 sind
und alle anderen auf 0, dann
Der Compiler macht dann wieder deine heiß geliebte Hex-Zahl drauss. Im
Assembler Output macht das daher keinen Unterschied zu der von dir
propagierten Variante.
was macht wohl dieser Code auf logischer Ebene?
1
while(PIND&0x43)
2
;
recht viel kann man darüber nicht sagen, ausser dass er solange wartet,
solange 3 bestimmte Pins am Port D auf 1 sind. Aber warum und wieso,
Fehlanzeige
Wohingegen mir der Code
1
while(SENSOR_PIN&(1<<OVERHEATED|
2
1<<PRESSURE_TOO_LOW|
3
1<<DOOR_OPEN))
4
;
schon eine ganz klare Vorstellung davon gibt, warum da eine Schleife
ist, und worauf da eigentlich gewartet wird bzw. welche Bedingungen
erfüllt sein müssen, damit es im Programm weiter geht.
Die Information, dass am Pin 0 der Temperatur Sensor seine Überhitzung
meldet, ist hingegen Information, die ich vom logischen Standpunkt aus
gesehen an dieser Stelle nicht brauche. Das sind Konfigurationswerte,
deren exakter Zahlenwert an dieser Stelle ziemlich uninteressant ist
bzw. sein sollte, solange er nur im gültigen Bereich liegt.
das ist nun wirklich syntaktischer Zucker. In beiden Fällen erkennt man
rasch, welches Signal welchem Pin zugeordnet ist UND welchen Sinn die
while-Schleife hat.
UND ... (was dir wichtig ist)
... man zahlt keinen Runtime-Penalty gegenüber
1
while(PIND&0x43)
2
;
Es ist nur eine andere Schreibweise, die in identischem Code mündet, die
aber einige dokumentarische Vorteile hat, wie du hoffentlich aus den
Beispielen gesehen hast.
Allerdings: ein wenig Mühe muss man sich beim Hinschreiben schon geben.
Ist aber so schlimm auch wieder nicht. Eine typische Codezeile wird 2
bis 3 mal gschrieben (inkl Korrekturen), wird aber typischerweise mehr
als 10 mal gelesen. D.h. das bischen Mehraufwand beim Tippen macht sich
durch schnelleres Coderfassen beim Lesen mehr als bezahlt.
Karl Heinz Buchegger schrieb:> #define OVERHEATED (1 << 0)> #define PRESSURE_TOO_LOW (1 << 1)> #define DOOR_OPEN (1 << 6)>> ...>>> while( SENSOR_PIN & ( OVERHEATED |> PRESSURE_TOO_LOW |> DOOR_OPEN ) )> ;
Mit dieser Schreibweise bin ich auch einverstanden, das ist wieder
schnell lesbar ;).
Wobei ich es so geschrieben hätte
#define OVERHEATED (1 << 0x01)
#define PRESSURE_TOO_LOW (1 << 0x02)
#define DOOR_OPEN (1 << 0x40)
Aber das ist geschmacks Sache und soll jeder so machen wie er mag. Im
Programm selber sieht es dann ja identisch aus.
M2 schrieb:> #define OVERHEATED 0x01> #define PRESSURE_TOO_LOW 0x02> #define DOOR_OPEN 0x40>> so meine ich
Das ist aber auch daneben. Bei der Schreibweise von Karl Heinz sieht man
auf den ersten Blick, das es sich bspw. bei DOOR_OPEN um Pin 6 handelt.
Bei Deiner Schreibweise darf man erst wieder rumrechnen. Ich lass lieber
den Compiler rechnen, der macht wenigstens keine Fehler dabei.
... schrieb:> M2 schrieb:>> #define OVERHEATED 0x01>> #define PRESSURE_TOO_LOW 0x02>> #define DOOR_OPEN 0x40>>>> so meine ich>> Das ist aber auch daneben. Bei der Schreibweise von Karl Heinz sieht man> auf den ersten Blick, das es sich bspw. bei DOOR_OPEN um Pin 6 handelt.> Bei Deiner Schreibweise darf man erst wieder rumrechnen.
Das wäre auch mein Einwand gewesen. Ich habs dann aber gelassen, weil
ich 0x40 dann nicht mehr ganz so schlimm finde, auch wenn ich keinen
Vorteil in der Hexzahl zu (1<<6) sehe.
> Ich lass lieber> den Compiler rechnen, der macht wenigstens keine Fehler dabei.
Das seh ich genauso wie du. Lass den Compiler die Routine aufgaben
übernehmen.
Karl Heinz Buchegger schrieb:> Das wäre auch mein Einwand gewesen. Ich habs dann aber gelassen, weil> ich 0x40 dann nicht mehr ganz so schlimm finde, auch wenn ich keinen> Vorteil in der Hexzahl zu (1<<6) sehe.
Ich selbst hab prinzipell auch kein Problem mit hex, wobei ich dann
allerdings eher noch auf oktal zurückgreifen würde. Ich hab aber auch
schon mehr als 25 Jahre damit zu tun.
War mir vorher schon klar das der einwand jetzt kommt ;) . Ich mags halt
so. Das soll jeder so machen wie er mag. Ich komme mit den HEX-Zahlen
gut klar. und wer HEX nicht mag kann auch Binär nehmen und dann sieht
man es wieder auf den ersten Blick.