Great suggestions by some of the most knowledgable contributors to the list.
I elected to go with a simple software approach using PWM, without lookup tables. Most of the code is to provide DT's Instant Interrupt.
I initialize the 16F690 HPWM at 32kHz, zero duty. With each TMR1 interrupt I increment the duty register until I reach the desired maximum voltage on the sawtooth, then start over at zero. A low-pass RC filter smooths the output. Peak voltage and frequency are easily modified. I retained the oscope interrupt timing signal on RC.4; you will have to change some parameters if this is omitted.
Other ways to tackle this include a 555-based generator, R2R ladder network or dedicated parallel-interface DACs. Microchip has an application note http://www.microchip.com/stellent/id...pnote=en011071 that may be helpful.
Gary
	Code:
	'****************************************************************
'*  Name    : oscope clock 16F690 sawtooth generator
'*  Author  : gmg        Copyright (c) 2010 (yeah, right...)                                       
'*  Date    : 7/28/2010                                                                            
'*  Notes   : generates sawtooth wave for CRT time base 
'            Horiz: 1.5v=10 div, Vert: 2.0v=8 div max on CRT
            passive low pass RC filter on PWM output RC.5         
'************************************************************
@ __config _INTRC_OSC_NOCLKOUT & _MCLRE_OFF & _CP_OFF & _WDT_OFF
ADCON1=$0F                    'disable A/D 
VRCON=0                       'volt ref off      
CM1CON0.0=0 : CM2CON0.0=0   	'comparators off
ANSEL=0 : ANSELH=0
OSCCON=%01110000              ;8MHz intosc
DEFINE OSC 8
'-------------- pins
'PWM_out           var    portc.5
TRISC=0:TRISB=0
PORTC=0: PORTB=0
'-------------- variables
version		con	107
i               var      byte
j               var      byte
temp            var      BYTE 
tempword        var      word
duty_reg        var      word
HLevel          var      byte
VLevel          var      byte
HOrigin         var      byte
CLEAR
read 0, temp
if temp<>version then write 0, version	'store sw version in EEPROM 0
'----  setup HPWM on PORTC.5
hpwm 1, 0, 32000 		'32kHz PWMN out on PORTC.5
'----- setup DT instant interrupt TMR1            
INCLUDE "DT_INTS-14.bas"     ; Base Interrupt System
INCLUDE "ReEnterPBP.bas"     ; Include if using PBP interrupts  (cf. asm interrupts)
ASM
INT_LIST  macro ;            IntSource,    Label,      Type,  ResetFlag?
                INT_Handler   TMR1_INT,   ReloadTMR1,   ASM,  no    ; MUST be first
                INT_Handler   TMR1_INT,   _T1handler,   PBP,  yes
    endm                                                                                  .
    INT_CREATE               ; Creates the interrupt processor
ENDASM
@Freq       = 6000                 ; interrupt frequency, 1.7msec period gives 600Hz screen sweep
@Prescaler  = 1                   ; Timers Prescaler setting
T1CON = $00                       ; $30 = Prescaler 1:8, TMR1 OFF   ; $00=1:1, $10=1:2, $20=1:4, $30=1:8 --  NB: T1CON Must match @Prescaler value
@ INT_ENABLE  TMR1_INT            ; enable Timer 1 interrupts
GOSUB StartTimer                  ; Start the Timer
'-------   Main
while 1=1		'loop forever   
wend
;____This routine is Called on each TMR1 Interrupt____________________________
T1handler:
       ISR:          
duty_reg=duty_reg+1
if duty_reg>140 then duty_reg=0       'increment duty_reg each interrupt for ramp function     
trisc.5=1
CCP1CON.4=duty_reg.0                 '10bit PWM 
CCP1CON.5=duty_reg.1 
tempword=duty_reg & %1111111100
CCPR1L=tempword>>2
trisc.5=0 
   HIGH PORTC.4    		'TEMP oscope timing pulse, retained to preserve timing
   PAUSEUS 10                
   LOW PORTC.4     
@ INT_RETURN
;---[TMR1 reload - interrupt handler]-----------------------------------------
ASM                               ; Calculate Timer Reload Constant
ReloadInst  = 8                   ; # of Intructions used to reload timer
  if ((Prescaler == 1)||(Prescaler == 2)||(Prescaler == 4)||(Prescaler == 8))
MaxCount    = 65536 + (ReloadInst / Prescaler)
TimerReload = MaxCount - (OSC*1000000/4/Prescaler/Freq)
    if ((TimerReload < 0) || (TimerReload > (65535-ReloadInst)))
        error Invalid Timer Values - check"OSC", "Freq" and "Prescaler"
    endif
  else
      error Invalid Prescaler
  endif
ENDASM
@Timer1 = TMR1L                   ; map timer registers to a word variable
Timer1       VAR WORD EXT
TimerReload  CON EXT              ; Get the External Constant
TMR1ON       VAR T1CON.0          ; Alias the Timers ON/OFF bit
;---Reload Timer1------
ASM
ReloadTMR1
    MOVE?CT  0, T1CON, TMR1ON     ;  1     stop timer
    MOVLW    LOW(TimerReload)     ;  1     Add TimerReload to the 
    ADDWF    TMR1L,F              ;  1     value in Timer1
    BTFSC    STATUS,C             ;  1/2
    INCF     TMR1H,F              ;  1
    MOVLW    HIGH(TimerReload)    ;  1
    ADDWF    TMR1H,F              ;  1
    MOVE?CT  1, T1CON, TMR1ON     ;  1     start timer
  INT_RETURN
ENDASM
;---Start/Stop controls -----
StartTimer:
    Timer1  = TimerReload         ; Load Timer
    TMR1ON = 1                    ; start timer
RETURN
StopTimer:
    TMR1ON = 0                    ; stop timer
RETURN
END
 
				
			
Bookmarks