bigdogguru
Administrator

- Joined
- Mar 12, 2010
- Messages
- 9,821
- Helped
- 2,350
- Reputation
- 4,694
- Reaction score
- 2,272
- Trophy points
- 1,413
- Location
- Southwest, USA
- Activity points
- 62,397
Hi D@nny,
Producing sinusoidal waveforms with PWM is an effective technique, using a PIC 16F to generate the PWM limits the effective frequency of the sine wave to a just few hundred Hertz due to clocking limitations. Generation of 50Hz is more that doable the appnote below details the calculation necessary to implement an efficient and effective design as you can see from the example source code these PWM Sinusoidal Generators use a lookup table which you should be familiar with at this point. The example also uses a 2-pole low pass RC filter, which allows the fundamental harmonic to pass while effectively filtering any higher frequency harmonics.
MicroChip Appnote:
D/A Conversion Using PWM and R-2R Ladders to Generate Sine and DTMF Waveforms
Source for above appnote
If you have an additional questions concerning sinusoidal wave generation after reading the appnote, feel free to ask. I have considerable reference material on the subject.
Producing sinusoidal waveforms with PWM is an effective technique, using a PIC 16F to generate the PWM limits the effective frequency of the sine wave to a just few hundred Hertz due to clocking limitations. Generation of 50Hz is more that doable the appnote below details the calculation necessary to implement an efficient and effective design as you can see from the example source code these PWM Sinusoidal Generators use a lookup table which you should be familiar with at this point. The example also uses a 2-pole low pass RC filter, which allows the fundamental harmonic to pass while effectively filtering any higher frequency harmonics.
MicroChip Appnote:
D/A Conversion Using PWM and R-2R Ladders to Generate Sine and DTMF Waveforms
Source for above appnote
Code:
;
;*********************************************************************
; 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 !
If you have an additional questions concerning sinusoidal wave generation after reading the appnote, feel free to ask. I have considerable reference material on the subject.