Hallo, Ich beschäftige mich gerade das erste mal mit SPI. Ich benutze Codevision einen Mega8515 und einen MAX7221 7-Seg-Treiber. (http://www.datasheetcatalog.com/datasheets_pdf/M/A/X/7/MAX7221.shtml) Mein einziger Erfolg bisher war, alle Segmente zum Leuchten zu brigen. Erstens bin ich mir nämlich nicht sicher was ich bei Clock Phase und Clock Polarity einstellen muss, also welchen SPI-Mode. Des weiteren ist mir noch nicht ganz klar, wie ich die 2 x 8 Bit senden soll. Einfach SPI(0xff) und in der nächsten Zeile die zweite 8 bit funkt nicht. Hätte mich eh gewundert. noch was: Aus dem Datenblatt: "LOAD/CS must go high concurrently with or after the 16th rising clock edge, but before the next rising clock edge or data will be lost." Wie weiß ich wann die 16te Flanke kommt. Mit dem Interrupt? Wäre für ein kurzes Beispiel mit der Codevision-Funktion sehr dankbar!
Hallo Tester, der SPI wird ähnlich wie die UART beschreiben. Byte in den Puffer und raus geht es. Wenn fertig dann Int und nächstes rein. Kann ich leider nicht genau sagen. Ich habe das bei meinen MAX 7221 zu fuss gemacht, da sie an einem 2051 dran sind. Der hat kein HW SPI. zu Fuß muß man drauf achten wann die Load/CS Leitung hoch geht. Eben frühestens mit dem Letzten Bit. Spätestens danach. Mit der Phase/Polarity hatte ich zu fuß auch nichts zu tun. Mache ich ja alles selber. CLR CS, Bit anlegen, Takt, alles 16 Mal oder 32 oder 64 und SETB CS. ich hoffe das hilft dir. Gruß
Hier meine Routinen die für einen 7219 waren, müsste also auch auf den 7221 übertragbar sein:
1 | void segWrite (unsigned char data_out){ |
2 | |
3 | unsigned char loop, mask; |
4 | |
5 | for (loop=0,mask=0x80;loop<8;loop++, mask=mask>>1) |
6 | |
7 | {
|
8 | |
9 | PORT_SCK_7219 &= ~(1<<PIN_SCK_7219); |
10 | |
11 | if (data_out & mask) |
12 | |
13 | PORT_MOSI_7219 |= (1<<PIN_MOSI_7219); |
14 | |
15 | else
|
16 | |
17 | PORT_MOSI_7219 &= ~(1<<PIN_MOSI_7219); |
18 | |
19 | PORT_SCK_7219 |= (1<<PIN_SCK_7219); |
20 | |
21 | }
|
22 | |
23 | PORT_SCK_7219 &= ~(1<<PIN_SCK_7219); |
24 | |
25 | }
|
26 | |
27 | |
28 | |
29 | void segAusgabe (unsigned char address, unsigned char data) { |
30 | |
31 | PORT_CS_7219 |= (1<<PIN_CS_7219); // Chip Select |
32 | |
33 | segWrite(address); |
34 | |
35 | segWrite(data); |
36 | |
37 | PORT_CS_7219 &= ~(1<<PIN_CS_7219); // Chip Unselect |
38 | |
39 | }
|
40 | |
41 | |
42 | |
43 | void segInit (void) { |
44 | |
45 | unsigned char loop; |
46 | |
47 | |
48 | |
49 | DDR_SCK_7219 |= (1<<PIN_SCK_7219); |
50 | |
51 | DDR_MOSI_7219 |= (1<<PIN_MOSI_7219); |
52 | |
53 | DDR_CS_7219 |= (1<<PIN_CS_7219); |
54 | |
55 | |
56 | |
57 | for (loop = 0; loop < 4; loop++) { // 4 mal um Fehler zu eliminieren |
58 | |
59 | segAusgabe(0x0c, 0x01); // Shutdown aus |
60 | |
61 | segAusgabe(0x09, 0xff); // Decode-Mode: alles auf Code B |
62 | |
63 | segAusgabe(0x0a, 0x08); // Intensität |
64 | |
65 | segAusgabe(0x0b, 0x05); // 6 digits |
66 | |
67 | }
|
68 | |
69 | |
70 | |
71 | for (loop = 1; loop <= 6; loop++) |
72 | |
73 | segAusgabe(loop, 0x0A); // "-" auf allen Anzeigen anzeigen |
74 | |
75 | }
|
Viel spaß damit
1 | /*****************
|
2 | Konstante Register
|
3 | ******************/
|
4 | //Hier werden KontrollRegister definiert
|
5 | |
6 | #define REG_DECODE 0x09
|
7 | #define REG_INTENSITY 0x0a
|
8 | #define REG_SCAN_LIMIT 0x0b
|
9 | #define REG_SHUTDOWN 0x0c
|
10 | #define REG_DISPLAY_TEST 0x0f
|
11 | |
12 | /*******************
|
13 | Konstanten Allgemein
|
14 | ********************/
|
15 | //6 Routinen, um die Ausgangspins high oder low zu setzen
|
16 | |
17 | #define DIN_PORT P4
|
18 | #define DIN_DDR P4
|
19 | #define DIN_BIT 0x04 //liegt auf Pin10 der Pfosten-Stiftleiste
|
20 | #define DIN_0() (DIN_PORT &= ~DIN_BIT) //Pin 4.2 auf low
|
21 | #define DIN_1() (DIN_PORT |= DIN_BIT) //Pin 4.2 auf high
|
22 | |
23 | #define CLK_PORT P4
|
24 | #define CLK_DDR P4
|
25 | #define CLK_BIT 0x01 //liegt auf Pin4 der Pfosten-Stiftleiste
|
26 | #define CLK_0() (CLK_PORT &= ~CLK_BIT) //Pin 4.0 auf low
|
27 | #define CLK_1() (CLK_PORT |= CLK_BIT) //Pin 4.0 auf high
|
28 | |
29 | #define LOAD_PORT P4
|
30 | #define LOAD_DDR P4
|
31 | #define LOAD_BIT 0x10 //liegt auf Pin7 der Pfosten-Stiftleiste
|
32 | #define LOAD_0() (LOAD_PORT &= ~LOAD_BIT) //Pin 4.4 auf low
|
33 | #define LOAD_1() (LOAD_PORT |= LOAD_BIT) //Pin 4.4 auf high
|
34 | |
35 | #define INTENSITY_MAX 0x0f //Konstante fuer maximale Leuchtstaerke
|
36 | |
37 | |
38 | /*************
|
39 | Unterprogramme
|
40 | **************/
|
41 | |
42 | void MAX7219_Init (void); |
43 | void MAX7219_ShutdownStart (void); |
44 | void MAX7219_ShutdownStop (void); |
45 | void MAX7219_DisplayTestStart (void); |
46 | void MAX7219_DisplayTestStop (void); |
47 | void MAX7219_SetBrightness (char brightness); |
48 | void MAX7219_Clear (void); |
49 | void ziffern (void); |
50 | |
51 | void MAX7219_Write (unsigned char reg_number, unsigned char dataout); |
52 | |
53 | unsigned char z; //wird fuer den NO-OP Befehl des MAX7219 benoetigt |
54 | |
55 | |
56 | |
57 | |
58 | |
59 | |
60 | void MAX7219_Init (void) |
61 | {
|
62 | // DIN, CLK & LOAD als Ausgang definieren
|
63 | DIN_DDR |= DIN_BIT; |
64 | CLK_DDR |= CLK_BIT; |
65 | LOAD_DDR |= LOAD_BIT; |
66 | |
67 | MAX7219_Write(REG_DECODE, 0xFF); //Decode Mode B einschalten fr alle Digits |
68 | MAX7219_SetBrightness(INTENSITY_MAX); //Helligkeit der Segmente definieren |
69 | MAX7219_Write(REG_SCAN_LIMIT, 0x04); //5-Digits aktivieren |
70 | MAX7219_ShutdownStop(); //normaler Betrieb - kein Shutdown Mode |
71 | MAX7219_DisplayTestStart(); //Test Betrieb - alle Digits leuchten! |
72 | }
|
73 | |
74 | void MAX7219_ShutdownStart (void) |
75 | |
76 | /* Schaltet das Display ab - Shutdown Mode */
|
77 | {
|
78 | MAX7219_Write (REG_SHUTDOWN, 0); |
79 | }
|
80 | |
81 | void MAX7219_ShutdownStop (void) |
82 | |
83 | /* Bringt das Display aus dem Shutdown Mode */
|
84 | {
|
85 | MAX7219_Write (REG_SHUTDOWN, 1); |
86 | }
|
87 | |
88 | void MAX7219_DisplayTestStart (void) |
89 | |
90 | /* Schaltet alle Segmente ein - Test Mode*/
|
91 | {
|
92 | MAX7219_Write (REG_DISPLAY_TEST, 1); |
93 | }
|
94 | |
95 | void MAX7219_DisplayTestStop (void) |
96 | |
97 | /* Bringt das Display aus dem Test Mode */
|
98 | {
|
99 | MAX7219_Write (REG_DISPLAY_TEST, 0); |
100 | }
|
101 | |
102 | void MAX7219_SetBrightness (char brightness) |
103 | |
104 | /* Setzt die Helligkeit des Displays*/
|
105 | {
|
106 | brightness &= 0x0f; |
107 | MAX7219_Write (REG_INTENSITY, brightness); |
108 | }
|
109 | |
110 | void MAX7219_Clear (void) |
111 | |
112 | /* Loescht das Display*/
|
113 | {
|
114 | char k; |
115 | for (k=1; k<=5; k++) |
116 | {
|
117 | MAX7219_Write (k, 0x00); |
118 | }
|
119 | }
|
120 | |
121 | void MAX7219_Write (unsigned char reg_number, unsigned char dataout) |
122 | |
123 | /* Hier werden die Daten in die Register der Displays geschrieben - MSB (15) zuerst*/
|
124 | {
|
125 | char i,g; |
126 | LOAD_0(); |
127 | |
128 | // Datenbits D15-D12 werden beliebig (z.b.: '0') uebertragen:
|
129 | for (i=0;i<4;i++) |
130 | {
|
131 | DIN_0(); |
132 | CLK_1(); |
133 | CLK_0(); |
134 | }
|
135 | // Datenbits D11-D8 (Registeradresse) werden uebertragen:
|
136 | for (i=4;i>0;i--) |
137 | {
|
138 | unsigned char mask = 1 << (i-1); |
139 | if (reg_number & mask) |
140 | {
|
141 | DIN_1(); |
142 | }
|
143 | else
|
144 | {
|
145 | DIN_0(); |
146 | }
|
147 | CLK_1(); |
148 | CLK_0(); |
149 | }
|
150 | // Datenbits D7-D0 (Daten) werden uebertragen:
|
151 | for (i=8; i>0; i--) |
152 | {
|
153 | unsigned char mask = 1 << (i-1); |
154 | if (dataout & mask) |
155 | {
|
156 | DIN_1(); |
157 | }
|
158 | else
|
159 | {
|
160 | DIN_0(); |
161 | }
|
162 | CLK_1(); |
163 | CLK_0(); |
164 | }
|
165 | // No-op Register beschreiben
|
166 | if (z>>0) |
167 | {
|
168 | for (g=0;g<z;g++) |
169 | {
|
170 | for (i=0;i<4;i++ //beliebig (z.b.: '0') uebertragen |
171 | )
|
172 | {
|
173 | DIN_0(); |
174 | CLK_1(); |
175 | CLK_0(); |
176 | }
|
177 | for (i=4;i>0;i-- //In NO-OP Register 0x00 schreiben |
178 | )
|
179 | {
|
180 | DIN_0(); |
181 | |
182 | CLK_1(); |
183 | CLK_0(); |
184 | }
|
185 | for (i=8;i>0;i-- //beliebig (z.b.: '0') uebertragen |
186 | )
|
187 | {
|
188 | DIN_0(); |
189 | CLK_1(); |
190 | CLK_0(); |
191 | }
|
192 | }
|
193 | }
|
194 | LOAD_1(); |
195 | }
|
196 | |
197 | void ziffern (void) |
198 | {
|
199 | if (v==1) |
200 | {
|
201 | /*Hier findet die Auswertung der Timerwerte die im Feld t1
|
202 | gespeichert wurden statt. Jede Ziffer muss aus der Zahl
|
203 | mithilfe von Rechenoperationen ermittelt werden*/
|
204 | |
205 | unsigned int aa, xx, b1,d1,f1,g1; |
206 | unsigned long f,ziffer; |
207 | unsigned char fehl; |
208 | |
209 | fehl = 0; //Fehler Zehlvariable 0 setzen |
210 | for (aa=1;aa<=9;aa++) |
211 | {
|
212 | if (t1[aa] == 0) |
213 | {
|
214 | fehl++; |
215 | }
|
216 | }
|
217 | if (fehl == 0 //es sind alle beschrieben |
218 | )
|
219 | {
|
220 | for (aa=1;aa<10;aa++) |
221 | {
|
222 | z=aa-1; |
223 | xx=5; |
224 | |
225 | f=t1[aa]; |
226 | ziffer= f/10000; |
227 | MAX7219_Write (xx,(unsigned char)ziffer); |
228 | |
229 | b1=f%10000; |
230 | ziffer = b1/1000; |
231 | xx--; |
232 | MAX7219_Write (xx,(unsigned char)ziffer); |
233 | |
234 | d1=b1%1000; |
235 | ziffer=d1/100; |
236 | xx--; |
237 | MAX7219_Write (xx,(unsigned char)ziffer); |
238 | |
239 | f1=d1%100; |
240 | ziffer=f1/10; |
241 | xx--; |
242 | MAX7219_Write (xx,(unsigned char)ziffer); |
243 | |
244 | g1=f1%10; |
245 | ziffer=g1; |
246 | xx--; |
247 | MAX7219_Write (xx,(unsigned char)ziffer); |
248 | MAX7219_SetBrightness(INTENSITY_MAX); |
249 | }
|
hallo. zur SPI: CPOL gibt an, ob die erste flanke ("leading edge") steigend oder fallend ist. anders gesagt: CPOL legt den "ruhepegel" des CLK-signals fest. in deinem fall ist er LOW. CPHA gibt an, mit welcher flanke die daten übernommen werden. in deinem fall mit der "leading edge", die hier die steigende ist (siehe "Figure 1. Timing Diagram", seite 6 im datenblatt). stelle also beide werde auf 0. der rest läuft dann so: - SPI konfigurieren (interrupt aktivieren nicht vergessen!) - erstes datenbyte ins senderegister schreiben - 1. SPI-Interrupt: evtl. empfangene daten ablegen, dann zweites datenbyte schreiben - 2. SPI-Interrupt: evtl. empfangene daten ablegen, übertragung beendet -> chip select wegnehmen der satz "LOAD/CS must go high concurrently with or after the 16th rising clock edge, but before the next rising clock edge or data will be lost." heißt ganz einfach, daß in die LOW-phase des signals "LOAD/CS" maximal 16 steigende flanken des clock-signals fallen dürfen, sonst werden die daten verworfen. gruß michael
Guten Morgen ihr Nachtschwärmer! Danke erstmal. CPOL und CPHA auf 0. Auf das bin ich nach lagem Studium des Datenblatts auch gekommen. Aber danke für die Bestätigung. Die Routinen werd heut Nachmittag probieren. Ich geb dann bescheid... thks
Hallo, Ich bringe dieses SCH**** Ding nicht zum laufen. Habe eure Routinen probiert. Funktionieren ebenso wenig wie meine. Es leuchten immer alle Segmente. Jeman d einen Idee? Der µC steckt aufm STK500, MAX7221 auf einem Steckbrett. Leider bin ich kein Besitzer eines Oszis. Ich würd mir diese stinkenden Bits gern mal ansehen...
Tester wrote: > Ich bringe dieses SCH**** Ding nicht zum laufen. Habe eure Routinen > probiert. Ich hätte auch noch eine, läuft wie dumm: Beitrag "DCF77 Uhr in C mit ATtiny26" Ist sogar für Anzeigen mit gemeinsamer Anode. Aber solange Du nichts von Dir zeigst, kann auch keiner Deinen Fehler sehen. Peter
OK, anhängender code müsste meiner Meinung nach einfach nur mal eine Zahl am 7-Seg ausgeben. Aber bei leuchten alle Segmente. auch mit Stefans code. Also dachte ich an ein Hardware-Problem. Komm aber nicht drauf. Danke für alle Denkanstöße... (oder Lösungen ;-)
Wahnsinn, das geht ja schnell hier! könnte trotzdem bitte mal jemand einen Blick auf den Code werfen? Oder ists wirklich ein Hardware-Problem? Danke
Wo ist die Funktion spi() definiert ? Wo wird der Interrupt enabled und warum erst die Umstände mit dem Interrupt ? Läuft das Programm überhaupt durch ? Statt tonnenweise Copy&Paste, mach lieber ne Unterfunktion, dann muß man sich nicht den gleichen Schnulli wieder und wieder durchlesen. D.h. der Code wird wesentlich übersichtlicher und fehlerfreier. Peter
Hallo, Den Interrupt deswegen, damit er mit dem senden der zweiten 8bit wartet bis die ersten fertig sind. Oder ist das nicht notwendig. Ich habs halt so gemacht weil es anders nicht funktionierte. Das Programm läuft durch. (PORTC=Leds vom STK500) aber am Digit steht immer nur "8." Was mache ich mit der nicht benutzen Dout-Leitung vom MAX7221?
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.