Forum: Mikrocontroller und Digitale Elektronik 7 Segment Anzeige auf verschiedenen Ports


von Henry (Gast)


Lesenswert?

Hallo
Ich möchte mit einem kleinen Attiny 2 x 7 Segment Anzeige ansteuern. 
Dazu möchte ich das Array nutzen:
1
char charArray[] = 
2
  {      //  ABCDEFG  Segments
3
    0b1111110,     // 0
4
    0b0110000,     // 1
5
    0b1101101,     // 2
6
    0b1111001,     // 3
7
    0b0110011,     // 4
8
    0b1011011,     // 5
9
    0b1011111,     // 6
10
    0b1110000,     // 7
11
    0b1111111,     // 8
12
    0b1111011,     // 9
13
    0b1110111,     // 10  "A"
14
    0b0011111,     // 11  "B"
15
    0b1001110,     // 12  "C"
16
    0b0111101,     // 13  "D"
17
    0b1001111,     // 14  "E"
18
    0b1000111,     // 15  "F"
19
    0b0000000,     // 16  Space
20
    0b0000001      // 17  '-'
21
  };
Bei dieser Tabelle liegen alle Ausgänge auf Port A. Ansteuerung damit:
1
PORTA &= ~(1<<PINA0);  // Schaltet Pin PA0 Segment d AZ1 ein
2
    _delay_ms(500);      // Pause 500 ms
3
    PORTA |= (1<<PINA0);  // Schaltet Pin PA0 Segment d AZ1 aus
4
    _delay_ms(500);      // Pause 500 ms
5
    
6
    PORTB &= ~(1<<PINB2);  // Schaltet Pin PB2 Segment e AZ1 ein
7
    _delay_ms(500);      // Pause 500 ms
8
    PORTB |= (1<<PINB2);  // Schaltet Pin PB2 Segment e AZ1 aus
9
    _delay_ms(500);      // Pause 500 ms
Wenn ich PIN.. ersetze durch
1
PORTA &= ~(0b00001000);  // Schaltet Pin PA3 Segment a AZ1 ein
2
    _delay_ms(500);      // Pause 500 ms
3
    //PORTA |= (1<<PINA3);  // Schaltet Pin PA3 Segment a AZ1 aus
4
    
5
    PORTA |= (0b00001000);  // Schaltet Pin PA3 Segment a AZ1 aus
6
    _delay_ms(500);      // Pause 500 ms
kann ich ja nur die Werte aus der oberen Tabelle nehmen. Da aber die 
Anzeige auf Port A und Port B angeschlossen ist, funktioniert das nicht.
Wie kann ich das machen?
LG Henry

: Verschoben durch Moderator
von yesitsme (Gast)


Lesenswert?

Ein Schaltplan wäre jetzt schön...

von N. M. (mani)


Lesenswert?

Deine Beispiele machen teilweise nicht richtig Sinn. Du verwendest dein 
charArray nirgends in deinem Code!?

Mit der Glaskugelbrille sage ich, Teile deine Liste in 2 Listen (einmal 
für PORTA und einmal für PORTB) auf.
In jedem Array dürfen dann nur die Beteiligten Pins jeweils getrennt 
nach PORTX stehen.

Dann sind es in Zukunft halt 4 Zugriffe.
Irgendwie so in der Art:
1
PORTA&= ~(charArrayA[8]);
2
PORTA|= (charArrayA[i]);
3
4
PORTB&= ~(charArrayB[8]);
5
PORTB|= (charArrayB[i]);

von MaWin (Gast)


Lesenswert?

Henry schrieb:
> Da aber die Anzeige auf Port A und Port B angeschlossen ist,
> funktioniert das nicht.
> Wie kann ich das machen?
> LG Henry

Dein CharArray muss eben 2 Bytes enthalten (z.B. als unsigned int oder 
als struct { unsigned char A,B; } eines für die zu setzenden Ausgänge 
auf PortA und eines für die Ausgänge auf Port }B, und der Code donnert 
die entweder inklusive der unbenutzten Bits raus, oder maskiert die 
benutzten  z.B. benutzt bit 0 bis bit 5:

portA = (pinA&0xE0)|CharArray[value].A;

von N. M. (mani)


Lesenswert?

Oder liegt die erste sieben Segment an einem anderen Port als die 
Zweite?
Das geht nicht hervor...

von W.S. (Gast)


Lesenswert?

Henry schrieb:
> Wie kann ich das machen?

Das wäre etwas, das du dir selber bereits ausgedacht haben solltest, 
bevor du dein Projekt hier vorstellst.

Wer von den Lesern deines Beitrages hat denn ein genau gleiches Projekt 
wie du selbst, einschließlich einer genau gleichen Schaltung, 
Leiterplatte usw.?

W.S.

von Henry (Gast)


Lesenswert?

N. M. schrieb:
> Deine Beispiele machen teilweise nicht richtig Sinn. Du verwendest dein
> charArray nirgends in deinem Code!?

Ja das stimmt. Verwende das Array nicht.
Habe die Ports so aufgeteilt:

// PA5 - Anode 1
// PA7 - Anode 2
// PA3 - Segment a
// PA2 - Segment b
// PA1 - Segment c
// PA0 - Segment d
// PB2 - Segment e
// PB1 - Segment f
// PB0 - Segment g

Bin gerade dabei den Aufruf der Ports zu machen. Dabei bin ich auf das 
Problem gekommen. Habe vorher nur einzelne Segmente zum testen 
angesteuert. Wollte als nächstes die Zeichen ansteuern und dann den 
Timer dazu.

W.S. schrieb:
> Wer von den Lesern deines Beitrages hat denn ein genau gleiches Projekt
> wie du selbst, einschließlich einer genau gleichen Schaltung,
> Leiterplatte usw.?

Wahrscheinlich keiner, ist klar. Warum kann man bei einem Problem nicht 
fragen? Meine Kenntnissevon C sind nicht überdurchschnittlich. Es reicht 
halt um eine LED blinken zu lassen. Bitte keine Aussage wie "lies dein C 
Buch". Habe dort nachgeschlagen, leider ohne Lösung.

von Schlaumaier (Gast)


Lesenswert?

Hänge deine Anzeige an je Ziffer einen PCF-8574.

Dann schick den die Bit-Folge aus deinen Array und das war's. Geht sogar 
ohne Array wenn du eine Sub benutzt.

Sub (Text as string, Stelle as integer)

x = bit_array

if Text = "1" then x = 0b1111110
.
.
.

if stelle = 1 then setze_Pcf8574 (027, x)

end sub


' Das ist ein code-Struktur-Aufbau nix zum Abtippen.

Ansonsten gebe ich yesitsme Recht.

yesitsme schrieb:
> Ein Schaltplan wäre jetzt schön...

von Henry (Gast)


Lesenswert?

Habe es erst mal so gemacht:
1
// Zahl 1 - Segment b, c                -      PA1, PA2
2
// Zahl 2 - Segment a, b, g, e, d       - PA0,      PA2, PA3, PB0,     PB2 
3
// Zahl 3 - Segment a, b, g, c, d       - PA0, PA1, PA2, PA3, PB0
4
// Zahl 4 - Segment f, g, b, c          -      PA1, PA2,      PB0, PB1
5
// Zahl 5 - Segment a, f, g, c, d       - PA0, PA1,      PA3, PB0, PB1    
6
// Zahl 6 - Segment a, f, g, c, d, e    - PA0, PA1,      PA3, PB0, PB1, PB2     
7
// Zahl 7 - Segment a, b, c             -      PA1, PA2, PA3
8
// Zahl 8 - Segment a, f, b, g, e, c, d - PA0, PA1, PA2, PA3, PB0, PB1, PB2     
9
// Zahl 9 - Segment a, f, b, g, c, d    - PA0, PA1, PA2, PA3, PB0, PB1      
10
// Zahl 0 - Segment a, b, c, d, e, f,   - PA0, PA1, PA2, PA3,      PB1, PB2    
11
// Buch A - Segment e, g, f, a, b, c    -      PA1, PA2, PA3, PB0, PB1, PB2     
12
// Buch b - Segment f, g, e, c, d       - PA0, PA1,           PB0, PB1, PB2    
13
// Buch C - Segment a, f, e, d          - PA0,           PA3,      PB1, PB2
14
// Buch d - Segment b, g, e, c, d       - PA0, PA1, PA2,      PB0,      PB2 
15
// Buch E - Segment a, f, g, e, d       - PA0,           PA3, PB0, PB1, PB2
16
// Buch F - Segment a, f, g, e          -                PA3, PB0, PB1, PB2
17
// Zeic - - Segment g                   - PB0
18
19
// Zahl 1 - PA1, PA2
20
PORTA &= ~(0b00000110);  // Schaltet Pin am AZ1 ein
21
_delay_ms(500);      // Pause 500 ms
22
PORTA |= (0b00000110);  // Schaltet Pin am AZ1 aus
23
_delay_ms(500);      // Pause 500 ms
24
    
25
// Zahl 2 - PA0, PA2, PA3, PB0, PB2 
26
PORTA &= ~(0b00001101);  // Schaltet Pin am AZ1 ein
27
PORTB &= ~(0b00000101);  // Schaltet Pin am AZ1 ein
28
_delay_ms(500);      // Pause 500 ms
29
PORTA |= (0b00001101);  // Schaltet Pin am AZ1 aus
30
PORTB |= (0b00000101);  // Schaltet Pin am AZ1 aus
31
_delay_ms(500);      // Pause 500 ms
32
    
33
// Zahl 3 - PA0, PA1, PA2, PA3, PB0
34
PORTA &= ~(0b00001111);  // Schaltet Pin am AZ1 ein
35
PORTB &= ~(0b00000001);  // Schaltet Pin am AZ1 ein
36
_delay_ms(500);      // Pause 500 ms
37
PORTA |= (0b00001111);  // Schaltet Pin am AZ1 aus
38
PORTB |= (0b00000001);  // Schaltet Pin am AZ1 aus
39
_delay_ms(500);      // Pause 500 ms
40
41
// Zahl 4 - PA1, PA2, PB0, PB1
42
PORTA &= ~(0b00000110);  // Schaltet Pin am AZ1 ein
43
PORTB &= ~(0b00000011);  // Schaltet Pin am AZ1 ein
44
_delay_ms(500);      // Pause 500 ms
45
PORTA |= (0b00000110);  // Schaltet Pin am AZ1 aus
46
PORTB |= (0b00000011);  // Schaltet Pin am AZ1 aus
47
_delay_ms(500);      // Pause 500 ms
48
    
49
// Zahl 5 - PA0, PA1, PA3, PB0, PB1
50
PORTA &= ~(0b00001011);  // Schaltet Pin am AZ1 ein
51
PORTB &= ~(0b00000011);  // Schaltet Pin am AZ1 ein
52
_delay_ms(500);      // Pause 500 ms
53
PORTA |= (0b00001011);  // Schaltet Pin am AZ1 aus
54
PORTB |= (0b00000011);  // Schaltet Pin am AZ1 aus
55
_delay_ms(500);      // Pause 500 ms
56
    
57
// Zahl 6 - PA0, PA1, PA3, PB0, PB1, PB2
58
PORTA &= ~(0b00001011);  // Schaltet Pin am AZ1 ein
59
PORTB &= ~(0b00000111);  // Schaltet Pin am AZ1 ein
60
_delay_ms(500);      // Pause 500 ms
61
PORTA |= (0b00001011);  // Schaltet Pin am AZ1 aus
62
PORTB |= (0b00000111);  // Schaltet Pin am AZ1 aus
63
_delay_ms(500);      // Pause 500 ms
64
    
65
// Zahl 7 - PA1, PA2, PA3
66
PORTA &= ~(0b00001110);  // Schaltet Pin am AZ1 ein
67
_delay_ms(500);      // Pause 500 ms
68
PORTA |= (0b00001110);  // Schaltet Pin am AZ1 aus
69
_delay_ms(500);      // Pause 500 ms
70
71
// Zahl 8 - PA0, PA1, PA2, PA3, PB0, PB1, PB2
72
PORTA &= ~(0b00001111);  // Schaltet Pin am AZ1 ein
73
PORTB &= ~(0b00000111);  // Schaltet Pin am AZ1 ein
74
_delay_ms(500);      // Pause 500 ms
75
PORTA |= (0b00001111);  // Schaltet Pin am AZ1 aus
76
PORTB |= (0b00000111);  // Schaltet Pin am AZ1 aus
77
_delay_ms(500);      // Pause 500 ms
78
    
79
// Zahl 9 - PA0, PA1, PA2, PA3, PB0, PB1
80
PORTA &= ~(0b00001111);  // Schaltet Pin am AZ1 ein
81
PORTB &= ~(0b00000011);  // Schaltet Pin am AZ1 ein
82
_delay_ms(500);      // Pause 500 ms
83
PORTA |= (0b00001111);  // Schaltet Pin am AZ1 aus
84
PORTB |= (0b00000011);  // Schaltet Pin am AZ1 aus
85
_delay_ms(500);      // Pause 500 ms
86
  
87
// Zahl 0 - PA0, PA1, PA2, PA3,      PB1, PB2
88
PORTA &= ~(0b00001111);  // Schaltet Pin am AZ1 ein
89
PORTB &= ~(0b00000110);  // Schaltet Pin am AZ1 ein
90
_delay_ms(500);      // Pause 500 ms
91
PORTA |= (0b00001111);  // Schaltet Pin am AZ1 aus
92
PORTB |= (0b00000110);  // Schaltet Pin am AZ1 aus
93
_delay_ms(500);      // Pause 500 ms
94
95
// Buch A - PA1, PA2, PA3, PB0, PB1, PB2
96
PORTA &= ~(0b00001110);  // Schaltet Pin am AZ1 ein
97
PORTB &= ~(0b00000111);  // Schaltet Pin am AZ1 ein
98
_delay_ms(500);      // Pause 500 ms
99
PORTA |= (0b00001110);  // Schaltet Pin am AZ1 aus
100
PORTB |= (0b00000111);  // Schaltet Pin am AZ1 aus  
101
_delay_ms(500);      // Pause 500 ms
102
103
// Buch b - PA0, PA1, PB0, PB1, PB2
104
PORTA &= ~(0b00000011);  // Schaltet Pin am AZ1 ein
105
PORTB &= ~(0b00000111);  // Schaltet Pin am AZ1 ein
106
_delay_ms(500);      // Pause 500 ms
107
PORTA |= (0b00000011);  // Schaltet Pin am AZ1 aus
108
PORTB |= (0b00000111);  // Schaltet Pin am AZ1 aus
109
_delay_ms(500);      // Pause 500 ms
110
111
// Buch C - PA0, PA3, PB1, PB2
112
PORTA &= ~(0b00001001);  // Schaltet Pin am AZ1 ein
113
PORTB &= ~(0b00000110);  // Schaltet Pin am AZ1 ein
114
_delay_ms(500);      // Pause 500 ms
115
PORTA |= (0b00001001);  // Schaltet Pin am AZ1 aus
116
PORTB |= (0b00000110);  // Schaltet Pin am AZ1 aus
117
_delay_ms(500);      // Pause 500 ms
118
119
// Buch d - PA0, PA1, PA2, PB0, PB2
120
PORTA &= ~(0b00000111);  // Schaltet Pin am AZ1 ein
121
PORTB &= ~(0b00000101);  // Schaltet Pin am AZ1 ein
122
_delay_ms(500);      // Pause 500 ms
123
PORTA |= (0b00000111);  // Schaltet Pin am AZ1 aus
124
PORTB |= (0b00000101);  // Schaltet Pin am AZ1 aus
125
_delay_ms(500);      // Pause 500 ms
126
  
