Using the ADC in the 16F877A to measure short signals from a Piezo

Status
Not open for further replies.
I'm not using the rectifier for FFT, that's a completely separate channel and a separate part of the project. The rectifier is for measuring time delay.

Also ADRESH means the high values for the 10 bit conversion, so I meant to say left justified, meaning 256 values and a 20mV step quantisation. I accidentally miscalculated and thought I only had 7 bits.

The conversion time in the datasheet says that conversion takes around 2 - 6 microseconds - is this information reliable?

I do understand that the A/D converter has 10 bits, and I want to use the high 8 bits - ADRESH. However I will have to put a threshold on my input to ignore noise underneath 50mV.

Also is it alright if I supply VREF with 15V? It will still give me the 0V - 5.12V range right?

With the FFT thing, I actually have 5 piezos on a drum, 4 on each "corner" which are going through the full wave rectifying circuit to measure amplitude and time delay at the same time. The 5th piezo is in the centre and is connected directly to the line in of the computer, of which we'll be performing FFT experiments on separately - It's kinda like killing two birds with one stone - so the FFT has nothing to do with this circuit or the PIC chip whatsoever and any questions asked in this thread from me will be mostly to do with how to program the chip, whether I'm doing it right or doing something horrendously wrong as I expect I will be doing as I am completely new to coding for PIC chips and have to learn it within the next week or so.

I'm sure I'll be absolutely fine with your support though.

Once I get the chance I'll grab some shots of the waveform sample through the rectifier - The full wave rectifier was extremely important and in some waveforms the initial peak (which is what we'll be measuring the time delay from) was inverted.

Also a last question for today, is it ok for a voltage of around -200mV to go into the A/D as the signal seems to dip below the 0V line for a few milliseconds after a drum hit, or will a small voltage like that damage it as well?
 
Last edited:
The conversion time in the datasheet says that conversion takes around 2 - 6 microseconds - is this information reliable?

Would be if you were reading it right - that's not conversion time, that's Tad. Look underneath that for conversion time - 12Tad. Works out to 13khz or so - but that's for RC mode. You can get it to go faster if you use the clock. I've reliably gotten a little over 30khz conversions on that chip.

DON'T PUT 15V ON VREF! Look under "Absolute Maximum Ratings". See where it says not to go much above Vdd? You can wreck it with a higher voltage. You have about a 5V dynamic range, good enough for what you're doing.
 
Also a last question for today, is it ok for a voltage of around -200mV to go into the A/D as the signal seems to dip below the 0V line for a few milliseconds after a drum hit, or will a small voltage like that damage it as well?


-.2V won't damage it because that is within the -.3V limit listed under "Absolute Maximum Ratings".
 
Heh, got it, I hadn't read that far into the manual yet, but I'll do so, good thing I'm asking this all to make sure before I actually program the chip and test it out.

I'll look into the voltage maximum values right now.
 
If a signal greater than the recommended maximum voltage comes in on the Analogue ports, is it ok as long as it doesn't last for more than a less than a millisecond?
 
If a signal greater than the recommended maximum voltage comes in on the Analogue ports, is it ok as long as it doesn't last for more than a less than a millisecond?

Pins are protected with diodes to Vdd and Vss, so LOW current inputs are no problem.
 
If you use rail-to-rail opamps (like an LM6132) and run them +5V and gnd, it will prevent this from being an issue.
 
If you use rail-to-rail opamps (like an LM6132) and run them +5V and gnd, it will prevent this from being an issue.

Unfortunately rail-to-rail opamps aren't actually so, they are 'near' rail-to-rail devices.

BTW - congratulations on the Brit Award
 
More response -- other issues

You seem to be in good hands so I almost did not respond, but there may be other issues.

Why is amplitude so important? I suspect it has a lot to do with both how hard the strike is, and how accurate. If you do not control for one then will your result be meaningfull.

If you do not want anything but the peak ( even if rectified ) you should consider: smoothing the wave form, google peak detector, google sample and hold.

I am not quite sure how the single op amp full wave rectifier works but:

I think it may pass more than the op amp power supply voltage through its feedback network when the diode is cut off.

I think it may have a high output impedance on the half wave, again when the diode is cut off. ADC converters like low impedance, see the spec sheet.
 
You do raise a very valid point, Amplitude in fact isn't all too important, this is mainly an exercise to measure the time delay between 4 or more points on a drum skin.

