Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

How to generate a pulse of 20kHz?

Status
Not open for further replies.

VRL_15

New Member
Following is my code to produce 23 Hz signal

list p=12f629, f=inhx32
#include <p12f629.inc>

__CONFIG _WDT_OFF&_INTRC_OSC_NOCLKOUT&_BODEN_ON&_CP_OFF&_PWRTE_ON

COUNTER equ 0x21
COUNTER1 equ 0x22
temp equ 0x23
M1 equ 0x24
M2 equ 0x25
M3 equ 0x26
M4 equ 0x27
COUNTER2 equ 0x28
COUNTER3 equ 0x29
;ANSEL equ 0x9F
;cblock 0x20
;d1
; d2
;endc
;**********************************************************************
ORG 0x000 ; processor reset vector
goto init ; go to beginning of program


ORG 0x004 ; interrupt vector location
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
;movlw 20h
;movwf GPIO
;movlw 02h
;movwf COUNTER

;Variable definitions
;M1 on time of pulse
;M2 off time of pulse
;M3 number of pulses
;M4 on time of pulse
;M5 off time of pulse
;M6 number of pulses

movlw .22 ;on time of pulse #1
movwf M1
movlw .22 ;off time of pulse #1
movwf M2

goto main

main:

call lowtest
;decfsz COUNTER,1
goto main

lowtest:
bsf GPIO,5
call Delay
bcf GPIO,5
call Delay1

return


Delay movf M1,0
movwf COUNTER
nop
decfsz temp,f
goto $-2
decfsz COUNTER,f
goto $-4
retlw 00


Delay1 movf M2,0
movwf COUNTER1
nop
decfsz temp,f
goto $-2
decfsz COUNTER1,f
goto $-4
retlw 00

end
 
For 23Hz signal I can enter on time/ off time as 22milliseconds as .22

but when I enter the ontime as .0.02 to get 20kHz signal using the same code
it gives me an error

I would appreciate your advice on this one

Thanks and Best Regards
 
To get a 20khz signal you need a period of .05 mSec, or 50 uSec. A freq. that high is best done using hardware PWM. This PIC does not have such a peripheral.

Your current 44ms period for a 23Hz signal has an error of 1.2% which is significant!

You are trying to enter a floating point number into an 8 bit integer, which is impossible. You need to understand the difference between integer & floating point math. F.P. math requires some custom coding in 12F series PICs, there is no built in function for it. F.P. math also takes a lot longer to compute.

If u must use this PIC you'll have to use an interrupt that triggers every (25 -x) uSec, where x is the number of instruction cycles for the code to execute. Such an interrupt adds a lot of overhead as you are using a high % of the processing time being in an Interrupt service Request at 20Khz. We use 1/2 the period of 50uSec in order to have a 50% Duty Cycle square wave pulse from a GPIO pin.

In order to ALSO have a 23Hz option, you should have the same interrupt service request increment a 2 -byte integer to a value of 1150, b4 reseting. When that integer hits 1150, you toggle the GPIO pin for the 23Hz signal.




To make this work all this code must be <25 uSec or < 25 instruction cycles. Sounds possible with some tight coding in asm.

have a look at this thread for a working example using the interrupt on the 12f629.

https://www.electro-tech-online.com...ncies-at-gpio4-and-gpio5-in-pic12f629.112682/
 
Last edited:
If you switch to the 12F683 then you can use timer2 with a period of 25uS and have a much simpler ISR.
Code:
ISR	bcf	PIR1,TMR2IF
	btfsc	PORTA,0
	goto	ClrIt
	bsf	PORTA,0
	retfie
ClrIt	bcf	PORTA,0
	retfie
Assuming a 4 Meg clock the above will use about 33% of the processor time.

Mike.
 
Last edited:
I'm wondering if this isn't a homework assignment...it's rather similar to the link I posted b4 and the OP never indicate WHY they want these frequencies.
 
To get a 20khz signal you need a period of .05 mSec, or 50 uSec. A freq. that high is best done using hardware PWM. This PIC does not have such a peripheral.

Not at all - it's trivial, and mostly much more accurate, to simply do it in software - the PWM module is only really useful if you're wanting to do something else at the same time.

Presumably, from the frequencies mentioned, he's wanting an audio squarewave generator? - the PWM module would only provide you a fairly small number of fixed frequencies.
 