127
// Buch E - PA0, PA3, PB0, PB1, PB2
128
PORTA &= ~(0b00001001);  // Schaltet Pin am AZ1 ein
129
PORTB &= ~(0b00000111);  // Schaltet Pin am AZ1 ein
130
_delay_ms(500);      // Pause 500 ms
131
PORTA |= (0b00001001);  // Schaltet Pin am AZ1 aus
132
PORTB |= (0b00000111);  // Schaltet Pin am AZ1 aus
133
_delay_ms(500);      // Pause 500 ms
134
135
// Buch F - PA3, PB0, PB1, PB2
136
PORTA &= ~(0b00001000);  // Schaltet Pin am AZ1 ein
137
PORTB &= ~(0b00000111);  // Schaltet Pin am AZ1 ein
138
_delay_ms(500);      // Pause 500 ms
139
PORTA |= (0b00001000);  // Schaltet Pin am AZ1 aus
140
PORTB |= (0b00000111);  // Schaltet Pin am AZ1 aus
141
_delay_ms(500);      // Pause 500 ms
142
143
// Zeic - - PB0
144
PORTB &= ~(0b00000001);  // Schaltet Pin am AZ1 ein
145
_delay_ms(500);      // Pause 500 ms
146
PORTB |= (0b00000001);  // Schaltet Pin am AZ1 aus
147
_delay_ms(500);      // Pause 500 ms
Habe es erst mal so gemacht. Damit kann ich die gewünschten Zeichen 
anzeigen. Ist nicht die beste Lösung.
Werde mal die Stromaufnahme messen.

von B. W. (yesitsme)


Lesenswert?

Henry schrieb:
> Warum kann man bei einem Problem nicht
> fragen?

Fragen ist das beste was du machen kannst. ABER du musst auch soviel 
Kontext geben, so das man das Problem verstehen kann.

Mir fallen jetzt mehere Möglichkeiten ein, wie man das jetzt lösen kann.

z.B.: Du speicherst Port und Pin in einem Array und loopst beim Update 
der Anzeige da drüber. Ungefähr so:
1
struct PP {
2
    port;
3
    pin;
4
}
5
6
struct PP pins[] = {
7
    // LSB of charArray[x]
8
    {PORTB, PINB0}, // Segment G
9
    {PORTB, PINB1}, // Segment F
10
...
11
    {PORTA, PINA2}, // Segment B
12
    {PORTA, PINA3}, // Segment A
13
    // MSB of charArray[x]
14
}
15
16
17
void updateSegments( value ){
18
    tmp = charArray[value];
19
    for(x=0; x<7; x++){
20
        if(tmp & 1){ // check if LSB is set
21
            // set pin
22
            pins[x].port = pins[x].port | pins[x].pin;
23
        } else {
24
            // clear pin
25
            pins[x].port = pins[x].port & ~pins[x].pin;
26
        }
27
        tmp = tmp >> 1;
28
    }
29
}

Ja, ich weiß... Datentypen fehlen...

von B. W. (yesitsme)


Lesenswert?

Oder du hast je ein charArray[] für PORTA und PORTB und maskierst die 
Bits passend raus. Ungefähr so:
1
byte charArrayPA[] = {
2
    //....ABCD
3
    0b00001111, // number 0
4
...
5
    0b00001111, // number 9
6
}
7
byte maskPA = 0b00001111;
8
9
byte charArrayPB[] = {
10
    //.....EFG
11
    0b00000110, // number 0
12
...
13
    0b00000011, // number 9
14
}
15
byte maskPB = 0b00000111;
16
17
void updateSegments( value){
18
    tmp = charArrayPA[value];
19
    PORTA = (PORTA & ~maskPA) | tmp;
20
    tmp = charArrayPB[value];
21
    PORTB = (PORTB & ~maskPB) | tmp;
22
}

Bin mir jetzt nicht ganz sicher wegen der Pegel. Eventuell musst du die 
relevanten Bits in den beiden Lookuptables invertieren.
1
    //.....EFG
2
    0b00000110, // number 0
3
4
--->
5
6
    //.....EFG
7
    0b00000001, // number 0

: Bearbeitet durch User
von Henry (Gast)


Lesenswert?

Habe die Stromaufnahme gemessen.
Der Prozessor nimmt ohne Anzeige ca. 6-10mA
und mit Anzeige max 19mA bei Anzeige einer 8. Als Programm habe ich das 
obere genommen, allerdings mit verlängerter Anzeigezeit. Unterschiede in 
der Helligkeit der einzelnen Segmente sind nicht zu sehen.

B. W. schrieb:
> z.B.: Du speicherst Port und Pin in einem Array und loopst beim Update
> der Anzeige da drüber. Ungefähr so:

Dies Möglichkeit gefäält mir. Mal sehen ob ich das so hinkriege.

B. W. schrieb:
> Fragen ist das beste was du machen kannst. ABER du musst auch soviel
> Kontext geben, so das man das Problem verstehen kann.

Leider reagieren einige Leute hier sehr komisch auf Fragen. Das geht von 
Hilfe, über das C-Buch bis hin zu verbalen Beleidigungen.
Danke für deine Hilfe

von Johannes S. (Gast)


Lesenswert?

Henry schrieb:
> B. W. schrieb:
>> z.B.: Du speicherst Port und Pin in einem Array und loopst beim Update
>> der Anzeige da drüber. Ungefähr so:
>
> Dies Möglichkeit gefäält mir. Mal sehen ob ich das so hinkriege.

das sollte gehen, nur für den Zugriff auf den Port gibt es noch es 
Makro: _SFR_IO8(SFRNo);

SFRNo ist dann ein uint8_t.

von Axel S. (a-za-z0-9)


Lesenswert?

Henry schrieb:
> Leider reagieren einige Leute hier sehr komisch auf Fragen. Das
> geht von Hilfe, über das C-Buch bis hin zu verbalen Beleidigungen.

Es könnte vielleicht damit zusammenhängen, daß du im falschen Forum 
bist. Hier ist "Projekte & Code". Und die Beschreibung ist:

> Hier könnt ihr eure Projekte, Schaltungen oder Codeschnipsel
> vorstellen und diskutieren. Bitte hier keine Fragen posten!

Da du eine Anfängerfrage(!) zum µC hast, gehört sie in "Mikrocontroller 
und Digitale Elektronik". Aber eigentlich wäre es besser, wenn du mal 
einen Augenblick selber darüber nachdenken würdest. Vielleicht auch 
mal ein Tutorial durcharbeiten. Man muß nicht mit jeder Frage, die sich 
nicht sofort und auf den ersten Blick beantwortet, gleich in ein Forum 
rennen und die Leute dort belästigen.

von Schlaumaier (Gast)


Lesenswert?

Eine dumme Frage.

Wenn es eh auf ein Atiny ist, wieso nimmst du nicht eine Fertige Libs.

von Heiner (Gast)


Lesenswert?

@Schlaumeier

Welche libs soll er denn nehmen??

TO:
Welcher Atiny soll es denn sein?

von Schlaumaier (Gast)


Lesenswert?

Heiner schrieb:
> @Schlaumeier
>
> Welche libs soll er denn nehmen??

Ich dachte da an diese Anleitung. ;) Erschien mir irgendwie logisch.

Die benutzen zwar eine 4-Stellige Anzeige aber das ist eh Wurst.

Weil man muss ja die Lib eh initialisieren (sieh ersten Zeilen im Code).

von Schlaumaier (Gast)


Lesenswert?

Kleine Anmerkung am Rande.

Ich kenne nicht alle Chips der ATiny-Serie. Aber ich kennen den Atiny-85 
sehr gut.

Und der kann keine 7-Segment-Anzeige ohne Hilfs-Chips ansteuern.
Hat ja nur 8 Pins damit erschreckt der keine 7-Segment-Anzeige.
Die braucht nämlich 7 Pins für die LED's und 1 Pin für die Auswahl der 
Ziffer ;)

Weshalb ich in meinen Code oben davon ausgegangen bin, das mind. 1 
PCF-9574 als Bus-Expander (i2c-Bus) nachgeschaltet ist.

Dann muss der TO nur für jede Ziffer die Bit-Sequenz festlegen, und dann 
die Bit-Sequenz in einen Rutsch zum PCF-8574 senden. Die passenden 
"Mikro-Leds" (was anders sind da alles nämlich nicht) werden geschaltet 
und alles ist gut.

Den Code oben von mir, nur leicht anpassen je nach CHIP und Ansteuerung.

Da ich noch kein Schaltplan gesehen habe, kann ich nicht mehr Infos 
geben.

Sein Code ist jedenfalls vielleicht !! Funktionsfähig aber 1000 % zu 
lang.

Ich persönlich würde so ne Primitive Sache sogar (s.Code oben) OHNE Libs 
machen.

von Schlaumaier (Gast)


Lesenswert?

Schlaumaier schrieb:
> Ich dachte da an diese Anleitung. ;) Erschien mir irgendwie logisch.

https://funduino.de/nr-12-7-segment-anzeige

Ich werde alt oder bin zu schnell für meine Tastatur :)

von Schlaumaier (Gast)


Lesenswert?

Kleiner Hinweis.

In den besten Buch was ich zum Arduino kenne und habe (20 Euro bei 
Amazon, in Prime kostenlos) macht der Autor das über ein Schieberegister 
mit > 36 Zeilen Code OHNE Libs. Und das sogar bei einer 4 Stelligen 
Anzeige. ;)

https://www.amazon.de/Arduino-Kompendium-Elektronik-Programmierung-Projekte/dp/3966450399

Das ist DAS Buch für Arduino-Anfänger.  Hat selbst mir viel neues 
gezeigt. Was ich manchmal komplizierter gemacht habe.

Und beschreibt die "üblichen" Komponenten und Module die es für die 
Arduinos gibt. Mit Code die ans laufen zu bringen.

Mir war es die Kohle wert. Habe aber in PRIME Probe gelesen. ;)

von Henry (Gast)


Lesenswert?

Benutze einen Attiny 84 auf Steckbrett. Die Belegung der Pins habe ich 
bereits oben angegeben.
Man kann das ganze auch gern in einen anderen Bereich verlegen, habe 
kein Problem damit.
Ist den Hilfe an bestimmte Bereiche gebunden?
Mit dem Code zu lang geb ich dir vollkommen recht. Er ist noch sehr 
umständlich und lang. Es ist der erste Versuch ein laufendes Programm zu 
schreiben. Es kommt ja auch noch die Anzeige auf 2 7-Segmend Anzeige 
dazu. Da gibt es noch einiges zu tun für mich.

von Schlaumaier (Gast)


Lesenswert?

Henry schrieb:
> Benutze einen Attiny 84 auf Steckbrett.

Ich habe mir den gerade mal angesehen. Wenn du den DIREKT nutzt, sind 
deine Pins weg. ;)

Eine 7-Segment-Anzeige ist nix anders als 7 LED's. Also kannst du sie 
auch genau SO ansteuern.

Du braucht für eine also 7 -Segment-Anzeige 7 PIN + 1 Pin je Ziffer.

Also machst du folgendes.

Du schreibst dir eine SUB-Routine. An die übergibst du das Zeichen (Zahl 
ist auch ein Zeichen) + die Stelle an der das Zeichen erscheinen soll.

********** Variante mit Zusatz-Chip (PCF-8574 oder Schieberegister)

In der Routine machtst du

If Zeichen = "1" then 010101001  ' Du setzt als alle LEDS auf EIN die du 
dafür brauchst.

Als = 16 abfragen.

Dann kommen die Sende-Befehle

If ziffer = 1  then  ' der 2 Parameter des Aufrufs
 ' sende Bit-folge an Chip
end if

Wenn du ein PCF-8574 mit der Passenden Libs hast, brauchst du nur mit 
EINER Zeile die ganze Bit-Sequenz zu senden. und VORHER die passende 
Ziffer zu aktivieren.

Geht auch mit einen Schieberegister.

*** Variante ohne Zusatzchip.

Machst du es von Hand (also ohne Zwischenchip), Dann machst du 
folgendes.

Die selbe SUB mit den selben Aufruf

Aber mit Vorspann.

Aktive Ziffer auswählen.

ALLE Segmente auf AUS.

Dann kommt.
If Zeichen = "1" then
  pin_Segment_a = high
  pin_Segment b = high
end if

Du musst also für jedes Zeichen NUR die passenden Pins auf high (an) 
setzen.

Da du im Vorspann vorher alles aus gemacht hast reicht das völlig aus.

In den Beispiel ist es aber erforderlich das du ALLE Pins vorher 
Deklarierst, damit der Atiny weiß was er da dran hängen hat.

Und wie schon erwähnt. Ich halte diese Variante für MIST, weil danach 
bei deinen Chip kaum noch Pins für andere Sachen übrig bleiben.

Fertig.

Aber wie sagte man schon vor 2000 Jahren. Viele Wege führen nach Rom ;)


Ich bin grundsätzlich der Meinung man soll die Pins am Chip sparsam 
verbrauchen. Weshalb ich IMMER ein Treiberchip für Anzeigen (auch LCD' 
Anzeigen) benutze. Für so ne Dummen Anzeige min. 8 Pins opfern geht mir 
gewaltig gegen den Strich.  Aber jeden da seine.















fertig.

von Patrick L. (Firma: S-C-I DATA GbR) (pali64)


Lesenswert?

Alternativ zum :
Schlaumaier schrieb:
> PCF-8574
Kannst du auch ein: ES47121P16 Verwenden.
1
//              ES47121P16
2
//              ______________________
3
//       SCL---|( 1)SCL        VCC(16)|---VCC(3,3V~5V)
4
//{Dig1(12)}---|( 2)Dig1       SDA(15)|---SDA
5
//{SegD(11)}---|( 3)SegD      SegB(14)|---{SegB(10)}
6
// {SegF(9)}---|( 4)SegF      Dig2(13)|---{Dig2(8)}
7
// {SegP(7)}---|( 5)SegP      Dig3(12)|---{Dig3(6)}
8
// {SegA(5)}---|( 6)SegA      SegG(11)|---{SegG(4)}
9
// {SegE(3)}---|( 7)SegE      SegC(10)|---{SegC(2)}
10
//       GND---|( 8)GND       Dig4 (9)|---{Dig4(1)}
11
//              ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
12
;Command Funktion:
13
; 0xxx=Display Value  [xx:xx]. Where xxx=$000~$FFF          Display=(00:00~40:95)
14
; 1xxx=Display        [bx:xx]. Where x:= 0~5 and xx=$00~$3B Display=(b0:~b5:)(:00~:59) 
15
; 20xx=Display        [Hx:xx]. Where xx=$00~$FF             Display=(0~255)
16
; 30xx=Display        [AP:xx]. Where xx=$00~$3C             Display=(0~60)
17
; 40xx=Display        [EP:xx]. Where xx=$00~$3C             Display=(0~60)
18
; 50xx=Display        [HP:xx]. Where xx=$00~$5A             Display=(0~90)
19
;   60=Display Store  [Stor].  
20
;   70=Display Linear [bLin].  
21
;   80=Display Log.   [bLOG].  
22
;   90=Display Breaket[----].  
23
; Bnxx=Segment Write  [XX:XX]. Where xx=$00~$FF Write direct  Bit 76543210
24
;      to Segment Buffer on Digit (n)                         Seg PGFEDCBA
25
;      Where  n=0->Digit1/n=1->Digit2/n=2->Digit3/n=3->Digit4/
26
;
27
              ; Seg PGFEDCBA    ;|Dis|Cod|Adress       ; Adress |   Segments            | 
28
LED_seg       DB    00111111b   ;| 0 | 0 |             ;  1000h |   _________           | 
29
              DB    00000110b   ;| 1 | 1 |             ;  1001h |  |\   A   /|          | 
30
              DB    01011011b   ;| 2 | 2 |             ;  1002h |  | |¯¯¯¯¯| |   /¯¯\   | 
31
              DB    01001111b   ;| 3 | 3 |             ;  1003h |  |F|     |B|   |UP|   | 
