Forum: Mikrocontroller und Digitale Elektronik 7-Segment-Anzeigen mit gemischten Ports


von Axel L. (ligonap)


Lesenswert?

Hallo Zusammen!

Ich habe folgendes Problem: Ein ATMega48 (TQFP) soll als Rückwärtszähler 
(300-000) dienen. Hierfür sind drei 7-Segment-Anzeigen (gemeinsame 
Kathode) direkt an den ATMega angeschlossen.
Soweit, sogut, aber die drei Ports C, B und D bedienen nicht jeweils ein 
Display, wie es am einfachsten ist, sonder gemischt:

Hunderter    Ports
    0 - -    C3,C4,C5,D3,D2,D1
    1 - -    C4,C5
    2 - -    C3,C4,D3,D2,D0
    3 - -    C3,C4,C5,D3,D0

Zehner
    - 0 -    B4,B5,B7,B6,C0,C1
    - 1 -    B5,B7
    - 2 -    B4,B5,B6,C0,C2
    - 3 -    B4,B5,B7,B6,C2
    - 4 -    B5,B7,C1,C2
    - 5 -    B4,B7,B6,C1,C2
    - 6 -    B4,B7,B6,C0,C1,C2
    - 7 -    B4,B5,B7
    - 8 -    B4,B5,B7,B6,C0,C1,C2
    - 9 -    B4,B5,B7,B6,C1,C2

Einer
    - - 0    D7,D6,D5,B0,B1,B2
    - - 1    D6,D5
    - - 2    D7,D6,B0,B1,B3
    - - 3    D7,D6,D5,B0,B3
    - - 4    D6,D5,B2,B3
    - - 5    D7,D5,B0,B2,B3
    - - 6    D7,D5,B0,B1,B2,B3
    - - 7    D7,D6,D5
    - - 8    D7,D6,D5,B0,B1,B2,B3
    - - 9    D7,D6,D5,B0,B2,B3

Am Port D4 befindet sich ein Taster, dessen Betätigungen rückwärts 
gezählt werden sollen und am Port C6 ist der Reset-Taster angeschlossen.

Wie lässt sich ein Array (für Bascom) für die drei Anzeigen aufstellen? 
Beim Datenblatt des ATMega blicke ich nicht ganz durch.

von Jobst M. (jobstens-de)


Lesenswert?

Ach Du heiliger Bimbam - die Segmente haben Bezeichnungen von a bis g.
Es wäre einfacher dies anzugeben.
1
  a
2
f   b
3
  g
4
e   c
5
  d

Schon wäre auch die Übersicht für Dein Programm einfacher ...


Gruß

Jobst

von Reinhard R. (reirawb)


Lesenswert?

Und immer dran denken: Maximalstrom für Vcc und GND-Pins ist 200 mA.
Bei einer Anzeige von "088" werden 20 LEDs angesteuert, also max. 10 mA 
je LED.

Multiplexbetrieb? 
http://www.mikrocontroller.net/articles/AVR-Tutorial:_7-Segment-Anzeige#Mehrere_7-Segment_Anzeigen_.28Multiplexen.29

Reinhard

von STK500-Besitzer (Gast)


Lesenswert?

>Wie lässt sich ein Array (für Bascom) für die drei Anzeigen aufstellen?

Für jede Anzeige ein Array mit drei Spalten für die Ports.
Darin werden werden dann die Bits entsprechend des anzuzeigenden Musters 
gesetzt.
Am Ende der Zählroutine schreibt man die drei Bytes für jeden Port 
verodert an den Port.

von Axel L. (ligonap)


Lesenswert?

Das sind bereits die Ports des ATMega48, um die LEDs der Segmente 
richtig anzusteuern.

In der a-bis-g-Notation der Segmente wäre dies:

C3,C4,C5,D3,D2,D1,D0 = a3,b3,c3,d3,e3,f3,g3

B4,B5,B7,B6,C0,C1,C2 = a2,b2,c2,d2,e2,f2,g2

D7,D6,D5,B0,B1,B2,B3 = a1,b1,c1,d1,e1,f1,g1

Alle Segmente werden direkt angesteuert, kein Multiplexbetrieb (was 
durchaus einfacher wäre).

