#1 2025-06-07 20:25:21

Kvins
Учасник
Зареєстрований: 2025-06-07
Повідомлень: 12

Допомога з написанням коду Arduino Nano (Arduino IDE)

Всім міцного!

Хлопці потребую допомоги у написанні скетчу.

Задача:
Маємо PWM сигнал з іншого пристрою, треба з нього по команді (умова (average < 20)), перетворити на логічну одиницю і якщо через деякий час  ще буде такий саме імпульс, на нуль.  Використовую порт з LED, щоб бачити як відпрацьовує логіка.

#define NUM_READINGS 500
int average;
int outPin = 13;

void setup() {
  digitalWrite(13, LOW);
  Serial.begin(9600);
}
void loop() {
  long sum = 0;                                  // локальна змінна sum
  for (int i = 0; i < NUM_READINGS; i++) {      // згідно з кількістю усереднень
    sum += analogRead(0);                        // сумуємо значення з датчика змінної sum
  }
  average = sum / NUM_READINGS;                  // знаходимо середнє арифметичне, поділивши суму на число вимірів
  Serial.println(average);                       // для прикладу виводимо в порт
  if (average < 20) {                             // умова на потрібний імпульс (шим)
  digitalWrite(outPin, HIGH);                // робимо високий рівень
 
    } else {
  
    digitalWrite(13, LOW);
  }
}

Є нюанс, справа в тому, що імпульс пробігає декілька разів і в мене, порт падає в LOW. Можливо, я все роблю не правильно, є інший алгоритм...
Підскажіть як це можна реалізувати.
Дякую! smile

Неактивний

#2 2025-06-07 23:23:45

dimich
Учасник
Зареєстрований: 2023-12-01
Повідомлень: 445

Re: Допомога з написанням коду Arduino Nano (Arduino IDE)

Kvins пише:

Маємо PWM сигнал з іншого пристрою

Яка частота PWM? Якщо не фіксована, то який допустимий діапазон: мінімум та максимум?

Якщо це PWM, чому ви читаєте аналогове значення, а не дискретне? Чи PWM попередньо фільтрується, і на вході аналоговий сигнал? Тоді яка різниця, як він формується, PWM чи іншим способом?

Kvins пише:

треба з нього по команді (умова (average < 20))

Вважаючи, що ви робите по 500 виборок, це значить коефіцієнт заповнення 4%? Чи якась фіксована напруга у випадку аналогового сигналу?

Kvins пише:

перетворити на логічну одиницю і якщо через деякий час  ще буде такий саме імпульс, на нуль.

Тобто умовою перемикання виходу на протилежне значення є перехід коефіцієнту заповнення від значення 4% і вище до значення нижче 4%, чи як?

EDIT: про 4% писав до того як звернув увагу, що там analogRead(), а не digitalRead(). Тоді ще менше зрозуміло, яка саме умова перемикання вихода. Бо значення 20 від analogRead() - це десь 2% від Vcc, тобто приблизно 0.1 вольт для 5-вольтової ардуіни або 0.06 вольт для 3.3-вольтової.

Kvins пише:

імпульс пробігає декілька разів і в мене, порт падає в LOW

У вашій спробі реалізації стан виходу залежить тільки від поточного середнього значення, без врахування поточного стану виходу.

Також, частота виборки залежить від тактової частоти процесора та інших сторонніх факторів, таких як версія компілятора та опції збірки.

Kvins пише:

Можливо, я все роблю не правильно, є інший алгоритм... Підскажіть як це можна реалізувати.

Ви не могли б описати умову задачі, а не своє бачення її реалізації?

Остання редакція dimich (2025-06-08 01:21:25)

Неактивний

#3 2025-06-08 00:03:27

jokeer
Гість

Re: Допомога з написанням коду Arduino Nano (Arduino IDE)

Звичайно PWM  з польотного контроллера має частоту 50 гц і довжину імпульсу 1..2 мс. Якщо вам для цього, то простіше за все налаштувати переривання по зміні рівня і вимірювати час.

#4 2025-06-08 00:13:05

dimich
Учасник
Зареєстрований: 2023-12-01
Повідомлень: 445

Re: Допомога з написанням коду Arduino Nano (Arduino IDE)

І для дискретного вихода у вигляді T-триггера потрібен або гистерезис, або таймаут. Бо на граничних значеннях вихід буде тіліпатись туди-сюди неконтрольовано.

Неактивний

#5 2025-06-08 10:57:32

