; Demonstriert Fliesskomma-Umwandlung in ; Assembler, (C)2003 www.avr-asm-tutorial.net ; ; Die Aufgabe: Ein 8-Bit-Analog-Wandler-Signal ; in Binaerform wird eingelesen, die Zahlen ; reichen von hex 00 bis FF. ; Diese Zahlen sind umzurechnen in eine ; Fliesskommazahl zwischen 0,00 bis 5,00 ; Volt. ; ; Der Programmablauf: ; 1. Multiplikation mit 502 (hex 01F6). ; Dieser Schritt multipliziert die Zahl mit ; den Faktoren 500 und 256 und dividiert ; mit 255 in einem Schritt. ; 2. Das Ergebnis wird gerundet und das letzte ; Byte abgeschnitten. ; Dieser Schritt dividiert durch 256, indem ; das letzte Byte des Ergebnisses ignoriert ; wird. Davor wird das Bit 7 des Ergebnisses ; abgefragt und zum Runden des Ergebnisses ; verwendet. ; 3. Die erhaltene Zahl wird in ASCII-Zeichen ; umgewandelt und mit einem Dezimalpunkt ; versehen. ; Das Ergebnis, eine Ganzzahl zwischen 0 und ; und 500 wird in eine Dezimalzahl verwan- ; delt und in der Form 5,00 als Fliesskomma- ; zahl in ASCII-Zeichen dargestellt. ; ; Die verwendeten Register: ; Die Routinen benutzen die Register R8 bis R1, ; ohne diese vorher zu sichern. Zusaetzlich wird ; das Vielzweckregister rmp verwendet, das in ; der oberen Registerhaelfte liegen muss. Bitte ; beachten, dass diese verwendeten Register ; nicht mit anderen Verwendungen in Konflikt ; kommen koennen. ; ; Zu Beginn wird die 8-Bit-Zahl im Register ; R1 erwartet. ; ; Die Multiplikation verwendet R4:R3:R2 zur ; Speicherung des Multiplikators 502 (der ; bei der Berechnung maximal 8 mal links ge- ; schoben wird - Multiplikation mit 2). Das ; Ergebnis der Multiplikation wird in den Re- ; gistern R7:R6:R5 berechnet. ; Das Ergebnis der sogenannten Division durch ; 256 durch Ignorieren von R5 des Ergebnisses ; ist in R7:R6 gespeichert. Abhaengig von Bit ; 7 in R5 wird zum Registerpaar R7:R6 eine ; Eins addiert. Das Ergebnis in R7:R6 wird ; in das Registerpaar R2:R1 kopiert. ; Die Umwandlung der Binaerzahl in R2:R1 in ; eine ASCII-Zeichenfolge verwendet das Paar ; R4:R3 als Divisor fuer die Umwandlung. Das ; Ergebnis, der ASCII-String, ist in den Re- ; gistern R5:R6:R7:R8 abgelegt. ; ; Weitere Bedingungen: ; Die Umwandlung benutzt Unterprogramme, daher ; muss der Stapel funktionieren. Es werden ; maximal drei Ebenen Unterprogrammaufrufe ; verschachtelt (benoetigt sechs Byte SRAM). ; ; Umwandlungszeiten: ; Die gesamte Umwandlung benoetigt 228 Taktzyklen ; maximal (Umwandlung von $FF) bzw. 79 Takt- ; zyklen (Umwandlung von $00). Bei 4 MHz Takt ; entspricht dies 56,75 Mikrosekunden bzw. 17,75 ; Mikrosekunden. ; ; Definitionen: ; Register .DEF rmp = R16 ; als Vielzweckregister verwendet ; ; AVR-Typ ; Getestet fuer den Typ AT90S8515, die Angabe ; wird nur fuer den Stapel benoetigt. Die Routinen ; arbeiten auf anderen AT90S-Prozessoren genauso ; gut. .NOLIST .INCLUDE "8515def.inc" .LIST ; ; Start des Testprogramms ; ; Schreibt eine Zahl in R1 und startet die Wand- ; lungsroutine, nur fuer Testzwecke. ; .CSEG .ORG $0000 rjmp main ; main: ldi rmp,HIGH(RAMEND) ; Richte den Stapel ein out SPH,rmp ldi rmp,LOW(RAMEND) out SPL,rmp ldi rmp,$FF ; Wandle FF um mov R1,rmp rcall fpconv8 ; Rufe die Umwandlungsroutine no_end: ; unendliche Schleife, wenn fertig rjmp no_end ; ; Ablaufssteuerung der Umwandlungsroutine, ruft die ; verschiedenen Teilschritte auf ; fpconv8: rcall fpconv8m ; Multipliziere mit 502 rcall fpconv8r ; Runden und Division mit 256 rcall fpconv8a ; Umwandlung in ASCII-String ldi rmp,'.' ; Setze Dezimalpunkt mov R6,rmp ret ; Alles fertig ; ; Unterprogramm Multiplikation mit 502 ; ; Startbedingung: ; +--+ ; |R1| Eingabezahl, im Beispiel $FF ; |FF| ; +--+ ; +--+--+--+ ; |R4|R3|R2| Multiplikant 502 = $00 01 F6 ; |00|01|F6| ; +--+--+--+ ; +--+--+--+ ; |R7|R6|R5| Resultat, im Beispiel 128.010 ; |01|F4|0A| ; +--+--+--+ ; fpconv8m: clr R4 ; Setze den Multiplikant auf 502 ldi rmp,$01 mov R3,rmp ldi rmp,$F6 mov R2,rmp clr R7 ; leere Ergebnisregister clr R6 clr R5 fpconv8m1: or r1,R1 ; Pruefe ob noch Bits 1 sind brne fpconv8m2 ; Noch Einsen, mach weiter ret ; fertig, kehre zurueck fpconv8m2: lsr R1 ; Schiebe Zahl nach rechts (teilen durch 2) brcc fpconv8m3 ; Wenn das niedrigste Bit eine 0 war, ; dann ueberspringe den Additionsschritt add R5,R2 ; Addiere die Zahl in R4:R3:R2 zum Ergebnis adc R6,R3 adc R7,R4 fpconv8m3: lsl R2 ; Multipliziere R4:R3:R2 mit 2 rol R3 rol R4 rjmp fpconv8m1 ; Wiederhole fuer das naechste Bit ; ; Runde die Zahl in R7:R6 mit dem Wert von Bit 7 von R5 ; fpconv8r: clr rmp ; Null nach rmp lsl R5 ; Rotiere Bit 7 ins Carry adc R6,rmp ; Addiere LSB mit Uebertrag adc R7,rmp ; Addiere MSB mit Uebertrag mov R2,R7 ; Kopiere den Wert nach R2:R1 (durch 256 teilen) mov R1,R6 ret ; ; Wandle das Wort in R2:R1 in einen ASCII-Text in R5:R6:R7:R8 ; ; +---+---+ ; + R2| R1| Eingangswert 0..500 ; +---+---+ ; +---+---+ ; | R4| R3| Dezimalteiler ; +---+---+ ; +---+---+---+---+ ; | R5| R6| R7| R8| Ergebnistext (fuer Eingangswert 500) ; |'5'|'.'|'0'|'0'| ; +---+---+---+---+ ; fpconv8a: clr R4 ; Setze Dezimalteiler auf 100 ldi rmp,100 mov R3,rmp rcall fpconv8d ; Hole ASCII-Ziffer durch wiederholtes Abziehen mov R5,rmp ; Setze Hunderter Zeichen ldi rmp,10 ; Setze Dezimalteiler auf 10 mov R3,rmp rcall fpconv8d ; Hole die naechste Ziffer mov R7,rmp ldi rmp,'0' ; Wandle Rest in ASCII-Ziffer um add rmp,R1 mov R8,rmp ; Setze Einer Zeichen ret ; ; Wandle Binaerwort in R2:R1 in eine Dezimalziffer durch fortgesetztes ; Abziehen des Dezimalteilers in R4:R3 (100, 10) ; fpconv8d: ldi rmp,'0' ; Beginne mit ASCII-0 fpconv8d1: cp R1,R3 ; Vergleiche Wort mit Teiler cpc R2,R4 brcc fpconv8d2 ; Carry nicht gesetzt, subtrahiere Teiler ret ; fertig fpconv8d2: sub R1,R3 ; Subtrahiere Teilerwert sbc R2,R4 inc rmp ; Ziffer um eins erhoehen rjmp fpconv8d1 ; und noch einmal von vorne ; ; Ende der Fliesskomma-Umwandlungsroutinen ; ; ; Ende des Umwandlungstestprogramms ;