Difference between revisions of "AVR Embedded Tutorial - Multiplex/de"

From Lazarus wiki
Jump to navigationJump to search
Line 13: Line 13:
 
Die Ausgabe erfolgt über zwei Schieberegister (74HC595). Wen der AVR genügend GPIO hat, kann man dies auch über diese machen.
 
Die Ausgabe erfolgt über zwei Schieberegister (74HC595). Wen der AVR genügend GPIO hat, kann man dies auch über diese machen.
  
====Werte der einzelnen Segmente====
+
Wie man die GPIO und Schieberegister anteuert, steht hier:
Als Beispiel wird eine 4-stellige 7-Segmentanzeige angesteuert.
+
* [[AVR Embedded Tutorial - Simple GPIO on and off output/de|GPIO]]
 +
* [[AVR Embedded Tutorial - Shiftregister/de|Schieberegister]]
 +
 
 +
====Digits Konstante für 7-Segmentanzeige====
 +
In dieser Konstante sind die LED-Kombinationen der Ziffern gespeichert. Zusätzlich sind noch HEX-Zeichen gespeichert.
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
var
+
const
   zahl: array[0..3] of byte;
+
   digits: packed array[0..15] of byte = (
 +
  %00111111,  // = 0
 +
  %00000110,  // = 1
 +
  %01011011,  // = 2
 +
  %01001111,  // = 3
 +
  %01100110,  // = 4
 +
  %01101101,  // = 5
 +
  %01111101,  // = 6
 +
  %00000111,  // = 7
 +
  %01111111,  // = 8
 +
  %01100111,  // = 9
 +
  %01110111,  // = a
 +
  %01111100,  // = b
 +
  %00111001,  // = c
 +
  %01011110,  // = d
 +
  %01111001,  // = e
 +
  %01110001); // = f
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 
+
====Werte der einzelnen Segmente====
====Digits Konstante für 7-Segmentanzeige====
+
Als Beispiel wird eine 4-stellige 7-Segmentanzeige angesteuert. Wen man einen grösseren Multiplex will, muss man dies Zahl erhöhen.
In dieser Konstante sind die LED-Kombinationen der Ziffern gespeichert. Zusätzlich sind noch HEX-Zeichen, Blank und Minus gespeichert.
 
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
 
const
 
const
   digits: packed array[0..17] of byte = (
+
   anzSegment = 4;
    %00111111,  // = 0
+
var
    %00110000,  // = 1
+
  zahl: array[0..anzSegment - 1] of byte;
    %10011011,  // = 2
+
</syntaxhighlight>
    %10111001,  // = 3
 
    %10110100,  // = 4
 
    %10101101,  // = 5
 
    %10101111,  // = 6
 
    %00111000,  // = 7
 
    %10111111,  // = 8
 
    %10111101,  // = 9
 
  
    %10110111,  // = a
 
    %10111100,  // = b
 
    %10111001,  // = c
 
    %10011110,  // = d
 
    %10111001,  // = e
 
    %10110001,  // = f
 
    %00000000,  // = blank
 
    %10000000); // = -
 
</syntaxhighlight>
 
  
 
====Multiplex====
 
====Multiplex====
Das ist das Herz des Multiplexes.
+
Das ist das Herz des Multiplexes. Bei jedem Durchlauf des Timers, wird das Segment gewechselt. Wen man dies sehen will, muss man die Timerfrequenz reduzieren, das man dies von Auge sieht.Für dieses Beispiel wird der Timer0 verwendet.
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
   procedure Timer0_Interrupt; public Name 'TIMER0_COMPA_ISR'; interrupt;
+
   procedure Timer0_Interrupt; public Name 'TIM0_COMPA_ISR'; interrupt;
  var
 
    d: integer;
 
 
   const
 
   const
     p: byte = 0;
+
     segPos: byte = 0;
 
   begin
 
   begin
     p := p + 1;                   // Anzeigen durchzählen
+
     segPos := segPos + 1;
     if (p > 3) then begin
+
     if (segPos > anzSegment - 1) then begin
       p := 0;
+
       segPos := 0;
 
     end;
 
     end;
  
     WritePortD(latchPin, False);
+
     WritePortA(latchPin, False);
     WritePortD(latchPin, True);
+
     WritePortA(latchPin, True);
  
     shiftOut595(digits[zahl[p]]); // Digit aus Tabelle
+
     shiftOut595(digits[zahl[segPos]]); // Aktuelle Ziffer im Segment ansteuern.
     shiftOut595(1 shl p);         // Zu zeigende Anzeige
+
     shiftOut595(1 shl segPos);         // Aktuelles Segment aktivieren.
 
   end;
 
   end;
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 
====Delay====
 
====Delay====
Ein einfaches Delay.
+
Ein einfaches Delay. dies wird beim Zifferwechsel in der Hauptschleife benötigt.
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
 
procedure delay;
 
procedure delay;
Line 80: Line 81:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
====Initialisierung und Hauptloop====
+
====Initialisierung und Hauptschleife====
 +
Hier der Timer0 für den Mutiplex initialisiert, auch werden die benötigten Port auf Ausgabe geschalten.
 +
 
 +
Genaueres über Timer hier: [[AVR Embedded Tutorial - Timer/Counter/de|Timer]]
 +
 
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
 
begin
 
begin
   cli();
+
   // Interrupt sperren.
 