von STK500-Besitzer (Gast)


Lesenswert?

>Alle Segmente werden direkt angesteuert, kein Multiplexbetrieb (was
>durchaus einfacher wäre).

Da wirst du dann trotzdem noch ein paar Treiber brauchen.

von Karl H. (kbuchegg)


Lesenswert?

STK500-Besitzer schrieb:
>>Wie lässt sich ein Array (für Bascom) für die drei Anzeigen aufstellen?
>
> Für jede Anzeige ein Array mit drei Spalten für die Ports.
> Darin werden werden dann die Bits entsprechend des anzuzeigenden Musters
> gesetzt.
> Am Ende der Zählroutine schreibt man die drei Bytes für jeden Port
> verodert an den Port.

Und nicht vergessen: vorher mit einem UND alle Portbits für eine Stelle 
gezielt auf 0 setzen.

von Karl H. (kbuchegg)


Lesenswert?

Axel L. schrieb:

> Wie lässt sich ein Array (für Bascom) für die drei Anzeigen aufstellen?
> Beim Datenblatt des ATMega blicke ich nicht ganz durch.

Das ist einer der wenigen Fälle, wo dir auch das Datenblatt tatsächlich 
nicht weiter hilft. In deinem Fall geht es einzig und alleine um eine 
geschickte Methode wie man aus der Kentnis einer Zahl ableitet, welche 
Bits an welchem Port durch eine geschickte Systematik gezielt mit einem 
ODER auf 1 zu setzen sind.
Das ist reines Programmierhandwerk und hat mit dem Mega erst mal gar 
nichts zu tun.

von Thomas (Gast)


Lesenswert?

Sieh mal hier:
Beitrag "Standard LCD mit Controller steuern"

da hab ich LCDs an einen Controller angeschlossen. Die Segmente sind 
kunterbunt an den Ports verteilt. Der Code ist in C. Denke das ist so 
wie gefordert.
Ob es eleganter geht weiß ich nicht, es funktioniert aber so...
Gruß
Thomas

von Axel L. (ligonap)


Lesenswert?

Thomas schrieb:
> Sieh mal hier:
> Beitrag "Standard LCD mit Controller steuern"
>
> da hab ich LCDs an einen Controller angeschlossen. Die Segmente sind
> kunterbunt an den Ports verteilt. Der Code ist in C. Denke das ist so
> wie gefordert.


Mist, in C kenne ich mich nicht aus. Programmiere halt sehr selten.
Die einzelnen Ports kann ich ohne Probleme ansprechen. Zumindest läuft 
der µC.

Mir scheint, eine gemischte Portverteilung kommt selten vor. ;)

von Jobst M. (jobstens-de)


Lesenswert?

Axel L. schrieb:
> Mir scheint, eine gemischte Portverteilung kommt selten vor. ;)

Nein, gerade beim ATmega48/88/168 passiert mir das auch häufig.


Ich kenne mich nicht mit Bascom aus - die Aufgabe ist aber so trivial, 
daß dieses Problem auch für Anfänger recht fix in Assembler zu lösen 
ist.


1. Du hast einen Zähler von 300 auf 0

In Bascom musst Du Dich vermutlich nicht darum kümmern, aber ich würde 
hier jeder Dezimalstelle ein Byte geben und gesondert abziehen, sobald 
ein Übertrag der vorherigen Stelle kommt. Die Stelle, die den Übertrag 
erzeugt hat, wird auf 9 gesetzt. Ansonsten musst Du die 3 Dezimalstellen 
aus der fertigen Zahl erzeugen.

Damit hast Du 3 Bytes: Hunderter, Zehner und Einser


2. Du benötigst eine Tabelle mit 3*10 Einträgen a 3 Byte

Die drei Byte repräsentieren dabei die 3 Ports (die kompletten).
Für Hunderter, Zehner und Einser werden nun 3 Umsetzungen mit dieser 
Tabelle gemacht und die 3 3-Byte-Ergebnisse verODERt.
Das Ergebnis wird auf die 3 Ports geschrieben.


