Thanks Martin,
Loads of good info to get going with.
Much appreciated
Loads of good info to get going with.
Much appreciated


[I] delayVal = analogRead(delayPin); // Read the delay pot[/I] [I] mainDelay = defMainDelay + delayVal * clockCycle; // Offset main sample delay[/I]
[I]mainDelay = defMainDelay + (delayVal >> 1) * clockCycle; // Offset main sample delay[/I]
[I]mainDelay = defMainDelay + (delayVal >> 2) * clockCycle; // Offset main sample delay[/I]
[I] word potRead = 0; ... ... potRead = analogRead(delayPin); // Read the delay pot [/I] [I]if ([/I][I]potRead [/I][I]> (delayVal + 16)) delayVal = [/I][I]potRead [/I][I]- 16; else if [/I][I]([/I][I]potRead [/I][I]< (delayVal - 16)) delayVal = [/I][I]potRead [/I][I]+ 16;[/I] [I] mainDelay = defMainDelay + delayVal * clockCycle; // Offset main sample delay[/I]
// Arduino Pulse Induction Metal Detector
// Pin assignments
byte txPin = 8; // Assign pin 8 to TX output
byte mainSamplePin = 9; // Assign pin 9 to main sample pulse
byte efeSamplePin = 10; // Assign pin 10 to EFE sample pulse
byte audioPin = 11; // Assign pin 11 to audio chopper
byte boostPin = 12; // Assign pin 12 to boost switch
byte delayPin = A0; // Assign delay pot to A0
// Program constants
const float normalPower = 50E-6; // Normal TX-on time (50us)
const float boostPower = 100E-6; // Boost TX-on time (100us)
const float clockCycle = 62.5E-9; // Time for one clock cycle (1/16MHz)
const unsigned long maxCount = 65535; // Value of 2^16 - 1
const byte readDelayLimit = 100; // Wait 100 TX periods (100ms) before reading delay pot
const byte mosfetOn = HIGH; // Mosfet turns on when transmitter input high
const byte mosfetOff = LOW; // Mosfet turns off when transmitter input low
const byte syncDemodOn = LOW; // Sample gate turns on when input high
const byte syncDemodOff = HIGH; // Sample gate turns off when input low
// Detector timings
float txOn = normalPower; // TX-on time using normal power mode
float defMainDelay = 10E-6; // Default main sample delay (10us)
float mainDelay = defMainDelay; // Main sample pulse delay
float mainSample = 50E-6; // Main sample pulse width (50us)
float efeDelay = 240E-6; // EFE sample pulse delay (240us)
float efeSample = mainSample; // EFE sample pulse width (same as main sample)
float txPeriod = 1E-3; // TX period (1ms)
// Timing offsets
float txOnOffset = 3E-6; // TX-on pulse offset (3us)
float mainDelayOffset = 4.2E-6; // Main delay pulse offset (4.2us)
float mainSampleOffset = 3E-6; // Main sample pulse offset (3us)
float efeDelayOffset = 12E-6; // EFE delay pulse offset (12us)
float efeSampleOffset = 4E-6; // EFE sample pulse offset (4us)
float txPeriodOffset = 30E-6; // TX period offset (30us)
// Program variables
float temp1, temp2, temp3, temp4, temp5, temp6; // Intermediate calculation variables
word txOnCount; // TX pulse
word mainDelayCount; // Main sample delay
word mainSampleCount; // Main sample pulse
word efeDelayCount; // EFE sample delay
word efeSampleCount; // EFE sample pulse
word txPeriodCount; // TX period
word potValue; // Voltage at the delay pot
word delayVal = 0; // Delay pot value
boolean readDelayPot = false; // Delay pot read (true or false)
byte intState = 0; // Interrupt state machine
byte readDelayCounter = 0; // Read delay pot counter
void setup() {
pinMode(txPin, OUTPUT); // Set TX pin to output mode
pinMode(mainSamplePin, OUTPUT); // Set main sample pin to output mode
pinMode(efeSamplePin, OUTPUT); // Set EFE sample pin to output mode
pinMode(boostPin, INPUT_PULLUP); // Set Boost switch pin to input mode with pullup resistor
calcTimerValues(); // Calculate all timer values
noInterrupts(); // Disable interrupts
TCCR1A = 0; // Initialize Timer1 registers
TCCR1B = 0;
TIMSK0 = 0; // Clear Timer0 mask register to eliminate jitter
TCNT1 = txOnCount; // Load Timer1 with TX-on count
TCCR1B |= (1 << CS10); // No prescaling for Timer1
TIMSK1 |= (1 << TOIE1); // Enable Timer1 overflow interrupt
interrupts(); // Enable interrupts
analogWrite(audioPin, 127); // Set audioPin with 50% duty cycle PWM
}
void calcTimerValues() {
if (digitalRead(boostPin) == HIGH) { // Get boost switch position
txOn = normalPower; // Set TX-on to 50us if HIGH
} else {
txOn = boostPower; // Set TX-on to 100us if LOW
}
temp1 = (txOn - txOnOffset) / clockCycle;
txOnCount = maxCount - int(temp1); // TX-on count for Timer1
temp2 = (mainDelay - mainDelayOffset) / clockCycle;
mainDelayCount = maxCount - int(temp2); // Main sample delay count for Timer1
temp3 = (mainSample - mainSampleOffset) / clockCycle;
mainSampleCount = maxCount - int(temp3); // Main sample pulse count for Timer1
temp4 = (efeDelay - efeDelayOffset) / clockCycle;
temp4 -= temp3 + temp2;
efeDelayCount = maxCount - int(temp4); // EFE sample delay count for Timer1
temp5 = (efeSample - efeSampleOffset) / clockCycle;
efeSampleCount = maxCount - int(temp5); // EFE sample pulse count for Timer 1
temp6 = (txPeriod - txPeriodOffset) / clockCycle;
temp6 -= temp1 + temp2 + temp3 + temp4 + temp5;
txPeriodCount = maxCount - int(temp6); // TX period count for Timer1
}
ISR(TIMER1_OVF_vect) {
switch (intState) {
case 0:
TCNT1 = txOnCount; // Load Timer1 with TX-ON count
digitalWrite(txPin, mosfetOn); // Turn on Mosfet
intState = 1;
break;
case 1:
TCNT1 = mainDelayCount; // Load Timer1 with main sample delay count
digitalWrite(txPin, mosfetOff); // Turn off Mosfet
intState = 2;
break;
case 2:
TCNT1 = mainSampleCount; // Load Timer1 with main sample pulse count
digitalWrite(mainSamplePin, syncDemodOn); // Turn on main sample gate
intState = 3;
break;
case 3:
TCNT1 = efeDelayCount; // Load Timer1 with EFE sample delay count
digitalWrite(mainSamplePin, syncDemodOff); // Turn off main sample gate
if (readDelayPot == false) { // Check if read delay pot flag is false
readDelayCounter++; // Increment read delay counter
if (readDelayCounter >= readDelayLimit) { // Check if read delay counter has reached limit
readDelayPot = true; // Enable read of delay pot
readDelayCounter = 0; // Clear read delay counter
}
}
intState = 4;
break;
case 4:
TCNT1 = efeSampleCount; // Load Timer1 with EFE sample pulse count
digitalWrite(efeSamplePin, syncDemodOn); // Turn on EFE sample gate
intState = 5;
break;
case 5:
TCNT1 = txPeriodCount; // Load Timer1 with TX period count
digitalWrite(efeSamplePin, syncDemodOff); // Turn off EFE sample gate
intState = 0;
break;
default:
intState = 0;
break;
}
}
void loop() {
if (readDelayPot == true) {
potRead = analogRead(delayPin); // Read the delay pot
if (potRead > (delayVal + 16)) delayVal = potRead - 16;
else if (potRead < (delayVal - 16)) delayVal = potRead + 16;
mainDelay = defMainDelay + delayVal * clockCycle; // Offset main sample delay
calcTimerValues(); // Calculate new timer values
readDelayPot = false; // Set read delay pot flag to false
}
}
// Arduino Pulse Induction Metal Detector
// Pin assignments
byte txPin = 8; // Assign pin 8 to TX output
byte mainSamplePin = 9; // Assign pin 9 to main sample pulse
byte efeSamplePin = 10; // Assign pin 10 to EFE sample pulse
byte audioPin = 11; // Assign pin 11 to audio chopper
byte boostPin = 12; // Assign pin 12 to boost switch
byte delayPin = A0; // Assign delay pot to A0
// Program constants
const float normalPower = 50E-6; // Normal TX-on time (50us)
const float boostPower = 100E-6; // Boost TX-on time (100us)
const float clockCycle = 62.5E-9; // Time for one clock cycle (1/16MHz)
const unsigned long maxCount = 65535; // Value of 2^16 - 1
const byte readDelayLimit = 100; // Wait 100 TX periods (100ms) before reading delay pot
const byte mosfetOn = HIGH; // Mosfet turns on when transmitter input high
const byte mosfetOff = LOW; // Mosfet turns off when transmitter input low
const byte syncDemodOn = LOW; // Sample gate turns on when input high
const byte syncDemodOff = HIGH; // Sample gate turns off when input low
// Detector timings
float txOn = normalPower; // TX-on time using normal power mode
float defMainDelay = 10E-6; // Default main sample delay (10us)
float mainDelay = defMainDelay; // Main sample pulse delay
float mainSample = 50E-6; // Main sample pulse width (50us)
float efeDelay = 240E-6; // EFE sample pulse delay (240us)
float efeSample = mainSample; // EFE sample pulse width (same as main sample)
float txPeriod = 1E-3; // TX period (1ms)
// Timing offsets
float txOnOffset = 3E-6; // TX-on pulse offset (3us)
float mainDelayOffset = 4.2E-6; // Main delay pulse offset (4.2us)
float mainSampleOffset = 3E-6; // Main sample pulse offset (3us)
float efeDelayOffset = 12E-6; // EFE delay pulse offset (12us)
float efeSampleOffset = 4E-6; // EFE sample pulse offset (4us)
float txPeriodOffset = 30E-6; // TX period offset (30us)
// Program variables
float temp1, temp2, temp3, temp4, temp5, temp6; // Intermediate calculation variables
word txOnCount; // TX pulse
word mainDelayCount; // Main sample delay
word mainSampleCount; // Main sample pulse
word efeDelayCount; // EFE sample delay
word efeSampleCount; // EFE sample pulse
word txPeriodCount; // TX period
word potRead; // Voltage at the delay pot
word delayVal = 0; // Delay pot value
boolean readDelayPot = false; // Delay pot read (true or false)
byte intState = 0; // Interrupt state machine
byte readDelayCounter = 0; // Read delay pot counter
void setup() {
pinMode(txPin, OUTPUT); // Set TX pin to output mode
pinMode(mainSamplePin, OUTPUT); // Set main sample pin to output mode
pinMode(efeSamplePin, OUTPUT); // Set EFE sample pin to output mode
pinMode(boostPin, INPUT_PULLUP); // Set Boost switch pin to input mode with pullup resistor
calcTimerValues(); // Calculate all timer values
noInterrupts(); // Disable interrupts
TCCR1A = 0; // Initialize Timer1 registers
TCCR1B = 0;
TIMSK0 = 0; // Clear Timer0 mask register to eliminate jitter
TCNT1 = txOnCount; // Load Timer1 with TX-on count
TCCR1B |= (1 << CS10); // No prescaling for Timer1
TIMSK1 |= (1 << TOIE1); // Enable Timer1 overflow interrupt
interrupts(); // Enable interrupts
analogWrite(audioPin, 127); // Set audioPin with 50% duty cycle PWM
}
void calcTimerValues() {
if (digitalRead(boostPin) == HIGH) { // Get boost switch position
txOn = normalPower; // Set TX-on to 50us if HIGH
} else {
txOn = boostPower; // Set TX-on to 100us if LOW
}
temp1 = (txOn - txOnOffset) / clockCycle;
txOnCount = maxCount - int(temp1); // TX-on count for Timer1
temp2 = (mainDelay - mainDelayOffset) / clockCycle;
mainDelayCount = maxCount - int(temp2); // Main sample delay count for Timer1
temp3 = (mainSample - mainSampleOffset) / clockCycle;
mainSampleCount = maxCount - int(temp3); // Main sample pulse count for Timer1
temp4 = (efeDelay - efeDelayOffset) / clockCycle;
temp4 -= temp3 + temp2;
efeDelayCount = maxCount - int(temp4); // EFE sample delay count for Timer1
temp5 = (efeSample - efeSampleOffset) / clockCycle;
efeSampleCount = maxCount - int(temp5); // EFE sample pulse count for Timer 1
temp6 = (txPeriod - txPeriodOffset) / clockCycle;
temp6 -= temp1 + temp2 + temp3 + temp4 + temp5;
txPeriodCount = maxCount - int(temp6); // TX period count for Timer1
}
ISR(TIMER1_OVF_vect) {
switch (intState) {
case 0:
TCNT1 = txOnCount; // Load Timer1 with TX-ON count
digitalWrite(txPin, mosfetOn); // Turn on Mosfet
intState = 1;
break;
case 1:
TCNT1 = mainDelayCount; // Load Timer1 with main sample delay count
digitalWrite(txPin, mosfetOff); // Turn off Mosfet
intState = 2;
break;
case 2:
TCNT1 = mainSampleCount; // Load Timer1 with main sample pulse count
digitalWrite(mainSamplePin, syncDemodOn); // Turn on main sample gate
intState = 3;
break;
case 3:
TCNT1 = efeDelayCount; // Load Timer1 with EFE sample delay count
digitalWrite(mainSamplePin, syncDemodOff); // Turn off main sample gate
if (readDelayPot == false) { // Check if read delay pot flag is false
readDelayCounter++; // Increment read delay counter
if (readDelayCounter >= readDelayLimit) { // Check if read delay counter has reached limit
readDelayPot = true; // Enable read of delay pot
readDelayCounter = 0; // Clear read delay counter
}
}
intState = 4;
break;
case 4:
TCNT1 = efeSampleCount; // Load Timer1 with EFE sample pulse count
digitalWrite(efeSamplePin, syncDemodOn); // Turn on EFE sample gate
intState = 5;
break;
case 5:
TCNT1 = txPeriodCount; // Load Timer1 with TX period count
digitalWrite(efeSamplePin, syncDemodOff); // Turn off EFE sample gate
intState = 0;
break;
default:
intState = 0;
break;
}
}
void loop() {
if (readDelayPot == true) {
potRead = analogRead(delayPin); // Read the delay pot
/* update delayVal with hysteresis to avoid ADC and pot jitter */
if (potRead > (delayVal + 16)) delayVal = potRead - 16;
else if (potRead < (delayVal - 16)) delayVal = potRead + 16;
mainDelay = defMainDelay + delayVal * clockCycle; // Offset main sample delay
calcTimerValues(); // Calculate new timer values
readDelayPot = false; // Set read delay pot flag to false
}
}

Comment