jokeR
Учасник
Зареєстрований: 2024-12-12
Повідомлень: 101

Re: Допомога з написанням коду Arduino Nano (Arduino IDE)

Конкретно що не так з вашим кодом. Ви 500 разів підряд читаєте значення з АЦП і рахуєте середнє значення. Зазвичай так роблять, коли інтервал часу, на якому усереднюють, відомий. У вашому випадку - ні. 500 відліків - невідомо скільки мікросекунд.
Далі. АЦП вертає значення від 0 до 1024, 1024 відповідає, якщо не помиляюсь, 3.3 В. Що таке 20 незрозуміло, але це дуже близько до рівня шуму. Скоріше за все, воно ловить завади від живлення.

Неактивний

#6 2025-06-08 11:35:07

dimich
Учасник
Зареєстрований: 2023-12-01
Повідомлень: 445

Re: Допомога з написанням коду Arduino Nano (Arduino IDE)

Схоже, автор хотів зробити щось типу фільтра ковзаючим вікном з прямокутною віконною функцією. Але в загальному випадку для цього потрібно зберігати попередні значення в буфері. При кожному новому семплі найстаріше значення віднімати від акумульованої суми, замість нього записувати нове значення і додавати його до акумульованої суми.
Для періодичного сигналу можна і без збереження, але похибка залежить від співвідношення тривалості вікна та періоду сигналу.
Для бінарного сигналу можна замість самих значень 0/1 зберігати тривалості між фронтами, і по них рахувати середнє.
В будь-якому разі, як уже зазначили, потрібно знати, за який проміжок часу середнє.

Але це здогадки. Що насправді хоче автор - відомо тільки автору, чекаєм на зрозумілий опис задачі.

jokeR пише:

500 відліків - невідомо скільки мікросекунд.

Можна приблизно оцінити. В ардуіно тактова частота АЦП встановлюється 125 кГц, тобто при 10 бітах на семпл та буфері в 500 семплів це десь 40 мс на буфер. Це не враховуючи часу на виконання коду.   

jokeR пише:

АЦП вертає значення від 0 до 1024, 1024 відповідає, якщо не помиляюсь, 3.3 В.

До 1023 smile В ардуіно АЦП atmega328p за замовчуванням вимірює відносно Vcc (тобто 5 або 3.3 В), але можна перемкнути на Vref або внутрішнє джерело 1.1 В.

Неактивний

#7 2025-06-08 11:40:37

jokeR
Учасник
Зареєстрований: 2024-12-12
Повідомлень: 101

Re: Допомога з написанням коду Arduino Nano (Arduino IDE)

#define PIN_INPUT 2 // Arduino Nano - pin2 or pin3 only
#define PWM_WIDTH_FALSE 1400
#define PWM_WIDTH_TRUE 1600

unsigned long pulse_start = 0;
unsigned long pulse_width = 0;
bool state_from_pwm = false;

void catch_int()
{
   if (digitalRead(PIN_INPUT))
   {
    pulse_start = micros();
   } else {
    pulse_width = micros() - pulse_start;
    if (pulse_width < PWM_WIDTH_FALSE) 
    {
      state_from_pwm = false;
    } else if (pulse_width > PWM_WIDTH_TRUE)
    {
      state_from_pwm = true;
    };
    digitalWrite(LED_BUILTIN, state_from_pwm);
   };
}


void setup() {

  pinMode(LED_BUILTIN, OUTPUT); 
  pinMode(PIN_INPUT, INPUT);
  attachInterrupt(digitalPinToInterrupt(PIN_INPUT), catch_int, CHANGE);
  interrupts();
}

void loop() {
}

Десь так. Очікуються імпульси на вході D2. Якщо ваші 20 - це 1/20 від 50 гц, тобто 1 мс, то варто взяти за межу середину допустимого інтервалу (1.5мс), і додати гістерезис +-100 мкс, для захисту від спрацьовувань близько до межі. Сподіваюсь, вгадав.
Хоча, якщо я вгадав, то мені здається, що ваша задача вирішується і без додаткового контроллера.

Неактивний

#8 2025-06-08 11:41:42

Kvins
Учасник
Зареєстрований: 2025-06-07
Повідомлень: 12

Re: Допомога з написанням коду Arduino Nano (Arduino IDE)

jokeR пише:

Конкретно що не так з вашим кодом. Ви 500 разів підряд читаєте значення з АЦП і рахуєте середнє значення. Зазвичай так роблять, коли інтервал часу, на якому усереднюють, відомий. У вашому випадку - ні. 500 відліків - невідомо скільки мікросекунд.
Далі. АЦП вертає значення від 0 до 1024, 1024 відповідає, якщо не помиляюсь, 3.3 В. Що таке 20 незрозуміло, але це дуже близько до рівня шуму. Скоріше за все, воно ловить завади від живлення.

Згоден!

Так, замало. Але мені цього вистачає, щоб зловити команду на запуск. Нажаль осцила нема, щоб зробити точні заміри імпульсів. Ціль - Продублювати запуск умовного сервомотору, тіки з логічною одиницею або нулем.

Слухаю порт, де значення можуть бути різними від 0 до 1023. Коли інший пристрий знаходится в режимі очікування, то сигнал PWM йде приблизно зі значеннями 69-74, а коли йде команда на виконання, то маємо десь 18-21. (умовні значення). і роблю порт (13) HIGH. Через деякий час поступає таж сама команда з умовним значенням 18-20 мені потрібно зробити порт (13) LOW. При тому коді, що скинув вишче, світлодіод блимкае приблизно 4 рази, та тухне. Та якщо убрати

  } else {
  
    digitalWrite(13, LOW);
  }

світлодіод світиться постіно. Потрібно щоб він тух при подальшому, коли середне аріфмітичне (18-21) з'явиться в виборці.

Остання редакція Kvins (2025-06-08 11:42:38)

Неактивний

#9 2025-06-08 11:48:29

jokeR
Учасник
Зареєстрований: 2024-12-12
Повідомлень: 101

Re: Допомога з написанням коду Arduino Nano (Arduino IDE)

Про серву схоже вгадав wink
Ви хочете щоб кожне відкривання серви перемикало стан пристрою (щоб лампочак вмикалась і вимикалась)?

Неактивний

#10 2025-06-08 12:01:17

Kvins
Учасник
Зареєстрований: 2025-06-07
Повідомлень: 12

Re: Допомога з написанням коду Arduino Nano (Arduino IDE)

jokeR пише:
#define PIN_INPUT 2 // Arduino Nano - pin2 or pin3 only
#define PWM_WIDTH_FALSE 1400
#define PWM_WIDTH_TRUE 1600

unsigned long pulse_start = 0;
unsigned long pulse_width = 0;
bool state_from_pwm = false;

void catch_int()
{
   if (digitalRead(PIN_INPUT))
   {
    pulse_start = micros();
   } else {
    pulse_width = micros() - pulse_start;
    if (pulse_width < PWM_WIDTH_FALSE) 
    {
      state_from_pwm = false;
    } else if (pulse_width > PWM_WIDTH_TRUE)
    {
      state_from_pwm = true;
    };
    digitalWrite(LED_BUILTIN, state_from_pwm);
   };
}


void setup() {

  pinMode(LED_BUILTIN, OUTPUT); 
  pinMode(PIN_INPUT, INPUT);
  attachInterrupt(digitalPinToInterrupt(PIN_INPUT), catch_int, CHANGE);
  interrupts();
}

void loop() {
}

Десь так. Очікуються імпульси на вході D2. Якщо ваші 20 - це 1/20 від 50 гц, тобто 1 мс, то варто взяти за межу середину допустимого інтервалу (1.5мс), і додати гістерезис +-100 мкс, для захисту від спрацьовувань близько до межі. Сподіваюсь, вгадав.
Хоча, якщо я вгадав, то мені здається, що ваша задача вирішується і без додаткового контроллера.

Дякую за відповідь. Протестив вашу задумку. Але навіть в режимі очікування спрацовує

state_from_pwm = true;

1

Остання редакція Kvins (2025-06-08 12:09:17)

Неактивний

#11 2025-06-08 12:02:23

Kvins
Учасник
Зареєстрований: 2025-06-07
Повідомлень: 12

Re: Допомога з написанням коду Arduino Nano (Arduino IDE)

jokeR пише:

Про серву схоже вгадав wink
Ви хочете щоб кожне відкривання серви перемикало стан пристрою (щоб лампочак вмикалась і вимикалась)?


Так

Неактивний

#12 2025-06-08 12:16:32

jokeR
Учасник
Зареєстрований: 2024-12-12
Повідомлень: 101

Re: Допомога з написанням коду Arduino Nano (Arduino IDE)

Якась незвичайна серва у вас wink

#define PIN_INPUT 2 // Arduino Nano - pin2 or pin3 only
#define PWM_WIDTH_FALSE 1400
#define PWM_WIDTH_TRUE 1600