Wenn Du den vollen Strom pro Port nutzen möchtest, kannst Du die 
einzelnen Dezimalstellen auch einschalten, einen Moment warten und dann 
wieder ausschalten. (Dann die nächste Stelle usw.)
Im Prinzip ein Multiplexing.
Der mittlere Strom wird sich aber dadurch auch verringern.
Benötigst Du mehr Strom, benötigst Du Treiber.


Gruß

Jobst

von STK500-Besitzer (Gast)


Lesenswert?

>Und nicht vergessen: vorher mit einem UND alle Portbits für eine Stelle
>gezielt auf 0 setzen.

Nö:

PORTA = A0 OR A1 OR A2

(Falls das in etwa BASCOM ist...)

von Karl H. (kbuchegg)


Lesenswert?

STK500-Besitzer schrieb:
>>Und nicht vergessen: vorher mit einem UND alle Portbits für eine Stelle
>>gezielt auf 0 setzen.
>
> Nö:
>
> PORTA = A0 OR A1 OR A2
>
> (Falls das in etwa BASCOM ist...)

Das geht aber nur dann, wenn an Port A nur die Segmente für zb die 
Zehnerstellen wären. Sobald an einem Port die Segmente für 2 Stellen 
liegen (und bei ihm sind sie das) hast du damit ein Problem, wenn du 
jeweils nur 1 Stelle verändern willst.

Ausserdem wird man das sinnvollerweise nicht so machen, sonder für jede 
Stelle ein Array mit allen Mustern für alle Ziffern haben

In C
1
struct Digits
2
{
3
  uint8_t  portD;
4
  uint8_t  portC;
5
  uint8_t  portB;
6
};
7
8
struct Digits Hunderter[] =
9
{
10
  { 0b00000011, 0b00111000, 0b00000000 },   // 0
11
  { 0b00000000, 0b00110000, 0b00000000 },   // 1
12
  { 0b00000101, 0b00011000, 0b00000000 },   // 2
13
  { 0b00001001, 0b00111000, 0b00000000 },   // 3
14
};
15
16
struct Digits HunderterMask =
17
  { 0b00001111, 0b00111000, 0b00000000 };
18
19
struct Digits Zehner[] =
20
  ...
21
22
struct Digits ZehnerMask =
23
  ...
24
25
struct Digits Einer[] =
26
  ....
27
28
struct Digits EinerMask =
29
  ....
30
31
void OutputDigit( struct Digits* mask, struct Digits* digits }
32
{
33
  if( mask->portB != 0 ) {
34
    PORTB &= ~mask->portB;
35
    PORTB |= mask->portB;
36
  }
37
38
  if( mask->portC != 0 ) {
39
    PORTC &= ~mask->portC;
40
    PORTC |= mask->portC;
41
  }
42
43
  if( mask->portD != 0 ) {
44
    PORTD &= ~mask->portD;
45
    PORTD |= mask->portD;
46
  }
47
}
48
49
int main()
50
{
51
  uint8_t e, z, h;
52
53
  ...
54
55
  for( h = 0; h < 4; ++h ) {
56
    OutputDigit( &HunderterMask, &Hunderter[h] );
57
58
    for( z = 0; z < 9 + 1; ++z ) {
59
      OutputDigit( &ZehnerMask, Zehner[h] );
60
61
      for( e = 0; e < 9 + 1; ++e ) {
62
        OutputDigit( &EinerMask, &Einer[h] );
63
      }
64
    }
65
  }
66
}

von STK500-Besitzer (Gast)


Lesenswert?

>Das geht aber nur dann, wenn an Port A nur die Segmente für zb die
>Zehnerstellen wären. Sobald an einem Port die Segmente für 2 Stellen
>liegen (und bei ihm sind sie das) hast du damit ein Problem.

Nee, erst sortiert man nach Digits und dann nach Ports:

z.B. Anzeige von 304

PortA = A0[3] OR A1[0] OR A2[4]
PortB = B0[3] OR B1[0] OR B2[4]
PortC = C0[3] OR C1[0] OR C2[4]

Oder sehe ich da was falsch?
In Bascom kann man das wahrscheinlich sowieso nicht so machen, das 
Bascom ja nur paarweise Operationen zulässt, oder?

von Karl H. (kbuchegg)


Lesenswert?

STK500-Besitzer schrieb:

