Hallo ich bin neu hier und hab gleich mal eine Frage ;) ich kenn mich mit microcontrollern und der Programmiersprache C nicht wirklich gut aus. Aber würde mein Programm so arbeiten wie ich will? Ich möchte lediglich ein Schieberegister über zwei Ports ansteuern und ein Byte reinschieben. Für die leute hier sicherlich keine große sache aber da ich noch am Anfang steh schon nicht ganz einfach ;) Am Ende sollte dann ein 8 Kanal Lauflicht rauskommen, klar das das ganze einfachr gehn würde aber mir geht es jez erst mal um das Verständnis von Schieberegistern :) ********************************************************************* #include <avr/io.h> #define F_CPU 8000000UL //CPU Takt = 8MHz #define SR_DDR DDRB //DDRB als SR_DDR definieren #define SR_PORT PORTB //PORTB als SR_PORT definieren #define SR_0 PB0 //PB0 als SR_0 definieren (Clock) #define SR_1 PB1 //PB1 als SR_1 definieren (Data) #define Sprchr 8 //8 Speicher für Schieberegister volatile uint8_t memory[Sprchr]; //8 Speicher für Schieberegister void set_memory (uint8_t i) //Unterprogramm Daten ins SR schieben { uint8_t j; for(j=7; j>=0; j--) //8 Bit ins SR schieben { if((memory[i]>>j) & 1) //Bits jeweils mit 1 verunden SR_PORT |= (1<<SR_1); //wenn Bit=1 SR_1 auf HIGH else SR_PORT &= ~(1<<SR_1); // wenn Bit=0 SR_1 auf LOW SR_PORT |= (1<<SR_0); //HIGH Flanke => schieben SR_PORT &= ~(1<<SR_0); //LOW } } int main (void) { SR_DDR=0xFF; //SR_PORT auf Ausgang und LOW SR_PORT=0x00; uint8_t n=0; memory[0] = 0b00000001; memory[1] = 0b00000010; memory[2] = 0b00000100; memory[3] = 0b00001000; memory[4] = 0b00010000; memory[5] = 0b00100000; memory[6] = 0b01000000; memory[7] = 0b10000000; while(1) set_memory(n); n++; if(n==7) n=0; } ********************************************************************* Wär nett wenn mal jemand drüber schaun könnte und mir Fehler aufdecken könnte. Ich hoff das nichts dabei ist, wo ich ausgelacht werde :D Hab mir auch gleich ein paar Schieberegister bestellt, damit ich das ganze jetzt noch in meinem Urlaub ausprobieren kann. Danke schonmal :) Hammersn
Hammersn schrieb: > void set_memory (uint8_t i) //Unterprogramm Daten ins SR schieben warum übergibst du hier nur den Index,statt direkt die Daten? Es funktioniert zwar so, setzt aber globale Datenspeicher voraus. Wäre nicht nötig, wenn du das z.B. so machen würdest:
1 | void setmemmory(uint8_t data) |
2 | {
|
3 | for(uint8_t i = 7 ; i ; --i) |
4 | {
|
5 | if(data & 0x01) // unterstes Bit überprüfen, LSB first |
6 | SR_PORT |= (1<<SR_1); |
7 | else
|
8 | SR_PORT &= ~(1<<SR_1); |
9 | |
10 | SR_PORT |= (1<<SR_0); //HIGH Flanke => schieben |
11 | SR_PORT &= ~(1<<SR_0); //LOW |
12 | |
13 | data >>=1; //data um eins links schieben für den nächsten Durchlauf |
14 | }
|
15 | }
|
Ah ok danke :) dann kann ich also gleich: setmemory(255) damit alle Schieberegisterports auf HIGH wären. Das macht das ganze auch übersichtlicher :) und eine delay zeit muss ich auch noch einfügen stimmt. Danke für eure Hilfe Hammersn
Welches Schieberegister möchtest du einsetzen? Ein 74x595 beispielsweise benötigt noch ein RCK (Register Clock) um die hineingeschobenen Daten in die Ausgangsregister zu übertragen. Gruß, Magnetus
Noch ein Tip. Bei deinem Code
1 | #define SR_DDR DDRB //DDRB als SR_DDR definieren
|
2 | #define SR_PORT PORTB //PORTB als SR_PORT definieren
|
3 | #define SR_0 PB0 //PB0 als SR_0 definieren (Clock)
|
4 | #define SR_1 PB1 //PB1 als SR_1 definieren (Data)
|
5 | #define Sprchr 8 //8 Speicher für Schieberegister
|
6 | |
7 | |
8 | volatile uint8_t memory[Sprchr]; //8 Speicher für Schieberegister |
9 | |
10 | void set_memory (uint8_t i) //Unterprogramm Daten ins SR schieben |
11 | {
|
12 | uint8_t j; |
13 | for(j=7; j>=0; j--) //8 Bit ins SR schieben |
14 | {
|
15 | if((memory[i]>>j) & 1) //Bits jeweils mit 1 verunden |
16 | SR_PORT |= (1<<SR_1); //wenn Bit=1 SR_1 auf HIGH |
17 | else
|
18 | SR_PORT &= ~(1<<SR_1); // wenn Bit=0 SR_1 auf LOW |
19 | |
20 | SR_PORT |= (1<<SR_0); //HIGH Flanke => schieben |
21 | SR_PORT &= ~(1<<SR_0); //LOW |
22 | |
23 | }
|
24 | }
|
hast du dir zwar #define für die Pins gemacht, an denen das SR angeschlossen ist, aber deine Namen sind nich so toll Warum nennst du den einen Pin SR_0? Wenn das der Clock Anschluss ist, dann nenn ihn doch auch so
1 | #define SR_CLOCK PB0
|
2 | #define SR_DATA PB1
|
dann sieht das in der Verwendung dann auch gleich so aus, dass in den Namen schon der Hinweis enthalten ist, welcher Pin denn da umgeschaltet wird
1 | #define SR_DDR DDRB
|
2 | #define SR_PORT PORTB
|
3 | #define SR_CLOCK PB0
|
4 | #define SR_DATA PB1
|
5 | |
6 | #define Sprchr 8 //8 Speicher für Schieberegister
|
7 | |
8 | volatile uint8_t memory[Sprchr]; //8 Speicher für Schieberegister |
9 | |
10 | void set_memory (uint8_t i) //Unterprogramm Daten ins SR schieben |
11 | {
|
12 | uint8_t j; |
13 | for(j=7; j>=0; j--) //8 Bit ins SR schieben |
14 | {
|
15 | if((memory[i]>>j) & 1) //Bits jeweils mit 1 verunden |
16 | SR_PORT |= (1<<SR_DATA); //wenn Bit=1 SR_1 auf HIGH |
17 | else
|
18 | SR_PORT &= ~(1<<SR_DATA); // wenn Bit=0 SR_1 auf LOW |
19 | |
20 | SR_PORT |= (1<<SR_CLOCK); //HIGH Flanke => schieben |
21 | SR_PORT &= ~(1<<SR_CLOCK); //LOW |
22 | |
23 | }
|
24 | }
|
Und noch was: Kommentiere nicht das was sowieso schon im Code steht. Kommentiere das was nicht im Code steht! Kommentare sollen erklären warum etwas passiert, nicht wie es passiert. Das
1 | if((memory[i]>>j) & 1) //Bits jeweils mit 1 verunden |
hier etwas mit 1 verundet wird, das sehe ich auch im Code. Dazu brauch ich keinen Kommentar. Viel wichtiger ist: warum machst du das? Generell solltest du bei jedem Kommentar überlegen, ob das was du im Kommentar hinschreiben willst wirklich notwendig ist, oder ob du nicht den Code so umändern kannst, dass du den Kommentar gar nicht brauchst. Ein guter Code ist sein eigener Kommentar! Kommentare sind dann nur noch notwendig um Verfahren, Algorithmen oder nähere Erleuterungen zu den Algorithmen zu geben. #define SR_1 PB1 //PB1 als SR_1 definieren (Data) Im Code steht das etwas definiert wird, genau darum steht dort ja #define. Daher braucht das kein Mensch im Kommentar. Was wird definiert? SR_1 wird als Preprozessor Konstante eingeführt. Im Kommentar erfährt man dann, dass es sich dabei um den DATA Anschluss des Schieberegisters handelt. Nur: wozu? Wenn du das #define gleich #define SR_DATA PB1 nennst, dann brauchst du den Kommentar nicht mehr. Alles was im Kommentar steht, steht jetzt im Code selber! Da fällt mir noch etwas auf:
1 | uint8_t j; |
2 | for(j=7; j>=0; j--) //8 Bit ins SR schieben |
überleg mal, welche Eigenschaft die aktuelle Zahl in j haben müsste, damit diese Schleife jemals aufhört. Und dann überleg, ob ein uint8_t diese Eigenschaft jemals haben kann.
Ich möchte das MC1 4021 verwenden aber ich glaub laut Datenblatt brauch ich bei diesem nur die Anschlüsse Clock und Ds. Gruß Hammersn
Jan Hammer schrieb: > Ich möchte das MC1 4021 verwenden aber ich glaub laut Datenblatt brauch > ich bei diesem nur die Anschlüsse Clock und Ds. Das ist dann keine gute Wahl. Nimm ein Schieberegister mit einem dezidiertem Output-Latch. Das ist universeller einsetzbar. Bei einem SR ohne Ausgangs-Latch hast du immer das Problem, dass du den kompletten Schiebevorgang auch an den Ausgangspins elektrisch siehst. Bei manchen Anwendungen spielt das keine Rolle. Bei vielen aber schon. Du hast dann während eines Schiebevorgangs keine stabilen Verhältnisse an den Pins.
Danke für die Tipps Karl heinz, das mit dem Code schreiben hab ich wirklich noch nicht so draußen aber du hast recht so ist das ganze übersichtlicher und meine Portnamen verwirren nicht so ;) Was du mir allerdings am Ende sagen möchtest habe ich nicht ganz verstanden. Meine Schleife wird doch 8 Mal durchlaufen oder? j fängt mit der Zahl 7 an und wird in jedem durchgang um eins verringert bis j den wert 0 erreicht. Oder müsste es --j heißen? Freundliche Grüße Hammersn
Jan Hammer schrieb: > Meine Schleife wird doch 8 Mal durchlaufen oder? Nein, wird sie nicht. > j fängt mit der Zahl 7 an und wird in jedem durchgang um eins verringert > bis j den wert 0 erreicht. j wird 0. Das ist schon richtig. Aber deswegen hört ja die Schleife nicht auf. Die Laufbedingung lautet: j >= 0 und solange diese Bedingung zutrifft, wird die Schleife wiederholt. Wenn j 0 geworden ist, dann ist ja die Bedingung 0 >= 0 erfüllt, denn j ist definitiv gleich 0 und damit wird die Schleife auf jeden Fall noch einmal ausgeführt. Nur: welchen Wert müsste denn j beispielsweise haben, damit diese Bedingung nicht mehr zutrifft und die Schleife daher abgebrochen wird? Kann j diesen Wert annehmen?
Ah okay jez versteh ich :) uint8_t kann ja nicht negativ werden aber von meiner Laufbedinung her müsste j negativ werden damit die Bedingung efüllt ist und meine Schleife abgebrochen wird. Ich müsste also j=0 schreiben oder? Danke&Grüße Hammersn
Jan Hammer schrieb: > Ah okay jez versteh ich :) > uint8_t kann ja nicht negativ werden aber von meiner Laufbedinung her > müsste j negativ werden damit die Bedingung efüllt ist Jetzt hast du es verstanden :-) > und meine > Schleife abgebrochen wird. > Ich müsste also j=0 schreiben oder? Überleg mal. Die SChleife wird solange wiederholt, wie die Laufbedingung zutrifft. j beginnt mit 7. Ist 7 gleich 0?
Ahhh ich bin doch dumm :D jetzt aber es müsste j>=1 heißen richtig? Mahlzeit Jan
Jan Hammer schrieb: > Ahhh ich bin doch dumm :D > > jetzt aber es müsste j>=1 heißen richtig? Und welche Werte kann j dann annehmen? Sind es die, die du haben willst? :-) (Du beginnst momentan mit Aus-der-Hüfte-Schnellschussaktionen. So was geht meistens ins Auge)
Karl heinz Buchegger schrieb: > (Du beginnst momentan mit Aus-der-Hüfte-Schnellschussaktionen. So was > geht meistens ins Auge) Das gute alte "trial and error" Prinzip ;o) Gruß, Magnetus
j kann meines erachtens nach 1 bis 255 werden oder? Wo ist diesmal mein Denkfehler? Ich geh mal an die frische luft vielleicht kann ich dann später wieder besser denken ;) Grüße Hammersn
Jan Hammer schrieb: > j kann meines erachtens nach 1 bis 255 werden oder? prinzipiell schon. Aber welche Werte wird j in for( j = 7; j >= 1; --j ) annehmen? Die sind es doch die dich interessieren, weil du mit diesen Werten innerhalb der Schleife etwas machst.
>> Ich möchte das MC1 4021 verwenden aber ich glaub laut Datenblatt brauch >Das ist dann keine gute Wahl. >Nimm ein Schieberegister mit einem dezidiertem Output-Latch. Das MC14021 ist ein Schieberegister parallel->seriell zum Einlesen von Daten. Bin ich der Erste, der das merkt und habe jetzt etwas gewonnen ?
So frische Luft geschnappt ;) willst du darauf hinaus, das die Schleife dann nur 7 mal durchlaufen wird und ich dann nur 7 Bit einlesen würde? dann müsste dich die Konstante j also auf 8 inkrementieren oder? ;) @Entwickler: wenn das ein Schieberegister nur zum parallelen einlesen und seriellem ausgeben ist, dann versteh ich das Logig Diagramm nich weil dort der inverter für Ds ja zu den Datenport des D-FlipFlop zeig? Und die Funkion des Pins P/S? Gruß Hammersn
Erst sagen, was ich gewonnen habe :-) Man kann auch diese Schieberegister kaskadieren um 16 oder mehr Bits einzulesen. Dazu schließt man DS an Q8 des Vorgängers an. Aber Du willst ja Daten ausgeben. Das kann man mit einen C4094 (MC14094B) machen; andere nehmen auch 74HC595. Für Deine beiden Portleitungen reicht auch ein 74xx164, der an seinen Ausgängen während des Schiebens immer "Müll" erzeugt.
Okay du hast den Datenblattpokal gewonnen ;) Hmm dann muss ich eben noch einmal bestelln aber dann nehm ich gleich das 74HC595. Shift Register Clear Input ist ja low aktiv und kann ich ja dann einfach auf Vcc legen wenn ich nicht noch einen pin extra zum löschen verwenden möchte. Und dann brauch ich natürlich noch einen Port Pin für Storage Register Clock Input den brauch ich um das Byte endgültig an die Ausgänge auszugeben oder? Da reicht ja dann z. B.:
1 | PORTB |= (1<<PB2); |
2 | PORTB &= ~(1<<PB2); |
Danke für die Hilfe Grüße Hammersn
>Okay du hast den Datenblattpokal gewonnen ;)
Ich nehme aber nur noch Marzipan von Leysieffer (oder auch aus Lübeck),
kein Lebkuchen!
Wenn Du doch noch Portpins frei hast, dann nimm den 3. für Registerclock
und den 4. für Clear.
Wenn nicht, könnte man Clear mit einem PowerOn-Reset ansteuern und mit
Diode, Kondensator und Widerstand aus Clock auch den Registerclock
verzögert aktivieren. Das ist aber Trickserei.
Ich denke das ich den Inhalt des Schieberegisters lösch, indem ich einfach 0x00 hinein schreib das müsste ja auch gehn ;) Da verschwend ich dann lieber einen Pin für Registerclock damit ich nicht rumtricksen muss ;) Grüße Hammersn
>Ich denke das ich den Inhalt des Schieberegisters lösch, indem ich >einfach 0x00 hinein schreib das müsste ja auch gehn ;) Im Prinzip ja, aber... Beim Einschalten werden die Lichter "zufällig" aufflackern, was keinen guten Eindruck macht.
Okay dann über einen Power-On Reset.Auf die Diode, den Kondensator und den Widerstand kommt es dann auch nicht an ;) Grüße Hammersn
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.