Pfad:
Home =>
AVR-Überblick =>
Anwendungen =>
Signal generator => Quellcode
(This page in English:
)
Quellcode für den Pulsweiten-Generator
; *****************************************************************
; * Pulsweiten-Generator, programmierbar ueber die SIO 9k6 8N1 *
; * Eingabe der Pulslaenge und der aktiven Dauer in µs per *
; * Terminal. Ausgabe der Pulse an Port D, Bit 2 des STK 200 *
; * Geschrieben fuer das STK200 board und AT90S8515, anpassbar *
; * an AT90S2313 oder aehnliche Chips mit SIO *
; * (C)2000 by info!at!avr-asm-tutorial.net, Bugs sind willkommen *
; *****************************************************************
;
.NOLIST
.INCLUDE "8515def.inc"
.LIST
;
; Used registers
;
.DEF rlpm=R0; Benutzt fuer LPM Befehle
.DEF rchar=R1; Zeichenpuffer SIO Kommunikation
.DEF rilo=R2; Low byte bei Zahleneingabe, Zaehler fuer aktiv high
.DEF rihi=R3; High byte bei Zahleneingabe, Zaehler fuer aktiv high
.DEF rjlo=R4; Low byte bei Multiplikation/inaktive phase
.DEF rjhi=R5; High byte bei Multiplikation/inactive phase
;
.DEF rmpr=R16; Vielzweckregister, byte/word
.DEF rcl=R18; Zykluszeit, word
.DEF rch=R19
.DEF ral=R20; Zeitraum fuer aktiv high, word
.DEF rah=R21
; X=R26/27: Zaehler fuer for Aktiv high
; Y=R28/29: Zaehler fuer inaktiv low
; Z=R30/31: Pointer fuer Lesen aus dem Programmspeicher
;
; Konstanten
;
.EQU OutPort=PortD; Ausgabeport fuer die Signale
.EQU DataDir=DDRD; Datenrichtungsregister des aktiven Ports
.EQU ActivePin=2; Gewuenschter Ausgabeanschluss
.EQU ModeControl=0b00000100; Mode Kontrollwort fuer Port
.EQU cDefCyc=25000; Default Wert fuer Zyklusdauer in us
.EQU cDefAct=2000; Default Wert fuer Aktiv High in us
.EQU fq=4000000; Quarzfrequenz auf dem Board in Hz
.EQU baud=9600; Baudrate fuer SIO Kommunikation
.EQU bddiv=(fq/(16*baud))-1; Baudratenteiler
.EQU ccr=0x0D; Carriage return character
.EQU clf=0x0A; Line feed character
.EQU cnul=0x00; NUL character
.EQU cesc=0x1B; ESCAPE character
.EQU cbel=0x07; Bell character
;
; Makro Pruefe Eingabewert auf Default und kopiere in Register
;
.MACRO Default
MOV @0,rilo; Kopiere den Eingabewert in das Registerpaar
MOV @1,rihi
MOV rmpr,rilo; Teste ob input Null ist
OR rmpr,rihi
BRNE nodef; Nich Null, setze Default nicht
LDI @0,LOW(@2); Setze default Wert
LDI @1,HIGH(@2)
nodef:
.ENDM
;
; Code segment startet hier
;
.CSEG
;
; Reset- und Interrupt-Vektoren, werden hier nicht benutzt
;
RJMP Start; Reset vector
RETI; Ext Int 0
RETI; Ext Int 1
RETI; Timer 1 Capt
RETI; Timer 1 CompA
RETI; Timer 1 CompB
RETI; Timer 1 OVF
RETI; Timer 0 OVF
RETI; Serial Transfer Complete
RETI; UART Rx Complete
RETI; UART Data register empty
RETI; UART Tx Complete
RETI; Analog Comparator
;
; Subroutine fuer String aussenden
;
TxStr:
SBIS USR,UDRE; Warte bis Sendepuffer leer ist
RJMP TxStr
LPM; Lese naechsten Buchstaben aus Programmspeicher
AND rlpm,rlpm; NUL = Ende des Strings
BRNE txsend
RET
txsend:
LPM; Lese den Buchstaben noch einmal
OUT UDR,rlpm; Sende Buchstaben
ADIW ZL,1; Zeige auf naechstes Byte im Speicher
RJMP TxStr
;
; Subroutine fuer den Zahlenempfang (word, 0..65535)
;
RxWord:
CLR rilo; Leere Puffer
CLR rihi
rxw1:
SBIS USR,RXC; Teste ob Buchstabe empfangen
RJMP rxw1; Kein Buchstabe vorhanden, wiederhole
IN rmpr,UDR; Hole das Zeichen von der SIO
OUT UDR,rmpr; Echo zurueck an das Terminal
CPI rmpr,ccr; Return char = Ende der Eingabe
BREQ rxwx
SUBI rmpr,'0'; Subtrahiere 48
BRCS rxwerr; Keine Dezimalzahl, zurueck mit Carry gesetzt
CPI rmpr,10; Ziffer >9?
BRCS rxwok; keine Dezimalzahl
rxwerr:
LDI ZL,LOW(2*ErrorStr); Sende Error String
LDI ZH,HIGH(2*ErrorStr)
RCALL TxStr
SEC; Setze Carry, keine zulaessige Zahl
RET
rxwok:
MOV rjlo,rilo; Kopie des word fuer Multiplikaton
MOV rjhi,rihi
LSL rilo; Multipliziere mit 2 = 2*
ROL rihi
BRCS rxwerr; Ueberlauf, zurueck mit Carry
LSL rilo; Multipliziere noch mal mit 2, = 4*
ROL rihi
BRCS rxwerr; Ueberlauf
ADD rilo,rjlo; Addiere Kopie, = 5*
ADC rihi,rjhi
BRCS rxwerr; Ueberlauf
LSL rilo; Multipliziere mit 2, = 10*
ROL rihi
BRCS rxwerr; Ueberlauf
CLR rjhi; Addiere die Dezimalzahl
ADD rilo,rmpr
ADC rihi,rjhi
BRCS rxwerr; Ueberlauf
RJMP rxw1; Warte auf naechstes Zeichen
rxwx:
SBIS USR,UDRE; Warte bis Sendepuffer leer
RJMP rxwx
LDI rmpr,clf; Sende zusaetzlichen Zeilenvorschub
OUT UDR,rmpr
CLC; Clear carry, keine Fehler
RET
;
; Start des Programmes
;
Start:
;
; Benutze den Stack fuer Unterprogramme
;
LDI rmpr,HIGH(RAMEND); Stack auf hoechste RAM Adresse
OUT SPH,rmpr
LDI rmpr,LOW(RAMEND)
OUT SPL,rmpr
;
; Initiieren Port output
;
LDI rmpr,ModeControl; Setze output Modus
OUT DataDir,rmpr; an Datenrichtungsregister
;
; Initiiere SIO Kommunikation
;
LDI rmpr,bddiv; Setze Baudrate
OUT UBRR,rmpr
LDI rmpr,0b00011000; Enable von TX und RX
OUT UCR,rmpr
;
; Sende Hello Sequenz
;
hello:
LDI ZH,HIGH(2*InitStr); Point Z auf String
LDI ZL,LOW(2*InitStr)
RCALL TxStr
;
; Hole Wert fuer die Gesamtdauer
;
getcycle:
LDI ZH,HIGH(2*CycleStr); Point Z auf String
LDI ZL,LOW(2*CycleStr)
RCALL TxStr
RCALL RxWord
BRCS getcycle; Wiederhole, wenn Fehler
Default rcl,rch,cDefCyc
;
; Hole Wert fuer die aktive Dauer
;
getactive:
LDI ZH,HIGH(2*ActiveStr); Point Z auf String
LDI ZL,LOW(2*ActiveStr)
RCALL TxStr
RCALL RxWord
BRCS getactive; Wiederhole, wenn Fehler
Default ral,rah,cDefAct
;
; Berechne Zaehlerwert fuer die aktive Dauer
;
MOV XL,ral; Berechne aktive Zeit
MOV XH,rah
SBIW XL,5; mindestens 4 Zyklen
BRCS getcycle; ungueltige aktive Dauer
ADIW XL,1; Mindestens ein Zyklus erforderlich
MOV rilo,XL
MOV rihi,XH
;
; Berechne Dauer der inaktiven Zeit
;
MOV YL,rcl; Berechne inaktive Zeit
MOV YH,rch
SUB YL,XL; Subtrahiere Aktive Zeit
SBC YH,XH
BRCS getcycle; Aktive Zeit kuerzer als Gesamtzeit
SBIW YL,5; Subtrahiere Schleifenverzoegerung
BRCS getcycle; Weniger als drei Schleifendurchgaenge geht nicht
ADIW YL,1; minimum 1 loop
MOV rjlo,YL
MOV rjhi,YH
LDI ZH,HIGH(2*WaitStr); Gib ok-String aus
LDI ZL,LOW(2*WaitStr)
RCALL TxStr
;
; Zaehlen beginnt hier, pruefe ob Zeichen auf SIO
;
ctloop:
SBI OutPort,ActivePin; Starte aktive Phase
ActLoop:
SBIW XL,1; 0.5 µs
BRNE ActLoop; 0.5 µs
SBIC USR,RXC; Teste ob SIO RX leer
RJMP getcycle; Hole Eingabe von SIO
CBI Outport,ActivePin; Starte inaktive phase
InactLoop:
SBIW YL,1; 0.5 µs
BRNE InactLoop; 0.5 µs
MOV XL,rilo; Setze Zaehlerstand neu
MOV XH,rihi
MOV YL,rjlo
MOV YH,rjhi
NOP
NOP
RJMP ctloop; starte von vorne
;
; Text Strings fuer zum Senden, ANSI kodiert!
;
ErrorStr:
.DB cbel,ccr,clf,cesc,'[','3','3','m'
.DB "Fehler bei der Eingabe! "
.DB ccr,clf,cnul,cnul
ActiveStr:
.DB cesc,'[','3','2','m','*'
.DB "Gib inaktive Zeit ein (default = 2,000):"
.DB cesc,'[','3','1','m',' '
.DB cnul,cnul
CycleStr:
.DB cesc,'[','3','2','m','*'
.DB "Gib Zykluszeit ein (default = 25,000):"
.DB cesc,'[','3','1','m',' '
.DB cnul,cnul
WaitStr:
.DB cesc,'[','3','5','m','B'
.DB "etrieb auf dem Port."
.DB ccr,clf,cesc,'[','3','7','m','E'
.DB "ingabe einer neuen Zyklusdauer stoppt den Generator."
.DB ccr,clf,cnul,cnul
InitStr:
.DB cesc,'[','0',59,'1',59,'3','7',59,'4','0','m'; Setze Screenfarben
.DB cesc,'[','H',cesc,'[','J' ; ANSI Clear screen
.DB ccr,clf,ccr,clf
.DB "Hallo Welt! "
.DB ccr,clf
.DB "Hier ist der Pulsweitengenerator bei der Arbeit!"
.DB ccr,clf
.DB "Alle Zeiten in Mikrosekunden, im Bereich 5..65535."
.DB ccr,clf
.DB "Neuer Wert unterbricht den Betrieb bis komplett eingegeben"
.DB ccr,clf,cnul,cnul
;
Check:
.DW check
;
; Ende des code segments
;
©2002 by http://www.avr-asm-tutorial.net