При помощи контроллера Arduino можно собрать простейший детектор металла.
Кроме контроллера, для этого понадобится всего несколько деталей: катушка из проволоки (60 витков провода 0.4 мм, диаметр — 6.3 см), резистор (100 Ом) и конденсатор (10 мкФ). Для звуковой индикации используется обычный бузер.
Используя Arduino Nano и 9-вольтовую батарейку (типа Крона) — можно уместить всё устройство в коробочку из-под тик-така.
Код для Arduino — metal_detector.ino
//Metal detector based on pulse delay in LR circuit
//Connect a coil beween pin 10 and pin 8,
//a 100 Ohm resistor between pin 8 and ground,
//a speaker in series with a 10muF capacitor between pin 12 and ground,
//a reset-button between A0 and ground.
//Reference coil: 60 turns, diameter 6cm, AWG26 (0.4mm) wire. L~300muH, R~2Ohm
//
//R. Oldeman Oct 11 2020, CC BY-NC-SA 4.0 licence
#define debug false
//some parameters
#define sensitivity 5000 //threshold as a fraction of reference
#define aimtime 160000 //aim for measurement every 160k cycles (=10ms)
#define LEDpulselen 16000 //length of the LED pulse in clock cycles
#define cycles 40 //number of clock cycles reserved for calculations
#define printfrac 50 //fraction of measurements printed when in debug mode
//pin definitions - cannot change freely!
#define pulsepin 10 //must be pin 10 - TIMER1B output
#define probepin 8 //must be pin 8 - input capture pin
#define LEDpin 13 //if changed also need to update the direct-port writing
#define soundpin 12 //if changed also need to update the direct-port writing
#define resetpin A0 //can be changed freely
//global variables - shared between main loop and measurement function
long int imeas=0; //counts the number of measurements performed
int absdiff; //absolute value of difference wrt reference
long int phase=0; //tracks integral of absdiff
long int phasemax; //value at which the phase counter turns over
int LEDcycles=0; //number of cycles that the LED pin stays high
int LEDcycle=0; //cycle index of the LED pulse
void setup() {
noInterrupts(); //disable all inerrupts to avoid glitches
if(debug)Serial.begin(9600);
pinMode(pulsepin,OUTPUT);
digitalWrite(pulsepin,LOW);
pinMode(probepin,INPUT);
pinMode(LEDpin,OUTPUT);
digitalWrite(LEDpin,LOW);
pinMode(soundpin,OUTPUT);
digitalWrite(soundpin,LOW);
pinMode(resetpin,INPUT_PULLUP);
//setup timer1 to FASTPWM on pin 10
TCCR1A=0B00100011;
TCCR1B=0B00011001;
}
//perform measurement of delay of the trailing edge
long int meas(int period, int minlen, int maxlen, int steplen, int nloop){
long int sum=0;
int nmiss=0;
OCR1A=period; //set the period
TIFR1 |= 0B00000001; //clear the timer overflow bit
for(int iloop=0; iloopphasemax){
phase-=phasemax;
LEDcycle=LEDcycles;
PORTB=(PORTB|0B00100000); //switch on LED
PORTB=(PORTB^0B00010000); //invert sound pin - click!
}
//switch off LED when it's been on long enough
if(LEDcycle>0){
LEDcycle--;
if(LEDcycle==0)PORTB=(PORTB&(!0B00100000));
}
}
}
if (nmiss>0)sum=0; //invalidate the result if there have been missing pulses
return sum;
}
//flash LED with error code indefinitely if there's been an error
void go_error(byte errorcode){
if(debug){
Serial.print("ERROR ");
Serial.print(errorcode);
if(errorcode==1)Serial.println(": No pulse on probe pin - check connections");
if(errorcode==2)Serial.println(": Delay too short - try more windings");
if(errorcode==3)Serial.println(": Delay too long - try fewer windings");
if(errorcode==4)Serial.println(": No robust pulse on pulselength scan - check coil resistance");
}
//enable in interrupts to use delay() and flash to indicate error code
interrupts();
while(true){
for(byte i=0; i800)go_error(3); // too long
//choose pulsing parmeters based on measured delay time
int minlen=3*tau;
int maxlen=5*tau;
int period=maxlen+2*tau+cycles;
LEDcycles=LEDpulselen/period+1;
// repeat loop or speed up loop to approach aimed duration of measurement
int steplen=1;
int nloop=1;
float tottime=float(period)*(maxlen-minlen);
if (tottime>aimtime*(3.0/2.0)) steplen=round(tottime/aimtime);
if (tottime0)ref+=1; //absorb slow drifts
if(diff<0)ref-=1;
}
if(debug){
sum+=diff;
sumsq+=long(diff)*long(diff);
if (imeas%printfrac==0){
float mean=float(sum)/printfrac;
float rms=sqrt( (float(sumsq)/printfrac) - pow(mean,2.0) );
Serial.print(imeas);
Serial.print(" val ref diff phase ");
Serial.print(val);
Serial.print(" ");
Serial.print(ref);
Serial.print(" ");
Serial.print(diff);
Serial.print(" ");
Serial.print(mean);
Serial.print(" ");
Serial.print(rms);
Serial.println("");
sum=0; sumsq=0;
}
}
imeas++;
}
}
Ссылки
Minimal Arduino Metal Detector
По теме
Металлоискатель на Arduino
Arduino
Arduino, термины, начало работы
КМБ для начинающих ардуинщиков
Состав стартера (точка входа для начинающих ардуинщиков)
