xmult

This program tries to find the best multiple (harmonic) and divisor (ala TTL, HCMOS or PIC) to get closest to a desired low output frequency given that you start with a crystal. For example, if you've got a 3.579575 mhz crystal and you want 466 khz, use the third harmonic then divide by 23 to get 466.90109 khz for mixing with a 455 khz IF. If you can adust the oscillator with a trimmer cap to 3.57266666 you'll be dead on. This program uses harmonics rather than trying to anticipate what the overtone frequencies will be, so you may need one or more multiplier stages.

Dividing by 23 (or almost any other integer) with a PIC is really simple. There's a sample program at the bottom of the page. Download the free mplab from microchip and install it. Run through the simulation until you get the results you want, then find or borrow a programmer to write the program into the chip. Hint: you turn on an output pin, waste enough program cycles to use up half the amount of time, turn off the output pin, waste more time, then loop and do it over. That gives something close to a 50% duty cycle. The frequency the PIC's running at is your crystal frequency or a harmonic of it. The upper limit on frequency input comes from what the PIC can handle for a clock frequency.

If you've got a bunch of crystals, type or paste the frequencies in and the program will show the best matches. Crystal frequencies need to be in MHZ. 3.579545 is given as an example because almost everyone probably has one of those around (old NTSC colorburst frequency, found in junk TVs or VCRs). The list of crystals can be longer than the box: a scrollbar will appear when it's needed. You can use the same list over and over by clearing the log and entering different other numbers.

