www.mikrocontroller.net

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


Autor: Axel L. (ligonap)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Jobst M. (jobstens-de)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ach Du heiliger Bimbam - die Segmente haben Bezeichnungen von a bis g.
Es wäre einfacher dies anzugeben.
  a
f   b
  g
e   c
  d

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


Gruß

Jobst

Autor: Reinhard R. (reirawb)
Datum:

Bewertung
0 lesenswert
nicht 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-Tutori...

Reinhard

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Axel L. (ligonap)
Datum:

Bewertung
0 lesenswert
nicht 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).

Autor: STK500-Besitzer (Gast)
Datum:

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

Da wirst du dann trotzdem noch ein paar Treiber brauchen.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Axel L. (ligonap)
Datum:

Bewertung
0 lesenswert
nicht 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. ;)

Autor: Jobst M. (jobstens-de)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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...)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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
struct Digits
{
  uint8_t  portD;
  uint8_t  portC;
  uint8_t  portB;
};

struct Digits Hunderter[] =
{
  { 0b00000011, 0b00111000, 0b00000000 },   // 0
  { 0b00000000, 0b00110000, 0b00000000 },   // 1
  { 0b00000101, 0b00011000, 0b00000000 },   // 2
  { 0b00001001, 0b00111000, 0b00000000 },   // 3
};

struct Digits HunderterMask =
  { 0b00001111, 0b00111000, 0b00000000 };

struct Digits Zehner[] =
  ...

struct Digits ZehnerMask =
  ...

struct Digits Einer[] =
  ....

struct Digits EinerMask =
  ....

void OutputDigit( struct Digits* mask, struct Digits* digits }
{
  if( mask->portB != 0 ) {
    PORTB &= ~mask->portB;
    PORTB |= mask->portB;
  }

  if( mask->portC != 0 ) {
    PORTC &= ~mask->portC;
    PORTC |= mask->portC;
  }

  if( mask->portD != 0 ) {
    PORTD &= ~mask->portD;
    PORTD |= mask->portD;
  }
}

int main()
{
  uint8_t e, z, h;

  ...

  for( h = 0; h < 4; ++h ) {
    OutputDigit( &HunderterMask, &Hunderter[h] );

    for( z = 0; z < 9 + 1; ++z ) {
      OutputDigit( &ZehnerMask, Zehner[h] );

      for( e = 0; e < 9 + 1; ++e ) {
        OutputDigit( &EinerMask, &Einer[h] );
      }
    }
  }
}

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Axel L. (ligonap)
Datum:

Bewertung
0 lesenswert
nicht 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.

#include <avr/io.h>

struct Digits
{
  uint8_t  portD;
  uint8_t  portC;
  uint8_t  portB;
};

struct Digits Hunderter[] =
{
  { 0b00001110, 0b00111000, 0b00000000 },   // 0
  { 0b00000000, 0b00110000, 0b00000000 },   // 1
  { 0b00001101, 0b00011000, 0b00000000 },   // 2
  { 0b00001001, 0b00111000, 0b00000000 },   // 3
};

struct Digits HunderterMask =
  { 0b00001111, 0b00111000, 0b00000000 };

struct Digits Zehner[] =
{
  { 0b00000000, 0b00000011, 0b11110000 },   // 0
  { 0b00000000, 0b00000000, 0b10100000 },   // 1
  { 0b00000000, 0b00000101, 0b01110000 },   // 2
  { 0b00000000, 0b00000100, 0b11110000 },   // 3
  { 0b00000000, 0b00000110, 0b10100000 },   // 4
  { 0b00000000, 0b00000110, 0b11010000 },   // 5
  { 0b00000000, 0b00000111, 0b11010000 },   // 6
  { 0b00000000, 0b00000000, 0b10110000 },   // 7
  { 0b00000000, 0b00000111, 0b11110000 },   // 8
  { 0b00000000, 0b00000110, 0b11110000 },   // 9
};

struct Digits ZehnerMask =
  { 0b00000000, 0b00000111, 0b11110000 };

struct Digits Einer[] =
{
  { 0b11100000, 0b00000000, 0b00000111 },   // 0
  { 0b01100000, 0b00000000, 0b00000000 },   // 1
  { 0b11000000, 0b00000000, 0b00001011 },   // 2
  { 0b11100000, 0b00000000, 0b00001001 },   // 3
  { 0b01100000, 0b00000000, 0b00001100 },   // 4
  { 0b10100000, 0b00000000, 0b00001101 },   // 5
  { 0b10100000, 0b00000000, 0b00001111 },   // 6
  { 0b11100000, 0b00000000, 0b00000000 },   // 7
  { 0b11100000, 0b00000000, 0b00001111 },   // 8
  { 0b11100000, 0b00000000, 0b00001101 },   // 9
};

struct Digits EinerMask =
  { 0b11100000, 0b00000000, 0b00001111 };


