Bin grad dabei einen Code zu schreiben. Wie könnte man das vereinfachen...? if (a==0) write_0(); if (a==1) write_1(); if (a==2) write_2(); if (a==3) write_3(); if (a==4) write_4(); if (a==5) write_5(); if (a==6) write_6(); if (a==7) write_7(); if (a==8) write_8(); if (a==9) write_9(); danke für eure antworten
write_n n die zahl die am 7 seg ausgegeben wird also irgendwelche werte auf einem port. mfg
Hallo Christian! Häng doch mal den Quelltext (bzw. einen Ausschnitt) davon an. Sagt mehr als ewiges herumgestocher in der Luft ;) Grüße Chris
mach ein array, das du schon zur design-zeit mit konstanten werten füllst (für die jeweiligen ziffern der 7seg. anzeige) dann musst du nurnoch die entsprechende zahl auswählen aus diesem array pseudocode ungefähr so: array ziffern[11000, 00101, 10111] (die versch. kodierungen der ziffern) darauf kannst du dann mit einem index zugreifen, z.b. willst du die zahl "1" auf der 7seg. ausgeben, machst du: port = ziffern[1] ziffern[1] hätte in diesem beispiel den wert 00101, dies wär dann das was auf dem port ausgegeben wird. --> spart code, rechenzeit und nerven
hab mal einen bekannten gefragt der hat gemeint das geht mit einer sprungtabelle am besten geht wenn es durchgängige werte sind. wie heißt das im c im fachjargon? -> zu sprungtabelle hab ich im google fast nichts gefunden. mfg
Sprungtabellen sind arrays von Funktions-Pointern. Also z.B. void(*)(void) sprungTabelle[10] = { write_1, write_2, ... }; in main dann : sprungTabelle[a](); Ist aber in deinem Fall ueberfluessig, Stefans Vorschlag erscheint mir auch am sinnvollsten.
Schreibe nur eine write-Funktion für alle Ziffern, z.B.:
1 | #include<io.h> |
2 | |
3 | typedef unsigned char u8; |
4 | typedef signed char s8; |
5 | typedef unsigned short u16; |
6 | typedef signed short s16; |
7 | typedef unsigned long u32; |
8 | typedef signed long s32; |
9 | |
10 | |
11 | #define _A 0x02 //segment order
|
12 | #define _B 0x04
|
13 | #define _C 0x40
|
14 | #define _D 0x10
|
15 | #define _E 0x08
|
16 | #define _F 0x01
|
17 | #define _G 0x20
|
18 | #define _DP 0x80 //decimal point
|
19 | |
20 | #define _0 (u8)~( _A+_B+_C+_D+_E+_F ) //number pattern, low
|
21 | active
|
22 | #define _1 (u8)~( _B+_C )
|
23 | #define _2 (u8)~( _A+_B+ _D+_E+ _G )
|
24 | #define _3 (u8)~( _A+_B+_C+_D+ _G )
|
25 | #define _4 (u8)~( _B+_C+ _F+_G )
|
26 | #define _5 (u8)~( _A+ _C+_D+ _F+_G )
|
27 | #define _6 (u8)~( _A+ _C+_D+_E+_F+_G )
|
28 | #define _7 (u8)~( _A+_B+_C )
|
29 | #define _8 (u8)~( _A+_B+_C+_D+_E+_F+_G )
|
30 | #define _9 (u8)~( _A+_B+_C+_D +_F+_G )
|
31 | |
32 | u8 numbers[] = { _0, _1, _2, _3, _4, _5, _6, _7, _8, _9 }; |
33 | |
34 | |
35 | |
36 | // und hier kommt die super Funktion !!!
|
37 | |
38 | void write_0_9( u8 val ) |
39 | {
|
40 | PORTA = numbers[val]; |
41 | }
|
Peter
Einfachster Code ( wie in Teilen bereits oben vorgeschlagen): uint8_t digits = { 0b0000000, // Eine 1 z.B. für das Segment, das leuchten soll 0b0000011, ... // usw. jeweils die bitmuster die Du brauchst } void write( uint8_t i ) { PORT = digits[i] }
Nicht ganz. Ingo hat einen Fehler eingebaut :-) uint8_t digits [] = **** Und Peters Art die Konstanten zu bestimmen ist wesentlich schöner und übersichtlicher als die Bitmuster selbst zu bestimmen. Nach dem Motto: Lass den Compiler sich um die Bitdetails kümmern, der Programmierer soll sich nicht mit so einem Taschenrechnerkram rumärgern.
Sprungtabelle: Statt der Werte die Ausgegeben werden sollen stehen in der Tabelle die Adressen der jeweiligen Ausgabefunktion => Unnötiger Overhead im Quadrat ==> Sprungtabelle == Mit Kanonen auf Spatzen schießen!
@Peter & Karl-Heinz: Ihr habt ja recht. Pfui über mich! Dann aber vielleicht noch: #define _A (1<<PIN1) statt magic number?
> ==> Sprungtabelle == Mit Kanonen auf Spatzen schießen!
Im gegenstaendlichen Fall: Ja, klar. Voellig unnoetig.
Aber um mal das Prinzip zu demonstrieren:
Ich hab vor Jahren mal eine Z80 Simulation am PC gemacht
(in C++).
Die wesentliche Hauptschleife sah so aus:
void CPU::Run()
{
BYTE OpCode;
while( 1 ) {
OpCode = m_Ram[m_PC++];
(this->*m_Fnktions[OpCode])();
}
}
Dazu gibts dann einen Haufen Funktionen, die die Funktionalitaet
einzelner OP-Codes implementieren: zb
void CPU::CALL ()
{
WORD Address = FetchAddress();
PushStack( m_PC );
m_PC = Address;
}
void CPU::RET ()
{
m_PC = PopStack();
}
...
Dazu gibt es dann ein Array von Funktionszeigern ....
class CPU
{
....
void( CPU::* m_Fnktions[256] )();
}
... welches die Verknüpfung von Op_Codes zu den einzelnen
Funktionen herstellt:
CPU::CPU()
{
...
m_Fnktions[0xC9] = RET;
...
m_Fnktions[0xCD] = CALL;
...
In der Run-Schleife wird ueber den Program-Counter m_PC der
nechste OP-Code aus dem (simulierten) RAM geholt
OpCode = m_Ram[m_PC++];
dieser OpCode als Index in die Funktionszeiger-Tabelle genommen
m_Fnktions[OpCode]
und die entsprechende Funktion aufgerufen:
(this->*m_Fnktions[OpCode])();
(stoert euch jetzt nicht an der Syntax. Die ist in C++ so
notwendig, wenn man Funktionszeiger auf Memberfunktionen machen
moechte).
War also der OpCode gleich 0xCD dann wird die Funktion CALL
dafuer aufgerufen.
Sehr elegante Lösung! Kannst Du mir bitte erklären warum man: (this->*m_Fnktions[OpCode])(); schreiben muss und nicht (this->m_Fnktions[OpCode])(); Im Array steht doch ein Zeiger auf eine Memberfunktion. Eigentlich ist dann doch (this->m_Fnktions[OpCode]) der Zeiger auf die Funktion, und (this->m_Fnktions[OpCode])(); Dereferenzierung und Aufruf? Fragt sich Ingo
(this->m_Fnktions[OpCode])(); koenntest Du benutzen, wenn in m_Fnktions lauter Pointer auf freistehende Funktionen stünden. Das ist aber hier nicht der Fall. m_Fnktions enthaelt Pointer auf Memberfunktionen einer Klasse. Memberfunktionen muessen aber anders aufgerufen werden (der this Pointer innerhalb der Funktion muss ja besetzt werden). Daher ist eine neue Syntax notwendig: ->*
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.