![]() |
Tutorial zum Erlernen der AVR Assembler-Sprache von AVR-Einchip-Prozessoren AT90Sxxxx von ATMEL anhand praktischer Beispiele. Einfacher 8-Bit-Digital-zu-Analog-Wandler mit einem R/2R-Netzwerk |
R2R-Netzwerk Berechnungsprogramm, (C)2004 info !at! avr-asm-tutorial.net ------------------------------------------------------------------------ Bits Aufloesung: nr=8[bits], Bits=00000000 Spannungen: ub=5.000[V], ul=0.000[V], uh=5.000[V] Widerstaende: R1= 51k0, R2=100k0 Eingabekombinationen und Ausgabespannungen 00000000: 0.000[V] 00000001: 0.019[V] (Delta= 18.69[mV]) 00000010: 0.038[V] (Delta= 19.06[mV]) 00000011: 0.056[V] (Delta= 18.69[mV]) 00000100: 0.076[V] (Delta= 19.62[mV]) 00000101: 0.095[V] (Delta= 18.69[mV]) 00000110: 0.114[V] (Delta= 19.06[mV]) 00000111: 0.132[V] (Delta= 18.69[mV]) 00001000: 0.153[V] (Delta= 20.67[mV]) 00001001: 0.172[V] (Delta= 18.69[mV]) 00001010: 0.191[V] (Delta= 19.06[mV]) 00001011: 0.210[V] (Delta= 18.69[mV]) 00001100: 0.229[V] (Delta= 19.62[mV]) 00001101: 0.248[V] (Delta= 18.69[mV]) 00001110: 0.267[V] (Delta= 19.06[mV]) 00001111: 0.286[V] (Delta= 18.69[mV]) 00010000: 0.308[V] (Delta= 22.72[mV]) 00010001: 0.327[V] (Delta= 18.69[mV]) 00010010: 0.346[V] (Delta= 19.06[mV]) 00010011: 0.365[V] (Delta= 18.69[mV]) 00010100: 0.384[V] (Delta= 19.62[mV]) 00010101: 0.403[V] (Delta= 18.69[mV]) 00010110: 0.422[V] (Delta= 19.06[mV]) 00010111: 0.441[V] (Delta= 18.69[mV]) 00011000: 0.462[V] (Delta= 20.67[mV]) 00011001: 0.480[V] (Delta= 18.69[mV]) 00011010: 0.499[V] (Delta= 19.06[mV]) 00011011: 0.518[V] (Delta= 18.69[mV]) 00011100: 0.538[V] (Delta= 19.62[mV]) 00011101: 0.556[V] (Delta= 18.69[mV]) 00011110: 0.575[V] (Delta= 19.06[mV]) 00011111: 0.594[V] (Delta= 18.69[mV]) 00100000: 0.621[V] (Delta= 26.83[mV]) 00100001: 0.640[V] (Delta= 18.69[mV]) 00100010: 0.659[V] (Delta= 19.06[mV]) 00100011: 0.677[V] (Delta= 18.69[mV]) 00100100: 0.697[V] (Delta= 19.62[mV]) 00100101: 0.716[V] (Delta= 18.69[mV]) 00100110: 0.735[V] (Delta= 19.06[mV]) 00100111: 0.753[V] (Delta= 18.69[mV]) 00101000: 0.774[V] (Delta= 20.67[mV]) 00101001: 0.793[V] (Delta= 18.69[mV]) 00101010: 0.812[V] (Delta= 19.06[mV]) 00101011: 0.830[V] (Delta= 18.69[mV]) 00101100: 0.850[V] (Delta= 19.62[mV]) 00101101: 0.869[V] (Delta= 18.69[mV]) 00101110: 0.888[V] (Delta= 19.06[mV]) 00101111: 0.906[V] (Delta= 18.69[mV]) 00110000: 0.929[V] (Delta= 22.72[mV]) ... 01111110: 2.446[V] (Delta= 19.06[mV]) 01111111: 2.465[V] (Delta= 18.69[mV]) 10000000: 2.517[V] (Delta= 51.72[mV]) 10000001: 2.535[V] (Delta= 18.69[mV]) 10000010: 2.554[V] (Delta= 19.06[mV]) 10000011: 2.573[V] (Delta= 18.69[mV]) ...Man beachte den Sprung, wenn Bit 7 High wird! Die Spannung springt dann um mehr als zwei Digits. Das ist für ein 8-Bit-Netzwerk zu groß, aber akzeptabel für ein 4-Bit-Netzwerk.
; *************************************************************
; * R/2R-Netzwerk erzeugt eine Saegezahnspannung ueber Port D *
; * (C)2005 by info!at!avr-asm-tutorial.net *
; *************************************************************
;
.INCLUDE "8515def.inc"
;
; Register Definitionen
;
.DEF rmp = R16 ; Multipurpose Register
;
ldi rmp,0xFF; Alle Pins von Port D als Ausgang
out DDRD,rmp ; in Datenrichtungsregister
sawtooth:
out PORTD,rmp ; Inhalt von rmp an Port D ausgeben
inc rmp ; erhöhen
rjmp sawtooth ; und weiter fuer immer
; *****************************************************
; * R/2R-Netzwerk als Saegezahn ueber Port D *
; * (C)2005 by info!at!avr-asm-tutorial.net *
; *****************************************************
;
.INCLUDE "8515def.inc"
;
; Register Definitionen
;
.DEF rmp = R16 ; Multipurpose Register
;
ldi rmp,0xFF; Alle Pins von Port D auf Ausgang
out DDRD,rmp
sawtooth:
out PORTD,rmp ; Inhalt des Registers an Port ausgeben
inc rmp ; um Eins erhoehen
andi rmp,0x7F ; Bit 7 auf Null setzen
rjmp sawtooth ; und so weiter
; ***********************************************************
; * R/2R-Netzwerk produziert eine Dreieckspannung an Port D *
; * (C)2005 by info!at!avr-asm-tutorial.net *
; ***********************************************************
;
.INCLUDE "8515def.inc"
;
; Register Definitionen
;
.DEF rmp = R16 ; Multipurpose Register
.DEF rdl = R17 ; Verzoegerungszaehler
;
; Konstanten
;
.EQU maxAmp = 127 ; Maximum Amplitude
.EQU delay = 1 ; Verzoegerung, hoehere Werte machen niedrigere Frequenz
;
ldi rmp,0xFF; Alle Port-D-Pins als Ausgang
out DDRD,rmp
triangle:
clr rmp ; bei Null anfangen
loopup:
out PORTD,rmp ; an Port ausgeben
ldi rdl,delay ; Verzoegerung einstellen
delayup:
dec rdl ; Zaehler herunterzaehlen
brne delayup ; weiter mit zaehlen
inc rmp ; naechstgroesserer Wert
cpi rmp,maxAmp ; mit maximaler Amplitude vergleichen
brcs loopup ; wenn noch nicht erreicht, weiter hoch
loopdwn:
out PORTD,rmp ; Ausgabe rueckwaerts
ldi rdl,delay ; wieder verzoegern
delaydwn:
dec rdl ; herunterzaehlen
brne delaydwn ; weiter verzoegern
dec rmp ; naechstniedrigeren Wert einstellen
brne loopdwn ; wenn noch nicht Null, dann weiter
rjmp triangle ; und wieder von vorne fuer immer
; **********************************************************
; * Produziert einen Sinus an einem R/2R-Netzwerk an PORTD *
; * (C)2005 by avr-asm-tutorial.net *
; **********************************************************
;
.INCLUDE "8515def.inc"
;
; Register Definition
;
.DEF rmp = R16 ; Multipurpose Register
;
; Beginn des Programms
;
ldi rmp,0xFF ; Alle Pins von Port D sind Ausgang
out DDRD,rmp
ldi ZH,HIGH(2*SineTable) ; Z auf Tabelle im Flash
ldi ZL,LOW(2*SineTable)
clr rmp
loop1:
nop
nop
nop
loop2:
lpm ; Lesen aus der Tabelle
out PORTD,R0 ; Tabellenwert an Port D
adiw ZL,1 ; naechster Tabellenwert
dec rmp ; Ende der Tabelle erreicht?
brne loop1 ; nein
ldi ZH,HIGH(2*SineTable) ; Z wieder auf Tabellenanfang
ldi ZL,LOW(2*SineTable)
rjmp loop2 ; weiter so
;
; Ende Instruktionen
;
; Include der Sinustabelle
;
.INCLUDE "sine8_25.txt"
;
; Ende Programm
;
;
; Sinustabelle fuer 8 Bits D/A
; Tabellenlaenge = 256 Werte
; VCC=5.000V, uLow=0.000V, uHigh=2.500V
; (mit sinewave.pas erzeugt)
;
Sinetable:
.DB 64,65,67,68,70,72,73,75
.DB 76,78,79,81,82,84,85,87
.DB 88,90,91,92,94,95,97,98
.DB 99,100,102,103,104,105,107,108
.DB 109,110,111,112,113,114,115,116
.DB 117,118,118,119,120,121,121,122
.DB 123,123,124,124,125,125,126,126
.DB 126,127,127,127,127,127,127,127
.DB 128,127,127,127,127,127,127,127
.DB 126,126,126,125,125,124,124,123
.DB 123,122,121,121,120,119,118,118
.DB 117,116,115,114,113,112,111,110
.DB 109,108,107,105,104,103,102,100
.DB 99,98,97,95,94,92,91,90
.DB 88,87,85,84,82,81,79,78
.DB 76,75,73,72,70,68,67,65
.DB 64,62,61,59,58,56,54,53
.DB 51,50,48,47,45,44,42,41
.DB 39,38,36,35,34,32,31,30
.DB 28,27,26,25,23,22,21,20
.DB 19,18,17,15,14,13,13,12
.DB 11,10,9,8,8,7,6,5
.DB 5,4,4,3,3,2,2,2
.DB 1,1,1,0,0,0,0,0
.DB 0,0,0,0,0,0,1,1
.DB 1,2,2,2,3,3,4,4
.DB 5,5,6,7,8,8,9,10
.DB 11,12,13,13,14,15,17,18
.DB 19,20,21,22,23,25,26,27
.DB 28,30,31,32,34,35,36,38
.DB 39,41,42,44,45,47,48,50
.DB 51,53,54,56,58,59,61,62
; ******************************************************************
; * Musik mit dem STK200 und einem R/2R-Netzwerk *
; * PortD hat acht Tasten (active low), PortB generiert die Ausgabe*
; * fuer das R/2R-Netzwerk, spielt Noten wenn die Tasten betaetigt *
; * werden, fuer ATMEL AT90S8515 bei 4 MHz *
; * (C)2005 by info!at!avr-asm-tutorial.net *
; ******************************************************************
;
.NOLIST
.INCLUDE "8515def.inc"
.LIST
;
; Konstanten
;
.EQU clock = 4000000 ; Processortakt
.EQU cNSine = 32 ; Tabellelaenge Sinustabelle
;
.DEF rLen = R1 ; Register fuer Dauer der Ausgabe
.DEF rCnt = R2 ; Zaehler fuer die Verzoegerung
.DEF rmp = R16 ; Multipurpose Register
.DEF rTab = R17 ; Zaehler fuer Tabellenlaenge
;
ldi rmp,0xFF ; Alle Bits von Port B Ausgang => R/2R Netzwerk
out DDRB,rmp ; an Datenrichtungsregister
wtloop:
in rmp,PIND ; lese die Tasten
cpi rmp,0xFF ; alle Tasten inaktiv?
breq wtloop ; je, weiter warten bis aktiv
ldi ZH,HIGH(2*MusicTable) ; Z auf Tonhoehentabelle setzen
ldi ZL,LOW(2*MusicTable)
tabloop:
rol rmp ; Rotiere naechstes Bit in Carry
brcc tabfound ; gedrueckte Taste gefunden
adiw ZL,1 ; Z auf nachsten Tabellenwert
rjmp tabloop ; Pruefe naechstes Bit
tabfound:
lpm ; Lese Tonhoehenwert aus Tabelle in R0
mov rlen,R0 ; Kopiere in delay, R0 wird anderweitig benutzt
;
; Spiele einen Ton, bis die Tasten alle inaktiv sind
;
startsine:
ldi ZH,HIGH(2*SineTable) ; Z auf die Sinustabelle setzen
ldi ZL,LOW(2*SineTable)
ldi rTab,cNSine ; Laenge der Sinustabelle
;
; Der folgende Code ist timing-maessig optimiert, damit alle
; Teilschritte gleich lang dauern, die benoetigten Taktzyklen
; sind angegeben, wenn die Instruktion abgearbeitet ist,
; Taktzyklen waehrend Tabellenlesen / Taktzyklen am Tabellenende
;
loopsine:
in rmp,PIND ; 1/- Pruefe ob Tasten noch aktiv ist
cpi rmp,0xFF ; 2/-
breq wtloop ; 3/- Taste nicht mehr aktiv, gehe zurueck
nop ; 4/- verzoegern fuer Synchronisation
loopnext:
lpm ; 7/3 Lese Sinustabelle in R0
out PORTB,R0 ; 8/4 Kopiere zum R/2R-Netzwerk
mov rCnt,rLen ; 9/5 Setze Verzoegerungszaehler
; Verzoegerungsschleife, braucht 3*rLen-1 Taktzyklen
loopdelay:
dec rCnt ; (1) naechster Zaehlerwert
brne loopdelay ; (2/1) noch nicht Null
; 3*rLen+8/3*rLen+4 am Ende der Verzoegerung
adiw ZL,1 ; 3*rLen+10/3*rLen+6 naechster Tabellenwert
dec rTab ; 3*rLen+11/3*rLen+7 Anzahl Tabellenwerte
brne loopsine ; 3*rLen+13/3*rLen+8 naechster Tabellenwert
ldi ZH,HIGH(2*SineTable) ; -/3*rLen+9 Neuanfang Tabelle
ldi ZL,LOW(2*SineTable) ; -/3*rLen+10
ldi rTab,cNSine ; -/3*rLen+11 Laenge der Sinustabelle
rjmp loopnext ; -/3*rLen+13 Neustart (ohne Tasten!)
;
; Tabelle fuer Verzoegerung zur Tonerzeugung der 8 Frequenzen
;
; Frequenz = clock / Tabellenlaenge / ( 3 * rLen + 13 )
; rLen = ( clock /Tabellenlaenge / Frequenz - 13 ) / 3
;
MusicTable:
; f=261.6 293.7 329.6 349.2 392.0 440.0 493.9 523.2 (Sollwert)
.DB 155, 138, 122, 115, 102, 90, 80, 75
; f=261.5 292.7 329.8 349.2 391.9 441.7 494.1 525.2 (Istwert)
; Unterschiede zwischen Soll und Ist wegen Rundung und Aufloesung)
;
; Sinustabelle fuer 8 Bits D/A
; Tabellenlaenge = 32 Werte
; VCC=5.000V, uLow=0.000V, uHigh=2.500V
; (mit sinewave.pas erzeugt)
;
Sinetable:
.DB 64,76,88,99,109,117,123,126
.DB 128,126,123,117,109,99,88,76
.DB 64,51,39,28,19,11,5,1
.DB 0,1,5,11,19,28,39,51
;
; Ende des Programms
;