The old "garbage in : garbage out" maxim applies here. If you enter a value that's not actually a number the results are unpredictable. It won't blow up your computer (except maybe if you're using Internet Explorer). This may take a while to calculate and you don't need to pay attention to what's happening in the log except at the end (you may have to scroll it).

How this works:
For each crystal frequency you enter, the program calculates harmonics until they would go above the max frequency you entered that your divider logic can handle. Then it tries dividing each of those frequencies by 2 and up to the maximum feasible divisor you entered. It subtracts that frequency from the target frequency you entered and looks at the absolute value. If it's the closest match found so far it keeps it. When its gone through all the harmonics and all the divisors the best match is output. Once it's given a best match, it "back-calculates" by multiplying the target freqency by the best divisor, then dividing by the harmonic number to give the exact frequency you need to trim the crystal to.

If you're trying to get some small frequency like 60 HZ out of a crystal like 3.579 MHZ, set the max divisor really big. The program does work for getting 60 hz from 3.579 MHZ, but the divisor has to be free to go up to 59659. Trimming the crystal to 3.57954 MHZ gets exactly 60 HZ out. I haven't written a PIC program for a divisor that big, but you'd just turn on the output pin, count up half the divisor, turn the pin off, and count the other half. Actually you'd preload the counts and count down to 0 because 0 is easy to detect. You could even make a more versatile divider by using DIP switches to set the count, but then you'd need a bigger PIC with more I/O pins to be able to read the switches. Trying to get 3.885 MHZ from 3.579 doesn't work. You can get really dead on with PL tones this way though.

Crystals (MHZ):
Enter the max frequency (MHZ) of your divider logic family (20 MHZ for TTL, etc.):
Enter the maximum feasible divisor (255 or higher for a PIC):
Enter the target frequency you want out (in KHZ):

Log

As promised, here's an example program. This was for a 12F683 PIC, a little 8-pin one that costs about $2 from Mouser. The first section, above main, is directives to the assembler. The section down to loop1 is setup: both of these sections should stay the same for a 12F683.

The part of the program that does the dividing is the bottom part, so this is what you adjust for different divisors. There are 4 cycles of overhead. The BSF at loop1 turns the output pin on, the BCF turns it back off. Adjust the number of NOP lines for what you need (the numbers after the semicolons are me counting cycles). The upper limit on the divisor really comes from how much memory the chip's got for holding NOP statements. For very high divisors this isn't really the best way to do it. For instance if you divide 3.579545 MHZ by 59659.083 you can get 60 HZ to run a clock or an inverter. You can't divide by non-integers, but with a trimmer cap on the crystal you can pull it a little.

By using a different counting scheme having 4 or more 1-byte registers that count down to 0 then borrow from the next one up it's possible to get divisors like 25635322908 in fact almost twice that. (Counting down once in each half of the cycle, 6 processor cycles per count.) That's about 2 hours per cycle from a 3.579545 MHZ crystal. Unless your frequency counter also does periods (the reciprocal of cycles) the simulator's about the only way to see what the circuit's doing, and of course you can test without wiring or programming anything. It took my computer overnight to simulate enough to get to the 25635322908 count, and I'm still working on formulas to calculate the output from the input, so that'll be on a different page. I'm getting a little bored with it.

You can step through the program in MPLAB (or Piklab and gpsim under Unix), so watch how many cycles go where. You can download MPLAB and datasheets from http://www.microchip.com. Both are free: they're trying to sell the chips.

To count the divisor you're getting open the .asm file in MPLAB in the editor. On the main menu at the top of the MPLAB window do Debugger -> Select Tool -> MPLAB SIM. In the new Debugger menu, choose Stopwatch. Click on the line with "loop1 BSF GPIO,4", then right-click and choose "Run to cursor". It will stop before executing this line, which is the entry point to the loop. The count shown in the Stopwatch includes these lines, but they're not part of the loop. Either use the Zero button or remember the count and subtract in your head. Now do "Run to cursor" again and it will show the number of processor cycles in one loop. Adjust the number of NOPs to get what you need, making the same number of changes above and below the line with "BCF GPIO,4 ; turn off output pin". Turning the output on or off take 1 processor cycle each, each NOP takes 1 cycle, and the GOTO at the end takes 2 cycles.

You can find a wide variety of programmers (the device that writes the program into the chip) on the web. If you've got a serial or parallel port you can find plans for really simple ones you can build for under $5 but you'll need to write your own programming software if it's non-standard. You may be able to borrow one or get someone to load the program into the chip for you.

The PICs require a programming voltage around 12 volts, but for normal operation they run on 5 volts. The current drain is tiny (they're CMOS), so a 78L05 and a couple of bypass caps, or maybe even a 5.1 volt zener with a bypass cap fed through a resistor would do. Input frequency goes to pin 2, output comes from pin 3, pin 8 is ground, pin 1 is +5 volts.

This program is static: it doesn't change when you change the numbers above. You have to add and remove NOPs to get the divisor you want.

; divide by 23	AB1JX
; no timer, no interrupt

; keep these lines in:
	list      p=12F683        ; list directive to define processor
	#include <P12F683.INC>    ; processor specific variable definitions
	errorlevel  -302          ; suppress message 302 from list file
	__CONFIG   _FCMEN_ON & _IESO_OFF & _CP_OFF & _CPD_OFF & _BOD_OFF & _MCLRE_ON & _WDT_OFF & _PWRTE_ON & _EC_OSC
	ORG     0x000             ; processor reset vector
	goto    main              ; go to beginning of program
	ORG     0x0004             ; interrupt vector location 
	ORG		0x000A
main
	BCF	STATUS,RP0	; select bank 0 (bank 0)
	CLRF	GPIO	; init GPIO (bank 0)
	CLRF	CMCON0	; turn off comparators (bank 0)
	BSF	STATUS, RP0	; select bank 1
	CLRF	TRISIO	; clear tri-state, set all to outputs (bank 1) (should go to 8)
	CLRF	WPU		; turn off weak pull-ups (bank 1)
	CLRF	IOC		; turn off interrupt on change (bank 1)
	CLRF	ANSEL	; turn off analog inputs (bank 1)
	BCF STATUS, RP0	; back to bank 0
	; end of initialization
	; Adjust # of NOPS below as needed
	; overhead here without NOPs is 4 cycles
loop1	BSF	GPIO,4	; turn on output pin (pin 3)
	NOP	;1
	NOP	;2
	NOP	;3
	NOP	;4
	NOP	;5
	NOP	;6
	NOP	;7
	NOP	;8
	NOP	;9
	NOP	;10
	BCF	GPIO,4 ; turn off output pin
	NOP	;1
	NOP	;2
	NOP	;3
	NOP	;4
	NOP	;5
	NOP	;6
	NOP	;7
	NOP	;8
	NOP	;9
	GOTO loop1
	END	; anything past end directive doesn't get assembled

AB1JX / calcs