This time we're going to extend the pulse counting example from the last instalment to be able to measure frequency. The code is short but a little complex.
To measure frequency we need to count pulses over a known period of time. We saw how Timer 2 can count pulses. We can also use Timer 1 to count a period of time for us.
We'll use Timer 2 in the same pulse counting mode as before where it counts transitions on line PB6. We'll put Timer 1 in the single shot mode where it counts down to zero from a known value at the system clock rate.
We'll count the number of pulses we see over this period of time and display it. Then we'll repeat forever. This is essentially what a device called a digital frequency counter does.
We poll the timer to see when it reaches zero. This is not very efficient and a nice enhancement would be to make this interrupt driven but we want to keep it simple for now. We will look at an interrupt driven example later in this series.
Ideally we would like to convert the result to an actual frequency. To do that we need to divide the number of pulses by the time period (i.e. to get cycles per second or Hertz). If we did this, a good sample rate might be one that is one over a multiple of 2, e.g. 1/16, 1/32, or 1/64 of a second since we can do this calculation by shifting the data by a number of bits rather than doing a full divide operation. For this example I used a 20 Hertz sample rate and didn't calculate the frequency. I used the one's complement trick described in the last experiment to convert the count down to a count up.
The hardware setup here is a little messy. We need a source of pulses, i.e. a square wave at the appropriate TTL (5V) level. Initially I used the calibrate output of my oscilloscope as it puts out 2 volts peak to peak at around 1 KHz. This worked well enough to confirm that I got the right results.
I then used an audio oscillator (an old EICO model 377) to give me a source that I could vary in frequency. I set it to square wave output and then drove it through a 74LS04 inverter chip. I was concerned about possibly damaging the VIA chip if I inadvertently set the output voltage too high. This way I only risked damaging an inexpensive IC from my junk box.
You can see the setup below.
EICO Signal Generator |
Breadboarded Circuit with 74LS04 Chip |
The source code is below. Based on the information above and the comments in the code is should be self-explanatory.
.include "6522.inc"
ECHO = $FFEF ; Woz monitor
PRBYTE = $FFDC ; Woz monitor
CR = $0D ; Carriage return
COUNT = 49998 ; 20 Hz sample rate
LDA #$00
STA IER ; disable all interrupts
LDA #%00100000
STA ACR ; T1 single shot PB7 disabled, T2 pulse count mode
LOOP:
LDA #
STA T1CL ; Set low byte of count
LDA #>COUNT
STA T1CH ; Set high byte of count
LDA #$FF ; Set count for T2
STA T2CL ; Set low byte of count
LDA #$FF
STA T2CH ; Set high byte of count
WAIT:
LDA T1CH ; wait for timer T1 to count down to zero
BNE WAIT
LDA T1CL
BNE WAIT
LDA T2CH ; get high byte of T2 count
EOR #$FF ; take 1's complement
JSR PRBYTE ; print it
LDA T2CL ; get low byte of T2 count
EOR #$FF ; take 1's complement
JSR PRBYTE ; print it
LDA #CR
JSR ECHO ; print newline
JMP LOOP ; repeat forever
As one example (the one shown on the display in the picture below), the input was at about 100KHz. I counted about $13AE pulses, or 5038 decimal. I used a 20 Hz sampling rate. 5038 * 20 Hz = 10,076 Hz. So my reading looks about right.
Signal Generator Output on Oscilloscope |
Output of Program |
My signal generator only went up to about 200KHz and I was able to measure this frequency.
You can imagine building a digital frequency counter using a 6502 and a VIA chip. In fact some modern counters a simple processor (e.g. a PIC) and some kind of display and not much more.
No comments:
Post a Comment