Path: Home =>
AVR-Overview =>
Applications =>
Signal generator => Source code
; **************************************************************
; * Pulse Width Generator, programmable via Serial I/O 9k6 8N1 *
; * Input cycle length in µs first, then active cycle in µs *
; * Default cycle length is 25,000 µs, default active cycle is *
; * 2,000 µs. Output is on Port D, Bit 2 *
; * Written for the STK200 board, AT90S8515 *
; * (C)2000 by info!at!avr-asm-tutorial, error reports welcome *
; **************************************************************
;
.NOLIST
.INCLUDE "8515def.inc"
.LIST
;
; Used registers
;
.DEF rlpm=R0; Used for LPM commands
.DEF rchar=R1; Character buffer for SIO communications
.DEF rilo=R2; Low byte word input/active loop
.DEF rihi=R3; High byte word input/active loop
.DEF rjlo=R4; Low byte for multiplication/inactive loop
.DEF rjhi=R5; High byte for multiplication/inactive loop
;
.DEF rmpr=R16; A multipurpose register, byte/word
.DEF rcl=R18; Desired cycle time, word
.DEF rch=R19
.DEF ral=R20; Desired active time, word
.DEF rah=R21
; X=R26/27: Counter for Active time
; Y=R28/29: Counter for inactive time
; Z=R30/31: Pointer for program memory read operation
;
; Constants
;
.EQU OutPort=PortD; Desired output port
.EQU DataDir=DDRD; Data direction register of that port
.EQU ActivePin=2; Desired output pin
.EQU ModeControl=0b00000100; Control word for port
.EQU cDefCyc=25000; Default cycle length in µs
.EQU cDefAct=2000; Default active high length in µs
.EQU fq=4000000; Xtal frequency on board in Hz
.EQU baud=9600; Baudrate for SIO communication
.EQU bddiv=(fq/(16*baud))-1; Baudrate divider
.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
;
; Macro Check input value for default and transfer to desired register
;
.MACRO Default
MOV @0,rilo; Copy result to desired register pair
MOV @1,rihi
MOV rmpr,rilo; Test if input is zero
OR rmpr,rihi
BRNE nodef; Not zero, don't set default value
LDI @0,LOW(@2); Set to default value
LDI @1,HIGH(@2)
nodef:
.ENDM
;
; Code segment start
;
.CSEG
;
; Reset- and interrupt-vectors, interrupts not used here
;
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 for string transmit
;
TxStr:
SBIS USR,UDRE; Wait until transmit buffer empty
RJMP TxStr
LPM; Read next character from program memory
AND rlpm,rlpm; NUL = end of string
BRNE txsend
RET
txsend:
LPM; Read the same char again
OUT UDR,rlpm; Tx character read
ADIW ZL,1; point to next char im memory
RJMP TxStr
;
; Subroutine for receiving a number (word, 0..65535)
;
RxWord:
CLR rilo; Set buffer to zero
CLR rihi
rxw1:
SBIS USR,RXC; Test if rx buffer empty
RJMP rxw1; receive char not available, repeat
IN rmpr,UDR; Get the char from the SIO
OUT UDR,rmpr; Echo this character
CPI rmpr,ccr; Return char = end of input
BREQ rxwx
SUBI rmpr,'0'; Subtract 48
BRCS rxwerr; not a decimal number, return wit carry set
CPI rmpr,10; number >9?
BRCS rxwok; legal decimal number
rxwerr:
LDI ZL,LOW(2*ErrorStr); Echo error string
LDI ZH,HIGH(2*ErrorStr)
RCALL TxStr
SEC; Set carry flag, not a legal number
RET
rxwok:
MOV rjlo,rilo; Copy word for multiplicaton
MOV rjhi,rihi
LSL rilo; Multiply with 2 = 2*
ROL rihi
BRCS rxwerr; Overflow, return with carry set
LSL rilo; Multiply again by 2, = 4*
ROL rihi
BRCS rxwerr; Overflow, return with carry set
ADD rilo,rjlo; Add copy, = 5*
ADC rihi,rjhi
BRCS rxwerr; Overflow, return with carry set
LSL rilo; Multiply by 2, = 10*
ROL rihi
BRCS rxwerr; Overflow, return with carry set
CLR rjhi; Add the decimal number
ADD rilo,rmpr
ADC rihi,rjhi
BRCS rxwerr; Overflow, return with carry set
RJMP rxw1; Get next character
rxwx:
SBIS USR,UDRE; Wait until transmit buffer empty
RJMP rxwx
LDI rmpr,clf; Transmit additional line feed char
OUT UDR,rmpr
CLC; Clear carry, no errors
RET
;
; Start of program
;
Start:
;
; Setup the stack for the use of subroutines
;
LDI rmpr,HIGH(RAMEND); Stack setting to highest RAM adress
OUT SPH,rmpr
LDI rmpr,LOW(RAMEND)
OUT SPL,rmpr
;
; Initiate Port D to output on Bit 2
;
LDI rmpr,ModeControl; Set output pin
OUT DataDir,rmpr; to Data Direction register
;
; Initiate SIO communication
;
LDI rmpr,bddiv; Set baud rate
OUT UBRR,rmpr
LDI rmpr,0b00011000; Enable TX and RX
OUT UCR,rmpr
;
; Transmit the hello sequence
;
hello:
LDI ZH,HIGH(2*InitStr); Point Z to string
LDI ZL,LOW(2*InitStr)
RCALL TxStr
;
; Get value for total cycle length
;
getcycle:
LDI ZH,HIGH(2*CycleStr); Point Z to string
LDI ZL,LOW(2*CycleStr)
RCALL TxStr
RCALL RxWord
BRCS getcycle; Repeat if error
Default rcl,rch,cDefCyc
;
; Get value for active cycle length
;
getactive:
LDI ZH,HIGH(2*ActiveStr); Point Z to string
LDI ZL,LOW(2*ActiveStr)
RCALL TxStr
RCALL RxWord
BRCS getactive; Repeat if error
Default ral,rah,cDefAct
;
; Calculate counter value for active time
;
MOV XL,ral; Calculate active time
MOV XH,rah
SBIW XL,5; at least 4 cycles
BRCS getcycle; illegal active time
ADIW XL,1; At least one cycle required
MOV rilo,XL
MOV rihi,XH
;
; Calculate counter value for inactive time
;
MOV YL,rcl; Calculate inactive time
MOV YH,rch
SUB YL,XL; Subtract active time
SBC YH,XH
BRCS getcycle; Active time longer than cycle time
SBIW YL,5; Subtract loop delays
BRCS getcycle; Less than 3 loop cycles are illegal
ADIW YL,1; minimum 1 loop
MOV rjlo,YL
MOV rjhi,YH
LDI ZH,HIGH(2*WaitStr); Output operating string
LDI ZL,LOW(2*WaitStr)
RCALL TxStr
;
; Counting loop starts here, check char at SIO available?
;
ctloop:
SBI OutPort,ActivePin; Start active phase
ActLoop:
SBIW XL,1; 0.5 µs
BRNE ActLoop; 0.5 µs
SBIC USR,RXC; Test if rx buffer empty
RJMP getcycle; get new cycle time
CBI Outport,ActivePin; Start Inactive phase
InactLoop:
SBIW YL,1; 0.5 µs
BRNE InactLoop; 0.5 µs
MOV XL,rilo; Refresh counters
MOV XH,rihi
MOV YL,rjlo
MOV YH,rjhi
NOP
NOP
RJMP ctloop; start a new cycle
;
; Text strings for transmit, ANSI screen encoded!
;
ErrorStr:
.DB cbel,ccr,clf,cesc,'[','3','3','m'
.DB "Error in input! Repeat input! "
.DB ccr,clf,cnul,cnul
ActiveStr:
.DB cesc,'[','3','2','m','*'
.DB "Input active time (default = 2,000):"
.DB cesc,'[','3','1','m',' '
.DB cnul,cnul
CycleStr:
.DB cesc,'[','3','2','m','*'
.DB "Input cycle time (default = 25,000):"
.DB cesc,'[','3','1','m',' '
.DB cnul,cnul
WaitStr:
.DB cesc,'[','3','5','m','C'
.DB "ontinued operation. "
.DB ccr,clf,cesc,'[','3','7','m','E'
.DB "nter new cycle length to stop and restart generator."
.DB ccr,clf,cnul,cnul
InitStr:
.DB cesc,'[','0',59,'1',59,'3','7',59,'4','0','m'; Set screen colours
.DB cesc,'[','H',cesc,'[','J' ; ANSI Clear screen
.DB ccr,clf,ccr,clf
.DB "Hello world!"
.DB ccr,clf
.DB "This is the pulse width generator at work."
.DB ccr,clf
.DB "All times in micro-seconds, accepted range 5..65535."
.DB ccr,clf
.DB "New value stops operation until all input is completed. "
.DB ccr,clf,cnul,cnul
;
Check:
.DW check
;
; End of code segment
;
©2002 by http://www.avr-asm-tutorial.net