unsigned long pulse_start = 0;
unsigned long pulse_width = 0;
bool state_from_pwm = false;

void catch_int()
{
   if (digitalRead(PIN_INPUT))
   {
    pulse_start = micros();
   } else {
    pulse_width = micros() - pulse_start;
    if (pulse_width < PWM_WIDTH_FALSE) 
    {
      state_from_pwm = false;
    } else if (pulse_width > PWM_WIDTH_TRUE)
    {
      state_from_pwm = true;
    };
    digitalWrite(LED_BUILTIN, state_from_pwm);
   };
}


void setup() {

  pinMode(LED_BUILTIN, OUTPUT); 
  pinMode(PIN_INPUT, INPUT);
  Serial.begin(115200);
  attachInterrupt(digitalPinToInterrupt(PIN_INPUT), catch_int, CHANGE);
  interrupts();
}

unsigned long ts_next = 0;
unsigned long pw;
void loop() {
  if (millis() > ts_next)
  {
    ts_next = millis() + 1000;
    noInterrupts();
    pw = pulse_width;
    interrupts();
    Serial.println(pw);
  };
}

Ну давайте спробуємо виміряти, що у вас там за PWM.

Неактивний

#13 2025-06-08 12:28:10

Kvins
Учасник
Зареєстрований: 2025-06-07
Повідомлень: 12

Re: Допомога з написанням коду Arduino Nano (Arduino IDE)

Znmok-ekrana-2025-06-08-122551.png

В режимі очікування, порт D2

Остання редакція Kvins (2025-06-08 12:29:04)

Неактивний

#14 2025-06-08 12:40:34

jokeer
Гість

Re: Допомога з написанням коду Arduino Nano (Arduino IDE)

щось це не схоже на pwm. Або десь земля відірвана.
Розказуйте, якщо це не секретна бімба wink

#15 2025-06-08 12:50:19

Kvins
Учасник
Зареєстрований: 2025-06-07
Повідомлень: 12

Re: Допомога з написанням коду Arduino Nano (Arduino IDE)

jokeer пише:

щось це не схоже на pwm. Або десь земля відірвана.
Розказуйте, якщо це не секретна бімба wink

Інший пристрій це STM32F103 яка управляє сервомоторами зі зворотнім зв'язком у виді микроперемекача. Я вимикаю конектор мотора та туди ціпляюсь портом D2 (два пина: сигнал та GND)

Неактивний

#16 2025-06-08 13:05:57

jokeR
Учасник
Зареєстрований: 2024-12-12
Повідомлень: 101

Re: Допомога з написанням коду Arduino Nano (Arduino IDE)

Трохи дивно виходить.  Ну давайте поміряємо період імпульсів.

#define PIN_INPUT 2 // Arduino Nano - pin2 or pin3 only
#define PWM_WIDTH_FALSE 1400
#define PWM_WIDTH_TRUE 1600

unsigned long pulse_start = 0;
unsigned long pulse_width = 0;
unsigned long period = 0;
unsigned long pulse_prev_start = 0;
bool state_from_pwm = false;

void catch_int()
{
   if (digitalRead(PIN_INPUT))
   {
    pulse_prev_start = pulse_start;
    pulse_start = micros();
   } else {
    pulse_width = micros() - pulse_start;
    if (pulse_width < PWM_WIDTH_FALSE) 
    {
      state_from_pwm = false;
    } else if (pulse_width > PWM_WIDTH_TRUE)
    {
      state_from_pwm = true;
    };
    digitalWrite(LED_BUILTIN, state_from_pwm);
   };
}


void setup() {

  pinMode(LED_BUILTIN, OUTPUT); 
  pinMode(PIN_INPUT, INPUT);
  Serial.begin(115200);
  attachInterrupt(digitalPinToInterrupt(PIN_INPUT), catch_int, CHANGE);
  interrupts();
}

unsigned long ts_next = 0;
unsigned long pw;
void loop() {
  if (millis() > ts_next)
  {
    ts_next = millis() + 1000;
    noInterrupts();
    pw = pulse_width;
    period = pulse_start - pulse_prev_start;
    interrupts();
    Serial.print(period); 
    Serial.print(" ");
    Serial.println(pw);
  };
}

Неактивний

#17 2025-06-08 14:08:09

Kvins
Учасник
Зареєстрований: 2025-06-07
Повідомлень: 12