> Nee, erst sortiert man nach Digits und dann nach Ports:
>
> z.B. Anzeige von 304
>
> PortA = A0[3] OR A1[0] OR A2[4]
> PortB = B0[3] OR B1[0] OR B2[4]
> PortC = C0[3] OR C1[0] OR C2[4]

Ah, so meinst du das. Alle 3 Stellen in einem Rutsch zusammengeodert 
ausgeben.
OK. Auf den einen Port Pin mit dem Taster müsste man aufpassen, aber 
auch das ist natürlich machbar.

> In Bascom kann man das wahrscheinlich sowieso nicht so machen, das
> Bascom ja nur paarweise Operationen zulässt, oder?

Meines Wissens: ja.
Aber da kenn ich mich in BASCOM auch zu wenig aus

Aber wahrscheinlich wird es wieder mal an der Erkentnis scheitern, dass 
es auch in BASCOM möglich ist, einen Port (wie jedes andere 
Prozessorregister auch) als ganzes mit einem Bitmuster zu beschreiben 
und man sich eben das Bitmuster im Vorfeld zurecht legen muss.

von Axel L. (ligonap)


Lesenswert?

Ich habe mal den C-Code genommen und ein paar Änderungen vorgenommen, da 
wohl einige Fehler vorlagen. Eine Ausgabe findet statt, nur mit dem 
Runterzählen von 300 bis 000 klappt es nicht so. Der Zähler startet bei 
300, geht auf 807 und dann werden sinnlose Zeichen auf dem letzten 
Segment ausgegeben.

1
#include <avr/io.h>
2
3
struct Digits
4
{
5
  uint8_t  portD;
6
  uint8_t  portC;
7
  uint8_t  portB;
8
};
9
10
struct Digits Hunderter[] =
11
{
12
  { 0b00001110, 0b00111000, 0b00000000 },   // 0
13
  { 0b00000000, 0b00110000, 0b00000000 },   // 1
14
  { 0b00001101, 0b00011000, 0b00000000 },   // 2
15
  { 0b00001001, 0b00111000, 0b00000000 },   // 3
16
};
17
18
struct Digits HunderterMask =
19
  { 0b00001111, 0b00111000, 0b00000000 };
20
21
struct Digits Zehner[] =
22
{
23
  { 0b00000000, 0b00000011, 0b11110000 },   // 0
24
  { 0b00000000, 0b00000000, 0b10100000 },   // 1
25
  { 0b00000000, 0b00000101, 0b01110000 },   // 2
26
  { 0b00000000, 0b00000100, 0b11110000 },   // 3
27
  { 0b00000000, 0b00000110, 0b10100000 },   // 4
28
  { 0b00000000, 0b00000110, 0b11010000 },   // 5
29
  { 0b00000000, 0b00000111, 0b11010000 },   // 6
30
  { 0b00000000, 0b00000000, 0b10110000 },   // 7
31
  { 0b00000000, 0b00000111, 0b11110000 },   // 8
32
  { 0b00000000, 0b00000110, 0b11110000 },   // 9
33
};
34
35
struct Digits ZehnerMask =
36
  { 0b00000000, 0b00000111, 0b11110000 };
37
38
struct Digits Einer[] =
39
{
40
  { 0b11100000, 0b00000000, 0b00000111 },   // 0
41
  { 0b01100000, 0b00000000, 0b00000000 },   // 1
42
  { 0b11000000, 0b00000000, 0b00001011 },   // 2
43
  { 0b11100000, 0b00000000, 0b00001001 },   // 3
44
  { 0b01100000, 0b00000000, 0b00001100 },   // 4
45
  { 0b10100000, 0b00000000, 0b00001101 },   // 5
46
  { 0b10100000, 0b00000000, 0b00001111 },   // 6
47
  { 0b11100000, 0b00000000, 0b00000000 },   // 7
48
  { 0b11100000, 0b00000000, 0b00001111 },   // 8
49
  { 0b11100000, 0b00000000, 0b00001101 },   // 9
50
};
51
52
struct Digits EinerMask =
53
  { 0b11100000, 0b00000000, 0b00001111 };