@Mosaic

I need 10khz pulse at GPIO4 and 20khz pulse at GPIO5 in PIC12f629

I tried the code you once mentioned but I am not getting the desired result.

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(.65511)
movwf TMR1L
movlw HIGH(.65511)
movwf TMR1H
;do time base ticks
Incf Timebase3,f
Incf Timebase23,f
movlw .10000 subwf Timebase23,w
skpz
goto Next_timebase
clrf Timebase23
movlw b'00100000'
xorwf GPIO,f ; toggle GPIO5 at 23Hz
Next_timebase;
movlw .20000 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

movlw LOW(.65511)
movwf TMR1L
movlw HIGH(.65511)
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
 
two frequencies at the same time

@Mosaic

I need 10khz pulse at GPIO4 and 20khz pulse at GPIO5 in PIC12f629

I tried the code you once mentioned but I am not getting the desired result.

list p=12f629, f=inhx32
#include <p12f629.inc>

__CONFIG _WDT_OFF&_INTRC_OSC_NOCLKOUT&_BODEN_ON&_CP_OFF&_PW RTE_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(.65511)
movwf TMR1L
movlw HIGH(.65511)
movwf TMR1H
;do time base ticks
Incf Timebase3,f
Incf Timebase23,f
movlw .10000 subwf Timebase23,w
skpz
goto Next_timebase
clrf Timebase23
movlw b'00100000'
xorwf GPIO,f ; toggle GPIO5 at 23Hz
Next_timebase;
movlw .20000 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

movlw LOW(.65511)
movwf TMR1L
movlw HIGH(.65511)
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
 
Um...judging from what you have done....there's a basic misunderstanding of what's going on.
Since this is a virtual repeat of a solution with the 3Hz /23Hz question, I can't see why you are not able to follow along.

I'll give u a hint:

We are dealing in PERIODS to generate FREQUENCIES. a 20Khz frequency has a period of 50uSec, or a on/off pulse in 50 uSec, which is easily handled by a 25uSec on period and a 25uSec off period in each cycle. Because of the tight timing required to achieve this in a 1MIP (4Mhz) clocked PIC you must optimise the ISR to efficiently pulse the GPIO. A 10Khz signal has twice the period of a 20Khz signal.

What I would do is establish a counter integer variable driven by the 25uSec interrupt. Thus the bit 0 or LSB will toggle every 25uSec (20kHz)and bit 1 every 50 uSec (10khz) and can be used to drive the GPIO4 & GPIO5 with a swapf command used to shift bits 0,1 to bits 4,5 before writing to the PORT.

The trick in this is the code used to run the count must be checked for instruction cycles (1 inst = 1 uSec except for goto/call = 2uSec) consumed and then subtracted from the interrupt period to keep your timing accurate. I mentioned this in your other thread.

If this is all u need then the context saving in the ISR can be eliminated to save inst. cycles.

Please don't start multiple threads on this.
 
Not at all - it's trivial, and mostly much more accurate, to simply do it in software - the PWM module is only really useful if you're wanting to do something else at the same time.

My point of view here is the % utilisation of the PIC processing makes it almost a dedicated task in software, whereas doing high freq. in HW leaves the PIC able to do other tasks.
 
Your ISR is already longer than the 25uS that you have available. Switch to a pic with timer2 and do as I suggested in your previous thread.

And, keep to one thread in future.

Mike.
 
My point of view here is the % utilisation of the PIC processing makes it almost a dedicated task in software, whereas doing high freq. in HW leaves the PIC able to do other tasks.

Which is what I said - except it's unlikely that you would want to be doing other tasks while doing this.

As I said previously, it's far easier to do, far more accurate, and far more versatile to do it in software than using timers or PWM modules - as long as you don't want the processor to do something else at the same time.
 
Hello there,