+
  asm cli end;
 +
 
 
   // Ports auf Ausgabe schalten.
 
   // Ports auf Ausgabe schalten.
   ModePortD(dataOutPin, True);
+
   DDRA := (1 shl dataOutPin) or (1 shl latchPin) or (1 shl clockPin);
  ModePortD(latchPin, True);
 
  ModePortD(clockPin, True);
 
  
 
   // -- Timer initialisieren
 
   // -- Timer initialisieren
   TCCR0A := (1 shl WGM01);
+
   TCCR0A := (1 shl 1);
 
   TCCR0B := TCCR0B or %101;
 
   TCCR0B := TCCR0B or %101;
   TIMSK := TIMSK or (1 shl OCIE0A);
+
   TIMSK0 := TIMSK0 or (1 shl OCIE0A);
   sei();
+
 
   // --- Ende timer
+
  // Interrupt frei geben.
 +
   asm sei end;
 +
 
 +
   // Hauptschleife
 
   repeat
 
   repeat
 
     zahl[0] := 1;
 
     zahl[0] := 1;
Line 109: Line 116:
 
     delay;
 
     delay;
 
   until 1 = 2;
 
   until 1 = 2;
end.
+
end;
 
</syntaxhighlight>
 
</syntaxhighlight>

Revision as of 18:50, 11 November 2017

Warning-icon.png

Warnung: In Arbeit

Multiplex

Portzugriffe

Wie die Schieberegisterbefehle auf die Ports zugreifen, siehe hier: GPIO-Ausgabe.
Nicht vergessen die Ausgänge auch als Ausgang einzustellen (DDRx).

AVR Embedded Tutorial - Shiftregister/de

Beispiel

Bei jedem Timerdurchlauf, wird ein anderes Segment angesteuert. Somit muss der Timer 4 mal durchlaufen, bis ein Frame aktualisiert ist. Für eine konstante Wiederholfrequenz, ist der Timer am besten geeignet, da er regelmässig aufgerufen wird. Man könnte ein Multiplex auch in der Hauptloop machen, aber wen dort eine kleine Pause vorkommt, dann fängt die Anzeige an zu flackern.

Die Ausgabe erfolgt über zwei Schieberegister (74HC595). Wen der AVR genügend GPIO hat, kann man dies auch über diese machen.

Wie man die GPIO und Schieberegister anteuert, steht hier:

Digits Konstante für 7-Segmentanzeige

In dieser Konstante sind die LED-Kombinationen der Ziffern gespeichert. Zusätzlich sind noch HEX-Zeichen gespeichert.

const
  digits: packed array[0..15] of byte = (
  %00111111,  // = 0
  %00000110,  // = 1
  %01011011,  // = 2
  %01001111,  // = 3
  %01100110,  // = 4
  %01101101,  // = 5
  %01111101,  // = 6
  %00000111,  // = 7
  %01111111,  // = 8
  %01100111,  // = 9
  %01110111,  // = a
  %01111100,  // = b
  %00111001,  // = c
  %01011110,  // = d
  %01111001,  // = e
  %01110001); // = f

Werte der einzelnen Segmente

Als Beispiel wird eine 4-stellige 7-Segmentanzeige angesteuert. Wen man einen grösseren Multiplex will, muss man dies Zahl erhöhen.

const
  anzSegment = 4;
var
  zahl: array[0..anzSegment - 1] of byte;


Multiplex

Das ist das Herz des Multiplexes. Bei jedem Durchlauf des Timers, wird das Segment gewechselt. Wen man dies sehen will, muss man die Timerfrequenz reduzieren, das man dies von Auge sieht.Für dieses Beispiel wird der Timer0 verwendet.

  procedure Timer0_Interrupt; public Name 'TIM0_COMPA_ISR'; interrupt;
  const
    segPos: byte = 0;
  begin
    segPos := segPos + 1;
    if (segPos > anzSegment - 1) then begin
      segPos := 0;
    end;

    WritePortA(latchPin, False);
    WritePortA(latchPin, True);

    shiftOut595(digits[zahl[segPos]]); // Aktuelle Ziffer im Segment ansteuern.
    shiftOut595(1 shl segPos);         // Aktuelles Segment aktivieren.
  end;

Delay

Ein einfaches Delay. dies wird beim Zifferwechsel in der Hauptschleife benötigt.

procedure delay;
var
  i: integer;
begin
  for i := 0 to 200 do asm Nop end;
end;

Initialisierung und Hauptschleife

Hier der Timer0 für den Mutiplex initialisiert, auch werden die benötigten Port auf Ausgabe geschalten.

Genaueres über Timer hier: Timer

begin
  // Interrupt sperren.
  asm cli end;

  // Ports auf Ausgabe schalten.
  DDRA := (1 shl dataOutPin) or (1 shl latchPin) or (1 shl clockPin);

  // -- Timer initialisieren
  TCCR0A := (1 shl 1);
  TCCR0B := TCCR0B or %101;
  TIMSK0 := TIMSK0 or (1 shl OCIE0A);

  // Interrupt frei geben.
  asm sei end;

  // Hauptschleife
  repeat
    zahl[0] := 1;
    zahl[1] := 2;
    zahl[2] := 3;
    zahl[3] := 4;
    delay;

    zahl[0] := 5;
    zahl[1] := 6;
    zahl[2] := 7;
    zahl[3] := 8;
    delay;
  until 1 = 2;
end;