A simple (crude, but might just work) solution is to count zero-crossings over time. I am not sure what timer support the CodeVision library provides, but I'll assume you have a 1 millisecond resolution tick count and a 1 millisecond resolution delay. If not you'll have to provide your own using a timer peripheral.
int measureFrequency( int dc_offset )
{
int zero_x_count = 0 ;
delayms(1) ; // align to the tick boundary
int start = tickms() ;
int previous_sign = read_adc1() = dc_offset < 0 ? -1 : 1 ;
// Count zero x for 1 second
while( tickms() - start < 1000 )
{
delayms(1) ;
int sign = read_adc1() = dc_offset < 0 ? -1 : 1 ;
if( sign != previous_sign )
{
zero_x_count++ ;
}
}
// Frequency = zero-x / 2
return zero_x_count >> 1 ;
}
The dc_offset
argument is the quiescent ADC reading corresponding to no signal (silence). You could measure that separately, by taking an average over time while no string is plucked. A more sophisticated method is to use high pass IIR filter with a very low cut-off frequency (a DC-blocking filter) to remove the offset from the signal in real-time.
The 1ms delay between readings is hopefully sufficient to prevent false counts due to higher-frequency harmonics and noise in the reading but you will have to experiment. The waveform for a plucked string is complex and may defeat this simple approach.
Ideally you's have an analogue anti-aliasing filter on the input with a cut-off frequency of about 500Hz; that will make it more reliable by removing these higher-frequency components.
A more sophisticated digital signal processing (DSP) approaches include:
- Fast Fourier Transform (FFT) and find the peak frequency.
- create a digital band-pass filter for each string frequency and measure the response at each frequency.
The advantage of this second approach is you can in fact tune all strings simultaneously just by strumming an open chord. In this case though you are not measuring the frequency, but the signal level at that frequency. You need a very narrow band and good rejection and frankly the ATMega is probably not up to it.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…