32
              DB    01100110b   ;| 4 | 4 |             ;  1004h |  | |     | |   \__/   | 
33
              DB    01101101b   ;| 5 | 5 |             ;  1005h |  |/_______\|   Dig2   | 
34
              DB    01111101b   ;| 6 | 6 |             ;  1006h |   <   G   >           | 
35
              DB    00000111b   ;| 7 | 7 |             ;  1007h |  |\¯¯¯¯¯¯¯/|          | 
36
              DB    01111111b   ;| 8 | 8 |             ;  1008h |  | |     | |   /¯¯\   | 
37
              DB    01101111b   ;| 9 | 9 |             ;  1009h |  |E|     |C|   |LP|   | 
38
              DB    01110111b   ;| A | A |             ;  100Ah |  | |_____| |   \__/   | 
39
              DB    01111100b   ;| b | B |             ;  100Bh |  |/   D   \|   DIG3   | 
40
              DB    00111001b   ;| C | C |             ;  100Ch |   ¯¯¯¯¯¯¯¯¯           | 
41
              DB    01011110b   ;| d | D |             ;  100Dh |                       |
42
              DB    01111001b   ;| E | E |             ;  100Eh |
43
              DB    01110001b   ;| F | F |             ;  100Fh |
44
              ;     Digit 1  | Digit 2 | Digit 3 | Digit 4 |
45
              ; Seg PGFEDCBA |PGFEDCBA |PGFEDCBA |PGFEDCBA |Displ| Adress |Command
46
LED_Inf       DB    01111100b                              ;b :  |  1010h | 1xxx
47
              DB    01110110b                              ;H :  |  1011h | 20xx
48
              DB    01110111b,11110011b                    ;AP:  |  1012h | 30xx
49
              DB    01111001b,11110011b                    ;EP:  |  1014h | 40xx
50
              DB    01110110b,11110011b                    ;HP:  |  1016h | 50xx
51
              DB    01101101b,01111000b,01011100b,01010000b;Stor |  1018h | 60
52
              DB    01111100b,00111000b,00000110b,01010100b;bLin |  101Ch | 70
53
              DB    01111100b,00111000b,00111111b,00111101b;bLOG |  1020h | 80
54
              DB    01000000b,01000000b,11000000b,01000000b;--.--|  1024h | 90
55
              DB    01111001b,01010000b,01010000b,01000000b;Err- |  102Ch | A0
56
              ;     76543210
57
Dis_X         DB    00000100b                              ;Dig.1|  1030h | Digit1
58
              DB    00001000b                              ;Dig.2|  1031h | Digit2
59
              DB    00010000b                              ;Dig.3|  1032h | Digit3
60
              DB    00100000b                              ;Dig.4|  1033h | Digit4

Dann kannst du direkt als Beispiel ein LT-4620HG anschließen und kannst 
direkt den Code senden.
Der Chip selber kümmert sich um den Rest.
Habe einfachheitshalber gerade ein Definition Beispiel angehängt.
Er kann softwaremäßig wählbar sowohl Comon Anode oder Katode ansteuern

Helligkeit einstellbar, Scannfrequenz einstellbar, Keine zusätzliche 
Komponenten nötig, Direkt mit I²C Ansprechbar.
BCD-DEZ und HEX Anzeige usw.

Dieser IC wurde speziell für 7Seg. LED-Displays wie Typ LT-4620HG
entwickelt(Die in Synthesizer/Keyboard verbaut wurden).

: Bearbeitet durch User
von yesitsme (Gast)


Lesenswert?

Patrick L. schrieb:
> Kannst du auch ein: ES47121P16 Verwenden.

Hast du mal das Datenblatt dazu? Irgendwer hat dazu zwar Werbung 
gebucht, aber ansonsten kennt mein Google den nicht.

von Henry (Gast)


Lesenswert?

Da gebe ich dir Recht, konnte diesen IC auch nicht finden.
Mit dem Attiny geht es mir nicht komplexe oder andere Schaltungen. 
Möchte einfach einen kleinen IC nur für diese Aufgabe haben. Verwende 
sonst meisten einen Atmega 16 oder 328.

von Henry (Gast)


Lesenswert?

Schlaumaier schrieb:
> Ich bin grundsätzlich der Meinung man soll die Pins am Chip sparsam
> verbrauchen. Weshalb ich IMMER ein Treiberchip für Anzeigen (auch LCD'
> Anzeigen) benutze. Für so ne Dummen Anzeige min. 8 Pins opfern geht mir
> gewaltig gegen den Strich.  Aber jeden da seine.

Ich möchte diesen Chip nur für die Anzeige einsetzen. Hauptsache die 
Pins reichen für diese Anwendung. Einen PCF8574 wird nicht rankommen. 
Eine Anwendung könnte z.B. eine (Stop) Uhr oder Rundenzähler sein. 
Könnte auch 2 bis 3 Anzeigen dieser Art nehmen und damit die Zeit 
anzeigen. Eine Verbindung könnte dann mit einem Bus erfolgen. Da nur 
dieser Code darauf laufen soll ist die Grösse des Codes eigentlich egal.
Einen PCF8574 benutze ich bereits an einem Display mit 2x16

von Patrick L. (Firma: S-C-I DATA GbR) (pali64)


Lesenswert?

yesitsme schrieb:
> Hast du mal das Datenblatt dazu? Irgendwer hat dazu zwar Werbung
> gebucht, aber ansonsten kennt mein Google den nicht.

Ja ich bin dabei ein Artikel hier im Wiki zu verfassen, wie ich diesen 
Chip in einer Helligkeitsteuerung verwende.

Der ES47121P16(DIP16) und ES47121S16(SOIC16) sind Kunden IC's die für 
versch. Synthi und Keyboards hergestellt wurden. Sie wurden nie 
offiziell als IC's bei Distries verkauft, sondern nur im Verbautem 
Zustand. Ich selber habe noch welche als Ersatzteile im Lager, so kam 
ich auf die Idee diese als LED Displaykontroller in einem "Programmable 
Dimmer-Projekt" Kundenauftrag zu verwenden, über welchen ich gerade 
ein Artikel für hier im "MC" am schreiben bin.

PS: Der Chip wird sogar immer noch hergestellt, gilt also "noch" nicht 
als Obsolete aber wird doch als NRND aufgeführt.
Darf aber als Ersatzteil verkauft werden, da die Verträge mit den 
meisten Hersteller von Keyboard, mittlerweile ausgelaufen sind.

Datenblatt kann ich dir per PN zusenden, öffentlich hier Posten muss ich 
zuerst Abklären ob ich dies Darf, da dies ja ein OEM Produkt ist. ;-)

Falls aber jemand Interesse hat, ich habe seit über 20 Jahren eine 
Stange der DIP16 Version hier im Ersatzteillager liegen, da ich bis 
heute noch nie einen, als Ersatzteil gebraucht habe, kam ich auch auf 
die Idee ihn bei einem Kleinkundenauftrag einzusetzen und 
hier,(Inspiriert durch genau diesen Thread hier) für welche die so etwas 
suchen, um das "Basteln" von Einzelstücken zu erleichtern, anzubieten.

Die Vergammeln sonnst hier noch im Lager, da sie scheinbar einfach nicht 
kaputtgehen wollen ..LOL...

PS2: Habe beim Durchsehen der Datenblätter übrigens gerade gesehen, dass 
es den auch in einer 60V Version für VFD gegeben hat, weis aber noch 
nicht ob auch dieser noch hergestellt wird.
Bei Interesse kann ich ja mal bei der Produktion in CH nachfragen.

: Bearbeitet durch User
von Schlaumaier (Gast)


Lesenswert?

Patrick L. schrieb:
> Kannst du auch ein: ES47121P16 Verwenden.

DU WIE.

Ich kann nur Chips verwenden die ich kenne und die ich bei Reichelt o.s. 
bekommen kann.

Beide Bedingungen erfüllt dein Chip nicht.

Henry schrieb:
> Ich möchte diesen Chip nur für die Anzeige einsetzen.

Dann benutze doch einfach die "Variante ohne Zusatzchip".

Musst halt nur ALLE Pins extra deklarieren (als Output) und dann 
dementsprechend die Pins an/aus schalten.

Auch kein Hexenwert.

Geht nach meiner Variante oder mit Lib und den Link oben.

von yesitsme (Gast)


Lesenswert?

Patrick L. schrieb:
> Sie wurden nie offiziell als IC's bei Distries verkauft, sondern nur im
> Verbautem Zustand.

Hmm... Keine Dokumentation und keine Verfügbarkeit... Den Chip muß ich 
unbedingt in meiner Schaltung haben...

von Patrick L. (Firma: S-C-I DATA GbR) (pali64)


Lesenswert?

yesitsme schrieb:
> Hmm... Keine Dokumentation und keine Verfügbarkeit... Den Chip muß ich
> unbedingt in meiner Schaltung haben...

Verfügbar ist er, und Datenblatt haben die Hersteller die ihn Verbaut 
haben (Wie wir z.B.) auch. Habe dir ja angeboten, wenn du Interesse hast 
per PN ein Datenblatt zuzusenden. Aber es geht ja hier nicht um einen 
Verkaufstread.

Ich wollte nur dem TO oder welchen die ähnliches aufbauen und ev. halt 
nicht so Fit im Programmieren sind, oder einfach ein Chip suchen die 
komplette 7Seg. Kontroller sind, diesen Chip als Alternative anbieten, 
weil er einfach in der Anwendung ist.

Ich muss keine verkaufen, die liegen auch noch gut 10 weitere Jahre im 
Lager,
Wollte ja nur ein Tipp zur Vereinfachung geben.

Es ist auch nicht gedacht damit Geld zu verdienen, für das habe ich 
definitiv zu wenige im Lager liegen, Der Aufwand würde sich nicht 
Rechtfertigen.
Ist echt nur als Hilfe gedacht, weil sie nun einmal da sind,
Ich habe die ja auch nur, weil ich damals gedacht habe "Muss ich ein 
paar im Lager haben falls mal einer Hopps geht". Was bis heute nicht 
eintraf.

: Bearbeitet durch User
von W.S. (Gast)


Lesenswert?

Henry schrieb:
> Meine Kenntnissevon C sind nicht überdurchschnittlich.

Das verlangt auch keiner von dir. Und mal ganz generell gesagt, ist es 
auch einigemaßen unerheblich, welche Programmiersprache du benutzt. 
Weitaus wichtiger ist es, programmieren zu können, also fähig zu sein, 
gute und tragfähige Algorithmen zum Lösen eines Problems zu erdenken. 
Das Niederschreiben in irgend einer Programmiersprache ist etwas, das 
erst danach kommt.

W.S.

von Achim H. (pluto25)


Lesenswert?

Henry schrieb:
> ein laufendes Programm zu schreiben.
Und es läuft. Damit ist alles gut.
Natürlich kann man immer alles anders machen aber es wird damit nicht 
besser. Vielleicht einfacher oder weniger Schreibarbeit oder schöner 
anzusehen für Person x. Alles irrelevant.
Solange die Anzeige hell genug, der Tinny kalt genug und Pinns genug da 
sind gibt es keinen Grund was zu ändern.
Vielleicht als Hobby um was zu tun?
Den Code kürzen?
Weniger Flash brauchen?
Ihn schneller machen?

von Henry (Gast)


Lesenswert?

A. H. schrieb:
> Vielleicht als Hobby um was zu tun?
> Den Code kürzen?
> Weniger Flash brauchen?
> Ihn schneller machen?

Hobby sagt es am besten. Ansonsten den Code kürzen.
Kann mir auch vorstellen, das alles per Bus übertragen wird. Nur noch 
ein Wert/Buchstabe übertragen und der Attiny macht die Darstellung 
allein.

von Achim H. (pluto25)


Lesenswert?

Henry schrieb:
>  das alles per Bus übertragen wird. Nur noch ein Wert/Buchstabe übertragen und
> der Attiny macht die Darstellung allein.

Da würde sich I2C anbieten, Die richtigen Pins sind noch frei :-)
Vielleicht immer zwei Zeichen übertragen, dan braucht der Tiny nicht zu 
überlegen welches jetzt angezeigt werden soll ;-)

Aber vieleicht vorher das Programm ü+berarbeiten damit auch beide 
Anzeigen (gleichzeitig) was zeigen. Dann muß es etwas hektischer werden 
(das _delay_ms(500)) muß ganz weg/durch einen zähler ersetzt werden. da 
beide Anzeigen <20ms gewechselt werden müssen:
etwa so
Porta wert 1
portb wert1+1an
_delay
portb 1aus
Porta wert 2
portb wert2+2an
-delay und nötige Bearbeitungen (neue Werte holen , etc
portb 2aus
goto etwa so ;-)

: Bearbeitet durch User
von Henry (Gast)


Lesenswert?

Habe das Programm etwas hübscher gemacht. Es wird nur eine Ziffer 
angezeigt.
Die beiden Pins für den Bus hatte ich freigelassen, da ich noch nicht 
wusste wie ich es genau mache.
1
#define F_CPU 8000000UL      // Angabe der Frequenz, wichtig für die Zeit
2
#include "util/delay.h"      // Einbindung Datei Pause
3
#include "avr/io.h"        // Einbindung Datei Ausgänge
4
5
void init_segment()
6
  {
7
    DDRA=0b10001111;      // Port A auf Ausgang schalten
8
    DDRB=0b00000111;      // Port B auf Ausgang schalten
9
    PORTA=0b10001111;      // Port A auf aus
10
    PORTB=0b00000111;      // Port B auf aus
11
  }
12
void clearsegment()
13
  {
14
  PORTA |=(1<<PORTA0)|(1<<PORTA1)|(1<<PORTA2)|(1<<PORTA3);
15
  PORTB |=(1<<PORTB0)|(1<<PORTB1)|(1<<PORTB2);
16
  }
17
void show_number(uint8_t number)            // Zeige Ziffern
18
  {
19
  switch(number)
20
    {  
21
      case 1:
22
      clearsegment();
23
    PORTA &=~((1<<PORTA1)|(1<<PORTA2));        // Ziffer 1 - b, c
24
      break;
25
    case 2:
26
    clearsegment();
27
    PORTA &=~((1<<PORTA3)|(1<<PORTA2)|(1<<PORTA0));  // Ziffer 2 - a, b, g, e, d
28
    PORTB &=~((1<<PORTB0)|(1<<PORTB2));
29
      break;
30
    case 3:
31
    clearsegment();
32
    PORTA &=~((1<<PORTA3)|(1<<PORTA2)|(1<<PORTA1)|(1<<PORTA0));  // Ziffer 3 - a, b, g, c, d
33
    PORTB &=~(1<<PORTB0);
34
      break;
35
    case 4:
36
    clearsegment();
37
    PORTA &=~((1<<PORTA2)|(1<<PORTA1));        // Ziffer 4 - f, g, b, c
38
    PORTB &=~((1<<PORTB1)|(1<<PORTB0));
39
      break;
40
    case 5:
41
    clearsegment();
42
    PORTA &=~((1<<PORTA3)|(1<<PORTA1)|(1<<PORTA0));    // Ziffer 5 - a, f, g, c, d  
43
    PORTB &=~((1<<PORTB1)|(1<<PORTB0));
44
      break;
45
    case 6:
46
    clearsegment();
47
    PORTA &=~((1<<PORTA3)|(1<<PORTA1)|(1<<PORTA0));    // Ziffer 6 - a, f, g, c, d, e
48
    PORTB &=~((1<<PORTB1)|(1<<PORTB0)|(1<<PORTB2));
49
      break;  
50
    case 7:
51
    clearsegment();
52
    PORTA &=~((1<<PORTA3)|(1<<PORTA2)|(1<<PORTA1));    // Ziffer 7 - a, b, c  
53
      break;  
54
    case 8:
55
    clearsegment();
56
    PORTA &=~((1<<PORTA3)|(1<<PORTA2)|(1<<PORTA1)|(1<<PORTA0));  // Ziffer 8 - a, f, b, g, e, c, d
57
    PORTB &=~((1<<PORTB1)|(1<<PORTB0)|(1<<PORTB2));
58
      break;  
59
    case 9:
60
    clearsegment();
61
    PORTA &=~((1<<PORTA3)|(1<<PORTA2)|(1<<PORTA1)|(1<<PORTA0));    // Ziffer 9 - a, f, b, g, c, d
62
    PORTB &=~((1<<PORTB1)|(1<<PORTB0));
63
      break;  
64
    case 0:
65
    clearsegment();
66
    PORTA &=~((1<<PORTA3)|(1<<PORTA2)|(1<<PORTA1)|(1<<PORTA0));    // Ziffer 0 - a, b, c, d, e, f,
67
    PORTB &=~((1<<PORTB2)|(1<<PORTB1));
68
      break;
69
    default: clearsegment();   
70
    }
71
  }    