54
55
56
void OutputDigit(struct Digits* mask, struct Digits* digits)
57
{
58
  if( mask->portB != 0 ) 
59
  {
60
    PORTB &= ~mask->portB;
61
    PORTB |= digits->portB;
62
  }
63
64
  if( mask->portC != 0 ) 
65
  {
66
    PORTC &= ~mask->portC;
67
    PORTC |= digits->portC;
68
  }
69
70
  if( mask->portD != 0 ) 
71
  {
72
    PORTD &= ~mask->portD;
73
    PORTD |= digits->portD;
74
  }
75
}
76
77
78
void delay_ms(int ms) 
79
{
80
81
  TCCR0B |= (1<<CS01) | (1<<CS00) ;
82
  int i ;
83
  for(i=0; i<ms; i++) {
84
85
    while(TCNT0<16) ;
86
    TCNT0=0;
87
  }
88
  TCCR0B=0;
89
}
90
91
int main()
92
{
93
94
// Als Ausgänge sind Definiert:
95
DDRD = 0b11101111;
96
DDRC = 0b00111111;
97
DDRB = 0b11111111;
98
99
  uint8_t e, z, h;
100
101
  for( h = 3; h > -1; --h ) {
102
    OutputDigit( &HunderterMask, &Hunderter[h] );
103
104
  delay_ms(100);
105
106
107
    for( z = 0; z > -1; --z ) {
108
      OutputDigit( &ZehnerMask, &Zehner[z] );
109
110
    delay_ms(100);
111
112
113
      for( e = 0; e > -1; --e )
114
     {
115
        OutputDigit( &EinerMask, &Einer[e] );
116
117
    delay_ms(100);
118
      }
119
    }
120
  }
121
}

von Weingut P. (weinbauer)


Lesenswert?

Ja, Bascom kann immer nur eine Operation in einem Schritt ... leider.
Gibt dann zum Teil ziemliche Monster an Formeln bei komplexeren
Berechnungen ... was solls.

Also, ich machs bei ner 16-Segment Anzeige so, dass ich nen Zeichensatz
als Bytes liegen habe, wo die einzelnen Segmente schon fertig
dekodiert sind.
Hab da mit ner Excel-Tabelle gearbeitet um die Bitwerte zu ermitteln
für jedes Zeichen. In meinem Fall waren es 2 Ports, daher 2 Bytes,
wenn er 3 Ports verwendet muss er also bei der Methode 3 Bytes 
schreiben.

Dann wirds schon kompliziert ... wenn auf den Ports noch andere Aktionen 
drauf sind, die nicht über ein Specieal-Functions-Register vor Zugriff 
durch den Befehl PORTx=y_byte geschützt sind muss er bevor er die 
Segmente setzt den jeweils benötigten Status des jeweiligen Ports per 
AND und OR
in das Byte erst setzen.

Bit sicher löschen: Byte_x=Byte_x AND &B11101111
Bit unabhängig setzen: Byte_x=Byte_x OR &B00010000

Oder der Zustand wird halt statisch in sein Zeichenarray geschrieben, so 
er
sich nie ändert ...

Beim Multiplexing wirds dann nochmal schön.

Hab das so gelöst, dass ich praktisch nen Framebuffer angelegt habe, n 
Array mit genau sovielen Bytes wie eben dargestellt werden müssen.

dim anzeigearray_1(5) as byte
dim anzeigearray_2(5) as byte

in der Timer ISR geh ich dann nur noch hin und schreibe zyklisch die 
enthaltenen Bytes auf die Ports und setze den Select auf das nächste 
Zeichen bzw. aktiviere die jeweilige Anzeigeeinheit. Bei Überlauf zurück 
zum Anfang versteht sich.

von STK500-Besitzer (Gast)


Lesenswert?

