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 *
; ************************************************************** 
; 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) 
; Code segment start 
; 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 
   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 
   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) 
   CLR   rilo; Set buffer to zero 
   CLR   rihi 
   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 
   LDI   ZL,LOW(2*ErrorStr); Echo error string 
   LDI   ZH,HIGH(2*ErrorStr)
   RCALL   TxStr 
   SEC; Set carry flag, not a legal number 
   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 
   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 
; Start of program 
; 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 
   LDI   ZH,HIGH(2*InitStr); Point Z to string 
   LDI   ZL,LOW(2*InitStr)
   RCALL   TxStr 
; Get value for total cycle length 
   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 
   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?
   SBI   OutPort,ActivePin; Start active phase 
   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 
   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 
   RJMP   ctloop; start a new cycle 
; Text strings for transmit, ANSI screen encoded! 
.DB   cbel,ccr,clf,cesc,'[','3','3','m' 
.DB   "Error in input! Repeat input! " 
.DB   ccr,clf,cnul,cnul
.DB   cesc,'[','3','2','m','*' 
.DB   "Input active time (default = 2,000):" 
.DB   cesc,'[','3','1','m',' ' 
.DB   cnul,cnul 
.DB   cesc,'[','3','2','m','*' 
.DB   "Input cycle time (default = 25,000):" 
.DB   cesc,'[','3','1','m',' ' 
.DB   cnul,cnul 
.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 
.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
.DW   check 
; End of code segment 

©2002 by