sin lookup table
;*********************************************************************
TITLE "PWM based sine wave generator"
LIST P=16C620, R=DEC
INCLUDE <P16C620.INC>
__CONFIG _BODEN_OFF&_CP_OFF&_PWRTE_ON&_WDT_OFF&_XT_OSC
;
;*********************************************************************
; File: SINE.ASM
; Author: Rob Stein
; Date: 12/20/95
; Assembler: MPASM V01.40
; Xtal: 20 Mhz
; Inst Clk: 5 Mhz (200nSec)
;*********************************************************************
; Description:
; Outputs a 60 Hz synthizied sine wave (32 step) via a general
; purpose I/O pin (RB1) into a low pass filter. A software PWM
; routine is used to create 32 seperate sinewave steps. This
; software was prototyped with the PICDEM1 board.
;
; Circuit Diagram:
;
; 2.7k 2.7k
; RB1 ___/\ /\ /\______/\ /\ /\________ Analog Output
; \/ \/ | \/ \/ |
; | |
; ----- 0.1uF ----- 0.1uF
; ----- -----
; | |
; GND GND
;
; ROM Usage: 98 words
;
; RAM Usage: 6 bytes
;
;************************* Constant Definition *********************
FXTAL EQU .20000000 ; Crystal Frequency
FINST EQU FXTAL/4 ; Instruction Cycle Frequency
FSINE EQU .60 ; Sine function frequency
STEP# EQU .32 ; Number of steps
FSTEP EQU FSINE * STEP# ; Step frequency
;************************* Register Definition *********************
TEMPW EQU 0x20 ; Temporary interupt storage for W
DELAYCNT1 EQU 0x21 ; Delay routine counter low
DELAYCNT2 EQU 0x22 ; Delay routine counter high
STEPCOUNT EQU 0x23 ; Sine step counter
OUTLOW EQU 0x24 ; PWM low cycle load for TMR0
OUTHIGH EQU 0x25 ; PWM high cycle load for TMR0
;************************* Bit Definition *********************
PWM EQU 0x01 ; RB1 used for PWM output
;*********************************************************************
; Reset Vector
;*********************************************************************
org 0x000
goto Start ; Begining of Program
;*********************************************************************
; Interupt Vector and Service Routine
; This interupt routine is entered via an overflow of TMR0 from
; 0xFF to 0x00. A test of RB1 determines if the next time state
; is a high or low cycle. The next interupt will occure based the
; TMR0 reload value (OUTLOW or OUTHIGH).
;
; The interupt routine was designed to use a minimial number of
; instruction cycles. This was done to maximize the PWM duty cycle
; range (ie. a 5 % to 95 % range is achievable with this ISR). Note
; that 'swapf' instructions are used to perform register moves without
; effecting the STATUS flags (this saves instruction cycles by
; eliminating the need to temporarily save the STATUS register).
;
;*********************************************************************
org 0x004 ; Interupt vector location
IntVector
movwf TEMPW ; Temporarily save W
btfsc PORTB,PWM ; Was this a Low cycle ?
goto PWMLow ; No ...
PWMHigh
swapf OUTHIGH,W ; Yes... Load high time without affecting STATUS flags
bsf PORTB,PWM
nop ; Delay to equalize high/low TMR0 load cycles
movwf TMR0 ; Load next edge interupt time
bcf INTCON,T0IF ; Clear TMR0 overflow flag
swapf TEMPW,F ; Swap saved W
swapf TEMPW,W ; Restore W
IntEndHi
retfie ; Return from Interupt
PWMLow
bcf PORTB,PWM
swapf OUTLOW,W ; Load low time
movwf TMR0 ; Load next edge interupt time
bcf INTCON,T0IF ; Clear TMR0 overflow flag
swapf TEMPW,F ; Swap saved W
swapf TEMPW,W ; Restore W
IntEndLo
retfie ; Return from Interupt
;*********************************************************************
; Main Routine
;*********************************************************************
Start
clrf STATUS ; Intitialize STATUS & select bank 0
bsf STATUS,RP0 ; Select register bank 1
movlw 0x88
movwf OPTION_REG ; 1:1 TMR0 prescaler, PORTB pull-ups disabled
movlw 0xFF
movwf TRISA ; Set Port_A as inputs
clrf TRISB ; Set Port_B as outputs
bcf STATUS,RP0 ; Select register bank 0
movwf PORTB ; PORT_B pins high
clrf TMR0 ; Initialize TMR0
movlw 0xA0
movwf INTCON ; Enable TMRO and global interupt
ResetStep
movlw STEP#
movwf STEPCOUNT ; Load counter for 32 steps
StepLoop
call Delay ; Software delay
movf STEPCOUNT,W ; Pass table offset via W
call SineTable ; Get table value
call SetPWM ; Set-up low & high PWM values
decfsz STEPCOUNT,F ; Next step
goto StepLoop
goto ResetStep
;*********************************************************************
; Set PWM Subroutine
; The following calculates the next low and high PWM time values.
; The two time values, OUTLOW and OUTHIGH, will be passed to the
; interupt service routine.
;*********************************************************************
SetPWM
bcf INTCON,GIE ; Disable interupts to protect ISR from...
; corrupting OUTLOW & OUTHIGH values
movwf OUTLOW ; Set PWM Duty Cycle
comf OUTLOW,W
addlw IntEndHi-IntVector ; Adjust for Int Service time
movwf OUTHIGH
movf OUTLOW,W
addlw IntEndHi-IntVector ; Adjust for Int Service time
movwf OUTLOW
swapf OUTLOW,F ; Swap nibbles so that interupt service...
swapf OUTHIGH,F ; will not corrupt STATUS
bsf INTCON,GIE ; Re-enable interupts
return
;*********************************************************************
; Look-up Table for Sine Wave
; This 32 entry table was generated to produce a 0.1*Vdd to
; 0.9*Vdd (typicaly 0.5 to 4.5 volt) sine function.
;*********************************************************************
SineTable
addwf PCL,F ; Increment into table
retlw .0 ; Dummy table value
retlw .128 ; 0 degree, 2.5 volt
retlw .148
retlw .167
retlw .185
retlw .200
retlw .213
retlw .222
retlw .228
retlw .230 ; 90 degree, 4.5 volt
retlw .228
retlw .222
retlw .213
retlw .200
retlw .185
retlw .167
retlw .148
retlw .128 ; 180 degree, 2.5 volt
retlw .108
retlw .89
retlw .71
retlw .56
retlw .43
retlw .34
retlw .28
retlw .26 ; 270 degree, 0.5 volt
retlw .28
retlw .34
retlw .43
retlw .56
retlw .71
retlw .89
retlw .108
;*********************************************************************
; Time Delay Sub-routine
; The time delay is used to create the precision 32 steps. The
; 32 step times totaled together add up to a 60 Hz rate. Note that
; constants DELAYCNT# are used so that other frequencies can easily
; generated (example: FSINE equ .50 for a 50 Hz sinewave).
;*********************************************************************
TDELAY EQU FINST/FSTEP ; # of delay count cycles
ADJTDELAY EQU TDELAY/3 - 55 ; Adjust for main routine cycles
TDELAYHI EQU high ADJTDELAY ; Most Significant Byte of TDELAY
TDELAYLO EQU low ADJTDELAY ; Least Sig. Byte of TDELAY
Delay
movlw TDELAYHI
movwf DELAYCNT2 ; Load high byte delay counter
clrf DELAYCNT1
LoopD1
decfsz DELAYCNT1,F ; Finished with 256 loops ?
goto LoopD1 ; No ... keep going
decfsz DELAYCNT2,F ; Yes... Done with TDELAYHI loops ?
goto LoopD1 ; No ...
movlw TDELAYLO ; Yes... Load low byte with adjust for...
movwf DELAYCNT1 ; main routine cycles.
LoopD2
decfsz DELAYCNT1,F ; Finished with TDELAYLO loops ?
goto LoopD2 ; No ... keep going
return ; Yes... Finished
END ; That's all Folks !