>uint8_t e, z, h;
>  for( h = 3; h > -1; --h ) {

Wie soll eine unsigned int einen Wert von -1 erreichen?


Der andere Kram ist aus meiner Sicht auf den ersten Blick völlig 
umständlich "programmiert".
1
struct Digits Hunderter[] =
2
{   // Port D   Port C      Port B
3
  { 0b00001110, 0b00111000, 0b00000000 },   // 0
4
  { 0b00000000, 0b00110000, 0b00000000 },   // 1
5
  { 0b00001101, 0b00011000, 0b00000000 },   // 2
6
  { 0b00001001, 0b00111000, 0b00000000 },   // 3
7
};
8
9
void OutputDigit(uint8 hunderter, uint8 zehner, uint8 einer)
10
{
11
    PORTD = Hunderter[hunderter][0] | Zehner[zehner][0] | Einer[einer][0] | (1<<4);
12
    PORTC = Hunderter[hunderter][1] | Zehner[zehner][1] | Einer[einer][1];
13
    PORTB = Hunderter[hunderter][2] | Zehner[zehner][2] | Einer[einer][2];
14
}
15
16
int main()
17
{
18
19
// Als Ausgänge sind Definiert:
20
DDRD = 0b11101111;
21
DDRC = 0b00111111;
22
DDRB = 0b11111111;
23
24
  uint8_t e, z, h;
25
26
  e = 0;
27
  z = 0;
28
  h = 3;
29
  do
30
  (        
31
   do
32
   {
33
    do
34
    {
35
    OutputDigit(h,z,e);
36
    delay_ms(1000);
37
    } while(e > 0);
38
    e = 9;
39
   } while(z > 0);
40
   z = 9;
41
   ) while(h>0)
42
   OutputDigit(0,0,0);
43
  while(1); // Endlosschleife
44
}

Sollte so funktionieren. Gewähr für einwandfreie Funktion übernehme ich 
aber nicht.
Und die Delay-Funktion solltest du dir noch mal angucken.
Die kann man "fertig kaufen".

von Axel L. (ligonap)


Lesenswert?

Wenn ich nur die Einer durchlaufen lassen, erhalte ich auf der 
Einer-Anzeige erstmal die Folge: 9-8-7-6-5-4-3-2-1-0
Nach einer kleinen Gedankenpause leuchten alle Anzeige mit kryptischen 
Symbolen auf und wieder läuft der Einer ebenfalls mit kryptischen 
Symbolen durch.
Ich habe so das Gefühl, dass die for-Schleife nicht endet. Wieso??
Lebt mein µC???
1
int main()
2
{
3
4
// Als Ausgänge sind Definiert:
5
DDRD = 0b11101111;
6
DDRC = 0b00111111;
7
DDRB = 0b11111111;
8
9
  uint8_t e, z, h;
10
11
      for( e = 9; e >= 0; e-- ) {
12
            OutputDigit( &EinerMask, &Einer[e] );
13
  }
14
}

von Axel L. (ligonap)


Lesenswert?

Wenn ich folgenden Code verwende:
1
int main()
2
{
3
4
// Als Ausgänge sind Definiert:
5
DDRD = 0b11101111;
6
DDRC = 0b00111111;
7
DDRB = 0b11111111;
8
9
  uint8_t e, z, h;
10
11
      for( e = 10; e > 0; e = e - 1 ) {
12
            OutputDigit( &EinerMask, &Einer[e - 1] );
13
14
  }
15
}

laufen die Einer von 9 bis 0, wie es sich gehört und stoppen.
Ich verstehe es absolut nicht, wieso " >= " nicht geht.

von Karl H. (kbuchegg)


Lesenswert?

Axel L. schrieb:

>   uint8_t e, z, h;
>
>       for( e = 9; e >= 0; e-- ) {

e ist ein unsigned.
Für jede Zahl, die in e überhaupt speicherbar ist, gilt: sie ist 
größer oder gleich 0.
Per Definition!

wenn du daher den Schleifenabbruch daran knüpfst, dass e nicht mehr 
größer oder gleich 0 sein darf, dann hast du mit Zitronen gehandelt. Der 
Fall wird in der Lebenszeit dieses Universums nicht mehr eintreten.

von Axel L. (ligonap)


Lesenswert?

Ok, Counter läuft nun von 300 runter auf 000.

Am Port D4 befindet sich ein Optokoppler (MOC3020) mit einem externen 
10k Pull-Up-Widerstand. Der Counter soll bei jedem Schaltvorgang über 
den Optokoppler sich nur um eins ändern.

Für den Test habe ich folgendes Programm:
1
#include <avr/io.h>
2
3
void delay_ms(int ms) 
4
{
5
  TCCR0B |= (1<<CS01) | (1<<CS00) ;
6
  int i ;
7
  for(i=0; i<ms; i++) {
8
9
    while(TCNT0<16) ;
10
    TCNT0=0;
11
  }
12
  TCCR0B=0;
13
}
14
15
int main()
16
17
{
18
19
DDRD = 0b11101111;
20
DDRC = 0b00111111;
21
DDRB = 0b11111111;
22
23
while(1) {
24
     
25
  delay_ms(250);
26
27
  if( PIND & (1 << PIND4)) {
28
29
// Anzeigewert zum Beginn: 300
30
PORTD = 0b11101001;
31
PORTC = 0b00111011;
32
PORTB = 0b11110111;
33
34
   } 
35
36
   if( !(PIND & (1 << PIND4))) {
37
38
// Anzeigewert zum Ende: 003
39
PORTD = 0b11101110;
40
PORTC = 0b00111011;
41
PORTB = 0b11111001;
42
43
   }
44
}
45
}

Wenn Strom auf dem µC liegt wird 300 angezeigt. Sobald der Optokoppler 
ein Impuls bekommt springt die Anzeige auf 003, aber nicht nach 250ms 
wieder zurück auf 300. Auch bei einem Reset an PD6 wird weiterhin 003 
angezeigt.

Was läuft da schief? Irgendwie wird PIND4 nicht mehr 0 zurückgesetzt.

von Axel L. (ligonap)


Angehängte Dateien:

Lesenswert?

Ich habe mit folgenden mini-Code den Optokoppler quasi als Taster 
getestet:
1
#include <avr/io.h>
2
3
int main(void)
4
{  
5
6
DDRD = 0b11101111;
7
   
8
  while(1) {
9
  
10
    if ( PIND & (1<<PIND4) )
11
    {
12
    PORTD |= ( 1 << PD6 );
13
    }
14
 
15
    if ( !(PIND & (1<<PIND4)) )
16
    {
17
    PORTD &= ~( 1 << PD6);   
18
    } 
19
  }
20
}

LED an PD6 leuchtet bis ich den Optokoppler 1x kurz aktiviere. Danach 
nichts mehr. Was läuft da schief? Anbei der Schaltplan.

von ... (Gast)


Lesenswert?

Da ist ein Triac im Optokoppler!
Dem wirst Du wohl erstmal den Saft klauen müssen, damit der wieder 
sperrt.

von Axel L. (ligonap)


Lesenswert?

... schrieb:
> Da ist ein Triac im Optokoppler!
> Dem wirst Du wohl erstmal den Saft klauen müssen, damit der wieder
> sperrt.

Na toll. Wenn man nicht immer aufpasst.
Und wie geht so etwas elegant, oder soll ich direkt auf einen 4N35 
ausweichen?

von Axel L. (ligonap)


Lesenswert?

So, habe den Triac gegen den 4N35 getauscht und der Counter mit drei 
7-Segmentanzeigen lüppt. :)

Vielen Dank an alle Tipp-Geber und Helfer.

Hier der C-Code:
1
#include <avr/io.h>
2
3
struct Digits
4
{
5
  uint8_t  portD;
6
  uint8_t  portC;
7
  uint8_t  portB;
8
};
9
10
struct Digits Hunderter[] =
11
{ //   Port D     Port C      Port B
12
  { 0b00001110, 0b00111000, 0b00000000 },   // 0
13
  { 0b00000000, 0b00110000, 0b00000000 },   // 1
14
  { 0b00001101, 0b00011000, 0b00000000 },   // 2
15
  { 0b00001001, 0b00111000, 0b00000000 },   // 3
16
  { 0b00000011, 0b00011000, 0b00000000 },   // 4
17
  { 0b00001011, 0b00101000, 0b00000000 },   // 5
18
  { 0b00001111, 0b00101000, 0b00000000 },   // 6
19
  { 0b00000000, 0b00111000, 0b00000000 },   // 7
20
  { 0b00001111, 0b00111000, 0b00000000 },   // 8
21
  { 0b00001011, 0b00111000, 0b00000000 },   // 9
22
  { 0b00001110, 0b00111000, 0b00000000 },   // 0
23
};
24
25
struct Digits HunderterMask =
26
  { 0b00001111, 0b00111000, 0b00000000 };
27
28
struct Digits Zehner[] =
29
{ //   Port D     Port C      Port B
30
  { 0b00000000, 0b00000011, 0b11110000 },   // 0
31
  { 0b00000000, 0b00000000, 0b10100000 },   // 1
32
  { 0b00000000, 0b00000101, 0b01110000 },   // 2
33
  { 0b00000000, 0b00000100, 0b11110000 },   // 3
34
  { 0b00000000, 0b00000110, 0b10100000 },   // 4
35
  { 0b00000000, 0b00000110, 0b11010000 },   // 5
36
  { 0b00000000, 0b00000111, 0b11010000 },   // 6
37
  { 0b00000000, 0b00000000, 0b10110000 },   // 7
38
  { 0b00000000, 0b00000111, 0b11110000 },   // 8
39
  { 0b00000000, 0b00000110, 0b11110000 },   // 9
40
  { 0b00000000, 0b00000011, 0b11110000 },   // 0
41
};
42
43
struct Digits ZehnerMask =
44
  { 0b00000000, 0b00000111, 0b11110000 };
45
46
struct Digits Einer[] =
47
{ //   Port D     Port C      Port B
48
  { 0b11100000, 0b00000000, 0b00000111 },   // 0
49
  { 0b01100000, 0b00000000, 0b00000000 },   // 1
50
  { 0b11000000, 0b00000000, 0b00001011 },   // 2
51
  { 0b11100000, 0b00000000, 0b00001001 },   // 3
52
  { 0b01100000, 0b00000000, 0b00001100 },   // 4
53
  { 0b10100000, 0b00000000, 0b00001101 },   // 5
54
  { 0b10100000, 0b00000000, 0b00001111 },   // 6
55
  { 0b11100000, 0b00000000, 0b00000000 },   // 7
56
  { 0b11100000, 0b00000000, 0b00001111 },   // 8
57
  { 0b11100000, 0b00000000, 0b00001101 },   // 9
58
  { 0b11100000, 0b00000000, 0b00000111 },   // 0
59
};
60
61
struct Digits EinerMask =
62
  { 0b11100000, 0b00000000, 0b00001111 };
63
64
void OutputDigit(struct Digits *mask, struct Digits *digits)
65
{
66
  if( mask->portB != 0 ) 
67
  {
68
    PORTB &= ~mask->portB;
69
    PORTB |= digits->portB;
70
  }
71
72
  if( mask->portC != 0 ) 
73
  {
74
    PORTC &= ~mask->portC;
75
    PORTC |= digits->portC;
76
  }
77
78
  if( mask->portD != 0 ) 
79
  {
80
    PORTD &= ~mask->portD;
81
    PORTD |= digits->portD;
82
  }
83
}
84
85
void delay_ms(int ms) 
86
{
87
88
  TCCR0B |= (1<<CS01) | (1<<CS00) ;
89
  int i ;
90
  for(i=0; i<ms; i++) {
91
92
    while(TCNT0<16) ;
93
    TCNT0=0;
94
  }
95
  TCCR0B=0;
96
}
97
98
int main()
99
{
100
101
// Als Ausgänge und Eingänge sind Definiert:
102
DDRD = 0b11101111;
103
DDRC = 0b00111111;
104
DDRB = 0b11111111;
105
106
  uint8_t e, z, h;
107
108
// Anzeigewert 300 zu beginn
109
PORTD = 0b11101001;
110
PORTC = 0b00111011;
111
PORTB = 0b11110111;
112
113
 while ( PIND & (1<<PIND4) ) ;
114
115
  for( h = 3; h > 0; h=h-1) {
116
    OutputDigit( &HunderterMask, &Hunderter[h-1] );
117
118
    for( z = 10; z > 0; z=z-1 ) {
119
      OutputDigit( &ZehnerMask, &Zehner[z-1] );
120
121
      for( e = 10; e > 0; e=e-1 ) {
122
        OutputDigit( &EinerMask, &Einer[e-1] );
123
124
    delay_ms(100);
125
    while ( PIND & (1<<PIND4) ) ;
126
127
      }
128
    }
129
  }
130
}

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.