Re: Допомога з написанням коду Arduino Nano (Arduino IDE)

if (average < 20)                                  // умова на потрібний імпульс (шим)
   {                             
    digitalWrite(outPin, HIGH);                // робимо високий рівень
 
    } else  if  digitalRead(outPin,HIGH) { // i якщо імпульс був знов через деякий час , де був HIGH
  
    digitalWrite(outPin, LOW);                // вимикаємо 

Наразі не компілюється, щось с синтаксисом..

Неактивний

#18 2025-06-08 14:18:12

jokeer
Гість

Re: Допомога з написанням коду Arduino Nano (Arduino IDE)

Можливо. Дивіться попередження компіляції.
Але спочатку розберіться що у вас там за сигнал. Не схоже це на pwm. .

>> сигнал PWM йде приблизно зі значеннями 69-74,

що це за значення, звідки ви його взяли?

#19 2025-06-08 14:20:51

Kvins
Учасник
Зареєстрований: 2025-06-07
Повідомлень: 12

Re: Допомога з написанням коду Arduino Nano (Arduino IDE)

jokeR пише:

Трохи дивно виходить.  Ну давайте поміряємо період імпульсів.


Znmok-ekrana-2025-06-08-141812.png

Неактивний

#20 2025-06-08 14:30:17

Kvins
Учасник
Зареєстрований: 2025-06-07
Повідомлень: 12

Re: Допомога з написанням коду Arduino Nano (Arduino IDE)

jokeer пише:

Можливо. Дивіться попередження компіляції.
Але спочатку розберіться що у вас там за сигнал. Не схоже це на pwm. .

>> сигнал PWM йде приблизно зі значеннями 69-74,

що це за значення, звідки ви його взяли?

Я дивився у мониторі порта зміни при натисканні команди серво
Znmok-ekrana-2025-06-08-142635.png

Неактивний

#21 2025-06-08 14:31:05

jokeer
Гість

Re: Допомога з написанням коду Arduino Nano (Arduino IDE)

Ну, що ми тут бачимо? Коли вимірюється період 20 мс - довжина імпульсу 2 мс. Схоже на правду. А інше якесь дивне. Ви там серву не від USB живите?

#22 2025-06-08 14:38:32

Kvins
Учасник
Зареєстрований: 2025-06-07
Повідомлень: 12

Re: Допомога з написанням коду Arduino Nano (Arduino IDE)

jokeer пише:

Ви там серву не від USB живите?

Ні, окреме живлення.

Неактивний

#23 2025-06-08 14:56:11

jokeer
Гість

Re: Допомога з написанням коду Arduino Nano (Arduino IDE)

Ну, покрутіть той stm32. Якщо з нього в іншому положенні вдасться отримати імпульси 1 мс - можна просто ігнорувати імпульси з неправильним періодом.

#24 2025-06-08 16:56:07

Kvins
Учасник
Зареєстрований: 2025-06-07
Повідомлень: 12

Re: Допомога з написанням коду Arduino Nano (Arduino IDE)

Хлопці все запрацювало cool

ось...

#define NUM_READINGS 600
int average;
int outPin = 13;
int inPWM = A0;

void setup() {
  digitalWrite(outPin, LOW);
  pinMode(13, OUTPUT);
  Serial.begin(9600);
}


void loop() {
  long sum = 0;  // локальна змінна sum
  for (int i = 0; i < NUM_READINGS; i++) {      // згідно з кількістю усереднень
    sum += analogRead(A0);                        // сумуємо значення з датчика змінної sum
  }
  average = sum / NUM_READINGS;                  // знаходимо середнє арифметичне, поділивши суму на число вимірів
  Serial.println(average);                       // для прикладу виводимо в порт
  delay(1000);
 
  if (average < 22 && digitalRead(outPin) == LOW)  // умова на потрібний імпульс (шим)
   {                             
    digitalWrite(outPin, HIGH);                // робимо високий рівень
   }
   else if (average < 22 && digitalRead(outPin) == HIGH) // і якщо імпульс був раніше
   {
    digitalWrite(outPin, LOW);                  // вимикаємо 
   }
            

}

Неактивний

#25 2025-06-08 17:05:08

Kvins
Учасник
Зареєстрований: 2025-06-07
Повідомлень: 12

Re: Допомога з написанням коду Arduino Nano (Arduino IDE)

Усім дякую за допомогу!

Неактивний

Швидке повідомлення

Введіть повідомлення і натисніть Надіслати

Підвал форуму