Hi everbody. I hope everyone is doing well. I'm writing this post here in order to seek help. I'm trying to merge the VDI code given by Don and VLF metal detector by following the link(https://github.com/dc42/arduino/blob...alDetector.ino), But I'm unable to get the required results. I'm to this stuff therefore, I'll be very thankful if anyone here could help me through this.
Note:
- I have combined the schematic uploaded by Don for VDI and https://github.com/dc42/arduino/blob.../Schematic.jpg.
- Currently with the code given below, on my LCD i'm able to see the TID numer but it's a fixed value(not changing).
************************************************
//Libraries declaration
#define TIMER1_TOP (263)
#define USE_3V3_AREF (1)
#define max_ampAverage 200
//enabling LCD
#include <LiquidCrystal.h>
LiquidCrystal lcd(6, 7, 10, 11, 12, 13); // Rs, En, D4, D5, D6, D7
//Digital pins connectivity
//arduino pins
const int calibrationPin = 2;
const int speaker = 3;
const int TxPin = 5;
const int T0InputPin = 4;
const int T0OutputPin = 9;
//Analog pins connectivity
const int receiverInputPin = A0;
int Tx = A1;
int Rx = A2;
//Variables initialization
float TxValue = 0;
float RxValue = 0;
float y;
int n = 0;
int cursorClmn = 0;
//int numSamples = 0;
float y_total;
float y_Avrg = 0;
int TID = 0;
//Declaring varaibles
// Variables used only by the ISR
int16_t bins[4];
uint16_t numSamples = 0;
const uint16_t numSamplesToAverage = 1024;
// Variables used by the ISR and outside it
volatile int16_t averages[4];
volatile bool sampleReady = false;
// Variables used only outside ISR
int16_t calib[4];
volatile uint8_t lastctr;
volatile uint16_t misses = 0;
const double halfRoot2 = sqrt(0.5);
const double quarterPi = 3.1415927/4.0;
const double radiansToDegrees = 180.0/3.1415927;
//Adjust the phase error produced after setting overflow flag of timer1
const float phaseAdjust = (45.0 * 32.0)/(float)(TIMER1_TOP + 1);
//Sensitivity adjustment(lower = greater sensitivity(can be adjusted by using a potentiomter or a rotary encoder)
float threshold = 7.0;
//Setup code here runs only one time
void setup()
{
lcd.begin(16, 2);
pinMode(calibrationPin, INPUT_PULLUP);
digitalWrite(T0OutputPin, LOW);
pinMode(T0OutputPin, OUTPUT);
digitalWrite(TxPin, LOW);
pinMode(TxPin, OUTPUT);
//Defining timers(keep track of detector oscillating Frequency
cli();
TCCR0A = 0;
TCCR0B = 0;
TIMSK0 = 0;
TIFR0 = 0x07;
TCNT0 = 0;
//Setting up timer0
TCCR0A = (1 << COM0B1) | (1 << WGM01) | (1 << WGM00);
TCCR0B = (1 << CS00) | (1 << CS01) | (1 << CS02) | (1 << WGM02);
OCR0A = 7;
OCR0B = 3;
sei();
//Initializing timer1
TCCR1A = 0;
TCCR1B = 0;
TIMSK1 = 0;
TIFR1 = 0x07;
TCNT1H = 0;
TCNT1L = 0;
//Setting up timer1
TCCR1A = (1 << COM1A1) | (1 << WGM11);
TCCR1B = (1 << WGM12) | (1 << WGM13) | (1 << CS10);
TCCR1C = 0;
OCR1AH = (TIMER1_TOP/2 >>
;
OCR1AL = (TIMER1_TOP/2 & 0xFF);
ICR1H = (TIMER1_TOP >>
;
ICR1L = (TIMER1_TOP & 0xFF);
TIMSK1 = (1 << TOIE1);
while (!sampleReady) {}
misses = 0;
sampleReady = false;
//Set up ADC to trigger and read channel 0 on timer1 overflow
#if USE_3V3_AREF
ADMUX = (1 << ADLAR);
#else
ADMUX = (1 << REFS0) | (1 << ADLAR);
#endif
ADCSRB = (1 << ADTS2) | (1 << ADTS1);
ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADATE) | (1 << ADPS2);
DIDR0 = 1;
Serial.begin(19200);
}
// Timer 0 overflow interrupt -> serves 2 purposes:
// 1. It clears the timer 0 overflow flag. If we don't do this, the ADC will not see any more Timer 0 overflows and we will not get any more conversions.
// 2. It increments the tick counter, allowing is to do timekeeping. We get 62500 ticks/second.
ISR(TIMER1_OVF_vect)
{
uint8_t ctr = TCNT0;
int16_t val = (int16_t)(uint16_t)ADCH;
if (ctr != ((lastctr + 1) & 7))
{
++misses;
}
lastctr = ctr;
int16_t *p = &bins[ctr & 3];
if (ctr < 4)
{
*p += (val);
if (*p >15000) *p = 15000;
}
else
{
*p -= val;
if (*p < -15000) *p = -15000;
}
if (ctr == 7)
{
++numSamples;
if (numSamples == numSamplesToAverage)
{
numSamples = 0;
if (!sampleReady)
{
memcpy((void*)averages, bins, sizeof(averages));
sampleReady = true;
}
memset(bins, 0, sizeof(bins));
}
}
}
//Main code to run repeatedly
void loop()
{
while (!sampleReady) {}
if (digitalRead(calibrationPin) == LOW)
{
for (int i = 0; i < 4; ++i)
{
calib[i] = averages[i];
}
lcd.setCursor(0,0);
lcd.print("Calibrating... ");
}
else
{
for (int i = 0; i < 4; ++i)
{
averages[i] -= calib[i];
}
const double f = 150.0;
// Message the results to eliminate sensitivity to the 3rd harmonic, and divide by 150
double bin0 = (averages[0] + halfRoot2 * (averages[1] - averages[3]))/f;
double bin1 = (averages[1] + halfRoot2 * (averages[0] + averages[2]))/f;
double bin2 = (averages[2] + halfRoot2 * (averages[1] + averages[3]))/f;
double bin3 = (averages[3] + halfRoot2 * (averages[2] - averages[0]))/f;
sampleReady = false; // we've finished reading the averages, so the ISR is free to overwrite them again
double amp1 = sqrt((bin0 * bin0) + (bin2 * bin2));
double amp2 = sqrt((bin1 * bin1) + (bin3 * bin3));
double ampAverage = (amp1 + amp2)/2.0;
// The ADC sample/hold takes place 2 clocks after the timer overflow
double phase1 = atan2(bin0, bin2) * radiansToDegrees + 45.0;
double phase2 = atan2(bin1, bin3) * radiansToDegrees;
if (phase1 > phase2)
{
double Equate = phase1;
phase1 = phase2;
phase2 = Equate;
}
double phaseAverage = ((phase1 + phase2)/2.0) - phaseAdjust;
if (phase2 - phase1 > 90.0)
{
if (phaseAverage < 0.0)
{
phaseAverage += 90.0;
}
else
{
phaseAverage -= 90.0;
}
}
lcd.print(" ");
if (ampAverage >= threshold)
{
if (phaseAverage < 0.0) // non-ferrous metals: -ve phase shift
{
first:
TxValue = analogRead (Tx); //it will be between 0 and 1023
RxValue = analogRead (Rx);
//Change SensorValues below to adjust VDI sensitivity
if (TxValue > 5) {
if (RxValue > 5) {
for (int n = 0 ; n < 85 ; n ++) //read Rx, Tx again in a loop 85 times
reread:
{
TxValue = analogRead(Tx);
RxValue = analogRead (Rx);
y=RxValue / TxValue;
if (y ==0) {
goto reread;
}
y_total = y_total + y;
}
}
}
else {
goto first;
}
y_Avrg = y_total/85;
TID = ((10 - y_Avrg) * 10);
cursorClmn = (10 - y_Avrg);
lcd.clear();
if (TID > 98 ) {
lcd.clear();
goto finish;
}
lcd.setCursor(0,0);
lcd.print("TID = ");
lcd.print (TID) ;
lcd.setCursor(9,0);
//if (TID = 100 ); {
// lcd.clear();
// goto finish;
//}
if ( TID > 85 ) {
lcd.print(" A");
goto DonePrinting;
}
if ( TID > 80 ) {
lcd.print (" B");
goto DonePrinting;
}
if ( TID > 71) {
lcd.print (" C");
goto DonePrinting;
}
if (TID > 39) {
lcd.print ("D");
goto DonePrinting;
}
if (TID > 0) {
lcd.setCursor (10,0);
lcd.print ("E");
goto DonePrinting;
}
} }
else
{
lcd.setCursor (10,0);
lcd.print ("F");
goto DonePrinting;
}
DonePrinting:
lcd.setCursor(0, cursorClmn);
lcd.print ("Detecting Metal");
finish:
delay (100);
numSamples = 0;
y_total = 0;
y_Avrg = 0;
y = 0;
}
}
Note:
- I have combined the schematic uploaded by Don for VDI and https://github.com/dc42/arduino/blob.../Schematic.jpg.
- Currently with the code given below, on my LCD i'm able to see the TID numer but it's a fixed value(not changing).
************************************************
//Libraries declaration
#define TIMER1_TOP (263)
#define USE_3V3_AREF (1)
#define max_ampAverage 200
//enabling LCD
#include <LiquidCrystal.h>
LiquidCrystal lcd(6, 7, 10, 11, 12, 13); // Rs, En, D4, D5, D6, D7
//Digital pins connectivity
//arduino pins
const int calibrationPin = 2;
const int speaker = 3;
const int TxPin = 5;
const int T0InputPin = 4;
const int T0OutputPin = 9;
//Analog pins connectivity
const int receiverInputPin = A0;
int Tx = A1;
int Rx = A2;
//Variables initialization
float TxValue = 0;
float RxValue = 0;
float y;
int n = 0;
int cursorClmn = 0;
//int numSamples = 0;
float y_total;
float y_Avrg = 0;
int TID = 0;
//Declaring varaibles
// Variables used only by the ISR
int16_t bins[4];
uint16_t numSamples = 0;
const uint16_t numSamplesToAverage = 1024;
// Variables used by the ISR and outside it
volatile int16_t averages[4];
volatile bool sampleReady = false;
// Variables used only outside ISR
int16_t calib[4];
volatile uint8_t lastctr;
volatile uint16_t misses = 0;
const double halfRoot2 = sqrt(0.5);
const double quarterPi = 3.1415927/4.0;
const double radiansToDegrees = 180.0/3.1415927;
//Adjust the phase error produced after setting overflow flag of timer1
const float phaseAdjust = (45.0 * 32.0)/(float)(TIMER1_TOP + 1);
//Sensitivity adjustment(lower = greater sensitivity(can be adjusted by using a potentiomter or a rotary encoder)
float threshold = 7.0;
//Setup code here runs only one time
void setup()
{
lcd.begin(16, 2);
pinMode(calibrationPin, INPUT_PULLUP);
digitalWrite(T0OutputPin, LOW);
pinMode(T0OutputPin, OUTPUT);
digitalWrite(TxPin, LOW);
pinMode(TxPin, OUTPUT);
//Defining timers(keep track of detector oscillating Frequency
cli();
TCCR0A = 0;
TCCR0B = 0;
TIMSK0 = 0;
TIFR0 = 0x07;
TCNT0 = 0;
//Setting up timer0
TCCR0A = (1 << COM0B1) | (1 << WGM01) | (1 << WGM00);
TCCR0B = (1 << CS00) | (1 << CS01) | (1 << CS02) | (1 << WGM02);
OCR0A = 7;
OCR0B = 3;
sei();
//Initializing timer1
TCCR1A = 0;
TCCR1B = 0;
TIMSK1 = 0;
TIFR1 = 0x07;
TCNT1H = 0;
TCNT1L = 0;
//Setting up timer1
TCCR1A = (1 << COM1A1) | (1 << WGM11);
TCCR1B = (1 << WGM12) | (1 << WGM13) | (1 << CS10);
TCCR1C = 0;
OCR1AH = (TIMER1_TOP/2 >>

OCR1AL = (TIMER1_TOP/2 & 0xFF);
ICR1H = (TIMER1_TOP >>

ICR1L = (TIMER1_TOP & 0xFF);
TIMSK1 = (1 << TOIE1);
while (!sampleReady) {}
misses = 0;
sampleReady = false;
//Set up ADC to trigger and read channel 0 on timer1 overflow
#if USE_3V3_AREF
ADMUX = (1 << ADLAR);
#else
ADMUX = (1 << REFS0) | (1 << ADLAR);
#endif
ADCSRB = (1 << ADTS2) | (1 << ADTS1);
ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADATE) | (1 << ADPS2);
DIDR0 = 1;
Serial.begin(19200);
}
// Timer 0 overflow interrupt -> serves 2 purposes:
// 1. It clears the timer 0 overflow flag. If we don't do this, the ADC will not see any more Timer 0 overflows and we will not get any more conversions.
// 2. It increments the tick counter, allowing is to do timekeeping. We get 62500 ticks/second.
ISR(TIMER1_OVF_vect)
{
uint8_t ctr = TCNT0;
int16_t val = (int16_t)(uint16_t)ADCH;
if (ctr != ((lastctr + 1) & 7))
{
++misses;
}
lastctr = ctr;
int16_t *p = &bins[ctr & 3];
if (ctr < 4)
{
*p += (val);
if (*p >15000) *p = 15000;
}
else
{
*p -= val;
if (*p < -15000) *p = -15000;
}
if (ctr == 7)
{
++numSamples;
if (numSamples == numSamplesToAverage)
{
numSamples = 0;
if (!sampleReady)
{
memcpy((void*)averages, bins, sizeof(averages));
sampleReady = true;
}
memset(bins, 0, sizeof(bins));
}
}
}
//Main code to run repeatedly
void loop()
{
while (!sampleReady) {}
if (digitalRead(calibrationPin) == LOW)
{
for (int i = 0; i < 4; ++i)
{
calib[i] = averages[i];
}
lcd.setCursor(0,0);
lcd.print("Calibrating... ");
}
else
{
for (int i = 0; i < 4; ++i)
{
averages[i] -= calib[i];
}
const double f = 150.0;
// Message the results to eliminate sensitivity to the 3rd harmonic, and divide by 150
double bin0 = (averages[0] + halfRoot2 * (averages[1] - averages[3]))/f;
double bin1 = (averages[1] + halfRoot2 * (averages[0] + averages[2]))/f;
double bin2 = (averages[2] + halfRoot2 * (averages[1] + averages[3]))/f;
double bin3 = (averages[3] + halfRoot2 * (averages[2] - averages[0]))/f;
sampleReady = false; // we've finished reading the averages, so the ISR is free to overwrite them again
double amp1 = sqrt((bin0 * bin0) + (bin2 * bin2));
double amp2 = sqrt((bin1 * bin1) + (bin3 * bin3));
double ampAverage = (amp1 + amp2)/2.0;
// The ADC sample/hold takes place 2 clocks after the timer overflow
double phase1 = atan2(bin0, bin2) * radiansToDegrees + 45.0;
double phase2 = atan2(bin1, bin3) * radiansToDegrees;
if (phase1 > phase2)
{
double Equate = phase1;
phase1 = phase2;
phase2 = Equate;
}
double phaseAverage = ((phase1 + phase2)/2.0) - phaseAdjust;
if (phase2 - phase1 > 90.0)
{
if (phaseAverage < 0.0)
{
phaseAverage += 90.0;
}
else
{
phaseAverage -= 90.0;
}
}
lcd.print(" ");
if (ampAverage >= threshold)
{
if (phaseAverage < 0.0) // non-ferrous metals: -ve phase shift
{
first:
TxValue = analogRead (Tx); //it will be between 0 and 1023
RxValue = analogRead (Rx);
//Change SensorValues below to adjust VDI sensitivity
if (TxValue > 5) {
if (RxValue > 5) {
for (int n = 0 ; n < 85 ; n ++) //read Rx, Tx again in a loop 85 times
reread:
{
TxValue = analogRead(Tx);
RxValue = analogRead (Rx);
y=RxValue / TxValue;
if (y ==0) {
goto reread;
}
y_total = y_total + y;
}
}
}
else {
goto first;
}
y_Avrg = y_total/85;
TID = ((10 - y_Avrg) * 10);
cursorClmn = (10 - y_Avrg);
lcd.clear();
if (TID > 98 ) {
lcd.clear();
goto finish;
}
lcd.setCursor(0,0);
lcd.print("TID = ");
lcd.print (TID) ;
lcd.setCursor(9,0);
//if (TID = 100 ); {
// lcd.clear();
// goto finish;
//}
if ( TID > 85 ) {
lcd.print(" A");
goto DonePrinting;
}
if ( TID > 80 ) {
lcd.print (" B");
goto DonePrinting;
}
if ( TID > 71) {
lcd.print (" C");
goto DonePrinting;
}
if (TID > 39) {
lcd.print ("D");
goto DonePrinting;
}
if (TID > 0) {
lcd.setCursor (10,0);
lcd.print ("E");
goto DonePrinting;
}
} }
else
{
lcd.setCursor (10,0);
lcd.print ("F");
goto DonePrinting;
}
DonePrinting:
lcd.setCursor(0, cursorClmn);
lcd.print ("Detecting Metal");
finish:
delay (100);
numSamples = 0;
y_total = 0;
y_Avrg = 0;
y = 0;
}
}
Comment