Seeing as I am new to coding, I will attempt to code something that will be able to detect this first, which will most likely be triggered off multiple times with one hit for now but I really just want something coming out the output and coming into a synthesizing patch I've built software side. I've already tried using software side to determine the time delay (or amplitude) but there seems to be a significant processing delay that makes data interpretation jumbled on the other side, which is why I will use the PIC chip to organize that information for me.

As with amplitude or maximum amplitude detection I believe I will omit that for now and return to it once the main task is complete, as that will just help develop my fluency in coding. Although... you just reminded me of the Envelope follower which might actually help with this eventually.
 
Last edited:
Ok I got this code to compile, and if I'm right all I have to do is import the *.hex file it makes, and program using an ICD2 to the PIC16F877A given the setup is correct.

===

#include <htc.h>

unsigned char timerStart;
unsigned int timerCount;
unsigned int timerEnd;

int adc_init(void){

// AC activate flag
// The PCFG bit will setup all PORTA inputs available to Analogue inputs
// AD result needs to be left justified
// 0000 AN0 - AN7 Analogue inputs

ADCON0 = 0x81;
ADCON1 = 0x00;

TRISA = 0x2F; // Set AN0 - AN4 on PORTA to be inputs
TRISB = 0x00;
TRISC = 0xC0; // Setting up USART for transmission from Tx PIN Asynchronous Mode
TRISD = 0x00;
TRISE = 0x17; // PSPMODE bit set to turn PORTE into I/O ports - AN5 - AN7 on PORTE to be inputs
PORTA = 0x00;
PORTB = 0x00;
PORTC = 0x00;
PORTD = 0x00;
PORTE = 0x00;

RCSTA = 0x80; // Serial Port ENABLE bit
TXSTA = 0x32; // Setting up USART for Tx


}

