Доработка металлоискателя Пират
(11-11-2025, 17:58)vako : А когда происходит измерение? В какой момент Вы опрашиваете ацп?
Да отвечал вроде бы как?
В цикле while замеряю 100 миллисекудны и опрашиваю цап. analogRead(INPUT_PIN)
Код:
while (millis() - startTime < 100) {        // Цикл 100 мс.
    int currentValue = analogRead(INPUT_PIN); // Считываю

(11-11-2025, 17:58)vako : И зачем делать регулировку считывания?
Сделаю так:
Зайдите в: ///// Амплитуда и звуковые схемы /////
Далее через if else if (amplitude > 300)
Регулировать двумя кнопками буду именно  (amplitude > 300).
Просто я на глаз выставил значение 300. При 285 уже можно начинать делать озвучку и индикацию. так вот с 285 до 300 я сделаю шкалу с шагом 1. И это будет как чувствительность.

(11-11-2025, 17:58)vako : ко времени
Я привязан к 100 миллисекундам.

В этом цикле я сравниваю минимальное и максимальное в течении 100 , обновляюсь  и нахожу разницу. На этой разнице я сделал алгоритм включения индикации и звука. Разница начинается от 285 и больше. А дальше уже через  if.

Код:
///// Измерение амплитуды на пине A0 /////
                       
  unsigned long startTime = millis();         // Сохраняю время
  int maxValue = 0;                           // максимальное значение для переменной
  int minValue = 1023;                        // минимальное значение для переменной
  while (millis() - startTime < 100) {        // Цикл 100 мс.
    int currentValue = analogRead(INPUT_PIN); // Считываю
    if (currentValue > maxValue) {            // Если текущее > максимального
      maxValue = currentValue;                // Обновляю максимальное
    }
    if (currentValue < minValue) {            // Если текущее < минимального
      minValue = currentValue;                // Обновляю минимальное
    }
  }
  int amplitude = maxValue - minValue;        // Калькулятор амплитуды
(11-11-2025, 18:16)-vlad- : (amplitude > 300).
При этой разнице уже красивая осцилограмма. Захват уверенный монетки где то 15 см уже!!!
А при amplitude > 285 начинает строится картинка и Пират ещё балаболит.
Так вот, или энкодером сделаю или кнопкам эту шкалу с шагом +1 или -1.

Ну а на шкалу от 285-300, сделаю озвучку...ну скажем tone(SPEAKER_PIN, 10). Она будет похожа на счетчик Гейгера в Пирате 111
(11-11-2025, 18:16)-vlad- : Да отвечал вроде бы как?
Вы наверное не понимаете, что я спрашиваю. На картинке белым сигнал после оу, желтый это то что на катушке. На белом сигнале прямоугольник это время открытия транзистора, после него идёт полезный сигнал, который надо анализировать. Там микросекунды и ацп надо запускать относительно фронта закрытия транзистора.

Файлы вложений Эскизы
   
#498 я и работаю с этим сигналом после ОУ.
Не с желтым, а с белым.
Покажите белый сигнал без цели и с целью. Он будет похож на мой корявенький с поста 498. Не с импульсом накачки, а с измерительным работаю (отметил красным).

Файлы вложений Эскизы
   
-vlad-, Вы делаете за 100мс около 1000 выборок ацп (100мкс). Это подойдёт для медленных сигналов, а у вас сигнал короткий и куда там эти выборки попадают неизвестно. Ацп у меги медленный, поэтому можно сделать допустим 100 выборок со сдвигом в 5-10мкс, а для этого надо привязаться к спаду импульса на затворе это ваш 9 пин.
vako, Да я уже Кену и gal и вам говорю, мне бы ваши познания в программировании...я бы такие вещи делал!!! Пока по такому принципу сделал (А0), подучусь чуть и дальше продолжу в другом коде, а этот уже оставлю как есть.
Threshold сделал на 2 кнопках и привязал к первому светодиоду (ledPin4 и SPEAKER_PIN, 1).

Теперь с ОУ идет сигнал и шкала регулировки от 150 до 399.
int threshold = 185;                // Начальный порог (ЧУВСТВИТЕЛЬНОСТЬ)

Если в своем бардаке найду 555, возможно на макетке протестирую сегодня. [attachment=9017]
-vlad-,вот пример, как реализовать чтение ацп со смещением.
Код:
#include <avr/interrupt.h>
#include <SPI.h>
#include <Wire.h>

// операции с битами
#define SetBit(x,y) (x|=(1<<y))
#define ClrBit(x,y) (x&=~(1<<y))
#define ToggleBit(x,y) (x^=(1<<y))
#define FlipBit(x,y) (x^=(1<<y)) // Same as ToggleBit. 
#define TestBit(x,y) (x&(1<<y))

#define adc_in A0  // вход сигнала

volatile int dutyCycleD10 = 2000;      //
const int pwmPin9 = 9;               // D9 Пин для IRF740 и катушки
const int pwmPin10 = 10;             // D10 для регулировки Чувствительности
const int pintest = 8;             // D10 для регулировки Чувствительности
volatile int nopdelay = 6;   //для цикла задержки nop 10мкс
volatile int i=0;
volatile int j=0;
volatile int adcdata[10]; // массив данных
volatile bool dataready = false; //готовность данных
volatile int sample_number=1;
volatile int mksdelay=0;

  void setup() {
  // put your setup code here, to run once:
   Serial.begin(250000);
   noInterrupts();

pinMode(pwmPin9, OUTPUT);                       // D9 Пин для IRF740 и катушки
pinMode(pwmPin10, OUTPUT);                      // D10 для регулировки Чувствительности
pinMode(pintest, OUTPUT);
     ///// ТАЙМЕР 1 Генерирую частоту 125Гц125мс(D9) и регулирую напряжение(D10)/////
                             ///// Подсказка от KEN /////
    
  TCCR1A = 0;
  TCCR1B = 0;
  TCCR1A |= (1 << WGM11);
  TCCR1B |= (1 << WGM13) | (1 << WGM12);
  TCCR1A |= (1 << COM1A1) | (1 << COM1B1);
  TCCR1A |= (1 << COM1A0); //инверсный шим
  TCCR1B |= (1 << CS11);
  ICR1 = 15999;           // ЧАСТОТА
  OCR1A = 255;            // ШИРИНА ИМПУЛЬСА
  OCR1B = dutyCycleD10;   // D10 при включении
  TIMSK1 |= (1 << OCIE1A); // Output Compare A Match Interrupt Enable
  interrupts();



}

void loop() {
  // put your main code here, to run repeatedly:
  if (dataready)
  {
    //SetBit(PORTB,0);//test
//   Serial.println("begin");
    Serial.print("номер выборки=");
    Serial.print(sample_number);
    Serial.println();
    for(j=0;j<10;j++)
    {
      Serial.println(adcdata[j]);
     
    }
//    Serial.println("tnd");
    dataready=false;
    //ClrBit(PORTB,0);//test
  }

}

   ISR(TIMER1_COMPA_vect) {
  // изменения состояния пина D9 (фронт)
  //SetBit(PORTB,0);//test
  nopdelay=6;//задержка 10мкс
  //sample_number=10;//test
  mksdelay=nopdelay*sample_number; //смещение
  for(i=0;i<mksdelay;i++){asm("NOP");}
  SetBit(PORTB,0);//test
  for(i=0;i<10;i++){adcdata[i]=analogRead(adc_in);}
  dataready = true;
  sample_number++;
  if(sample_number>10){sample_number=1;}
  ClrBit(PORTB,0);//test
  }
это осциллограммы:
   
Это старт первых 10 выборок после закрытия транзистора с задержкой около 15мкс
   
Это старт последних 10 выборок ацп.
   
Это общее время 10 выборок
-vlad-, и уберите оптрон и крутилку, от них всё равно никакого толку, надо просто поставить делитель на выход оу и с него снимать сигнал. Кнопки лучше от дребезга защитить аппаратно rc цепочкой: 1к на +5в и конденсатор 0.1 на землю.  Вместо электролита 1мкф на входе оу поставьте плёнку или на худой конец керамику.
vako, Блин, спасибо конечно за пример кода, но с битами... но , что то знакомое вижу, а что то вообще для меня мрак. Эта для меня ещё сложная тема, очень сложная. Тут вообще другой принцип обработки сигнала и я понимаю, почему в преведущих постах мы говорили на разных языках. Тут для меня ещё темный лес. Так то свой код я пишу по вечерам, страничку книжки почитал и сделал какие то заметки и реализовался в чем то. Вообще с выборками интересная тема. Смещение. Просто когда сам пишешь, то что то в голове откладывается и понимаешь что происходит в коде.

По поводу крутилки, я её оставлю пока. Ну........она мне нужна пока, в моем случае если с квартиры я выйду на улицу, то там пару-тройку сантиметров я могу выиграть ещё к моим 15 см на монетку. Мне нужна грубая настройка в не квартиры. Хотя можно выйти на улицу, найти точку подстроечником, вернуться домой и в мониторе порта посмотреть значение :
Serial.print("Current threshold: ");
Serial.println(threshold);
И это значение вписать в (по умолчанию):
int threshold = 185; // Начальный порог (ЧУВСТВИТЕЛЬНОСТЬ)

Кнопки. Я сделал PULLUP, только из тех побуждений, что бы меньше было на столе проводов и соплей на макетке.

От (DutyCycle) я избавился с глупой идеей с D10 - впихнуть то, что туда не следует впихивать и мешать такие сигналы.
Чувствительность я по другому сделал. Отправил код.
-vlad-, с битами всё просто. Это работает в несколько раз быстрее, чем ардуиновские абстракции. Вот например SetBit(PORTB,0); означает, что надо установить в 1  бит 0 в порту В, ClrBit это сбросить бит в 0, аналог digitalWrite, только быстрее. Если взять распиновку ардуины нано
распиновка то 0 биту порта В соответствует ножка D8 или 8 на плате ардуино.

(12-11-2025, 22:14)-vlad- : Тут для меня ещё темный лес.
Там нет ничего сложного. Просто из за медленного ацп считывание сигнала идёт со смещением, правда для этого нужно десять сигналов, но я не думаю, что за 80мс что то кардинально изменится.

(12-11-2025, 22:14)-vlad- : Кнопки. Я сделал PULLUP, только из тех побуждений, что бы меньше было на столе проводов и соплей на макетке.
В подтяжке стоят резисторы почти 100к, что для кнопок не очень хорошо. Резистор надо ставить меньше, у кнопок есть минимальный ток коммутации.