72
int main(void)
73
  {
74
    init_segment();
75
  uint8_t number = 0;
76
  while(1)
77
  for (;;)
78
    {
79
      if (number <=9)
80
      {
81
      show_number(number);
82
      _delay_ms(1000);
83
      number ++;
84
      }
85
    else
86
      {
87
        number =  0;  
88
      }
89
      }
90
  }
Es gibt verschiedene Möglichkeiten beide Ziffern anzusteuern.
Wie könnte es am besten gehen?

von B. W. (yesitsme)


Lesenswert?

Du willst die "persistence of vision" ausnutzen. Dazu musst du zwischen 
beiden Ziffern hin und herschalten. Idealerweise mit festem Zeittakt, da 
sonst eine Ziffer heller leuchtet als die andere oder es flackern kann.

Ich denke ich würde da einen Timer mit Interrupt verwenden. Das Programm 
berechnet das dazustellende Muster und schreibt es in einen Buffer. Die 
Interrupt routine kopiert den Buffer nur auf die Ports.

Die Interrupt routine könnte so aussehen:
1
byte displayData[2][2] = {
2
     //12..ABCD    .....EFG
3
    {0b01001111, 0b00000111},
4
    {0b10001111, 0b00000111}
5
};
6
byte currentDigit;
7
8
ISR updateDisplay(){
9
    PORTA = displayData[currentDigit][0];
10
    PORTB = displayData[currentDigit][1];
11
    currentDigit = (currentDigit + 1) % 2;
12
}

von Henry (Gast)


Lesenswert?

Wollte erst mal beide Ziffern darstellen ohne Timer um es für mich zu 
lernen. Da gibt es schon die ersten Fragen dazu. Frequenz muss <10 mS 
sein? Wie kann ich das machen das beide Ziffern dargestellt werden bzw, 
2 Unterschiedliche Ziffern. Extremfall sollte es durchzählen von 00 bis 
99. Ist z.b. gut für eine Stopuhr. Dachte dabei an 2 Schleifen in 
einander.
Die Funktion des Timers dabei bin ich noch am lesen.

von Henry (Gast)


Lesenswert?

B. W. schrieb:
> Ich denke ich würde da einen Timer mit Interrupt verwenden. Das Programm
> berechnet das dazustellende Muster und schreibt es in einen Buffer. Die
> Interrupt routine kopiert den Buffer nur auf die Ports.

Das versteh ich noch nicht. Wie soll das gehen?

von B. W. (yesitsme)


Lesenswert?

Anstatt direkt auf das Port zuschreiben schreibst du in displayData:
1
PORTB &=~((1<<PORTB1)|(1<<PORTB0)|(1<<PORTB2));
2
3
--->
4
5
displayData[digitToUpdate][1] = 0x07 & ~((1<<PORTB1)|(1<<PORTB0)|(1<<PORTB2));

Für PORTA musst du dir noch überlegen, wie du das Pattern für die Anoden 
da noch reinbekommst.

Und für die erstem Tests kannst du updateDisplay() auch so oft wie es 
geht in deiner Hauptscheife aufrufen.

: Bearbeitet durch User
von Ralph S. (jjflash)


Angehängte Dateien:

Lesenswert?

... weil ich das gerade für einen ATmega gemacht habe (Multiplexing 
einer 7-Segmentanzeige), habe ich das mal adaptiert für den hier 
genannten ATtinyx4 (wobei sich mir der Sinn - und ich mache sehr viele 
sinnlose Sachen - nicht erschließt, wenn man nach dem Multiplexen nur 
noch eine einzige Portleitung frei hat).

Zur Anzeige gebracht wird der Inhalt des Arrays ("Framebuffer")

fb_seg7[2]

wobei hier jedes Bit der 2 Bytes ein Segment der Anzeige repräsentiert. 
fb_seg[0] ist das rechte, fb_seg[1] das linke Digit.

Ein Timer1 Interrupt erledigt das Multiplexen, so dass ausschließlich 
ein Zugriff auf fb_seg7[x] die Anzeige steuert.

fb_setdez(uint8_t val) und fb_sethex(uint8_t val) beschreibt den 
Framebuffer, so dass bspw. ein Aufruf

fb_setdez(18); die Zahl 18 auf der Anzeige erscheinen läßt.

--------------------------------------------------

in mpx_2conc.h werden alle Angaben "zusammengepfriemmelt", die in 
Verbindung mit den Portpins stehen.

So sind sprechendere Namen gegeben um einen Portpin als Ausgang zu 
definieren:

PA4_output_init();

setzt den Portpin PA4 als Ausgang.
PA4_set(); / PA4_clr();   Setzt bzw. löscht einen Portpin.

PA4_input_init();

würde PA4 als Eingang mit eingeschalteten Pull-Up-Widerstand definieren,

is_PA4()

würde den PA4 Pin einlesen.

Mittels mpx_2conc.h ist es somit sehr einfach möglich, die Zuordnung der 
Pins an die Anzeige vorzunehmen:

#define seg_d     B1

ordnet das Segment d einer Anzeige dem Portpin B1 zu. Hier darf NICHT 
PB1 angegeben werden, da sonst die Verknüpfungen in mpx_2conc.h nicht 
richtig funktionieren.


Gruß,

Ralph

von Peter D. (peda)


Lesenswert?

Henry schrieb:
> Ich möchte mit einem kleinen Attiny 2 x 7 Segment Anzeige ansteuern.

Welcher denn?

Henry schrieb:
> Da aber die
> Anzeige auf Port A und Port B angeschlossen ist, funktioniert das nicht.

Warum machst Du dann sowas?
Am einfachsten ist die generische Lösung:
1
#define set_seg_a() PORTB |= 1<<5
2
// usw.
3
4
void led_out( uint8_t val )
5
{
6
  if (val & 1<<0) set_seg_a(); else clr_seg_a();
7
  if (val & 1<<1) set_seg_b(); else clr_seg_b();
8
  if (val & 1<<2) set_seg_c(); else clr_seg_c();
9
  if (val & 1<<3) set_seg_d(); else clr_seg_d();
10
  if (val & 1<<4) set_seg_e(); else clr_seg_e();
11
  if (val & 1<<5) set_seg_f(); else clr_seg_f();
12
  if (val & 1<<6) set_seg_g(); else clr_seg_g();
13
}

von MaWin (Gast)


Angehängte Dateien:

Lesenswert?

Ralph S. schrieb:
> weil ich das gerade für einen ATmega gemacht habe

So geht es mir auch.

Nicht multiplexen, aber 2 Ziffern statisch angesteuert an einem ATmega8, 
Segmente der 1er und 10er Stelle auf PortD und PortB verteilt wie es 
sich ergab:

PD0: G1, PD1: A1, PDC1, PD3: E1, PD4: D1, PD5: C10, PD6: E1, PD7: B1
PB0: B10, PB1: G10, PB2: A10, PB3: F10 PB6: D10, PB7: E10

Nur C der 10er ist also auf dem Port der 1er gelandet. Man muss nur die 
7-Segment Ziffernmuster passend codieren, und kann dann x von 0 bis 99 
ausgeben:
1
 struct { unsigned char D,B; } seg1={{0xDE,0x00},{0x84,0x00},{0x9,B,0x00},{0x97,0x00},{0xC5,0x00},{0x57,0x00},{0x5F,0x00},{0x86,0x00},{0xDF,0x00},{0xD7,0x00}};
2
 struct { unsigned char D,B; } seg10={{0x00,0x20},{0x01,0x20},{0xC7,0x00},{0x47,0x20},{0x0B,0x20},{0x4E,0x20},{0xCE,0x20},{0x05,0x20},{0xCF,0x20},{0x4F,0x20}};
3
4
 PORTD=seg1[x%10].D|seg10[x/10].D;
5
 PORTB=seg1[x%10].B|seg10[x/10].B;
Warum ein ATmega8 und diese Anzeige ? Weil das rumlag und den Job 
erfüllt

von Ralph S. (jjflash)


Angehängte Dateien:

Lesenswert?

Ralph S. schrieb:
> (wobei sich mir der Sinn - und ich mache sehr viele
> sinnlose Sachen - nicht erschließt, wenn man nach dem Multiplexen nur
> noch eine einzige Portleitung frei hat).

Jetzt zitiere ich mich mal selbst:
Eine Anwendung habe ich mal gefunden: ein Thermometer an der 
7-Segmentanzeige. Thermometer realisiert mittels 10k NTC Widerstand und 
Lookup-Table  und Interpolation der Stützstellen.

Beim Foto möge man mir verzeihen, ich habe nur eine 4-stellige Anzeige 
zur Verfügung gehabt und von daher sind nur 2 der 4 Stellen genutzt.

von Henry (Gast)


Lesenswert?

Peter D. schrieb:
> Warum machst Du dann sowas?
> Am einfachsten ist die generische Lösung:

Das versteh ich nicht. Hatte bisher nichts damit zu tun.
Ich verwende einen Attiny 84. Ersteinmal hatte ich den rumzuliegen da 
ich den mal falsch bestellt habe. Und zweitens reichen die Pins genau 
für die Aufgabe aus.
Möchte es versuchen eine grössere Aufgaben in mehrere kleine Teil zu 
zerlegen. Es wurde oben schon der I2C Bus angedacht. Ein Master soll die 
Aufgaben verteilen und die Ergebnisse zur Anzeige geben. Dachte dabei an 
"verteilte Intellegenz". Als Master dachte ich an den Atnega8/32 oder 
328 oder sogar an einen SAM. Natürlich nur was dabei mit meinem Wissen 
möglich ist.

von Schlaumaier (Gast)


Lesenswert?

Wie oben schon erwähnt.

Für LED-Displays (egal welcher Art) ist ein Port-Expander (ich liebe den 
PCF-8574) IMMER die beste Lösung wenn das Display von Allein kein Bus 
mitbringt.

Selbst bei den Großen AT-MEGA (54 Pins wenn ich das richtig im Kopf 
habe) würde ich ein Port-Expander nutzen.

Das hat 2 Gründe.

1. Ich kann das Display ohne KM an Kabel verbinden.
2. Die Ansteuerung ist bedeutet leichter in der Software.

Was heißt der Code wird bedeutend kürzer.

Und wenn man das Display mal tauschen muss, weil z.b. für die 
Erweiterung das 2 Zeilen Display nicht mehr ausreicht muss man auch 
nicht an der Hauptplatine herum spielen.

Das gilt auch für 7-Segment-Anzeigen.  Beispiel : du hast ein 2 Stellige 
und merkst das eine 4 Stellige besser wäre. Du hast vorher die Anzeige 
und den Port-Expander auf einer Hilfs-Platine montiert.

Du ziehst die Hilfs-Platine ab. Steckst die neue dran, verlegst noch 2 
Leitungen für Stelle 3 + 4 und bist fertig. Bisschen im Code 
nachgebessert.

Alles in allen ist das so sehr einfacher zu Händeln. Und die abgebaute 
Platine. Die kannst du Problemlos ohne viel Theater in ein anderes 
Projekt einbauen.

Und ich weiß wovon ich rede.  Ich habe in einer meiner 
Lieblings-Projekte die 1602 gegen eine 1604 getauscht.  Beide hatten 
eine Huckpack-Platine mit PCF-8574. Kabel abziehen, neuen dran, FERTIG.

Der größte Aufwand war, und das meine ich bitter ernst, das auf fräsen 
des Lochs im Gehäuse wo das größere Display rein sollte. !!

Gerade auf Steckboards wirst du so was lieben lernen. Da gilt : JE 
weniger Kabel desto besser. Die wackeln alle wie Hund mit Schwanz und 
erzeugen gerne Wackelkontakte.

von Henry (Gast)


Lesenswert?

Da geb ich dir Recht. Mit dem PCF8574 kann viel machen. Es ist immer der 
I2C Bus mit dabei. Finde diesen Bus eigentlich sehr gut. Was machst du 
aber wenn es den 8574 nicht mehr gibt und es nur noch den MCP23017 gibt. 
Ist im Grunde das selbe und hat noch einiges mehr. Das Programm kann man 
anpassen, ist klar. Habe auch (Farb) Displays mit Bus gesehen. Ist 
wahrscheinlich eine ganz andere Welt. Da gibt es noch viel zu lernen für 
mich.

von MaWin (Gast)


Lesenswert?

Schlaumaier schrieb:
> Für LED-Displays (egal welcher Art) ist ein Port-Expander (ich liebe den
> PCF-8574) IMMER die beste Lösung wenn das Display von Allein kein Bus
> mitbringt.

Warum kommt von Schlaumaier IMMER der gröbste Unsinn.

Die beste Lösung, kommerziell gerne verwendet, ist ein uC mit 
eingebauten Stromquellen und leistungsstarken Multiplexausgangen wie 
beim SinoWealth SH79F3212 oder PIC16F1764.

Zweitbeste Lösung für LED Anzeigen  ist ein Schieberegister-Treiber mit 
Konstantstromausgängen wie DM13 oder TLC5923 oder gleich multiplexfähig 
wie MAX7219 oder TB62709.

Aber all die kennt der rückständige Schlaumaier naturlich nicht.

Der PCF8574 ist das dümmste was man machen kann, weil er ein I/O 
Expander ist, also universell auch für Eingänge, die man nicht braucht 
und das Programmieren erschweren und unnötig teuer ist. Er begrenzt den 
Strom nicht selbst sondern braucht pro LED einen Vorwiderstand und 
schaltet nur nach Masse, ist für common cathode also ungeeignet Simple 
74HC595 wären sind billiger und besser.

von Ralph S. (jjflash)


Lesenswert?

Leute, es geht hier doch nicht darum, welche externen Chips die besseren 
sind. Der TO wollte eine Multiplexlösung ohne externen Chips.

Wenn er darüber spricht, an dem Tiny84 noch einen I2C Bus zu 
realisieren, muß er bei der Anzeige den DP weglassen. Dann hat er 7 Pins 
für die Segmente plus 2 Pins fürs multiplexen => in Summe 9. Plus 3 Pins 
für Vcc, Gnd und /reset sind 12. Hat er noch genau 2 Pins frei ( und 
keinen Dezimalpunkt auf der Anzeige ). Wie gesagt beim Thema bleiben. 
Wenn man eine einfache Lösung haben will, nimmt man einen Controller mit 
LED Konstantstromausgängen oder einen externen Chips, der das 
Multiplexen erledigt (TM1637, Max xxxx).

Beim TO geht's darum das Display ohne Chip zu verwenden und darum wie 
das geht. Hieraus kann er etwas lernen.

von Henry (Gast)


Lesenswert?

