I'm having issues with DC drift on a rather "how you doing" microphone input reader which I want to use as knock sensor.
The idea is a simple one, create a virtual ground between the +5V and ground using a simple resistor voltage divider and then use a speaker/microphone to inject voltage at the mid point, this is working better than expected however it looks like inductance or capacitance of the speaker coil is creating momentary DC drift, I have no real clue how to fix this, I tried strapping a resistor across the speaker terminals, one to stop high voltage spikes and was hoping that this would pin the DC offset, but as seen in the video it drifts, not by a great deal though and I could probably code this out, but would rather fix the issue.
Any ideas for resistor value or basically any thoughts on this and a good starting place to help me understand where I'm going wrong would be greatly appreciated. Thank you
Post a circuit diagram, with parts values.
And the code (read the forum rules first).
Stab in the dark: too high resistor values, and/or a capacitor on the virtual ground.
You should really use a contact microphone for a knock sensor.
A contact speaker (surface transducer) could do, but a bare 1" piezo disk (musical wishing cards) with a 1Megohm resistor across works well.
There is even a (poorly written) knockSensor example in the IDE.
Leo..
sorry I was having issues with the inline image displaying, found out the "how to"
the values of the divider resistors are 3.9K just used what I had to hand, I could probably use much higher as I'm only interested in creating a virtual ground for the A/C of the microphone/speaker, the pickup coils are from Band Hero drums and are surprisingly sensitive to minor hits and are what I also have to hand.
the code is from the knock sensor example as it was simple and plots well
At the very least you need to AC couple into the input, that is put the speaker through a capacitor. However the voltage you are going to get from any speaker / microphone is way way too small to give you any meaningful signal you can measure. You need to amplify the signal so it is 5V peak to peak to get a good signal.
I was surprised when hooked up the what I thought was a coil as I was getting very low values from using a speaker, oh well, next time I'll investigate a little further, I just didn't want to destroy what could have been a fine coil as It was taped up and foamed in
I'll keep the virtual ground point for now, as I don't want to inject negative voltage into my inputs.
It's all proof of concept Idea at the moment so the knock code is all I need to see if it worked.
How much shift/drift, and what do you mean momentary?
You generally don't want a virtual ground in this situation. You want the input biased at 2.5V so it can swing positive and negative from there. Then depending on the application you can subtract-out the bias in software.
Your connections are wrong but a coil WILL mess-up the voltage divider. You need a capacitor between the microphone and analog input to "isolate" the bias. A piezo will not mess-up the bias and you don't need the series capacitor.
[u]Here[/u] is a schematic. The two equal-value resistors provide the bias and the 10uF capacitor isolates the DC bias from the audio circuit while allowing the AC signal through. (You can leave out the 47nF capacitor.)
Generally, you need a preamplifier for a microphone, and that includes a speaker used as a microphone or a piezo used as a microphone. A piezo knock sensor might not need an amplifier, depending on how hard you "knock" it, but you need higher value resistors (1M to 10M) because low value resistors will kill the piezo signal.
You can run a line-level or headphone-level into the biased, capacitor-isolated, input without an amplifier.
With a piezo, you probably don't have to worry about negative voltages. The Arduino has (small) built-in protection diodes to protect it from negative voltages or voltages greater than +5V. Those little diodes won't protect it from high current so if you connect a 12V battery or 12V power supply, you'll kill it. But a piezo puts-out a very low current and you should be OK.
However, you do need a (high value) resistor across the Piezo to hold the DC input voltage at ground.
wow awesome thanks doug, will take me awhile to digest
I think the DC drift was created from the piezo adding voltage to the 5v rail, I've also added diodes in series to the divider on both +5v and ground and that seems to have cured the issue, although it has dropped the centre voltage a little, not an issue for me as I'm only looking to use this as an analogue trigger for midi project.
Currently the sensitivity is great, from the lightest of taps to hard hits, using a 100k across the peizo to lower its output more and that has helped to stop it clipping but has dulled the sensitivity a smidgen.
thank you all for your advise and help, the original circuit was most definitely crude, if I get any good results from my build I'll post up on it
Just connect the piezo between pin and ground, with a 1Megohm load resistor also from pin to ground.
A small piezo can't produce enough current to damage the pin protection 'diodes' of the analogue input,
(assuming you're not going to hit it with a hammer).
The 1Meg resistor is to refer the analogue input to ground (no DC offset).
Try this sketch. It reads the analogue pin multiple times, so bridges negative waves, and stores the peak value.
Leo..
// knock sensor/alarm
// Piezo, with 1Megohm load resistor across, connected to A0 and ground
// optional 5volt buzzer on pin 13
int threshold = 100; // alarm threshold from 1 (very sensitive) to 1022 <<<<<<<<
int alarmDuration = 100; // alarm duration in milliseconds <<<<<<<<
const byte piezoPin = A0;
int rawValue; // raw A/D readings
int piezoValue; // peak value
const byte onboardLED = 13; // onboard LED and/or buzzer
void setup() {
analogReference(INTERNAL); // remove this line if too sensitive
Serial.begin(115200); // serial monitor for raw piezo output
pinMode (onboardLED, OUTPUT);
}
void loop() {
// reset
piezoValue = 0;
// read
for (int x = 0; x < 250; x++) { // multiple A/D readings
rawValue = analogRead(piezoPin);
if (rawValue > piezoValue) {
piezoValue = rawValue; // store peaks
}
}
// print
if (piezoValue > 0) {
Serial.print(F("Piezo value is "));
Serial.println(piezoValue);
}
// action
if (piezoValue > threshold) {
Serial.print(F("Knock was over the threshold of "));
Serial.println(threshold);
digitalWrite (onboardLED, HIGH);
delay(alarmDuration);
digitalWrite (onboardLED, LOW);
}
}