Forum: Compiler & IDEs Schieberegister über zwei Ports


von Hammersn (Gast)


Lesenswert?

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

von MaWin (Gast)


Lesenswert?

Wird schon gehen, wird halt rasend schnell laufen.

von Floh (Gast)


Lesenswert?

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
}

von Jan H. (hammersn)


Lesenswert?

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

von Magnus M. (magnetus) Benutzerseite


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Jan H. (hammersn)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Jan H. (hammersn)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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?

von Jan H. (hammersn)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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?

von Jan H. (hammersn)


Lesenswert?

Ahhh ich bin doch dumm :D

jetzt aber es müsste j>=1 heißen richtig?

Mahlzeit

Jan

von Karl H. (kbuchegg)


Lesenswert?

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)

von Magnus M. (magnetus) Benutzerseite


Lesenswert?

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

von Jan H. (hammersn)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Entwickler (Gast)


Lesenswert?

>> 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 ?

von Jan H. (hammersn)


Lesenswert?

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

von Entwickler (Gast)


Lesenswert?

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.

von Jan H. (hammersn)


Lesenswert?

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

von Entwickler (Gast)


Lesenswert?

>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.

von Jan H. (hammersn)


Lesenswert?

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

von Entwickler (Gast)


Lesenswert?

>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.

von Jan H. (hammersn)


Lesenswert?

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
Noch kein Account? Hier anmelden.