Danke für deine Worte. Mit dem DP hast du recht, hatte vergessen es zu 
sagen.
Habe das Netz durchsucht und einige Infos zum Grund gefunden.
Ich brauche einen Timer, der einfachste reicht aus. Er muss mit ca.5ms 
zwischen den beiden Anzeigen umschalten, Die verbleibende Zeit muss er 
an sein. Dann muss ich der den Anzeigen jeweils den Inhalt zu ordnen. 
Bei 2 Anzeigen sind von 00 bis  99 alles möglich. Die Anzeigen von a bis 
f nehme ich erst mal nicht. So muss weiter lesen...

von Ralph S. (jjflash)


Lesenswert?

Henry schrieb:
> Er muss mit ca.5ms
> zwischen den beiden Anzeigen umschalten, Die verbleibende Zeit muss er
> an sein. Dann muss ich der den Anzeigen jeweils den Inhalt zu ordnen.

Du hast den Beitrag Beitrag "Re: 7 Segment Anzeige auf verschiedenen Ports" 
oben aber schon gelesen, oder?

Da ist der Timer(interrupt), der allerdings mit ca. 1 mS läuft, schon 
integriert und alles was du brauchst um die Anzeige zu steuern. Wenn du 
den Dezimalpunkt dort nicht brauchst, kannst du den Portpin frei lassen 
und diesen Pin dann einfach nicht als Ausgang initialisieren. Somit sind 
dann am Controller 2 Portpins frei.

von Schlaumaier (Gast)


Lesenswert?

Ralph S. schrieb:
> Leute, es geht hier doch nicht darum, welche externen Chips die besseren
> sind. Der TO wollte eine Multiplexlösung ohne externen Chips.

PERFEKTE Aussage.

Ich habe den PCF-8574 in Massen (> 20 Stk.) hier liegen. Und Widerstände 
(kosten SMD < 1 Cent) bestelle ich eh im 100er Paket.

Also löse ich ALS HOBBY eine Sache lieber mit den was ich habe, als das 
ich mir ein Haufen Spezialchips besorge, die den Job sicher besser 
erledigen können.

Der PCF-8574 (und sein großer Bruder) sind für mich genau das was auch 
in der Beschreibung steht. PORT-EXPANDER.  Sie stellen mir also mehr 
Pins zu Verfügung bzw. retten meine "Pins on Board" vor der Benutzung.

Ach und nur zu Info.
den MCP23017 habe ich auch 3 x hier liegen.

Und Schieberegister setze ich nur ein, wenn der I2C-Bus überlagert wird, 
da die i.r.R. hintereinander geschaltet werden können. Was bedeutet, so 
ca. ab der 17 LED setzte ich das dann ein.

Aber wie schon erwähnt. Ich mache das als Hobby. Mit den Dingen die ich 
zur Verfügung habe, und die ich preiswert kaufen kann. Und da ich keine 
Firma bin, sind Bestellungen bei Mouser oder Farnell auch außen vor. Und 
nein, dank der Lästereien hier, vertraue ich hier keinen Mehr, was heißt 
ich kann mich auch keiner Sammelbestellung anschließen. SORRY.  Also 
bastele ich mir den Sache die ich halt bei Reichelt + Co. bekomme.

Und da kostet der PCF-8574 < 1 Euro (jedenfalls in meiner letzten 
Bestellung)

Aber jeder baut anders.  Ich habe nur meine Gründe gesagt wieso ich es 
SO mache.

von Henry (Gast)


Lesenswert?

Ralph S. schrieb:
> Du hast den Beitrag Beitrag "Re: 7 Segment Anzeige auf verschiedenen
> Ports"
> oben aber schon gelesen, oder?

Hallo Ralph
Ja, den Beitrag habe ich gelesen. Bin dabei es zu verstehen. Die zweite 
(h) dabei bringt mich etwas durcheinander. Habe bisher kein Programm mit 
2 Datein gesehen. Wenn ich es richtig gesehen habe kann ich die Segmente 
frei angeben. Timer ist auch drin, habe ich gesehen.

Mit dem PCF8574 hast du vollkommen recht. Es gab hier auch schon eine 
Disput wie weit der PCF noch verwendet werden kann. Ist ja nicht mehr 
der Jüngste. Die Anwendung ist einfach und schnell. Habe mir die neuen 
ICs auch angesehen. Jeder IC hat seine Vor- und Nachteile.
Bin aber dabei die Leistung zu verteilen. Die Attiny sind für diese 
kleine Aufgabe sehr gut geeignet. Wenn man es schafft den Master richtig 
zu programmieren kann man viele Sachen machen. Mach die ganze Sache auch 
nur als Hobby und was ich mir leisten kann. Versuche lieber den IC zum 
Leben zu erwecken als mir das blöde Fernsehprogramm anzuschauen. Möchte 
meine grauen Zellen auch noch was bieten und nicht durch Langeweile dem 
Alk verfallen.

von Schlaumaier (Gast)


Lesenswert?

Henry schrieb:
> Versuche lieber den IC zum  Leben zu erwecken als mir das blöde Fernsehprogramm 
anzuschauen. Möchte  meine grauen Zellen auch noch was bieten und nicht durch 
Langeweile dem  Alk verfallen.

Ich auch. ;)

Aber ich habe pay_tv für Arme. Da ist Discovery und History mit drin. Da 
lernt man echt viel.

Da aber ich nicht nur Dokus schauen mag, habe ich mit Arduinos 
angefangen. Zuerst mit einen Starter-Kit mit UNO damit man mal ein 
Anfang hat. Dann schnell zu Nano weil so schön klein. Und als ich 
schnell gemerkt habe, was man damit alles machen kann, kamen mir viele 
schöne Ideen meine Modellautos (Revell + Co.) mal zu Beleuchten. Ergo 
bin ich dabei da Atiny-85 (Das Teil gab es SMD für unter 1 Euro /Stk. 
bei Reichelt) einzubauen und jede Menge Beleuchtung einzubauen. Wegen 
der Größe wird das nicht Elektronisch korrekt aber es funktioniert, das 
ist die Hauptsache. ;)

Wie gesagt. Mir muss was einfallen und dann baue ich es.

Kein Stress, keine Hektik und wenn es mal 5 Monate im Schrank liegt 
juckt das auch keinen.

von Ralph S. (jjflash)


Lesenswert?

Henry schrieb:
> Hallo Ralph
> Ja, den Beitrag habe ich gelesen. Bin dabei es zu verstehen. Die zweite
> (h) dabei bringt mich etwas durcheinander. Habe bisher kein Programm mit
> 2 Datein gesehen.

kein böse gemeintes "Oh jeh":

Kein größeres Programm (in C) wird aus einer einzelnen Datei bestehen 
(und kleinere wohl auch nicht).