void OutputDigit(struct Digits* mask, struct Digits* digits)
{
  if( mask->portB != 0 ) 
  {
    PORTB &= ~mask->portB;
    PORTB |= digits->portB;
  }

  if( mask->portC != 0 ) 
  {
    PORTC &= ~mask->portC;
    PORTC |= digits->portC;
  }

  if( mask->portD != 0 ) 
  {
    PORTD &= ~mask->portD;
    PORTD |= digits->portD;
  }
}


void delay_ms(int ms) 
{

  TCCR0B |= (1<<CS01) | (1<<CS00) ;
  int i ;
  for(i=0; i<ms; i++) {

    while(TCNT0<16) ;
    TCNT0=0;
  }
  TCCR0B=0;
}

int main()
{

// Als Ausgänge sind Definiert:
DDRD = 0b11101111;
DDRC = 0b00111111;
DDRB = 0b11111111;

  uint8_t e, z, h;

  for( h = 3; h > -1; --h ) {
    OutputDigit( &HunderterMask, &Hunderter[h] );

  delay_ms(100);


    for( z = 0; z > -1; --z ) {
      OutputDigit( &ZehnerMask, &Zehner[z] );

    delay_ms(100);


      for( e = 0; e > -1; --e )
     {
        OutputDigit( &EinerMask, &Einer[e] );

    delay_ms(100);
      }
    }
  }
}

Autor: Weingut Pfalz (weinbauer)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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".
struct Digits Hunderter[] =
{   // Port D   Port C      Port B
  { 0b00001110, 0b00111000, 0b00000000 },   // 0
  { 0b00000000, 0b00110000, 0b00000000 },   // 1
  { 0b00001101, 0b00011000, 0b00000000 },   // 2
  { 0b00001001, 0b00111000, 0b00000000 },   // 3
};

void OutputDigit(uint8 hunderter, uint8 zehner, uint8 einer)
{
    PORTD = Hunderter[hunderter][0] | Zehner[zehner][0] | Einer[einer][0] | (1<<4);
    PORTC = Hunderter[hunderter][1] | Zehner[zehner][1] | Einer[einer][1];
    PORTB = Hunderter[hunderter][2] | Zehner[zehner][2] | Einer[einer][2];
}

int main()
{

// Als Ausgänge sind Definiert:
DDRD = 0b11101111;
DDRC = 0b00111111;
DDRB = 0b11111111;

  uint8_t e, z, h;

  e = 0;
  z = 0;
  h = 3;
  do
  (        
   do
   {
    do
    {
    OutputDigit(h,z,e);
    delay_ms(1000);
    } while(e > 0);
    e = 9;
   } while(z > 0);
   z = 9;
   ) while(h>0)
   OutputDigit(0,0,0);
  while(1); // Endlosschleife
}


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".

Autor: Axel L. (ligonap)
Datum:

Bewertung
0 lesenswert
nicht 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???
int main()
{

// Als Ausgänge sind Definiert:
DDRD = 0b11101111;
DDRC = 0b00111111;
DDRB = 0b11111111;

  uint8_t e, z, h;

      for( e = 9; e >= 0; e-- ) {
            OutputDigit( &EinerMask, &Einer[e] );
  }
}

Autor: Axel L. (ligonap)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn ich folgenden Code verwende:
int main()
{

// Als Ausgänge sind Definiert:
DDRD = 0b11101111;
DDRC = 0b00111111;
DDRB = 0b11111111;

  uint8_t e, z, h;

      for( e = 10; e > 0; e = e - 1 ) {
            OutputDigit( &EinerMask, &Einer[e - 1] );

  }
}

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Axel L. (ligonap)
Datum:

Bewertung
0 lesenswert
nicht 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:
#include <avr/io.h>

void delay_ms(int ms) 
{
  TCCR0B |= (1<<CS01) | (1<<CS00) ;
  int i ;
  for(i=0; i<ms; i++) {

    while(TCNT0<16) ;
    TCNT0=0;
  }
  TCCR0B=0;
}

int main()

{

DDRD = 0b11101111;
DDRC = 0b00111111;
DDRB = 0b11111111;

while(1) {
     
  delay_ms(250);

  if( PIND & (1 << PIND4)) {

// Anzeigewert zum Beginn: 300
PORTD = 0b11101001;
PORTC = 0b00111011;
PORTB = 0b11110111;

   } 

   if( !(PIND & (1 << PIND4))) {

// Anzeigewert zum Ende: 003
PORTD = 0b11101110;
PORTC = 0b00111011;
PORTB = 0b11111001;

   }
}
}

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.

Autor: Axel L. (ligonap)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe mit folgenden mini-Code den Optokoppler quasi als Taster 
getestet:
#include <avr/io.h>

int main(void)
{  

DDRD = 0b11101111;
   
  while(1) {
  
    if ( PIND & (1<<PIND4) )
    {
    PORTD |= ( 1 << PD6 );
    }
 
    if ( !(PIND & (1<<PIND4)) )
    {
    PORTD &= ~( 1 << PD6);   
    } 
  }
}

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

