Guten Morgen! Ich habe eine ganz kurze Frage, bei der ich mir nicht ganz sicher bin und mir darum einfach ein paar weitere Meinungen einholen will. Vorweg: ich habe vor zwei Schieberegister (HC595)am SPI von einem Atmega8 zu betreiben. An jedem Ausgang der Schieberegister hängt eine LED (15 mA). Jetzt hab ich das so verschaltet, daß die Ausgänge 0-3 an den Anoden von vier LEDs hängen und die Ausgänge 4-7 an den Kathoden der anderen LEDs (wegen max. 70 mA durch Vcc bzw. GND). Wenn ich jetzt ein Byte angezeigt haben möchte und das MSB zuerst übertragen wird muß ich ja die obersten vier Bit invertieren. Und genau DA bin ich mir nicht sicher, wie das geht. Hab das jetzt so implementiert: SPDR = (data ^ 0xF0); Ist das richtig? Mit den Logikbefehlen komm ich immer etwas durcheinander... Und nochwas: im Tutorium wird ja so invertiert: PORTB ^= (1<<PB3); müßte das nicht auch so gehen: PORTB |= !(1<<PB3); Danke schonmal! helle :)
helle schrieb: > Hab das jetzt so implementiert: > > SPDR = (data ^ 0xF0); > Ist das richtig? Mit den Logikbefehlen komm ich immer etwas > durcheinander... Perfekt > Und nochwas: > im Tutorium wird ja so invertiert: PORTB ^= (1<<PB3); > müßte das nicht auch so gehen: PORTB |= !(1<<PB3); Nein. Wenn schon, dann PORTB |= ~(1<<PB3); Aber auch das toggelt nicht, sondern setzt alle Bits in PORTB ausser PB3 (bei PB3 hängt es davon ab, welchen Zustand PB3 vor der Operation hatte. Dieser wird nicht verändert). Einfach mal mit irgendeinem Byte durchspielen und du wirst sehen, was da passiert. ! ist die logische Negierung. Alles was nicht 0 ist wird zu 1. Alles was 0 ist wird zu 1 Das geht aber auf ein Byte als Ganzes und nicht auf einzelne Bits. Du musst unterscheiden zwischen den logischen Operationen und den Bitoperationen. Die logischen Operationen sehen ein Byte als eine Einheit an, die entweder 0 oder nicht 0 ist. zb 5. 5 ist perfekt um als TRUE zu gelten, da es nicht 0 ist. !5 ergibt aber 0. (weil 5 ja nicht 0 war. Daher ist die Negierung dazu die 0) Die Bitoperationen arbeiten auf den einzelnen Bits eines Bytes. log. Operationen && || ! (und oder nicht) Bitoperationen & | ^ ~ (und oder xor nicht)
Oh oh, jetzt hab ich doch noch ein Problem! Hab jetzt alles soweit richtig verdrahtet und ein Testprogramm (Lauflicht, bietet sich ja an) auf den Controller gezogen. Aber: bei dem "Übergang" vom 1. zum 2. Register klappt das nicht so, wie ich mir das vorgestellt hab. Und zwar hat Pin 1 vom zweiten SR immer den gleichen Zustand wie der letzte Pin vom ersten SR. Ich hab im Tutorium und im Datenblatt zwar gelesen, daß das eben so ist, aber wie soll das kaskadieren wie im Tutorium dann funktionieren? Ich will 16 Bit per SPI übertragen. Dazu ruf ich die Funktionen so auf:
1 | for(char i = 0; i < 16; i++) |
2 | {
|
3 | // oberes Byte übertragen
|
4 | data = (x >> 8); |
5 | transmit_byte_spi(data); |
6 | |
7 | // unteres Byte übertragen
|
8 | data = (speed & 0xFF); |
9 | transmit_byte_spi(data); |
10 | |
11 | _delay_ms(60); |
12 | x <<= 1; |
13 | }
|
14 | |
15 | int transmit_byte_spi(unsigned char data) |
16 | {
|
17 | // die nötigen I/Os zu Ausgängen machen
|
18 | spi_ddr |= ((1<<serial_data) | (1<<shift_clock) | ~(1<<output_sr)); |
19 | enable_spi; |
20 | disable_spi_pwm; |
21 | |
22 | SPDR = (data ^ 0xF0); |
23 | |
24 | while( !(SPSR & (1<<SPIF)) ) |
25 | {asm("NOP");} |
26 | |
27 | spi_ddr |= (1<<output_sr); |
28 | asm("NOP"); |
29 | |
30 | PORTB &= ~(1<<output_sr); |
31 | asm("NOP"); |
32 | PORTB |= (1<<output_sr); |
33 | asm("NOP"); |
34 | |
35 | disable_spi; |
36 | enable_spi_pwm; |
37 | |
38 | return transmit_cycles; |
39 | }
|
Die Ganzen Macros sind mit #defines hinterlegt. Der Ablauf ist ja eigentlich recht klar: oberes Byte übertragen warten Ausgabe (Puls an RCK) unteres Byte übertragen warten Ausgabe (Puls an RCK) Hab auch schon versucht die Ausgabe erst nach Übertragung der vollen 16 Bit zu machen, aber das hat nix geändert. Der Übergang vom 1. zum 2. SR passt nicht richtig... Wäre echt toll, wenn mir da einer einen Tipp geben könnt! Danke, helle
woz denn beide enden der led auf SRs? häng doch das eine an masse oder plus.
Das hier spi_ddr |= ((1<<serial_data) | (1<<shift_clock) | ~(1<<output_sr)); macht nicht das was du denkst. Man kann ein Bit nicht mit einem | löschen. Tu dir selbst einen Gefallen: Konfiguriere die DDRx einmal ganz am Programmanfang und lass sie dann in Ruhe! Du 'künstelst' im Moment zuviel noch ehe die Funktinoalität grundsätzlich steht.
Hi! Sorry, ich weiß grad nicht, was du meinst. Wie die LEDS angeklemmt sind steht in dem ersten Post. 4 pro SR activ-high, und vier sind active-low. Das ist die Schaltung, wie unter http://www.mikrocontroller.net/articles/AVR-Tutorial:_Schieberegister Nur 1) genau umgekehrt, also die Pins 0-3 active-high und die Pins 4-7 active-low, und 2) um ein weiteres SR erweitert.
@Karl Heinz: ja, danke für den Hinweis. Das war nicht so gemeint. Eigentlich sollte der Pin output_sr (s.o.) auch gesetzt werden. Ich fummel immer an den DDRx-Registern rum, damit sie auch garantiert an der richtigen Stelle im Programm die richtige Richtung haben. Hab es korrigiert, aber daran lag es nicht. Hab davon mal ein Video gemacht. So richtig erklären kann ich es mir noch nicht...
helle schrieb: > ja, danke für den Hinweis. Das war nicht so gemeint. Eigentlich sollte > der Pin output_sr (s.o.) auch gesetzt werden. Ich fummel immer an den > DDRx-Registern rum, damit sie auch garantiert an der richtigen Stelle im > Programm die richtige Richtung haben. Wie gesagt: Setzte sie einmal am Programmanfang. Sonst landest du nämlich ganz schnell in der Situation, dass das DDR falsch steht und du massenhaft Code durchforsten musst, um rauszufinden, wo du dich vertan hast. Setzt du sie aber nur am Anfang, dann brauchst du auch nur an einer Stelle kontrollieren. (Natürlich gibt es auch Ausnahmen. Wenn ein Pin zwischendurch kurz umgeschaltet werden muss, wie zb in einem TWI Interface) > Hab es korrigiert, aber daran lag es nicht. Ist mir beim drüberlesen nur aufgefallen.
Ich habe irgendwie so das Gefühl, daß der logische Ablauf bei mir noch nicht ganz richtig ist. Aber ich komm einfach nicht drauf, wo das sei könnte. Mache ich noch einen Fehler bei der Ausgabe der SR-Werte? Mir kommt das eigentlich richtig vor. Das durchschieben übernimmt ja das CLK-Signal vom SPI und wenn das fertig übertragen hat (also immer nach dem 8. bit) geb ich das aus. Oder? In dem Video entsprechen die LEDs von links nach rechts den Bits 0-15 von der int-Variablen, die Ausgegeben werden soll. Im Moment steh ich aufm Schlauch... VG, helle
Sorry, ich muß nochmal nerven, weil ich im Moment echt nicht so richtig weiter komme. Es geht immernoch um das Ansteuern von zwei kaskadierten Schieberegistern via SPI. Der Übergang vom 1. zum 2. Schieberegister will einfach nicht so richtig funktionieren, obwohl ich schon mit den CPOL- und CPHA-Bits gespielt habe, wie unter http://www.mikrocontroller.net/articles/Porterweiterung_mit_SPI beschrieben. Habe nochmal meinen vollständigen Quellcode und zwei Videos beigefügt. Das erste Video ist mit CPOL=CPHA=0, das zweite mit CPOL=CPHA=1.
1 | #define serial_data PB3
|
2 | #define shift_clock PB5
|
3 | #define output_sr PB2
|
4 | #define enable_spi (SPCR |= (1<<SPE))
|
5 | #define disable_spi (SPCR &= ~(1<<SPE))
|
6 | |
7 | void init_ports() |
8 | {
|
9 | DDRB = 0xFF; // Output for SPI |
10 | |
11 | PORTB |= (1<<output_sr); |
12 | }
|
13 | |
14 | void init_spi() |
15 | {
|
16 | // controller is SPI-"master", communication mode as in:
|
17 | // http://www.mikrocontroller.net/articles/Porterweiterung_mit_SPI
|
18 | SPCR |= (1<<SPE); // enable SPI |
19 | SPCR |= (1<<MSTR); |
20 | //SPCR |= (1<<CPOL);
|
21 | //SPCR |= (1<<CPHA);
|
22 | |
23 | SPSR |= (1<<SPI2X); // full speed, fcpu/2 -> 4 MHz |
24 | }
|
25 | |
26 | int main() |
27 | {
|
28 | init_ports(); |
29 | init_spi(); |
30 | |
31 | clear_shift_registers(); |
32 | |
33 | unsigned char data; |
34 | |
35 | while(1) |
36 | {
|
37 | x = 1; |
38 | |
39 | for(char i = 0; i < 16; i++) |
40 | {
|
41 | data = (x >> 8); |
42 | transmit_byte_spi(data); |
43 | |
44 | data = (x & 0xFF); |
45 | transmit_byte_spi(data); |
46 | |
47 | output_sr_latch(); |
48 | |
49 | x <<= 1; |
50 | |
51 | _delay_ms(300); |
52 | }
|
53 | }
|
54 | }
|
55 | |
56 | void output_sr_latch() |
57 | {
|
58 | PORTB &= ~(1<<output_sr); |
59 | asm("NOP"); |
60 | |
61 | PORTB |= (1<<output_sr); |
62 | }
|
63 | |
64 | void clear_shift_registers() |
65 | {
|
66 | transmit_byte_spi(0x00); |
67 | transmit_byte_spi(0x00); |
68 | output_sr_latch(); |
69 | }
|
70 | |
71 | void transmit_byte_spi(unsigned char data) |
72 | {
|
73 | enable_spi; |
74 | |
75 | SPDR = data; |
76 | |
77 | while( !(SPSR & (1<<SPIF)) ) |
78 | {asm("NOP");} |
79 | |
80 | disable_spi; |
81 | }
|
Hoffe nochmal, daß jemand Mitleid hat und da drüberguckt... Danke, Gruß, Helle
Hm, ich finds ein bißchen schade, daß keiner Lust hat mir zu helfen. Obwohl ich versucht habe alle Infaormationen, die dafür wichtig sein könnten, anzugeben. Wenn noch was fehlen sollte mach ich natürlich gern noch mehr Angaben. Aber z.Z. ist bei mir einfach Ende. Und wenn man allein nicht weiterkommt, ist doof, kennt ihr ja bestimmt auch... Naja, ok, ich probier noch etwas rum...
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.