Follow along with the video below to see how to install our site as a web app on your home screen.
Note: This feature may not be available in some browsers.
movlw .23
movwf loops
call delay
call delay
call delay
movlw 10h
xorwf gpio,1 ;to toggle GP4
decfsz loops,1
goto $-6
movlw 20h
xorwf gpio,1 ;to toggle GP5
goto $-11
delay ;7246uS
movlw .8
movwf fileA
movlw .225
movwf fileB
nop
decfsz fileB,1
goto $-2
decfsz fileA,1
goto $-4
retlw 00
Don't use that (garbage) code. That delay routine doesn't produce anything even close to 7426-usecs and that's not the correct number anyway.Try this code:
Code:movlw .23 movwf loops call delay call delay call delay movlw 10h xorwf gpio,1 ;to toggle GP4 decfsz loops,1 goto $-6 movlw 20h xorwf gpio,1 ;to toggle GP5 goto $-11 delay ;7426uS movlw .8 movwf fileA movlw .225 movwf fileB nop decfsz fileB,1 goto $-2 decfsz fileA,1 goto $-4 retlw 00
while(1)
{
Delay_us(7246); // will need to "tune" this value
A++;
if(A >= 23)
{
A = 0;
GPIO.F4 = ~GPIO.F4;
}
B++;
if(B >= 3)
{
B = 0;
GPIO.F5 = ~GPIO.F5;
}
}
unsigned char A, B;
unsigned int bres;
while(1)
{
while(!INTCON.T0IF); // wait for TMR0 to roll
INTCON.T0IF = 0; // clear roll flag
bres += 256; // add 256 to bres accumulator
if(bres >= 7246) // if period
{
bres -= 7246; // subtract period, retain error
A++;
if(A >= 23)
{
A = 0;
GPIO.F4 = ~GPIO.F4;
}
B++;
if(B >= 3)
{
B = 0;
GPIO.F5 = ~GPIO.F5;
}
}
}
;
; DDS Frequency (Fdds) = 13107.2 Hz (Fosc = 8.388608 MHz)
; Resolution (Fres) = Fdds / 2^16 = 0.2 Hz (16 bit accumulators)
; 3-Hz phase offset = 3 / 0.2 = 15
; 23-Hz phase offset = 23 / 0.2 = 115
;
radix dec
dualdds
clrf shadow ; |B0
movlw 15 ; phase offset for 3 Hz |B0
addwf accum1+0,F ; accum1 += phase1 |B0
skpnc ; |B0
incf accum1+1,F ; |B0
rlf accum1+1,W ; accum1.15 -> C |B0
rlf shadow,F ; |B0
movlw 115 ; phase offset for 23 Hz |B0
addwf accum2+0,F ; accum2 += phase2 |B0
skpnc ; |B0
incf accum2+1,F ; |B0
rlf accum2+1,W ; accum2.15 -> C |B0
rlf shadow,W ; |B0
movwf GPIO ; update GP1 & GP0 outputs |B0
DelayCy(160-16) ; 160 cycle DDS loop |B0
goto dualdds ; |B0
;
list p=12f629, f=inhx32
#include <p12f629.inc>
__CONFIG _WDT_OFF&_INTRC_OSC_NOCLKOUT&_BODEN_ON&_CP_OFF&_PWRTE_ON
W_TEMP Equ 0x20
STATUS_TEMP Equ 0x21
Timebase3 Equ 0x22
Timebase23 Equ 0x23
ORG 0x000 ; processor reset vector
goto init ; go to beginning of program
ORG 0x004 ; interrupt vector location
;context save next.
MOVWF W_TEMP ;copy W to temp register,could be in either bank
SWAPF STATUS,W ;swap status to be saved into W
BCF STATUS,RP0 ;change to bank 0 regardless of current bank
MOVWF STATUS_TEMP ;save status to bank 0 register
bcf PIR1,0; clr Timer1 Int flag
movlw LOW(.51043)
movwf TMR1L
movlw HIGH(.51043)
movwf TMR1H
;do time base ticks
Incf Timebase3,f
Incf Timebase23,f
movlw .3 ; test for 1/3 of 69HZ (23Hz)
subwf Timebase23,w
skpz
goto Next_timebase
clrf Timebase23
movlw b'00100000'
xorwf GPIO,f ; toggle GPIO5 at 23Hz
Next_timebase;
movlw .23 ; test for 1/23 of 69Hz ( 3hz)
subwf Timebase3,w
skpz
goto ISRDONE
clrf Timebase3
movlw b'00010000'
xorwf GPIO,f; toggle GPIO4 at 3Hz
ISRDONE; restore context
SWAPF STATUS_TEMP,W;swap STATUS_TEMP register into W, sets bank to original state
MOVWF STATUS ;move W into STATUS register
SWAPF W_TEMP,F ;swap W_TEMP
SWAPF W_TEMP,W ;swap W_TEMP into W
retfie; return to main from interrupt
init:
call 0x3FF ; retrieve factory calibration value
bsf STATUS,RP0 ; set file register bank to 1
movwf OSCCAL ; update register with factory cal value
bcf STATUS,RP0 ; set file register bank to 0
CLRF GPIO ;Init GPIO
MOVLW 07h ;Set GP<2:0> to
MOVWF CMCON ;digital IO
BSF STATUS,RP0 ;Bank 1
;CLRF ANSEL ;Digital I/O
MOVLW b'00001111' ;Sets inputs and outputs
MOVWF TRISIO ;and set outputs
BCF STATUS,RP0 ;Bank 0
;Setup Tmr1 int
; 1000,000/ 69 = 14493 ticks req'd b4 interrupt for a 69Hz base.
; 65536-14493 = 51043 => preload this into TMR1L/H to cause 14493 ticks b4 interrupt.
movlw LOW(.51043)
movwf TMR1L
movlw HIGH(.51043)
movwf TMR1H
banksel PIE1
bsf PIE1,0 ; Timer1 interrupt enable
banksel INTCON
bsf INTCON,6 ;peripheral int. enable
bsf INTCON,7 ; gen. int enable.
movlw b'00000101' ; timer1 setup bits, with 1:1 prescale
movwf T1CON ; => start timer1 running on a 1,000,000 tick filling TMR1L, TMR1H (65536) b4 interrupt happens
Main;
goto Main; perpetual loop unless more functions needed.
END
unsigned char A, B;
unsigned long bres;
while(1)
{
while(!INTCON.T0IF); // wait for TMR0 to roll
INTCON.T0IF = 0; // clear roll flag
bres += 25600; // add 256*100 to bres accumulator
if(bres >= 724638) // if period
{
bres -= 724638; // subtract period, retain error
A++;
if(A >= 23)
{
A = 0;
GPIO.F4 = ~GPIO.F4;
}
B++;
if(B >= 3)
{
B = 0;
GPIO.F5 = ~GPIO.F5;
}
}
}
Producing 3Hz at GP4 and 23Hz at GP5 at the same time.
cycle
movlw 30h
xorwf gpio,1 ;to toggle GP4 GP5 (say ON)
movlw .7
movwf loops
call delay
call delay
call delay
movlw 10h
xorwf gpio,1 ;to toggle GP4 3.5 times
decfsz loops,1
goto $-6
call delay
call delay
movlw 20h
xorwf gpio,1 ;to toggle GP5 for 23Hz (off)
call delay
movlw 10h
xorwf gpio,1 ;to toggle GP4 4 times
movlw .7
movwf loops
call delay
call delay
call delay
movlw 10h
xorwf gpio,1 ;to toggle GP4 7.5 times
decfsz loops,1
goto $-6
call delay
movlw 20h
xorwf gpio,1 ;to toggle GP5 (ON)
call delay
call delay
movlw 10h
xorwf gpio,1 ;to toggle GP4 8 times
movlw .7
movwf loops
call delay
call delay
call delay
movlw 30h
xorwf gpio,1 ;to toggle GP4 11.5 times GP5 (off)
decfsz loops,1
goto $-6
movlw .7
movwf loops
call delay
call delay
call delay
movlw 10h
xorwf gpio,1 ;to toggle GP4 15 times
decfsz loops,1
goto $-6
call delay
call delay
movlw 20h
xorwf gpio,1 ;to toggle GP5 (ON)
call delay
movlw 10h
xorwf gpio,1 ;to toggle GP4 15.5 times
movlw .7
movwf loops
call delay
call delay
call delay
movlw 10h
xorwf gpio,1 ;to toggle GP4 19 times
decfsz loops,1
goto $-6
call delay
movlw 20h
xorwf gpio,1 ;to toggle GP5 (off)
call delay
call delay
movlw 10h
xorwf gpio,1 ;to toggle GP4 19.5 times
movlw .6
movwf loops
call delay
call delay
call delay
movlw 30h
xorwf gpio,1 ;to toggle GP4 22.5 times
decfsz loops,1
goto $-6
call delay
call delay
call delay
goto cycle where GP4 = 23 times and GP5 (ON)
delay ;7246uS
movlw .8
movwf fileA
movlw .225
movwf fileB
nop
decfsz fileB,1
goto $-2
decfsz fileA,1
goto $-4
retlw 00
Nice system Mike! I'm not sure of accuracy with a fixed delay because of the variable execution time of your math code, so accuracy would suffer?
Mosaic- I think you haven't accounted for the interrupt latency and context saving times etc. And your code would still be limited to a period precision of 1 TMR0 count. Also, shouldn't you be toggling the pins at DOUBLE the base freq of 69, or you will generate tones at 1/2 the desired freq?
list p=12f629, f=inhx32
#include <p12f629.inc>
__CONFIG _WDT_OFF&_INTRC_OSC_NOCLKOUT&_BODEN_ON&_CP_OFF&_PWRTE_ON
W_TEMP Equ 0x20
STATUS_TEMP Equ 0x21
Timebase3 Equ 0x22
Timebase23 Equ 0x23
ORG 0x000 ; processor reset vector
goto init ; go to beginning of program
ORG 0x004 ; interrupt vector location
;context save next.
MOVWF W_TEMP ;copy W to temp register,could be in either bank
SWAPF STATUS,W ;swap status to be saved into W
BCF STATUS,RP0 ;change to bank 0 regardless of current bank
MOVWF STATUS_TEMP ;save status to bank 0 register
bcf PIR1,0; clr Timer1 Int flag
movlw LOW(.58299)
movwf TMR1L
movlw HIGH(.58299)
movwf TMR1H
;do time base ticks
Incf Timebase3,f
Incf Timebase23,f
movlw .3 ; test for 1/3 of 69HZ (23Hz)
subwf Timebase23,w
skpz
goto Next_timebase
clrf Timebase23
movlw b'00100000'
xorwf GPIO,f ; toggle GPIO5 at 23Hz
Next_timebase;
movlw .23 ; test for 1/23 of 69Hz ( 3hz)
subwf Timebase3,w
skpz
goto ISRDONE
clrf Timebase3
movlw b'00010000'
xorwf GPIO,f; toggle GPIO4 at 3Hz
ISRDONE; restore context
SWAPF STATUS_TEMP,W;swap STATUS_TEMP register into W, sets bank to original state
MOVWF STATUS ;move W into STATUS register
SWAPF W_TEMP,F ;swap W_TEMP
SWAPF W_TEMP,W ;swap W_TEMP into W
retfie; return to main from interrupt
init:
;call 0x3FF ; retrieve factory calibration value
bsf STATUS,RP0 ; set file register bank to 1
movwf OSCCAL ; update register with factory cal value
bcf STATUS,RP0 ; set file register bank to 0
CLRF GPIO ;Init GPIO
MOVLW 07h ;Set GP<2:0> to
MOVWF CMCON ;digital IO
BSF STATUS,RP0 ;Bank 1
;CLRF ANSEL ;Digital I/O
MOVLW b'00001111' ;Sets inputs and outputs
MOVWF TRISIO ;and set outputs
BCF STATUS,RP0 ;Bank 0
;Setup Tmr1 int
; 1000,000/ 69 = 14493/2 (on/off) ticks req'd b4 interrupt for a 69Hz base.
; 65536-7246 =58290 +9=> preload this into TMR1L/H to cause 14493/2 ticks b4 interrupt.
movlw LOW(.58299)
movwf TMR1L
movlw HIGH(.58299)
movwf TMR1H
banksel PIE1
bsf PIE1,0 ; Timer1 interrupt enable
banksel INTCON
bsf INTCON,6 ;peripheral int. enable
bsf INTCON,7 ; gen. int enable.
movlw b'00000101' ; timer1 setup bits, with 1:1 prescale
movwf T1CON ; => start timer1 running on a 1,000,000 tick filling TMR1L, TMR1H (65536) b4 interrupt happens
Main;
goto Main; perpetual loop unless more functions needed.
END
The code is isochronous Roman (no variable execution time). The DDS loop is exactly 160 cycles and the output is truly if not artificially "zero error" due to the specially selected clock frequency and DDS loop time.