Wahrscheinlich ohne dass du es bemerkst verwendest du für deine 
Programmierung auch mehrere Datei (bspw. durch ein #include 
<utils\delay.h>.

Eine "h-Datei" (Header) beinhaltet zum einen Deklarationen vorhandener 
Funktionen. Das heißt, es werden allgemein gehaltene Funktionen die in 
anderen Programmen auch genutzt werden können, in eine extra Datei 
geschrieben (die dann in aller Regel .c heißt). Die Ausarbeitung dieser 
Funktion nennt sich "definition". Die Header Datei ihrerseits, die im 
Hauptprogramm eingebunden wird, beinhaltet die Deklarationen. Eine 
Deklaration ist hierbei die Bekanntgabe, welche Funktionen vorhanden 
sind, und die in einem Hauptprogramm verwendet werden können.

Somit ist es möglich, das Hauptprogramm von den ausgelagerten Funktionen 
unabhängig voneinander zu compileren. Durch dieses compilieren entsteht 
kein lauffähiges Programm, sondern ein sogenannter Object-Code. Erst das 
Verbinden von Hauptprogramm und anderen externen Programmteilen (manche 
hier, vor allem Arduinonutzer nennen das gerne Lib) erzeugt ein 
lauffähiges Programm. Das Verbinden von mehreren Programmteilen zu einem 
lauffähigen Programm nennt man "linken", das Programm nennt man Linker. 
Im AVR-GCC ist ein Linkerprogramm integriert.

Zum Anderen sind ein einem Headerfile sogenannte "define" und "Macros" 
vorhanden.

Im einfachsten Fall kann man bei einem "define" sagen, dass es ein 
"suchen und ersetzen" in einem Hauptprogramm ist:

#define laufspeed     200


Egal wo nun im Hauptprorgramm "laufspeed" auftaucht, wird dieses durch 
den Wert 200 ersetzt:

_delay_ms(laufspeed);

im Hauptprogramm bedeutet nichts anderes als

_delay_ms(laufspeed);

Der Text eine .h Datei wird genau an der Stelle einefügt, an der diese 
mittels

#include "datei.h"

angegeben ist.

---------------------------------------------

In meinem Fall könnte also der komplette Textinhalt des .h - Files auch 
an dieser Stelle niedergeschrieben werden. Beim Compilieren meines 
Programmes ist also darauf zu achten, dass genau diese Datei sich im 
selben Verzeichnis befindet wie das Hauptprogramm.

In meinem Fall gibt es zu meiner h-Datei keine entsprechende .c Datei, 
da keine weiteren Funktionen (die hinzugelinkt werden müssten) 
existieren.

Hier sind nur Macros angegeben, die erst bei einem Aufruf im 
Hauptprogramm Programmcode erzeugen.

Diese Macros gewähren einen einfacheren Umgang mit den I/O Pins des 
Controllers und sind fast schon als eine Art Abstraktion anzusehen:
1
  #define MASK1                ( 1 << 1 )
2
3
  #define PA1_output_init()    ( DDRA |= MASK1 )
4
  #define PA1_set()            ( PORTA |= MASK1 )
5
  #define PA1_clr()            ( PORTA &= ~MASK1 )
6
  #define PA1_input_init()     { DDRA &= ~MASK1; PORTA |= MASK1; }
7
  #define is_PA1()             ( (PINA & MASK1) >> 1 )

Wann immer auch im Programmtext "MASK1" geschrieben wird, steht dort in 
Wirklichkeit (1 << 1 ), was einem Zahlenwert von 0x02 entspricht (auch 
das hätte man für MASK1 schreiben können.

PA1_output_init() wird somit durch:

DDRA |= (1 << 1);

ersetzt, dieses entspricht dem Initialisieren des Pins PA1 als Ausgang.

PA1_set() wird durch:

PORTA |= (1 << 1);

dieses entspricht dem Setzen eines Portpins auf 1.

Das ganze hat den Vorteil, wenn man dieses einmal für alle Pins eines 
Controllers gemacht hat, sich nicht mehr mit der Hardware 
auseinandersetzen zu müssen, wie denn ein Port zu initialisieren ist und 
wie dieser bspw. auf 1 oder gesetzt werden kann (eine ähnliche 
Vorgehensweise habe ich mit allen Controllerfamilien gemacht, die von 
mir eingesetzt werden, auch die der STM32 Familie).

Im Weiteren meiner .h Datei nehmen die defines in ihren Deklarationen 
etwas "kryptische" Formen an (nur die Deklaration, nicht deren 
verwendung):

Sie setzen nun mehrere Defines so zusammen, dass bspw. ein

kseg0_init()

entsteht. Du kannst innerhalb deines Hauptprogramms nun einfach 
kseg0_init(); hinschreiben, und der Port an dem die Multiplexleitung 0 
angeschlossen ist, wird initialisiert. Schreibst du also bspw. im 
Hauptprogramm:

#define kseg0    A5

so wird automatisch PA5 als Anschlussleitung für Multiplexlinie 0 
bestimmt. Das Hauptprogramm bedient sich nur dieses kseg0 und nicht den 
Hardwarenamen des Controllers.

Würdest du anstelle von A5 bswp. B2 angegeben, so wäre dann 
logischerweise B2 die Multiplexleitung (hier müßtest du dann natürlich 
den Anschluss der vorher für B2 vorgesehen war ändern).

Für ein erstes Ausprobieren kannst du auch schlicht die .h Datei nehmen, 
und deren Inhalt an die Stelle kopieren, an der das "include" auftaucht. 
Dieses macht aber den Sourcecode im Hauptprogramm relativ 
unübersichtlich

von Ralph S. (jjflash)


Lesenswert?

Ralph S. schrieb:
> Egal wo nun im Hauptprorgramm "laufspeed" auftaucht, wird dieses durch
> den Wert 200 ersetzt:
>
> _delay_ms(laufspeed);
>
> im Hauptprogramm bedeutet nichts anderes als
>
> _delay_ms(laufspeed);

muß natürlich heißen:

_delay_ms(200);

von Peter D. (peda)


Lesenswert?

Ralph S. schrieb:
> Du hast den Beitrag Beitrag "Re: 7 Segment Anzeige auf verschiedenen
> Ports"
> oben aber schon gelesen, oder?

Diese generische Lösung hatte ich auch vorgeschlagen. Wird ja nach 
SBI/CBI übersetzt, ist also schnell und wenig Code.
Maskieren über mehrere Ports hinweg verleitet dagegen schnell zu 
Fehlern.

von Ralph S. (jjflash)


Angehängte Dateien:

Lesenswert?

... in der Datei mpx_2digit_demo.c hat sich ein Fehler eingeschlichen. 
Die Funktion

void seg7_allclr(void)

stammt aus einer Version für gemeinsame Kathode (und nicht für 
gemeinsame Anode). Sie löscht nicht alle Segmente, sondern sie setzt 
alle. Dieses ist der Grund für ein leichtes Hintergrundleuchten der 
Digits, korrekt muß sie lauten:
1
/* --------------------------------------------------------
2
                         seg7_allclr
3
4
     schaltet alle Segmente einer Anzeige aus, funktioniert
5
     schneller als seg7_setbmp(0)
6
   -------------------------------------------------------- */
7
void seg7_allclr(void)
8
{
9
  a_segset();
10
  b_segset();
11
  c_segset();
12
  d_segset();
13
  e_segset();
14
  f_segset();
15
  g_segset();
16
  dp_segset();
17
}

von MaWin (Gast)


Lesenswert?

Ralph S. schrieb:
> Beim Foto möge man mir verzeihen, ich habe nur eine 4-stellige Anzeige
> zur Verfügung gehabt und von daher sind nur 2 der 4 Stellen genutzt.

Ich vermisse die Vorwiderstände, das ist unverzeihlich.

von Ralph S. (jjflash)


Lesenswert?

Henry schrieb:
> Die Attiny sind für diese
> kleine Aufgabe sehr gut geeignet. Wenn man es schafft den Master richtig
> zu programmieren kann man viele Sachen machen.

Wenn du den ATtiny wirklich nur als Anzeigentreiber verwenden magst, 
wärst du tatsächlich mit einem fertigen externen Anzeigentreiber besser 
bedient. Potentielle Bausteine sind hier:

- MAX7219 ( 8 x 8 Segmente)
- TM1637 ( 20pol. , 6 Digits zu je 8 Segmente, 16 Tasten)
- TM1638 ( 28 pol. , 10 Digits zu je 8 Segmente, 24 Tasten)
- TM1651 ( 16 pol. , 4 Digits zu je 7 Segmente, 7 Tasten)

Allen obigen Bausteinen gemein ist, dass sie, wenn sie mit einem Wert 
beschrieben wurden, diesen solange anzeigen bis dieser geändert wird.

Daneben kann tatsächlich auf die (ultrabilligen) Schieberegister 74HC595 
zurück gegriffen werden. Hier entsteht aber das kleinere Problem (wie 
bspw. mit den Chinamodulen, die diese in Verbindung mit 
7-Segmentanzeigen einsetzen), dass die serielle Ausgabe auf diesen 
Bausteinen dennoch gemultiplext werden muß (sofern nicht jedes einzelne 
Schieberegister statisch ein Digit ansprechen soll).

Bspw. können mit 2 kaskadierten Schieberegistern insgesamt 16 Pins 
gesteuert werden. Hier wären 8 Pins für die Segmente und 8 Pins für 
Multiplexleitungen frei. So könnten hier dann insgesamt nach dieser 
Methode 8 Digits angeschlossen werden. Nachteilig bei dieser Methode 
ist, dass hierfür innerhalb eines Interrupts die Anzeigen dennoch 
gemultiplext werden müssen (was bei einem expliziten Anzeigentreiber 
nicht der Fall ist).

Gegen einen Anzeigentreiber realisiert mit einem ATtiny spricht das 
Multiplexen an sich und das Fehlen von Kommunikationsschnittstellen. Ein 
serielles Protokoll mittels des USI (zudem noch als Slave) ist nicht 
wirklich lustig zu realisieren.

------------------------------------------------

Unabhängig davon bin ich am überlegen wie ein proprietärer (nur zu mir 
kompatibler) 1-Drahtbus aussehen könnte, damit über diesen bspw. ein 
ATtiny von einem anderen Controller aus angesprochen werden könnte. 
Dadurch, dass der Controller im Multiplexing beschäftigt ist, ist hier 
ein Timing einzuhalten nicht so ganz trivial

von Henry (Gast)


Lesenswert?

Hallo Ralph
Verwende an sich den HT16K33 sehr gern. Hat von Hause aus den I2C bus 
drin und kann sehr gut eine Matrix oder Balken ansteuern. Gibt es als 
Modul zum aufstecken. Hatte im Netz auch schon eine Laufschrift damit 
gesehen. Ist auch leicht zu programmieren. Auch USI gibt es ja im Netz. 
Muss mal schauen ob es nicht einen Attiny mit Bus gibt. Kann mich dran 
erinnern auch was dazu gesehen zu haben.
Warum kann man die Aufgaben nicht verteilen? Der Master organisiert 
alles und die einzelnen Slaves machen die Aufgaben. Dachte dabei an 
einen Encoder, Joystick oder Sprachausgabe mittels MP3 oder WAV020. Jede 
Platine hat seine spezielle Aufgabe. Im Grunde hat der Master mit der 
Anzeige auf einem Farb TFT Graphikdisplay so um 3 bis 5 Zoll schon genug 
zu tun.
Es gibt doch viele Baugruppen mit Bus, so wie den INA 219.

von Henry (Gast)


Lesenswert?

Bekomme noch einge Fehlermeldungen.
#define kseg1_init()          CONC(P,CONC(kseg1,_output_init()))
  #define kseg1_set()           CONC(P,CONC(kseg1,_set())
  #define kseg1_clr()           CONC(P,CONC(kseg1,_clr()))
Die mittlere Zeile verursacht ein
"Error'CONC' undeclared (first use in this function)"
Die anderen habe ich soweit gefunden, Fehlende Klammern oder vergessenes 
Semikolon, alles wahrscheinlich übertragungsfehler. Auf diesen kann ich 
mir leider keinen Reim machen.

von Henry (Gast)


Lesenswert?

Es fehlt eine Klammer !!!!!!

von Henry (Gast)


Lesenswert?

Es wird jetzt ohne Fehler übertragen. Es erfolgt auch eine Anzeige auf 
den beider 7-Segment. Allerdings wechseln die Segmente so schnell das 
nichts zu erkennen ist.

von Henry (Gast)


Lesenswert?

Habe den DP auskommentiert und die Segmente korrekt zugewiesen.
Da hast du ja ein richtiges Spielzeug programmiert. Eine Ziffer zählt 
ständig durch von 0 bis 9. Die andere Ziffer ist so schnell das man die 
einzelnen Zahlen nur ahnen kann und nach 99 kommt das umlaufende Segment 
als Abschluss. Sieht wirklich gut aus und zeigt die Funktion.
Damit fängt die Arbeit bei mir an, muss es noch verstehen.
Danke

von Ralph S. (jjflash)


Angehängte Dateien:

Lesenswert?

Henry schrieb:
> Eine Ziffer zählt
> ständig durch von 0 bis 9. Die andere Ziffer ist so schnell das man die
> einzelnen Zahlen nur ahnen kann und nach 99 kommt das umlaufende Segment

Dann stimmt noch etwas nicht. Das Demoprogramm zählt kontinuierlich 
hoch, Zeitdauer zwischen dem Hochzählen gleich 0,3 Sekunden.

Irgendwo ist da dann noch scheinbar der Wurm drin !

Wenn das zu schnell läuft, kann es sein, dass du irgendwo die Angabe für 
F_CPU nicht richtig eingestellt hast.

Kann es sein, dass dein ATtiny auf internem 8 MHz Takt hast aber F_CPU 
mit 1000000 deklariert ist?

Gehe einfach mal ganz am Anfang des Programms her und schreibe ein:

#define F_CPU   8000000ul

darüber und schaue, was er dann macht.

----------------------------

Außerdem wollte ich das jetzt einmal probieren, eine "Fernsteuerung" der 
Anzeige mittels eines anderen Controllers vorzunehmen.
Einfachkeitshalber habe ich hierfür dann den UART verwendet (mittels 
USI) und diesem UART schlicht die Möglichkeit genommen, etwas zu senden. 
Der ATtiny ist somit ein reiner Empfänger.

Natürlich habe ich mir jetzt keine Mühe gemacht, ein besonders stabiles 
Protokoll zu implementieren.

Des TO's wegen habe ich auch die UART-Funktionen nicht in eine andere 
Datei ausgelagert, weil ich nicht weiß, ob er weiß, wie man eine 
Sourcedatei zu einem bestehenden Programm hinzulinkt.

Das "Füttern" des ATtiny mittels UART funktioniert. Hierfür mußte jedoch 
der Anschluß PA6 frei gemacht werden, an dem bisher das Segment "g" 
angeschlossen war, weil auf diesem Anschluß, der Input für das USI ist.

Ist die Schaltung aufgebaut, so erwartet das Programm auf der seriellen 
Schnittstelle 3 Zeichen:
1
     - 1. Zeichen:   0 => kein dp wird angezeigt
2
                     1 => dp wird angezeigt
3
     - 2. Zeichen:   10er Stelle der Anzeige
4
     - 3. Zeichen:   1er Stelle der Anzeige

Sendet ein Host (über UART) bspw. "156" wird auf der Anzeige "5.6" 
angezeigt.
Wird ein Leerzeichen anstelle einer der beiden Ziffern gesendet, 
schaltet diese das betreffende Digit dunkel:

Mit "1 5" wird auf der Anzeige " .5" dargestellt.

von Heiner (Gast)


Lesenswert?

Henry hätte wohl mehr gelernt, wenn er das Programm selbst erstellt 
hätte.

So ist seine Eigenleistung gleich Null.

Stichwort „Hilfe zur Selbsthilfe“ 🤷‍♂️

von Henry (Gast)


Lesenswert?

Das stimmt nicht. Das Programm vorher habe ich selber geschrieben ohne 
jede Hilfe. Auch die erste Version stammt von mir allein.
Hilfe zur Sebsthilfe hat dabei eine ganz andere Bedeutung.
Wenn man im Netz so gut wie keine Tuts oder andere Erklärung findet 
bleibt einen nichts weiter übrig als zu fragen.
Wenn man eine funktionierenden Code bekommt kann man diesen auseinader 
nehmen und genau schauen wie man es macht. Einen Code der nicht 
funktioniert und man Tagelang damit verbringt ihn zum laufen zu bekommen 
nützt wenig und der Verdruss ist recht gross.

von Henry (Gast)


Lesenswert?

Du hast mit den 8 MHz recht, Asche auf mein Haupt. Gebe sehr oft diese 
Daten in eine extra Datei, so auch die Frequenz. Habe es diesmal total 
übersehen. Sorry.
Das musste ich noch anpassen:
1
// Zuordnung der Anschluesse der 7-Segmentanzeige zu den Portpins des Controllers
2
  #define kseg1         A5   // A3 -A7
3
  #define kseg0         A7   // A5 - A5
4
  #define seg_a         A3   // A1
5
  #define seg_b         A2   // A4
6
  #define seg_c         A1   // A7
7
  #define seg_d         A0   // B1
8
  #define seg_e         B2   // B0
9
  #define seg_f         B1   // A2
10
  #define seg_g         B0   // A6
11
  //#define seg_dp            B2
Damit laufen die Zahlen recht gemütlich durch.
Du hast es jetzt auch noch mit UART gemacht. Einfach toll. Werde es 
höchstwahrscheinlich nicht nehmen, da ich auf den I2C Bus gehen werde.
Die übergabe des Wertes soll dabei vom Master zum Slave gemacht werde.
Werde erst mal den Programm auseinder nehmen uns genau schauen wie es 
geht. Scheinbar gefällt des nicht allen

von Ralph S. (jjflash)


Lesenswert?

Henry schrieb:
> Werde es
> höchstwahrscheinlich nicht nehmen, da ich auf den I2C Bus gehen werde.

Hier mußt du dann tatsächlich den Dezimalpunkt komplett weglassen, damit 
du wieder 2 Pins frei hast.

Einen I2C-Slave auf einem ATtiny aufsetzen, das ganze noch wenn ein 
Timerinterrupt läuft, ist schon recht sportlich.

Mit Bitbanging I2C wirst du da (als Slave) nicht so weit kommen und das 
ganze mit USI ist schlicht eine Qual.

Ein einziges Mal habe ich das gemacht gehabt (ATtiny44 als I2C-Slave), 
auf dem ist aber kein Multiplex gelaufen und ich erinnere mich noch, 
dass ich mir die Haare gerauft habe. Leider finde ich die Datei in 
meinen Quellen nicht mehr.

Solltest du das hinbekommen, ist dir mein Respekt gewiss.

von Ralph S. (jjflash)


Lesenswert?

Heiner schrieb:
> Henry hätte wohl mehr gelernt, wenn er das Programm selbst erstellt
> hätte.
>
> So ist seine Eigenleistung gleich Null.
>
> Stichwort „Hilfe zur Selbsthilfe“ 🤷‍♂️

Hier könnte er als erstes einmal lernen, wie das Zusammenspiel von 
Compiler, Präprozessor und Linker funktioniert. Das wäre auch sehr 
hilfreich, wenn er weiter Programme aus dem Netz adaptieren möchte.

Dieses Zusammenspiel ist elementar und hat erst einmal nichts mit dem 
Codieren zu tun. Hier könnte er lernen, wie er das Multiplexing in eine 
.c / .h Kombination auslagern kann um sie bei Bedarf wieder zu 
verwenden.

Da aber seine Entwicklungsumgebung unbekannt ist, kann man hier nicht so 
wirklich helfen. Dem TO sei es aber angeraten sich dieses Zusammenspiel 
einmal genauer anzusehen.

Ein steiniger, aber sehr lehrreicher Weg, ist es, das ganze auf der 
Console zu tun und mittels Makefiles das zu realisieren.

Schauen wir einmal, was er hier noch so schreiben wird.

von Henry (Gast)


Lesenswert?

Ralph S. schrieb:
> Da aber seine Entwicklungsumgebung unbekannt ist, kann man hier nicht so
> wirklich helfen. Dem TO sei es aber angeraten sich dieses Zusammenspiel
> einmal genauer anzusehen.

Es braucht nichts unbekannt zu sein.
Arbeite mit den Atmel Studio 7, oder vielleicht nennt es sich gerade 
anders.
Dann verwende ich einen ICE (früher MK2), für erste Versuche einer 
Schaltung ein Breadboard mit 5v Speisung. Ansonsten gern kleine Platinen 
um SMD oder anderes zu nutzen. Kein Android oder ähnliches, lieber ganz 
normales C. Habe als Prozessot bisher den Attiny84, Attiny2313, Atmega 8 
und 32. Habe mir den Raspi angesehen, komme damit überhaupt nicht klar. 
Erste Versuche mit einem SAM21 und 32 Bit. Meistens IO Ansteuerung, auch 
TFT Farb Graphikdisplay. Habe dazu auch eigene h Datein geschrieben.
Handbuch "C von A-Z" liegt gleich neben den Tasten. Leider bin ich nicht 
der Profi der kompexe Programme vollkommen selber schreiben kann. Aus 
dieser Not herraus schaue ich gern auf andere Programme und versuche den 
Ablauf zu begreiffen. Das erfordert teilweise mehr Wissen um das zu 
verstehen. Nutze gern kleine Programme die frei sind um nicht jeden Tag 
alles neu zu erfinden.
Schau verstärkt auf den I2C Bus. Der gefällt mir sehr gut. Sorry, bin 
schon ein älteres Semester und alles dazu sebst gelernt, nichts 
studiert.
So, das sind meine Daten zu dem Thema. Falls noch was unklar, einfach 
fragen.

von Peter D. (peda)


Lesenswert?

Ralph S. schrieb:
> Einen I2C-Slave auf einem ATtiny aufsetzen, das ganze noch wenn ein
> Timerinterrupt läuft, ist schon recht sportlich.

Ach, das geht recht gut mit dem USI. Der Master muß allerdings das 
Clock-Stretching beherrschen. Aber das muß er immer, wenn der Slave ein 
MC ist, der noch andere Tasks ausführt.
Bei längeren Leitungen kann es allerdings nachteilig sein, daß das USI 
nicht die im I2C-Standard vorgeschriebenen Filter an den Eingängen hat. 
Ich würde daher immer eine CRC über die I2C-Pakete machen.

von Heiner (Gast)


Lesenswert?

Hallo!
Peter D. schrieb:

>
> Ach, das geht recht gut mit dem USI. Der Master muß allerdings das
> Clock-Stretching beherrschen. Aber das muß er immer, wenn der Slave ein
> MC ist, der noch andere Tasks ausführt.
> Bei längeren Leitungen kann es allerdings nachteilig sein, daß das USI
> nicht die im I2C-Standard vorgeschriebenen Filter an den Eingängen hat.
> Ich würde daher immer eine CRC über die I2C-Pakete machen.

Ich denke nicht, dass der TO mit dem von Dir erwähnten Clock–Stretching 
etc zurecht kommt, wenn ich sein Wissen bezgl C und den Prozessoren 
betrachte.
Ohne vorgekautes Beispiel wird das nix

SCNR 😉

Grüße Heiner

von Peter D. (peda)


Lesenswert?

Heiner schrieb:
> Ich denke nicht, dass der TO mit dem von Dir erwähnten Clock–Stretching
> etc zurecht kommt

Das Clock-Stretching macht der USI-Slave automatisch und ein korrekt 
implementierter Master reagiert darauf automatisch, d.h. hält seinen 
SCL-Takt solange an. Der Benutzer muß sich also nicht drum kümmern, man 
sieht es nur auf dem Oszi (verlängerte Low-Zeiten).

von Patrick L. (Firma: S-C-I DATA GbR) (pali64)


Lesenswert?

Peter D. schrieb:
> Das Clock-Stretching macht der USI-Slave automatisch

Und wenn alles sauber Programmiert ist löst die USI ein Interrupt aus 
wenn das Datenpaket (Oder wen vorhanden der FIFO Puffer voll) 
vollständig übertragen ist.

Das selbe gilt übrigens auch beim Master.

: Bearbeitet durch User
von Heiner (Gast)


Lesenswert?

Peter D. schrieb:
> Heiner schrieb:
>> Ich denke nicht, dass der TO mit dem von Dir erwähnten Clock–Stretching
>> etc zurecht kommt
>
> Das Clock-Stretching macht der USI-Slave automatisch und ein korrekt
> implementierter Master reagiert darauf automatisch, d.h. hält seinen
> SCL-Takt solange an. Der Benutzer muß sich also nicht drum kümmern, man
> sieht es nur auf dem Oszi (verlängerte Low-Zeiten).

Patrick L. schrieb:
> Peter D. schrieb:
>> Das Clock-Stretching macht der USI-Slave automatisch
>
> Und wenn alles sauber Programmiert ist löst die USI ein Interrupt aus
> wenn das Datenpaket (Oder wen vorhanden der FIFO Puffer voll)
> vollständig übertragen ist.
>
> Das selbe gilt übrigens auch beim Master.

Na, dann ist ja alles klar 😉

Und Henry kann mit der Implementierung beginnen - wobei ich mich 
erinnere, dass schon mal jemand (hier!) versucht hat, eine I2C 
Kommunikation von Attiny - Atmega128 (vergeblich?) zu implementieren und 
dann wohl am besagten Clock-Stretching gescheitert ist…

von Patrick L. (Firma: S-C-I DATA GbR) (pali64)


Lesenswert?

Heiner schrieb:
> dann wohl am besagten Clock-Stretching gescheitert ist…

Das muss speziell in der USI aktiviert werden.
Default ist Clock-Stretching disabled.

Möglich dass es in dem Thread wo du von Sprichst das Problem war. Kenne 
den Thread nicht und kann deshalb auch nix zu sagen ;-)

von Henry (Gast)


Lesenswert?

Das hat alles noch Zeit. Habe erst noch ein paar andere Sachen vor. 
Dachte dabei an einen Timer, Watchdoog, ADC und Porterweiterungen mit 
Interrupt. Da habe ich noch einiges zu lernen.

von Heiner (Gast)


Lesenswert?

Henry schrieb:
> Das hat alles noch Zeit. Habe erst noch ein paar andere Sachen
> vor.
> Dachte dabei an einen Timer, Watchdoog, ADC und Porterweiterungen mit
> Interrupt. Da habe ich noch einiges zu lernen.

Schau Dir mal die „Tuts“ von Achim S. (Bei makerconnect zu finden) an, 
sind vielleicht interessant für Dich

Und lies ein gutes C Buch 😉

von Henry (Gast)


Lesenswert?

Ich nutze das Buch "C von A bis Z" von Jürgen Wolf. Das wurde mehrfach 
hier als gut erwähnt. Brauche ich noch ein anderes.
Deinem Rat werde ich gern folgen.

von Henry (Gast)


Lesenswert?

Heiner schrieb:
> (Bei makerconnect zu finden)

Habe mir die Seiten bzw. Tuts angesehen. Konnte leider zu 7-Segment 
Anzeige nichts finden. Das mit dem Bus ist sehr interessant.

von Heiner (Gast)


Lesenswert?

Also Henry!

Das mit den 7-Segmentanzeigen wurde Dir doch lang und breit HIER schon 
erklärt, verstehen musst Du es schon selbst, Kollege!

Etwas Eigenleistung ist schon nötig 🤷‍♂️

von Manuel X. (vophatec)


Lesenswert?

Axel S. schrieb:
> gleich in ein Forum rennen und die Leute dort belästigen.

Genau da ist das Problem. Das so mancher offenbar elitärer Kreis hier 
sich belästigt fühlt.

:)

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

