Generate sawtooth with PIC?
I'd like to generate a sawtooth wave, 0 to +1.5v at several hundred Hz up to 1 kHz on a 16F690 or similar, to generate a time base for CRT.
Suggestions for an efficient way to do this on a PIC?
My alternatives are a 555 and RC circuit or parallel DAC. I've tried an I2C DAC, but it's too slow with I2CWRITE commands.
Thanks.
1 Attachment(s)
Generate sawtooth wave with PIC -- software solution.
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