AVR Programming/de

From Lazarus wiki
Jump to navigationJump to search

Deutsch (de) English (en)

Wichtige Hinweise zu AVR-Programmierung

Generell geht alles nicht, was dynamisch ist, zB. Classen, dynamische Arrays, dynamische Strings.

Integer

Der Standard-Integer ist nur 16Bit gross, somit wird nur ein Bereich von -32'768 bis +32'767 abgedeckt. Ansonsten muss man einen LongInt oder int32/uint32 nehmen.

Shiften

Da kleine Konstanten als 8Bit-Wert angenommen, gibt es beim Shiften mit einer Variable wen sie grösser 8 ist einen Überlauf. ( Stand: 26 Juli 2018 )
Als Abhilfe eine Typenumwandlung durchführen.
Beim Shiften mit einer Konstante wird automatisch ein 16Bit-Wert angenommen.

var
  b: UInt8
  i: UInt16;
...
begin
  b := 8;
  i := 1 shl b;         // i = 0    Überlauf
  i := UInt16(1) shl b; // i = 255  io.
  i := 1 shl 8;         // i = 255  io.

Array

Es ist keine dynamische Array erlaubt.

Classen

Classen gehen nicht auf einem AVR, alternativ Object nehmen.

Fliesskommazahlen

Werden von FPC nicht unterstützt. Stand: 21.05.2018

AVR unterstützt Fliesskommazahlen Hardwaremässig nicht.
Mit Arduino/AVR C++, kann man mit float rechnen, aber dies wird Softwaremässig emuliert. Ein double ist dort gleich wie ein float, beide in 16Bit breite.

Problem umgehen

Das Problem kann man umzugehen, wen man mit improvisierten Festkommazahlen rechnet.

Oder man nimmt eine andere Einheit. Als Beispiel ein Thermometer mit 1/10°. Man rechnet dabei mit 1/10°, anstelle mit ganzen Grad.
Den Dezimalpunkt setzt man dann erst bei der Ausgabe, wen man die Zahl in einen String umwandelt.


Die Anzeige geht dann von 00.0 bis 99.9 .

var
  Digit:String[4];

  procedure IntToDigit(val: UInt16);
  var
    achr: byte;
    leer: boolean;
  begin
    Digit[0] := #4; // Der String ist 4 Zeichen lang, inklusive Dezimalpunkt.

    // Hunderter
    achr := 0;
    while (val >= 100) do begin
      Dec(val, 100);
      Inc(achr);
      leer := False;
    end;
    if leer then begin
      achr := 16;
    end;
    Digit[1] := Char(achr);

    // Zehner
    achr := 0;
    while (val >= 10) do begin
      Dec(val, 10);
      Inc(achr);
      leer := False;
    end;
    if leer then begin
      achr := 16;
    end;
    Digit[2] := Char(achr);
    Digit[3] := '.';

    // Einer
    achr := 0;
    while (val >= 1) do begin
      Dec(val);
      Inc(achr);
    end;
    Digit[4] := Char(achr);
  end;


Siehe:

Rechnen mit Operatoren

Der AVR ist ein schlechter Rechenknecht. Rechnen kann er nur mit Ganzzahlen.
Die folgende Tabelle zeigt, was der AVR Hardwaremässig kann, alles andere muss der Compiler auf Softwarebasis emulieren.
Als Beispiel 3 * 4 setzt der Compiler beim ATtiny etwa so um 4 + 4 + 4. Bei gösseren Zahlen wird dies sehr langsam !

Operator ATtiny ATmega
+ Hardware Hardware
- Hardware Hardware
* Software Hardware
/ Software Software

Shift-Operatoren, wie shl und shr werden hervorragend unterstützt.

String

AVR unterstützen nur ShortString, dies muss mit folgendem Compilerschalter eingestellt werden.

{$H-} //  String = ShortString

Oder man deklariert den String so:

var
  s0: String[100]; // Stringlänge 100 Zeichen.
  s2: ShortString; // Stringlänge 255 Zeichen.

Plattform-Abfrag

Bei einem auf mehreren Plattformen gebrauchten Code, kann man abfragen, ob es sich um einen AVR handelt.

    {$ifdef cpuavr}
    UCSR0A := (0 shl U2X0); // Wird nur bei AVR berücksichtigt.
    {$endif}

Assembler

Bei AVR ist auch Inline-Assembler möglich, dies funktioniert gleich, wie auf dem PC, der grosse Unterschied ist, das man AVR-Assembler verwenden muss.
In diesem Beispielen sieht man, das die Label anders als bei Intel deklariert werden. Der Labelbezeichner muss mit .Lxxx beginnen.

Assemblerblock:

procedure MyAsmProc;
begin
  asm
    .L2:
    nop
    jmp .L2
  end;
end;

Komplette Assembler Procedure:

procedure MyAsmProc; assembler;
asm
  .L2:
  nop
  jmp .L2
end;

Ungültiges Label

Falsche Bezeichnung, das es nicht mit .L beginnt.

asm
  .ABC:  //  Syntax-Fehler !
  ...
end,

Einfacher Blinker in Assembler:

program Project1;
begin
  asm
    sbi 4, 5        // DDRD, Pin5 --> Output

// --- Hauptschleife
    .Lloop:
      sbi 5, 5      // PORTD, Pin5 --> On
      ldi r20, 50   // 50ms
      call .LDelay  // Delay

      cbi 5, 5      // PORTD, Pin5 --> Off
      ldi r20, 250  // 250ms
      call .LDelay  // Delay
    jmp .Lloop

// --- Delay
    .LDelay:
    .L1:
      ldi r21, 16 // 16MHz
      .L2:
        ldi r22, 250
        .L3:
          nop
          dec r22
        brne .L3
        dec r21
      brne .L2
      dec r20
    brne .L1
    ret
  end;
end.

Siehe auch

Autor: Mathias