Ralph S. schrieb:
>> (wobei sich mir der Sinn - und ich mache sehr viele
>> sinnlose Sachen - nicht erschließt,

Joh, ok dein Code funktioniert ABER ist unnötig complex (da die Segmente 
hier einzeln bearbeitet werden) und daher eher nicht size/speed/power 
optimal.

Ich würde z.B. mit dem gezeigten Makro (oder den Code direkt verwenden)

#define WBITM(r,m,v) (((r)&((0xFF)^(m)))|((m)&(v))) // write bit mask

pro Ziffer (oder auch nur pro Wert, also dann 2 statt 4 Aufrufe) zwei 
obige Port Anweisungen aufrufen. Für jedes Symbol (1-9, A-F) sind m 
(mask) und v (value) für die zwei r (port register) via LUT definiert.

Weiters könnten inaktive Segment Port-Lines Tristate gesetzt werden, für 
Power Save hins. der Porttreiber.

Und die Multiplex Freq wird nicht nur für Digits betrachtet/dynamisch 
gesetzt sondern hins. der Anzahl der aktiven Segmente. Spart wieder 
Power und die Ziffern sind immer alle gleich intensiv hell. Es lassen 
sich so auch Anzeigen verwenden und ausgleichen, wo die Segmente bei 
gleichen Strom unterschiedlich hell sind.

: Bearbeitet durch User
von Ralph S. (jjflash)


Lesenswert?

@Henry:

Vielleicht solltest du dich grundlegender mit bestimmten Techniken 
beschäftigen? Ich weiß jetzt nicht, wo genau deine Probleme sind, den 
Code zu verstehen, aber ich glaube (nach dem Blick in meine Glaskugel), 
das du grundlegendes noch nicht verstanden hast und evtl. "zu hoch" 
einsteigst. Du schreibst zwar von Timern und I2C Bus etc., aber ich 
glaube du hast bisher einfach Code zusammenkopiert und verwendet (ohne 
das Verständnis dafür zu haben).

Um "meinen" Code der 7-Segmentanzeige zu verstehen ist es von zentraler 
Bedeutung, den Timerinterrupt zu verstehen und ich habe dir das einmal 
vereinfacht. Solltest du das schon wissen was jetzt gleich kommt... 
smile, dann war es halt von meiner Seite für umsonst.

Im folgenden Programm wird eine Leuchtdiode mittels Timerinterrupt zum 
Blinken gebracht:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
#define F_CPU  8000000ul
5
6
// 1 << 6 = 0100 0000 bin = Maske fuer Bit Nr. 6 (von 0 an gezaehlt)
7
// ODER Verknuepfungen sind in der Lage ein Bit zu setzen
8
// UND - Verknuepfungen sind in der Lage ein Bit zu loeschen
9
// wird mit der negierten Masek einer ODER Verknuepfung eine
10
// UND - Verknuepfung vorgenommen, so wird das entsprechende Bit
11
// geloescht
12
13
#define MASK          (1 << 6)
14
15
#define led_init()    DDRA |= MASK
16
#define led_set()     PORTA |= MASK
17
#define led_clr()     PORTA &= ~ MASK
18
19
/* ----------------------------------------------------
20
                     Timer 1 Interrupt
21
22
     durch die Initialisierung in timer1_init wird
23
     dieser Interrupt alle 5 mS aufgerufen.
24
   ---------------------------------------------------- */
25
ISR (TIM1_COMPA_vect)
26
{
27
  static uint8_t led_cnt = 0;
28
29
  led_cnt++;
30
  if (led_cnt == 100) led_set();
31
  if (led_cnt == 200)
32
  {
33
    led_clr();
34
    led_cnt= 0;
35
  }
36
}
37
38
/* ----------------------------------------------------
39
                  timer1_init
40
41
     initialisiert Timer 1 so, dass die Interruptroutine
42
     alle 5 mS aufgerufen wird
43
   ---------------------------------------------------- */
44
void timer1_init(void)
45
{
46
  TCCR1B = 1 << WGM12 | 1<<CS10;
47
48
  // OCR1A = Vergleichsregister. Erreicht der Zaehler in TCNT1 diesen
49
  // Wert, so wird ein Interrupt ausgeloest, TCNT1 wird auf 0 zurueck
50
  // gesetzt
51
52
  OCR1A = F_CPU / 200;
53
  TCNT1 = 0;
54
55
  TIMSK1 = 1 << OCIE1A;
56
  sei();
57
}
58
59
/* ---------------------------------------------------------------------------
60
                                    M A I N
61
   --------------------------------------------------------------------------- */
62
int main(void)
63
{
64
  timer1_init();
65
  led_init();
66
67
  while(1);
68
}

Erklärungen:
-----------------------
F_CPU
-----------------------
Wichtig, sollte nirgendwo ein F_CPU definiert sein muß das in Zeile 4 
gemacht werden, weil später beim Initialisieren des Timers genau diese 
Angabe benötigt wird.

#define
-----------------------
Zeile 13 bis 17 ordnet der Verwendung der Portpins "sprechende" Namen 
zu. led_init() ist aussagekräftiger als ein DDRA |= 0x40; Hier weiß man 
sofort, dass der Anschluss initialisiert wird. Bei led_set() / led_clr() 
ist es noch klarer. Das Makro sagt hier, dass der Anschlußpin auf 1 oder 
0 gesetzt werden soll. Außerdem ist es sehr viel einfacher nur im 
#define bspw. den Portpin zu ändern anstelle im gesamten Programm, vor 
allen Dingen dann, wenn dieses setzen / rücksetzen mehr als einmal im 
Programm benötigt wird.

timer1_init()
-----------------------
ist das Einstellen des Timer1 für seine Verwendung. Timer 1 kann in 
mehreren Betriebsarten verwendet werden, hier wird er so eingestellt, 
dass er einen automatischen Interrupt generiert. Hierdurch ist es 
möglich, unabhängig von einem Main-Programm einen Programmaufruf zu 
starten, der nicht explizit aufgerufen wird. Somit ist ein 
"automatischer Intervallbetrieb" möglich. Im Vorliegenden Fall wird ein 
Compare-Modus (Vergleichsmodus) verwendet. Ein interner 16-Bit breiter 
Hardwarezähler wird automatisch hochgezählt. Der Zähler kann von 
unterschiedlichen Taktquellen gespeist werden. Im vorliegenden Fall wird 
er vom Prozessortakt gespeist (hier dann 8 MHz, die mittels den Fuses 
eingestellt sind).

Bei einem 8 MHz Takt entspricht ein Taktzyklus einer Zeit von t = 1 / f 
==> 1 / 8 MHz = 0,125 µS

Zeile 52 ist entscheidend dafür, wie häufig mein Interrupt (ISR) 
aufgerufen wird und gibt somit den Intervall vor, mit dem 
vollautomatisch der Interrupt gestartet wird. OCR1A ist ein 16-Bit 
breites Vergleichsregister. Erreicht der Zählerstand in TCNT1 (ebenfalls 
16-Bit breit) diesen Wert, wird der Interrupt ausgelöst. Im vorliegenden 
Fall ergibt F_CPU / 200 = 8000000 / 200 den Wert 40000. Nach 40000 
Zyklen also wird der Interrupt ausgelöst. Da ein Zyklus 0,125 µS lang 
ist, erfolgt ein Auslösen nach 40000 * 0,125 µS = 5 mS.

ISR (TIM1_COMPA_vect)
--------------------------
Dieses ist die Interruptroutine, die nun alle 5 mS selbsttätig im 
Intervall aufgerufen wird, egal wo sich das Hauptprogramm gerade 
befindet.

Hier möchten wir eine LED blinken lassen.

In Zeile 27 wird eine Variable led_cnt als static definiert. Dieses 
sorgt dafür, dass der Inhalt dieser Variable beim Beenden der 
Interruptfunktion nicht verloren geht und beim nächsten Aufruf verfügbar 
ist.

Nach dem 100sten Aufruf (100 x 5 mS = 0,5 S) wird die LED eingeschaltet, 
beim 200sten Aufruf wieder ausgeschaltet und die Variable zu 0 gesetzt. 
Dieses sorgt jetzt in dem Interrupt dafür, dass die LED blinkt.

main
------------------------

Im main Programm wird lediglich der Timer 1 für den Interrupt 
(Intervallbetrieb) sowie der Anschluß der LED initialisiert. Danach 
folgt in Zeile 67 eine Endlosschleife while(1);

"Eigentlich" dürfte das Programm nun gar nichts tun, weil in der 
Endlosschleife keine Anweisungen stehen. Allerdings wird diese 
Endlosschleife im Intervall unterbrochen und die Interruptroutine (mit 
dem LED-Blinken) ausgeführt.

------------------------------------------------------
So, sollte ich dich damit gelangweilt haben, tut mir das leid, wenn 
nicht, ist es für dich vllt. Interessant diesen Ablauf zu verstehen.
Genau dieses Vorgehen wird bei der Ansteuerung der gemultiplexten 
Anzeige verwendet: Der Interrupt bedient die Anschlußleitungen der 
7-Segmentanzeigen.

Analog hierzu kann man bspw. den Interruptbetrieb dahingehend 
modifizieren, dass man die Blinkdauer der LED aus dem Hauptprogramm 
modifizieren könnte:
1
uint8_t led_an  = 100;
2
uint8_t led_aus = 200;
3
4
ISR (TIM1_COMPA_vect)
5
{
6
  static uint8_t led_cnt = 0;
7
8
  led_cnt++;
9
  if (led_cnt == led_an) led_set();
10
  if (led_cnt == led_aus)
11
  {
12
    led_clr();
13
    led_cnt= 0;
14
  }
15
}
16
17
int main(void)
18
{
19
  timer1_init();
20
  led_init();
21
22
  led_an= 10;
23
  led_aus= 250;
24
  while(1);
25
}

Hier wurden jetzt 2 zusätzliche Variable eingeführt, led_an und led_aus. 
Mittels dieser beiden Variablen ist es möglich das Blinkverhalten im 
Interrupt zu beeinflussen. Ein bloßes Zuweisen von Werten an diese 
Variable im main Programm bestimmt die Pulse- und Pausezeiten der 
Leuchtdiode, ohne auf den Port der LED direkt zuzugreifen. Alles 
geschieht im Intervall. Analog hierzug gilt im übertragenen Sinne bei 
der 7-Segmentanzeige, dass lediglich der Inhalt des Framebuffers 
geändert werden muß, das Anzeigen alleine geschieht im Interrupt.

von Ralph S. (jjflash)


Lesenswert?

Apollo M. schrieb:
> #define WBITM(r,m,v) (((r)&((0xFF)^(m)))|((m)&(v))) // write bit mask

... und du bist dir sicher dass der TO das versteht ?

von Heiner (Gast)


Lesenswert?

Ralph S. schrieb:
> Apollo M. schrieb:
>> #define WBITM(r,m,v) (((r)&((0xFF)^(m)))|((m)&(v))) // write bit mask
>
> ... und du bist dir sicher dass der TO das versteht ?

+ 1 😉

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

Ralph S. schrieb:
> ... und du bist dir sicher dass der TO das versteht ?

Eher so - Ich bin mir jetzt nicht sicher, ob du das verstehst, weil das 
war für dich war!

von Ralph S. (jjflash)


Lesenswert?

Apollo M. schrieb:
> Eher so - Ich bin mir jetzt nicht sicher, ob du das verstehst, weil das
> war für dich war!

Ich habe es schon verstanden gehabt, aber um mich gehts hier ja nicht !

von Henry (Gast)


Lesenswert?

Versuche es mal in ein paar meiner Worte zu sagen:

Ralph S. schrieb:
> #define MASK          (1 << 6)
> #define led_init()    DDRA |= MASK
> #define led_set()     PORTA |= MASK
> #define led_clr()     PORTA &= ~ MASK

Du definierst eine Maske
- Bit 6 von PORT A
- vom DDRA
- PORTA |= - einschalten
- PORTA &= - ausschalten

- Es wird Timer 1 verwendet
- auf 5ms (hab allerdings noch nicht nachgerechnet)

Ralph S. schrieb:
> ISR (TIM1_COMPA_vect)
> {
>   static uint8_t led_cnt = 0;
>   led_cnt++;
>   if (led_cnt == 100) led_set();
>   if (led_cnt == 200)
>   {
>     led_clr();
>     led_cnt= 0;
>   }
> }

Die ISR wird unabhängig vom restlichen Programm alle 5 ms aufgerufen. 
Das Programm wird danach automtisch an der letzten Stelle weiter 
ausgeführt.
In der ISR schaltest du die LED die du in der Maske zugewiesen hast.
Zählvariable ist dabei led_cnt, wird zu Anfang auf 0 gesetzt.
led_cnt zählt bei jedem Durchlauf 1 hoch.
Mit led_cnt == sind Schaltpunkte definiert, 100 ein, 200 aus.
Bei 200 wird auch led_cnt auf 0 gesetzt. Und das ganze beginnt von vorn.
Hoffe das ich es richtig zusammengaêfasst habe.
So was ähnliches verwende ich selbst bei Muktitasking.
1
#define F_CPU 16000000UL  // Angabe der Quarzfrequenz, wichtig für die Zeit
2
#include <util/delay.h>    // Einbindung Datei Pause
3
#include <avr/io.h>      // Einbindung Datei Ausgänge
4
#include <avr/interrupt.h>
5
#include <stdint.h>
6
7
int16_t led1=0;
8
int16_t led2=0;
9
int taster1;
10
int taster2;
11
12
volatile int8_t flag_1ms;
13
14
ISR (TIMER0_COMPA_vect)
15
  {
16
    flag_1ms=1;
17
  }
18
19
int taste_lesen1()
20
  {
21
    if(PINA & 1<<PA3)
22
    return 1;
23
    else return 0;
24
  }
25
26
int taste_lesen2()
27
  {
28
    if(PINA & 1<<PA1)
29
    return 1;
30
    else return 0;
31
  }
32
33
void led_taster1(int taster1)
34
  {
35
    if(taster1==1)
36
                                                                     
37
      {
38
        PORTA &= ~(1<<PA4);    // Schaltet Pin  A4
39
        PORTA |= (1<<PA5);    // Schaltet Pin  A5
40
      }
41
    else
42
      {
43
        PORTA |= (1<<PA4);    // Schaltet Pin  A4
44
        PORTA &= ~(1<<PA5);    // Schaltet Pin  A5  
45
      }
46
  }
47
48
void led_taster2(int taster2)
49
  {
50
    if(taster2==1)
51
      {
52
        PORTC &= ~(1<<PC5);    // Schaltet Pin
53
        PORTC |= (1<<PC6);    // Schaltet Pin
54
      }
55
    else
56
      {
57
        PORTC |= (1<<PC5);    // Schaltet Pin
58
        PORTC &= ~(1<<PC6);    // Schaltet Pin    
59
      }
60
  }
61
62
void led_blinken1()
63
  {
64
    led1++;
65
    if(led1==300)
66
      {
67
        PORTA &= ~(1<<PA6);    // Schaltet Pin
68
        PORTA |= (1<<PA7);    // Schaltet Pin
69
      }
70
    else
71
      {
72
        if(led1==600)
73
  {
74
    PORTA |= (1<<PA6);    // Schaltet Pin
75
    PORTA &= ~(1<<PA7);  // Schaltet Pin
76
    led1=0;
77
  }
78
      }
79
  }
80
81
void timer_init()
82
  {          // Timer 0 konfigurieren
83
    TCCR0A = 0;      // CTC Modus
84
    TCCR0B = (1<<WGM01)|(1<<CS01)|(1<<CS00);    // Prescaler 64
85
                                                                     
86
    TCNT0=1;
87
    OCR0A=249;  
88
    TIMSK0|=(1<<OCIE0A);    // Compare Interrupt erlauben
89
  }
90
91
int main(void)
92
  {
93
    timer_init();
94
    DDRA=0b11110000;    // Port A auf Ausgang schalten
95
    DDRC=0b01100000;    // Port C auf Ausgang schalten
96
    sei();        // Global Interrupts aktivieren
97
    while(1)        // Programmschleife
98
      {  
99
        if(flag_1ms)
100
  {
101
    flag_1ms=0;      
102
    taster1 = taste_lesen1();  // Aufruf Unterprogramm 1
103
    led_taster1 (taster1);    // Aufruf Unterprogramm 2
104
    taster2 = taste_lesen2();  // Aufruf Unterprogramm 3
105
    led_taster2 (taster2);    // Aufruf Unterprogramm 4
106
    led_blinken1();        // Aufruf Unterprogramm 5  
107
  }  
108
      }
109
  }
Hab gerade gesehen das auch ein paar Fehler drin sind oder anders besser 
geht. Habe es nach der Anleitung von Falk gemacht. Es gibt ein Tut dazu 
im Wissen. Dazu gibt es dann noch verschiedene Abwandlungen dazu.
Das nächste Programm war eine "Einknopfbedienung" mit Encoder und 
Tasterentprellung nach Peter.
Möchte nur damit zeigen das mir ein Interrupt nicht fremd ist.

Apollo M. schrieb:
> #define WBITM(r,m,v) (((r)&((0xFF)^(m)))|((m)&(v))) // write bit mask

Das ist mir im Moment zu hoch, muss erst es auseinder nehmen.
Ich folge deinen Erklärungen ganz genau, lese die einzelnen Programme 
genau. Meistens sind einige Eigenarten der einzelnen Kollegen drin, die 
ich so nicht kenne, aber gut sind. Warum soll man nicht dazu lernen. 
Wenn ich meine früheren Codes betrachte und die von heute sind da auch 
deutliche Unterschiede drin.
Nimm einafch als Beispiel die Tasterentprellung von Peter. Ich kann 
nicht sagen wie es genau funktioniert, Das geht aber auch andern so, 
habe eine komplette Erklärung zu liegen, kann es anwenden und anpassen 
und es funktioniert. Das ist schon recht kompliziert für mich. Es 
fordert aber die grauen Zellen heraus.
Nochmal, lese alles was du schreibst mit sehr grossen Intresse, lerne 
gern von andern und bin aus der Zeit nur In und Out zu schalten raus.

von Henry (Gast)


Lesenswert?

Hab noch was gefunden:
1
#define F_CPU 16000000UL  // Angabe der Quarzfrequenz, wichtig für die Zeit
2
#include <util/delay.h>    // Einbindung Datei Pause
3
#include <avr/io.h>      // Einbindung Datei Ausgänge
4
int16_t led1=0;
5
void led_blinken1()
6
  {
7
    led1++;
8
    if(led1==300)
9
      {    
10
        PORTA &= ~(1<<PA6);    // Schaltet Pin
11
        PORTA |= (1<<PA7);    // Schaltet Pin
12
      }  
13
    else
14
      {
15
        if(led1==600)
16
  {
17
    PORTA |= (1<<PA6);    // Schaltet Pin
18
    PORTA &= ~(1<<PA7);  // Schaltet Pin
19
    led1=0;
20
  }
21
      }
22
  }
23
int main(void)
24
  {
25
    DDRA=0b11000000;    // Port A auf Ausgang schalten
26
    while(1)        // Programmschleife
27
      {
28
        led_blinken1();      // Aufruf Unterprogramm 1
29
        _delay_ms(1);
30
      }
31
  }

von Heiner (Gast)


Lesenswert?

Henry schrieb:
> So was ähnliches verwende ich selbst bei Muktitasking.
>


Na jetzt bin ich aber platt! "Muktitasking" (meinst wohl "Multitasking") 
- wenn Du Dich DAMIT beschäftigst bzw "verwendest", dann verstehe ich 
aber Deine bisherigen Probleme nicht - oder willst Du hier die Leser 
verar**???

Und Dein Hinweis auf Peter's Tastenentprellung (Du meinst wohl "Peda" 
Peter Danneger?) - Du verstehst sie zwar nicht, wendest sie aber an - 
wow!

