Pfad: Home => AVR-Überblick => Anwendungen => Signal generator => Quellcode

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