Autor: ... (Gast)
Datum:

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

Autor: Axel L. (ligonap)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Axel L. (ligonap)
Datum:

Bewertung
0 lesenswert
nicht 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:
#include <avr/io.h>

struct Digits
{
  uint8_t  portD;
  uint8_t  portC;
  uint8_t  portB;
};

struct Digits Hunderter[] =
{ //   Port D     Port C      Port B
  { 0b00001110, 0b00111000, 0b00000000 },   // 0
  { 0b00000000, 0b00110000, 0b00000000 },   // 1
  { 0b00001101, 0b00011000, 0b00000000 },   // 2
  { 0b00001001, 0b00111000, 0b00000000 },   // 3
  { 0b00000011, 0b00011000, 0b00000000 },   // 4
  { 0b00001011, 0b00101000, 0b00000000 },   // 5
  { 0b00001111, 0b00101000, 0b00000000 },   // 6
  { 0b00000000, 0b00111000, 0b00000000 },   // 7
  { 0b00001111, 0b00111000, 0b00000000 },   // 8
  { 0b00001011, 0b00111000, 0b00000000 },   // 9
  { 0b00001110, 0b00111000, 0b00000000 },   // 0
};

struct Digits HunderterMask =
  { 0b00001111, 0b00111000, 0b00000000 };

struct Digits Zehner[] =
{ //   Port D     Port C      Port B
  { 0b00000000, 0b00000011, 0b11110000 },   // 0
  { 0b00000000, 0b00000000, 0b10100000 },   // 1
  { 0b00000000, 0b00000101, 0b01110000 },   // 2
  { 0b00000000, 0b00000100, 0b11110000 },   // 3
  { 0b00000000, 0b00000110, 0b10100000 },   // 4
  { 0b00000000, 0b00000110, 0b11010000 },   // 5
  { 0b00000000, 0b00000111, 0b11010000 },   // 6
  { 0b00000000, 0b00000000, 0b10110000 },   // 7
  { 0b00000000, 0b00000111, 0b11110000 },   // 8
  { 0b00000000, 0b00000110, 0b11110000 },   // 9
  { 0b00000000, 0b00000011, 0b11110000 },   // 0
};

struct Digits ZehnerMask =
  { 0b00000000, 0b00000111, 0b11110000 };

struct Digits Einer[] =
{ //   Port D     Port C      Port B
  { 0b11100000, 0b00000000, 0b00000111 },   // 0
  { 0b01100000, 0b00000000, 0b00000000 },   // 1
  { 0b11000000, 0b00000000, 0b00001011 },   // 2
  { 0b11100000, 0b00000000, 0b00001001 },   // 3
  { 0b01100000, 0b00000000, 0b00001100 },   // 4
  { 0b10100000, 0b00000000, 0b00001101 },   // 5
  { 0b10100000, 0b00000000, 0b00001111 },   // 6
  { 0b11100000, 0b00000000, 0b00000000 },   // 7
  { 0b11100000, 0b00000000, 0b00001111 },   // 8
  { 0b11100000, 0b00000000, 0b00001101 },   // 9
  { 0b11100000, 0b00000000, 0b00000111 },   // 0
};

struct Digits EinerMask =
  { 0b11100000, 0b00000000, 0b00001111 };

void OutputDigit(struct Digits *mask, struct Digits *digits)
{
  if( mask->portB != 0 ) 
  {
    PORTB &= ~mask->portB;
    PORTB |= digits->portB;
  }

  if( mask->portC != 0 ) 
  {
    PORTC &= ~mask->portC;
    PORTC |= digits->portC;
  }

  if( mask->portD != 0 ) 
  {
    PORTD &= ~mask->portD;
    PORTD |= digits->portD;
  }
}

void delay_ms(int ms) 
{

  TCCR0B |= (1<<CS01) | (1<<CS00) ;
  int i ;
  for(i=0; i<ms; i++) {

    while(TCNT0<16) ;
    TCNT0=0;
  }
  TCCR0B=0;
}

int main()
{

// Als Ausgänge und Eingänge sind Definiert:
DDRD = 0b11101111;
DDRC = 0b00111111;
DDRB = 0b11111111;

  uint8_t e, z, h;

// Anzeigewert 300 zu beginn
PORTD = 0b11101001;
PORTC = 0b00111011;
PORTB = 0b11110111;

 while ( PIND & (1<<PIND4) ) ;

  for( h = 3; h > 0; h=h-1) {
    OutputDigit( &HunderterMask, &Hunderter[h-1] );

    for( z = 10; z > 0; z=z-1 ) {
      OutputDigit( &ZehnerMask, &Zehner[z-1] );

      for( e = 10; e > 0; e=e-1 ) {
        OutputDigit( &EinerMask, &Einer[e-1] );

    delay_ms(100);
    while ( PIND & (1<<PIND4) ) ;

      }
    }
  }
}

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.