von Ralph S. (jjflash)


Lesenswert?

Bei dem hier:

((r)&((0xFF)^(m))

könntest du es besser sehen wenn hier stehen würde:

((r) & ~(m))

Zu sehen ist hier eine UND-Verknüpfung mit m. In m wird jedes einzelne 
Bit invertiert. Somit werden die Bits in r gelöscht, die durch m 
maskiert sind.

Der Hintergrund:

Das ^ Zeichen bedeutet in C eine Exclusive-ODER Verknüpfung. Eine 
Exclusive-Oder Verknüpfung nimmt man bspw. auch gerne in FPGAS um 
steuern zu können, ob ein einzelnes Bit invertiert wird oder nicht.

Bsp.:
1
Bitnr.:     7 6 5 4   3 2 1 0
2
-----------------------------
3
0xff      = 1 1 1 1 _ 1 1 1 1
4
Maske_org = 1 1 0 0 _ 0 0 0 0
5
------------------------------
6
             XOR  
7
------------------------------
8
Maske_neu = 0 0 1 1 _ 1 1 1 1
9
r_org     = 1 1 1 0 _ 1 0 1 0
10
------------------------------
11
             UND
12
------------------------------
13
r_neu     = 0 0 1 0 _ 1 0 1 0

Wie du oben sehen kannst, werden aus r die oberen beiden Bits (Nr.7 und 
Nr. 6) geloescht, alle anderen bleiben unverändert.

--------------------------------------------------

Zu deinen Programmen:
1
void led_blinken1()
2
{
3
  led1++;
4
  if(led1==300)
5
  {    
6
    PORTA &= ~(1<<PA6);    // Schaltet Pin
7
    PORTA |= (1<<PA7);     // Schaltet Pin
8
  }  
9
  else
10
  {
11
    if(led1==600)
12
  {
13
    PORTA |= (1<<PA6);    // Schaltet Pin
14
    PORTA &= ~(1<<PA7);   // Schaltet Pin
15
    led1=0;
16
  }
17
}

Das ist einfach nicht schön zu lesen und aus den Kommentaren "Schaltet 
Pin" wird man später nicht wirklich schlau (zumindest dann nicht, wenn 
es etwas komplexer wird als nur LED blinken zu lassen). Dein Programm 
stellt einen Wechselblinker dar, welches 2 LEDs im Wechsel blinken läßt. 
Schöner (und besser leßbar) sieht es dann so aus (ich nenen die LEDS 
jetzt mal leda und ledb weil du den Namen led1 schon für den Zähler 
verwendet hast):
1
// statt (1 << PA6) kann man auch (1 << 6) schreiben, da irgendwo in den defines der
2
// Header zum avr_gcc stehen muß: #define PA6  (1 << 6)
3
4
#define leda_set  ( PORTA |= (1 << PA6) )
5
#define leda_clr  ( PORTA &= ~(1 << PA6) )
6
7
#define ledb_set  ( PORTA |= (1 << PA7) )
8
#define ledb_clr  ( PORTA &= ~(1 << PA7) )
9
10
void led_blinken1()
11
{
12
  led1++;
13
  if(led1==300)
14
  {    
15
    leda_clr();
16
    ledb_set();
17
  }  
18
  else
19
  {
20
    if(led1==600)
21
  {
22
    leda_set();
23
    ledb_clr();
24
    led1=0;
25
  }
26
}

Dieses macht die ganze Sache übersichtliche und wenn das Setzen / 
Rücksetzen mehr als einmal benötigt wird, erspart es Schreibarbeit und 
erleichtert zudem, an Controller angeschlossene Einheiten besser 
abzuändern.

von Heiner (Gast)


Lesenswert?

Ralph S. schrieb:
> Bei dem hier:
>

Deine Geduld (oder Selbstdarstellung) ist bewundernswert

Das weiß doch der Henry alles schon

Aber wenn's Dir ein gutes Gefühl gibt - weiter so!

von Ralph S. (jjflash)


Lesenswert?

Heiner schrieb:
> Deine Geduld (oder Selbstdarstellung) ist bewundernswert

okay... dann halte ich mich zurück, der TO soll, wenn er ernsthaft 
Fragen hat PN schreiben, dann ist hier niemand mehr belästigt !

von Heiner (Gast)


Lesenswert?

Ralph S. schrieb:
> Heiner schrieb:
>> Deine Geduld (oder Selbstdarstellung) ist bewundernswert
>
> okay... dann halte ich mich zurück, der TO soll, wenn er ernsthaft
> Fragen hat PN schreiben, dann ist hier niemand mehr belästigt !

Das hat mit Belästigen nichts zu tun, sondern mit der Bequemlichkeit, ja 
fast geistigen Trägheit (no offence!) des TO - wenn er, wie er selbst 
schreibt, Multitasking und Peda's Tastenentprellcode verwendet, dann 
sollte er auch die hier reingestellten Programme verstehen (auch die, 
die er selbst reingestellt hat), OHNE dass man sie ihm Bit für Bit 
vorkauen muss - und genau das machst Du.

Nix für ungut!

SCNR

von Henry (Gast)


Lesenswert?

Heiner schrieb:
> Das weiß doch der Henry alles schon
>
> Aber wenn's Dir ein gutes Gefühl gibt - weiter so!

Leider weiss Henry nicht alles. Sonst würde ich nicht diese Fragen 
stellen.
Gerade der Anschluss auf 2 Ports bereitet mir grosse Problem. Hatte 
bereits einige Programme dazu geschrieben (stehen oben) um Segmente zu 
testen.
Leider ist es in diesem Forum Standart geworden mit vielne Worten nichts 
zu sagen. Es gibt immer wieder Leute die es einen nicht zutrauen was 
allein zu machen. Wie will man einem Anfänger/Amateur die Freude an 
erreichten machen wenn man keine Hilfe bekommt. Mit Grundlagen 
anzufangen ist schon gut. Doch schnell kommt man zu Problemen die man 
kaum allein vernünftig gelöst bekommt.

von Joachim B. (jar)


Lesenswert?

Henry schrieb:
> Habe das Programm etwas hübscher gemacht.

wenn doch überall

Henry schrieb:
> switch(number)
>     {
>       case 1:
>       clearsegment();

wenn in jedem case und auch im default clearsegment(); aufgerufen wird, 
kannst du es auch einmal vor switch(number) aufrufen, dann muss es nicht 
im switch stehen!

von Johann Klammer (Gast)


Lesenswert?

MaWin schrieb:
> Nicht multiplexen, aber 2 Ziffern statisch angesteuert an einem ATmega8,
> Segmente der 1er und 10er Stelle auf PortD und PortB verteilt wie es
> sich ergab:

Bist du da noch unter den 200mA/device?

von Henry (Gast)


Lesenswert?

Meinst du die Stromaufnahme für den IC?
Laut Messung wird max. ca. 17mA genommen.

von MaWin (Gast)


Lesenswert?

Johann Klammer schrieb:
> Bist du da noch unter den 200mA/device?

140 (10mA, 330 Ohm).

von Ida O. (keil-er)


Angehängte Dateien:

Lesenswert?

Davon gibt's noch mehr. Direkt und auch PT6xxxx und andere NEC 
kompatible für LEDs+VFDs.
Auch mit "mehr-benutzung" von progmem müsste irgendwo liegen. Das fang 
ich jetzt auf Anhieb nicht.
Interesse? Dann guck ich demnächst durch und poste es.

von Heiner (Gast)


Lesenswert?

Hallo Ida O
zu Deinem Code - was soll denn:
1
   PORTB++;
 in Zeile 68 bewirken??
Kommentare wären auch nicht schlecht!

von Heiner (Gast)


Lesenswert?

Hallo Ida O

Und generell könnteste das MPX_DIG auch in ein Array schreiben und wie 
das andere Array behandeln, dann wäre der Code entsprechend kürzer

von Ida O. (keil-er)


Lesenswert?

Heiner schrieb:
> Hallo Ida O
> zu Deinem Code - was soll denn:   PORTB++;
>  in Zeile 68 bewirken??
> Kommentare wären auch nicht schlecht!

Portb ist mit 0x0F als Ausgang, da waren 4 einzelne LEDs dran, die 
einfach nur mit blinkten. Da an der anderen 4 Bits nichts angeschlossen 
war habe ich einfach nur PORTB++ gemacht.

Ich hatte mal so nen Splin überall 7-Segment Anzeigen zu verteilen. Da 
nahm ich immer einer Anzeige, hab so ein Grunggerüst zusammmengezimmert 
und dann irgendwelche Nachrichten für meine Freundin in 
"7-Segment-Speak" da drauf laufen lassen.
Da gibt's keine Kommentare zu und jetzt, teilweise Jahre später, fange 
ich nicht an das extra zu kommentieren. Wenn noch mehr Fragen 
auftauchen, dann erklär' ich es gern.

Heiner schrieb:
> Hallo Ida O
>
> Und generell könnteste das MPX_DIG auch in ein Array schreiben und wie
> das andere Array behandeln, dann wäre der Code entsprechend kürzer

Ja, ich weiss, das meinte ich mit "mehr benutzung" von PROGMEM.

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.