void main()
{
unsigned char i; // general index counter
unsigned char pLabel; // general storage
unsigned char pData[8]; // storage for A/D values from analogue inputs
unsigned char pTimer[8]; // storage for timer values
unsigned char acquire0; // Acquisition Time Delay counter
// adc_on = 1;
// Activate AD module
timerStart = 0;
timerCount = 0;
timerEnd = 255; // Ending value for when information is sent to USART

while (1)
{
{
// Channel 0 AN0 PIN 2
ADCON0 = 0x81;

acquire0=4;
for (i=1;i<acquire0;i++) //acquisiton time delay

{
asm("clrwdt");
}

ADGO=1; // Start conversion

while(ADGO==1)

{
asm("clrwdt");
}


if (ADRESH > pData[0])
{
timerStart = 1;
pData[0] = ADRESH; // Send value to pData[0];
pTimer[0] = timerCount; // Send timer value to pTimer[0];
}

}

{
asm ("clrwdt");
}

{
// Channel 1 AN1 PIN 3
ADCON0 = 0x89;

acquire0=4;
for (i=1;i<acquire0;i++) //acquisiton time delay

{
asm("clrwdt");
}

ADGO=1; // Start conversion

while(ADGO==1)

{
asm("clrwdt");
}


if (ADRESH > pData[1])
{
timerStart = 1;
pData[1] = ADRESH; // Send value to pData[1];
pTimer[1] = timerCount; // Send timer value to pTimer[1];
}
}

{
asm ("clrwdt");
}

{
// Channel 2 AN2 PIN 4
ADCON0 = 0x91;

acquire0=4;
for (i=1;i<acquire0;i++) //acquisiton time delay

{
asm("clrwdt");
}

ADGO=1; // Start conversion

while(ADGO==1)

{
asm("clrwdt");
}

if (ADRESH > pData[2])
{
timerStart = 1;
pData[2] = ADRESH; // Send value to pData[2]
pTimer[2] = timerCount; // Send timer value to pTimer[2];
}
}

{
asm ("clrwdt");
}

{
// Channel 3 AN3 PIN 5
ADCON0 = 0x99;

acquire0=4;
for (i=1;i<acquire0;i++) //acquisiton time delay

{
asm("clrwdt");
}

ADGO=1; // Start conversion

while(ADGO==1)

{
asm("clrwdt");
}



if (ADRESH > pData[3])
{
timerStart = 1;
pData[3] = ADRESH; // Send value to pData[3]
pTimer[3] = timerCount; // Send timer value to pTimer[3];
}

}

{
asm ("clrwdt");
}

{
// Channel 4 AN4 PIN 7
ADCON0 = 0xA1;

acquire0=4;
for (i=1;i<acquire0;i++) //acquisiton time delay

{
asm("clrwdt");
}

ADGO=1; // Start conversion

while(ADGO==1)

{
asm("clrwdt");
}

if (ADRESH > pData[4])
{
timerStart = 1;
pData[4] = ADRESH; // Send value to pData[4]
pTimer[4] = timerCount; // Send timer value to pTimer[4];
}

}

{
asm ("clrwdt");
}

{
// Channel 5 AN5 PIN 8
ADCON0 = 0xA9;

acquire0=4;
for (i=1;i<acquire0;i++) //acquisiton time delay

{
asm("clrwdt");
}

ADGO=1; // Start conversion

while(ADGO==1)

{
asm("clrwdt");
}



if (ADRESH > pData[5])
{
timerStart = 1;
pData[5] = ADRESH; // Send value to pData[5]
pTimer[5] = timerCount; // Send timer value to pTimer[5];
}

}

{
asm ("clrwdt");
}

{
// Channel 6 AN6 PIN 9
ADCON0 = 0xB1;

acquire0=4;
for (i=1;i<acquire0;i++) //acquisiton time delay

{
asm("clrwdt");
}

ADGO=1; // Start conversion

while(ADGO==1)

{
asm("clrwdt");
}

if (ADRESH > pData[6])
{
timerStart = 1;
pData[6] = ADRESH; // Send value to pData[6]
pTimer[6] = timerCount; // Send timer value to pTimer[6];
}

}

{
asm ("clrwdt");
}

{
// Channel 7 AN7 PIN 10
ADCON0 = 0xB9;

acquire0=4;
for (i=1;i<acquire0;i++) //acquisiton time delay

{
asm("clrwdt");
}

ADGO=1; // Start conversion

while(ADGO==1)

{
asm("clrwdt");
}

if (ADRESH > pData[7])
{
timerStart = 1;
pData[7] = ADRESH; // Send value to pData[7]
pTimer[7] = timerCount; // Send timer value to pTimer[7];
}

}

{
asm ("clrwdt");
}

/* This should be the code to send stored in the general purpose registers to the Tx*/

if (timerCount >= timerEnd)
{
TXREG = 0X55; // Send Data Send Byte

pLabel = 0xA0;

for (i = 0; i<8; i++)
{
TXREG = pLabel; // Send data i Byte 1 - Label A0
TXREG = pTimer; // Send data i Byte 2 - Timer Value
TXREG = pData; // Send data i Byte 3 - A/D result
pLabel++;
}

for(i = 0; i<8; i++) // clear A/D data and timer arrays
{
pData = 0;
pTimer = 0;
}


timerCount = 0; // Reset Timer
timerStart = 0; // Cycle complete - Turn timer off

{
asm ("clrwdt");
}
}

if (timerStart == 1)
{
timerCount++;
}

{
asm ("clrwdt");
}
} // End while(1)
} // End main


===

I was all excited on the other side hoping for something to happen... aaand all I got was background noise. I could get some funny signals out of stroking the PIC chip.

Yeah, stroking it, not very scientific or academic at all but hey I was stressed.

===

PS I'm using a MAX232 Serial driver chip, still I should be getting something from the serial output (TX) regardless.
 
Last edited:
Backgrond noise is better than a continuous 00 or FF, indicates your converter is probably reading the inputs.

But is there a signal for it to read? That comment about "stroking" the chip sounds to me like you have a floating input somewhere. It shouldn't be affected by hand capacitance.
 
Yes, there is a signal for it to read.

There is nothing coming in on channels 5 - 8 however, but with channels 1 - 4 there should be a short signal coming in from banging the drum repetitively.

Still there's nothing coming out of the PIC (I'm using an oscilloscope). I should be expecting quick bursts of alternating voltages of 0V - 5V if it's sending out a signal right?
 
You should get something going INTO the PIC (the A/D pin), but what's coming OUT is up to you.

Trace it from the piezo to the A/D pin if you are losing the signal.
 
Oh I'm definitely getting a signal going into the A/D pins, I've been testing that, the circuit's been working perfectly without any complaints. The PIC just doesn't seem to want to be doing anything though.
 
Ok got it, I'll see if I can get that to work. Otherwise I've just connected a full wave rectified sinewave of around 4V at 100Hz to one of the port inputs to see if that does anything. But nothing's seriously coming out the Tx Port at all.
 
Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…