; ************************************************************** ; * 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@avr-asm-tutorial.net, Bugs sind willkommen * ; ************************************************************** ; .NOLIST .INCLUDE "C:\avrtools\appnotes\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 ;