If i understand the question the OP wants to generate a 10kHz pulse and also a 20kHz pulse from the same PIC chip, and do nothing else. If that assumption is correct, then lets not skip over the most basic way of programming pulses in asm...
Since a 4MHz clock is easy to get with the PIC, if we assume that then each instruction cycle is worth 1us. That of course means that each 'nop' is worth 1us, and so of course 25 instructions are worth 25us and 50 instructions are worth 50us, etc. It todesnt take much to figure out that 20kHz requires a total of 50 instruction cycles and 10kHz requires 100 instruction cycles, and with about 1k of memory to work with all we really have to do is place (say) 39 nop's in memory followed by a port setting instruction, and follow that with another 9 nop's and then a port bit reset instruction. That will generate the 20kHz pulse.
To get both pulses, we would of course use two ports and instead of the bcf and bsf instructions we could load w with the required port bits and then movwf GPIO to set both ports at the same time. After the appropriate number of nop's we would then change GPIO to reset one bit of the two ports and leave the other one alone, then after another set of nop's set or reset the required GPIO bits again.
Using movwf GPIO is better anyway, but also that allows us to sync both outputs without a phase delay. So the code would look something like this:

START
movlw b'00000011' ;to set both ports to 1
movwf GPIO
nop
nop
nop
(etc.)
movlw b'00000001' ;leave one bit high (10kHz) and set the other low
movwf GPIO
nop
nop
(etc.)
movlw b'00000010 ;set one high and the other low
movwf GPIO
nop
nop
etc.
etc.
goto START

Using this technique you can get the frequencies as needed if you just change the output port GPIO once for every transition of both the 10kHz wave and the 20kHz wave. This is quite simple, but dont forget the goto takes 2 instruction cycles.
The accuracy however is only as good as the raw PIC rc oscillator, which is typically around 1 percent or so, so if you need better timing then you'll have to use an external crystal or oscillator.

Note that doing it this way takes quite a few instructions, but who cares if that's all we are using the PIC chip for anyway :)
This is also a good way to learn about some tricks for saving instructions if we want to use less nop's in the code (like calling a 'return' instruction, which takes up 4 instruction cycles) or creating a timing delay either constant or variable.
 
Last edited:
Couldn't you just toggle GP5 (the 20-KHz pin) every 25-usecs and toggle GP4 (the 10-KHz pin) every 50-usecs?

Code:
;
loop
        movf    GPIO,W          ;
        xorlw   b'00100000'     ; toggle GP5 (20-KHz) bit
        movwf   GPIO            ;
        DelayCy(25*usecs-3)     ; delay 25-usecs minus 3 cycles
        movf    GPIO,W          ;
        xorlw   b'00110000'     ; toggle GP5 (20-KHz) and GP4 (10-KHz) bits
        movwf   GPIO            ;
        DelayCy(25*usecs-5)     ; delay 25-usecs minus 5 cycles
        goto    loop            ;
 
Last edited:
Couldn't you just toggle GP5 (the 20-KHz pin) every 25-usecs and toggle GP4 (the 10-KHz pin) every 50-usecs?

Code:
;
loop
        movf    GPIO,W          ;
        xorlw   b'00100000'     ; toggle GP5 (20-KHz) bit
        movwf   GPIO            ;
        DelayCy(25*usecs-3)     ; delay 25-usecs minus 3 cycles
        movf    GPIO,W          ;
        xorlw   b'00110000'     ; toggle GP5 (20-KHz) and GP4 (10-KHz) bits
        movwf   GPIO            ;
        DelayCy(25*usecs-5)     ; delay 25-usecs minus 5 cycles
        goto    loop            ;

Looks like the plan to me I play with this last night and that looked like the easy way to I did it in swordfish

Like Nigel Goodwin said some simple software code . All the OP is wanting is 2 tones. So it wouldn't

look like he would be doing any thing else.
 
Last edited:
If you just increment the PORT every X period, then pin PORT.0 will toggle at 20kHz and pin PORT.1 will toggle at half the freqency, 10kHz. ;)

So that's;
Code:
Delay_x();
PORTA++;
 
If you just increment the PORT every X period, then pin PORT.0 will toggle at 20kHz and pin PORT.1 will toggle at half the freqency, 10kHz. ;)

Good point :D

Obviously it means you can't use the rest of the port for outputs, but as we're assuming it's not doing anything else that doesn't really matter.
 
Thank you for your suggestion

the delay loop for 20kHz and 10 kHz are fixed.

But if next time I have to change the frequency to some other value
I will have to change the delay cycle again.

is there any way I can keep the same delay loop throughout and use it for any frequency in the kHz range?

I would appreciate your help on this one.

Thanks and Best Regards
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top