Hallo zusammen, und zwar befasse ich mich seit Gestern das erste Mal mit dem Multiplexing. Mein erstes Ziel war es erstmal nur zwei 7-segment Anzeigen anzusteuern und einfach von 00 bis 99 im Sekundentakt hochzählen zu lassen. Im Prinzip funktioniert auch alles, er zählt von 00 bis 99 hoch. Aber wenn ich jetzt bei der Zehnerstelle die 1 habe, sind da ja nur die rechten beiden Segmente eingeschaltet. So und wenn nun die einer Stelle als durchschaltet dann sieht man das auch ganz minimal auch auf der Zehnerstelle. Ich denke es ist ein "Zeitmanagament-Problem" Also bei 18 würde die 1 Hell leuchten und ganz dunkel und blass leuchten auch die ganzen anderen Segmente mit, oder bei 13 nur die 3 Segmente zusätzlich in der Mitte. Und umgedreht das Selbe, bei 81 leuchten alle Segmente ganz blass und dunkel bei der Einerstelle mit. Anbei mal mein Quellcode. Ich habe ihn selbst geschrieben, da ich kein gutes Beispiel dafür gefunden habe. Ich fand immer nur Beispiele bei denen mit einem delay gearbeitet wurde, aber das ist ja nicht die saubere Art oder? Würde mich freuen wenn mir jemand sagen kann was bei mir falsch läuft oder wie man sowas generell angeht und richtig macht. Gruß marcel
Da du die Timer ja offenbar schon korrekt zu laufen gebracht hast, würde ich dir empfehlen, die Ansteuerung der 7Seg Anzeige ebenfalls in der ISR zu machen.
Was für ein gigantisches Programm. Keep it short & simple, dann verliert man vielleicht nicht den Überblick int i1 = i/10; PORTC = (1 << PD0); save1 = count2; PORTB = zahlen[i1]; if(save1 == count2-1) PORTC = (0 << PD0); int i2 = i%10; PORTC = (1 << PD1); save2 = count2; PORTB = zahlen[i2]; if(save2 == count2-1) PORTC = (0 << PD1); ersetzen gegen PORTB=0; if(count&1) { PORTC=1<<PD1; PORTB=zahlen[i/10]; } else { PORTC=1<<PD0; PORTB=zahlen[i%10]; }
@MaWin: So in der Art hatte ich es vorher auch gehabt und dabei taucht der Fehler zwar nicht auf, aber die Anzeigen an sich leuchten ziemlich schwach und dunkel. Jetzt leuchtet sie nur einige µS wodurch sie denke ich nicht so hell werden kann. Deswegen habe ich es ja so programmiert, dass erst nach einer Milisekunde die jeweilige Anzeige wieder abgeschaltet wird. Dadurch leuchtete die Anzeige hell, weil sie ja so eine ganze Milisekunde leuchten konnte. gruß marcel
> So in der Art hatte ich es vorher auch gehabt Ach. > und dabei taucht der Fehler zwar nicht auf Ach. > aber die Anzeigen an sich leuchten ziemlich schwach und dunkel. Tja, wie auch immer deine Ausschenbeschaltung ist, mit 1k Vorwiderständen ist es vielleicht dunkel. > Jetzt leuchtet sie nur einige µS Also weniger als die 998 µS zuvor > wodurch sie denke ich nicht so hell werden kann. Ich dachte es war dir schon zu dunkel. Wieso soll noch dunkler dann ein Fortschritt sein ?
Es soll nicht dunkler werden sondern heller. also die Vorwiderstände betragen alle 330 Ohm. wenn eine Anzeige so 1ms lang leuchtet dann wieder nicht und wieder 1ms lang leuchtet usw..... dann wird das schon ziemlich hell, also "normal". aber wenn die jetzt bei jedem Zyklus (der ja nur einige uS dauert) an und beim nächsten wieder ausgeschaltet werden, leuchten sie nicht lange genug um hell zu leuchten, sieht ziemlich schwach aus und leider nicht "normal". Also ich denke es liegt an der Zeit, weil je nach dem wie lange eine Anzeige an ist um so heller erscheint sie. mfg marcel
>aber wenn die jetzt bei jedem Zyklus (der ja nur einige uS dauert)
Siehe mein Beitrag
Ok Matthias, ich habe es mal gemacht, dennoch leider dieser "Geistereffekt" also bei 18 z.B. leuchten bei der ersten Anzeige rechts die beiden hell und der rest dunkel und schwach mit.... :( Habe es direkt so gemacht, dass jede Anzeige 1ms an sein darf und zwischen beiden 1ms ruhe sein muss. also: bei ms 0 darf anzeige 1 angehen bei ms 1 darf anzeige 1 ausgehen bei ms 2 darf anzeige 2 angehen bei ms 3 darf anzeige 2 ausgehen bei ms 4 wird von vorne gestartet Quellcode liegt bei und wird direkt in der ISR ausgeführt. gruß marcel
Du machst das zu kompliziert:
1 | #define cAnzahl 7
|
2 | |
3 | #define A 0b00000001
|
4 | #define B 0b00000010
|
5 | #define C 0b00000100
|
6 | #define D 0b00001000
|
7 | #define E 0b00010000
|
8 | #define F 0b00100000
|
9 | #define G 0b01000000
|
10 | |
11 | uint8_t PGM_Numbers[] PROGMEM = |
12 | {
|
13 | A | B | C | D | E | F, // 0 |
14 | B | C, // 1 |
15 | A | B | G | E | D, // 2 |
16 | A | B | C | D | G, // 3 |
17 | F | G | B | C, // 4 |
18 | A | F | G | C | D, // 5 |
19 | A | F | G | C | D | E, // 6 |
20 | A | B | C, // 7 |
21 | A | B | C | D | E | F | G, // 8 |
22 | A | B | C | D | F | G // 9 |
23 | };
|
24 | |
25 | |
26 | |
27 | volatile uint16_t u16TimeTick; |
28 | |
29 | volatile struct |
30 | {
|
31 | uint8_t au8Data[cAnzahl]; |
32 | uint8_t u8Col; |
33 | uint8_t u8Msk; |
34 | }
|
35 | scAnzeige; |
36 | |
37 | |
38 | ISR(TIMER0_OVF_vect) |
39 | {
|
40 | //-- Reload für 1ms Tick -----------------
|
41 | TCNT0 = 131; |
42 | u16TimeTick++; |
43 | |
44 | //-- 7Seg dunkel tasten ------------------
|
45 | PORTB = 0; |
46 | |
47 | //-- neue Spalte -------------------------
|
48 | scAnzeige.u8Col++; |
49 | scAnzeige.u8Msk <<= 1; |
50 | if ( scAnzeige.u8Col == sizeof(scAnzeige.au8Data) ) |
51 | {
|
52 | scAnzeige.u8Col = 0; |
53 | scAnzeige.u8Msk = 1; |
54 | }
|
55 | |
56 | //-- neue Daten ausgeben -----------------
|
57 | PORTC = scAnzeige.u8Msk; |
58 | PORTB = scAnzeige.au8Data[ scAnzeige.u8Col ]; |
59 | }
|
60 | |
61 | |
62 | void main ( void ) |
63 | {
|
64 | //-- lokale Variablen --------------------
|
65 | uint8_t u8Hilf1; |
66 | uint8_t u8Hilf2; |
67 | uint8_t u8Sec = 0; |
68 | |
69 | //-- Ports initialisieren ----------------
|
70 | DDRB = 0xFF; |
71 | DDRC = (1 << PD0) | (1 << PD1); |
72 | |
73 | //-- Timer initialisieren für Tick=1ms
|
74 | TIMSK |= (1<<TOIE0); |
75 | TCCR0 |= (1<<CS01); // IST DAS WIRKLICH vorteiler = 8 ?? |
76 | sei(); |
77 | |
78 | //-- Ablauf ------------------------------
|
79 | while (1) |
80 | {
|
81 | if ( u16TimeTick == 1000 ) |
82 | {
|
83 | u16TimeTick = 0; |
84 | |
85 | if ( ++u8Sec == 60 ) u8Sec = 0; |
86 | |
87 | u8Hilf1 = (u8Sec/10); |
88 | u8Hilf2 = (u8Sec%10); |
89 | scAnzeige.au8Data[0] = pgm_read_byte( &PGM_Numbers[ u8Hilf1 ] ); |
90 | scAnzeige.au8Data[1] = pgm_read_byte( &PGM_Numbers[ u8Hilf2 ] ); |
91 | }
|
92 | }
|
93 | }
|
Was allerdings das Übersprechen der Segmente noch erzeugen kann: Gibt mal die Beschaltung an PORTD0/1, also die Ansteuerung der beiden Segmente. Wenn du Emitterschaltung genommen hast, erzeugt dir bei hoher Sättigung die StorageTime das übersprechen..
Hi Matthias, also die Beschaltung ist wie hier: http://www.blafusel.de/bilder/misc/upc/timer/timer_sch.png also nur der Teil mit den 7-segment Anzeigen. An den beiden Transistoren habe ich auch 10 kOhm Widerstände an der Basis und vor den einzellnen Segmenten habe ich 330 Ohm Widerstände. Also ich habe deinen Code mal probiert, der scheint auch ohne Übersprechen zu funktionieren, aber bei "#define cAnzahl 7" ist es noch ziemlich blass und dunkel, bei "#define cAnzahl 2" ist es dann "normal"... also hätte man ja dann ein Problem, je mehr Anzeigen, desto dunkler? :/ Deinen Code habe ich jetzt noch nicht ganz verstanden, was du da mit Spalten willst und mit Msk, also der gesamte Multiplex-Vorgang scheint anders zu laufen. Finde es generell ziemlich kompliziert aufgebaut, dachte man sollte in die Interrupt Routinen nur das nötigste einbauen :/ Also ist von mir der Ansatz nicht richtig, die gesamte Anzeige mit kompletter Ziffer anzusteuern und einzuschalten, die beiden Anzeigen im wechsel?? gruß marcel
>also die Beschaltung ist wie hier: Ja. Das ist Emitterschaltung. Das kann (auch) ein Grund des Nachleuchtens sein. Mache mal folgendes: Tausche die npn durch pnp Transistoren: E kommt an die Anode der 7SegAnzeig, C kommt an Masse/GND. Und die Basis direkt ohne Vorwiderstand an den Portpin. Dazu muss die Ansteuerlogik negiert werden: Aus >>DDRC = (1 << PD0) | (1 << PD1); wird DDRC = ~( (1<<PD0) (1<<PD1) ); und aus >> PORTC = scAnzeige.u8Msk; wird PORTC = ~scAnzeige.u8Msk; >aber bei "#define cAnzahl 7" ist es... Hm. Hier hat sich ein Fehler meinerseits eingeschlichen. Statt der 7 muss bei dir eine 2 hin. >je mehr Anzeigen, desto dunkler? :/ Prinzipiell ja. Das liegt an deinem 330Ohm Vorwiderstand. Dessen Wert ist abhängig von der Anzahl der 7Seg-Anzeigen. Umso mehr du hast, umso kürzer leuchtet jede bis sie wieder dran ist. Deshalb muss in der kürzeren Zeit mehr Helligkeit erzeugt werden. Also kleinerer R, größerer Strom mehr hell. >Finde es generell ziemlich kompliziert aufgebaut, >dachte man sollte in die Interrupt Routinen nur das nötigste einbauen :/ Nur auf den ersten Blick. Hier ist das Ausgeben (also das Multiplexen) und das Ermitteln was auszugeben ist, strikt getrennt. Deshalb gibt es die Variable /scAnzeige.au8Data/ In der steht drin, was die Anzeigen anzeigen sollen. Diese Ausgabe wird durch den Timer-Int alle 1ms ausgeführt. Dieser TImer-Int ist schnell abgearbeitet, hat keine aufwendigen Rechnungen und keine Schleifen. Was ausgegeben werden soll, wird woanders (hier main) ermittelt. Anders formuliert: Main berechnet, wann immer main der Meinung ist, die Anzeige ändern zu müssen, neue Werte für die Variable /scAnzeige.au8Data/ Unabhängig davon wird alle 1ms diese Variable gelesen und per Multiplex zur Anzeige gebracht..
Schreib dir deinen auszugebenden Wert in ein Array und in der ISR dann nur die Ausgabe. Beispiel:
1 | ISR (TIMER1_OVF1_vect) // 1mSec. |
2 | {
|
3 | LED_OUT = DispDigit [2]; // Ausgabe Zehner Stelle |
4 | DIGIT_2 = ON; |
5 | _delay_us (SevenSegBrightness); |
6 | DIGIT_2 = OFF; |
7 | |
8 | LED_OUT = DispDigit [3]; // Ausgabe Einer Stelle |
9 | DIGIT_1 = ON; |
10 | _delay_us (SevenSegBrightness); |
11 | DIGIT_1 = OFF; |
12 | }
|
13 | |
14 | ....Ausgabe |
15 | |
16 | cli (); |
17 | for (m = 0; m < NoOfDigits; m++) { // errechneten Display Wert in 7Seg. Ziffern |
18 | DispDigit [m] = Tab7Seg [LedVal [m]]; // umkodieren |
19 | }
|
20 | DispDigit [DecPtPoS] &= SegDezP; // Dezimalpunkt setzen |
21 | sei (); |
Dann hast du auch definierte EIN / AUSschaltzeiten pro Digit. Das kann ich bei dir so nicht erkennen.
Hi Matthias, also jetzt weiß ich woher das Nachleuchten kam. Und zwar ist mir in Deinem Programm aufgefallen, dass Du bei jedem Tick die Datenleitungen (PORTB) komplett auf 0 setzt. Was ja auch richtig und auch sauber ist. Bei mir war es so, das auf PORTB immer irgendein Signal lag. Ich habe quasi bei bedarf das Signal auf PORTB gewechselt und immer nur die Anzeigen An und Ab (PORTC) geschaltet, da aber immer noch das signal auf PORTB lag, kam es denke ich zu einem Kriechstrom, der für ein blasses Nachleuchten gereicht hat. Nun mache ich es so, das nur wenn die Anzeige leuchten soll, das Signal (PORTB) und die Anzeige selbst (PORTC) für den Moment geschalten sind, ansonsten wieder komplett aus. Mein Quellcode liegt bei und funktioniert nun vernünftig. Ich danke dir für deine Hilfe :) gruß marcel
>Mein Quellcode liegt bei und funktioniert nun vernünftig.
Möglich. Aber das Konzept ist nicht vernünfig.
Nimm mal deine Vairable count2. Diese steuert ja das Timing der
Displayansteuerung. (vergleichbar mit meiner scAnzeige.u8Col )
Das diese Variable durch den Timer (2) alle 1ms verändert wird ist auch
in Ordnung.
Unsinn sind jetzt aber zwei Dinge:
Das main gibt jetzt so schnell wie es kann, Daten auf die Anzeigen aus
(je nach Wert 0,1,2,3). Wozu? Es reicht, dass bei Änderung der Variable
count2 zutun.
Das könntest du jetzt im main prüfen, aber das ist auch Unsinn. Denn du
weißt ja, wann diese Variable count2 geändert wurde: In der Timer-ISR.
=> Also die Ausgabe dort tun.
Und zweitens ist es Unsinn, permanent auszurechnen, was angezeigt werden
soll: Damit meine ich die Zuweisungen =zahlen[i/10] oder =zahlen[i%10].
Warum machst du die mit jedem Durchlauf, und nicht nur dann, wenn sich i
ändert?
Also sieh dir nochmal meinen COde an, und analysiere, was wann und warum
passiert...
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.