Difference between revisions of "AVR Programming/de"
(Created page with "{{Translate}} =Wichtige Hinweise zu AVR-Programmierung= Generell geht alles '''nicht''', was dynamisch ist, zB. Classen, dynamische Arrays, dynamische Strings. ==Classen== '...") |
(→String) |
||
(42 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
− | {{ | + | {{AVR Programming}} |
=Wichtige Hinweise zu AVR-Programmierung= | =Wichtige Hinweise zu AVR-Programmierung= | ||
Generell geht alles '''nicht''', was dynamisch ist, zB. Classen, dynamische Arrays, dynamische Strings. | 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 )<br> | ||
+ | Als Abhilfe eine Typenumwandlung durchführen.<br> | ||
+ | Beim Shiften mit einer Konstante wird automatisch ein 16Bit-Wert angenommen. | ||
+ | <syntaxhighlight lang="pascal"> | ||
+ | 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. | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==Array== | ||
+ | Es ist '''keine''' dynamische Array erlaubt. | ||
==Classen== | ==Classen== | ||
'''Classen''' gehen nicht auf einem AVR, alternativ '''Object''' nehmen. | '''Classen''' gehen nicht auf einem AVR, alternativ '''Object''' nehmen. | ||
+ | |||
+ | ==Fliesskommazahlen== | ||
+ | Werden von FPC nicht unterstützt. Stand: 21.05.2018<br> | ||
+ | |||
+ | AVR unterstützt Fliesskommazahlen Hardwaremässig '''nicht'''.<br>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.<br> | ||
+ | |||
+ | ===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.<br> | ||
+ | Den Dezimalpunkt setzt man dann erst bei der Ausgabe, wen man die Zahl in einen String umwandelt. | ||
+ | |||
+ | '''Hinweis:''' Es wird nicht auf Überlauf getestet. | ||
+ | |||
+ | Die Anzeige geht dann von 00.0 bis 99.9 . | ||
+ | <syntaxhighlight lang="pascal"> | ||
+ | var | ||
+ | Digit: String[4]; | ||
+ | |||
+ | // Erlaubte Werte fuer val: 0..999 | ||
+ | procedure IntToDigit(val: UInt16); | ||
+ | var | ||
+ | achr: byte; | ||
+ | begin | ||
+ | Digit[0] := #4; // Der String ist 4 Zeichen lang, inklusive Dezimalpunkt. | ||
+ | |||
+ | // Zehner | ||
+ | achr := 0; | ||
+ | while (val >= 100) do begin | ||
+ | Dec(val, 100); | ||
+ | Inc(achr); | ||
+ | end; | ||
+ | if achr=0 then begin | ||
+ | Digit[1] := Char(32); //32 dezimal ist [SPACE] in Ascii Tabelle | ||
+ | end else begin | ||
+ | Digit[1] := Char(achr + 48); | ||
+ | end; | ||
+ | |||
+ | // Einer | ||
+ | achr := 0; | ||
+ | while (val >= 10) do begin | ||
+ | Dec(val, 10); | ||
+ | Inc(achr); | ||
+ | end; | ||
+ | Digit[2] := Char(achr + 48); | ||
+ | |||
+ | // Dezimalpunkt | ||
+ | Digit[3] := '.'; | ||
+ | |||
+ | // Zehntel | ||
+ | achr := 0; | ||
+ | while (val >= 1) do begin | ||
+ | Dec(val); | ||
+ | Inc(achr); | ||
+ | end; | ||
+ | Digit[4] := Char(achr + 48); | ||
+ | end; | ||
+ | |||
+ | /* | ||
+ | IntToDigit(0); // Digit --> " 0.0" | ||
+ | IntToDigit(4); // Digit --> " 0.4" | ||
+ | IntToDigit(44); // Digit --> " 4.4" | ||
+ | IntToDigit(444); // Digit --> "44.4" | ||
+ | IntToDigit(999); // Digit --> "99.9" | ||
+ | */ | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | Siehe auch: | ||
+ | * [[AVR Embedded Tutorial - Int to digits/de|Ausgabe auf Digits (7 Segmentanzeige)]] | ||
+ | |||
+ | ==Rechnen mit Operatoren== | ||
+ | Der AVR ist ein schlechter Rechenknecht. Rechnen kann er nur mit Ganzzahlen.<br> | ||
+ | Die folgende Tabelle zeigt, was der AVR Hardwaremässig kann, alles andere muss der Compiler auf Softwarebasis emulieren.<br> | ||
+ | Als Beispiel '''3 * 4''' setzt der Compiler beim ATtiny etwa so um '''4 + 4 + 4'''. Bei gösseren Zahlen wird dies sehr langsam ! | ||
+ | {| class="wikitable" | ||
+ | |- | ||
+ | !Operator !! ATtiny !! ATmega | ||
+ | |- | ||
+ | |style="text-align:center"|+ || Hardware || Hardware | ||
+ | |- | ||
+ | |style="text-align:center"|- || Hardware || Hardware | ||
+ | |- | ||
+ | |style="text-align:center"|* || Software || Hardware | ||
+ | |- | ||
+ | |style="text-align:center"|/ || Software || Software | ||
+ | |- | ||
+ | |} | ||
+ | Shift-Operatoren, wie '''shl''' und '''shr''' werden hervorragend unterstützt. | ||
==String== | ==String== | ||
− | + | AVR unterstützen nur '''ShortString''', dies muss mit folgendem Compilerschalter eingestellt werden. | |
+ | <syntaxhighlight lang="pascal"> | ||
+ | {$H-} // String = ShortString | ||
+ | </syntaxhighlight> | ||
+ | Oder man deklariert den String so: | ||
+ | <syntaxhighlight lang="pascal"> | ||
+ | var | ||
+ | s0: String[100]; // Stringlänge 100 Zeichen. | ||
+ | s2: ShortString; // Stringlänge 255 Zeichen. | ||
+ | </syntaxhighlight> | ||
+ | Hinweis: Strings brauchen sehr viel Platz. So etwas '''verbraucht 256 Byte !!'''. Ein ATTiny2313 ist dabei überfordert. | ||
+ | <syntaxhighlight lang="pascal"> | ||
+ | var | ||
+ | s: ShortString = 'Hallo'; // Verbraucht 256 Byte ! | ||
+ | </syntaxhighlight> | ||
+ | Deshalb immer die maximale Länge vorgeben. | ||
+ | <syntaxhighlight lang="pascal"> | ||
+ | var | ||
+ | s: String[10] = 'Hallo'; // Braucht 11 Byte | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==Plattform-Abfrag== | ||
+ | Bei einem auf mehreren Plattformen gebrauchten Code, kann man abfragen, ob es sich um einen '''AVR''' handelt. | ||
+ | |||
<syntaxhighlight lang="pascal"> | <syntaxhighlight lang="pascal"> | ||
− | {$ | + | {$ifdef cpuavr} |
+ | UCSR0A := (0 shl U2X0); // Wird nur bei AVR berücksichtigt. | ||
+ | {$endif} | ||
</syntaxhighlight> | </syntaxhighlight> | ||
+ | ==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.<br> | ||
+ | In diesem Beispielen sieht man, das die Label anders als bei Intel deklariert werden. Der Labelbezeichner muss mit '''.L'''xxx beginnen. | ||
+ | |||
+ | ===Assemblerblock:=== | ||
+ | <syntaxhighlight lang="pascal"> | ||
+ | procedure MyAsmProc; | ||
+ | begin | ||
+ | asm | ||
+ | .L2: | ||
+ | nop | ||
+ | jmp .L2 | ||
+ | end; | ||
+ | end; | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ===Komplette Assembler Procedure:=== | ||
+ | <syntaxhighlight lang="pascal"> | ||
+ | procedure MyAsmProc; assembler; | ||
+ | asm | ||
+ | .L2: | ||
+ | nop | ||
+ | jmp .L2 | ||
+ | end; | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ===Ungültiges Label=== | ||
+ | Falsche Bezeichnung, das es nicht mit '''.L''' beginnt. | ||
+ | <syntaxhighlight lang="pascal"> | ||
+ | asm | ||
+ | .ABC: // Syntax-Fehler ! | ||
+ | ... | ||
+ | end, | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ===Einfacher Blinker in Assembler:=== | ||
+ | <syntaxhighlight lang="pascal"> | ||
+ | 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.</syntaxhighlight> | ||
== Siehe auch == | == Siehe auch == | ||
− | * Übersichtseite [[AVR Embedded Tutorial/de]] | + | * Übersichtseite [[AVR Embedded Tutorial/de|AVR Embedded Tutorial]] |
− | + | Autor: [[User:Mathias|Mathias]] | |
− | |||
− | [[ |
Latest revision as of 15:57, 10 June 2020
│
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.
Hinweis: Es wird nicht auf Überlauf getestet.
Die Anzeige geht dann von 00.0 bis 99.9 .
var
Digit: String[4];
// Erlaubte Werte fuer val: 0..999
procedure IntToDigit(val: UInt16);
var
achr: byte;
begin
Digit[0] := #4; // Der String ist 4 Zeichen lang, inklusive Dezimalpunkt.
// Zehner
achr := 0;
while (val >= 100) do begin
Dec(val, 100);
Inc(achr);
end;
if achr=0 then begin
Digit[1] := Char(32); //32 dezimal ist [SPACE] in Ascii Tabelle
end else begin
Digit[1] := Char(achr + 48);
end;
// Einer
achr := 0;
while (val >= 10) do begin
Dec(val, 10);
Inc(achr);
end;
Digit[2] := Char(achr + 48);
// Dezimalpunkt
Digit[3] := '.';
// Zehntel
achr := 0;
while (val >= 1) do begin
Dec(val);
Inc(achr);
end;
Digit[4] := Char(achr + 48);
end;
/*
IntToDigit(0); // Digit --> " 0.0"
IntToDigit(4); // Digit --> " 0.4"
IntToDigit(44); // Digit --> " 4.4"
IntToDigit(444); // Digit --> "44.4"
IntToDigit(999); // Digit --> "99.9"
*/
Siehe auch:
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.
Hinweis: Strings brauchen sehr viel Platz. So etwas verbraucht 256 Byte !!. Ein ATTiny2313 ist dabei überfordert.
var
s: ShortString = 'Hallo'; // Verbraucht 256 Byte !
Deshalb immer die maximale Länge vorgeben.
var
s: String[10] = 'Hallo'; // Braucht 11 Byte
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
- Übersichtseite AVR Embedded Tutorial
Autor: Mathias