Опять про чтение PWM , но про подключение.

Rus-12
Offline
Зарегистрирован: 27.03.2019

Стоит задача прочитать с Pwm выхода Ардуины сигнал pwm цифровым пином другой ардуины. С кодом проблем нет, но не работает ) В мониторе цифры хоть и  не хаотические, но бредово беспорядочные. Пробовал по всякому: и pulseIn и внешним прерыванием, результат одинаковый.

,Я подключаю проводом pwm выход одной платы напрямую к цифровому пину другой, земля общая. 

Вопрос: а не надо ли эту линию подтягивать к земле или питанию? Каким номиналом резистора? Я в этом не разираюсь, и от слова "подтягивающий резистор" мне делаеца дурно)

Заранее спасибо!

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Шим сигнал (PWM) для начала интегрировать нужно.  

Rus-12
Offline
Зарегистрирован: 27.03.2019

Нет. Не нужно.ь Можно воспользоваться стандартной функцией pulseIn, или по внешнему прерыванию посчитать период высокого и низкого уровня.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

тоись, тебе не в аналоговый пин нужно  вводить? 

Rus-12
Offline
Зарегистрирован: 27.03.2019

На данный момент пытаюсь в цифровой. Городить интегрирующую цепочку не хочу, да и не очень умею. Да и не надо..)

nik182
Offline
Зарегистрирован: 04.05.2015

Странно. Никогда проблем не было. Цифровой выход на цифровой вход без всяких подтягивающих резисторов и pulseIn всегда устойчиво работало. 

Onkel
Offline
Зарегистрирован: 22.02.2016

какие параметры ШИМ - частота, скважность? Я принимаю до 12 ШИМ сигналов с радиопультов (там не совсем ШИМ, но не будем о тонкостях)- все нормально, через внешние прерывания. Без всяких подтягивающих резисторов.

 

Rus-12
Offline
Зарегистрирован: 27.03.2019

Вот код. Вернул pulseIn, проверил все подключения, в мониторе 0. Устойчивый ноль. Единичку/нолик с цифрового пина исходной ардуинки на 3ю ножку получает нормально, а PWM не видит. При этом выход pwm работает - если подключить диодик с резистором - все нормально, меняет яркость.



#include "PWM.hpp"

//PWM my_pwm(2); // Setup pin 2 for PWM


void setup() {
 pinMode(3, INPUT);
 pinMode(2, INPUT);
 Serial.begin(9600);
 //my_pwm.begin(true); // PWM on pin 2 reading PWM HIGH duration
}

void loop() {
 boolean val = digitalRead(3);
 int pulse = pulseIn(2, HIGH);

  Serial.println(val); 
  Serial.println(pulse);

    //Serial.print("Value: ");
    //Serial.print(my_pwm.getValue());
    //Serial.print("\tAGE: ");
    //Serial.println(my_pwm.getAge());
  delay(3000);

}

параметры ШИМ - не знаю. Вероятнее всего частота - стандартная для Arduino, а скважность я меняю. Визуально диод от самого тусклого, до ярко-яркого. Ни тот ни другой никак не отзывается.

Rus-12
Offline
Зарегистрирован: 27.03.2019

Самое странное, что я проверил - перекинул с PWM выхода проводок на другой выход, который отдает импульсы на драйвер шагового двигателя. С него pulseIn честно прочитала ширину импульса в 10 мкс. Все работает, а с PWM нет. Хотя диод на PWM реагирует....где тут смайлик "чешу репу" ??

SLKH
Offline
Зарегистрирован: 17.08.2015

Rus-12 пишет:

Самое странное, что я проверил - перекинул с PWM выхода проводок на другой выход, который отдает импульсы на драйвер шагового двигателя. С него pulseIn честно прочитала ширину импульса в 10 мкс. Все работает, а с PWM нет. Хотя диод на PWM реагирует....где тут смайлик "чешу репу" ??

схема будет?

Onkel
Offline
Зарегистрирован: 22.02.2016

А если дать на источинике analogWrite(x,1) будет измерять? Это и будет примерно 10 или 5 мкс (в зависимости от пина выхода).  Или дайте функции pulseIn() дождаться спада импульса, а потом печатайте. Достаточно будет 2 мс с запасом. Мысля такая, что короткие импульсы успевает обработать, а спады длинных уходят на delay() и стираются при cледующем запуске pulseIn().

 

 

Rus-12
Offline
Зарегистрирован: 27.03.2019

дык а какая тут схема? Пин 11 с Uno - проводок - пин 2 на Нано. Земля Uno - проводок - земля Нано. Я не умею схему проводка рисовать )

Сама Uno - 3 осевой GRBL контроллер, поэтому поменять что-то в ней я не могу. Могу только G-кодами давать ей команды. Две оси заняты, а третья и выход PWM на шпиндель свободны. Нужно передать число с контроллера на удаленную ардуинку, чтобы та управляла своим локальным параметром на каретке станке. Хотелось бы чтобы это можно было делать пряямо в G-код программе. Типа часть программы сделали - параметр поменяли. Можно конечно это делать через останови вручную - но это фу, некультурно как-то.

Собственно была идея через PWM выход. Я какбе задаю обороты шпинделя из программы, а по сути это передаваемый параметр. Это можно длеать как угодно в управляющей программе. Но вот что-то не работает...

Onkel
Offline
Зарегистрирован: 22.02.2016

а с внешним прерыванием пробовали?

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016
Rus-12
Offline
Зарегистрирован: 27.03.2019

Бред какой-то - поставил явным образом тайм аут в функцции pulseIn - все заработало, потом убрал на умолчание (1 сек) все продолжает работать...

Onkel
Offline
Зарегистрирован: 22.02.2016

Rus-12 пишет:

Бред какой-то - поставил явным образом тайм аут в функцции pulseIn - все заработало, потом убрал на умолчание (1 сек) все продолжает работать...

Это не баг, это фичи многих библиотек для  Arduino IDE - необходимость танцев с бубном. Воспользуйтесь функцией внешнего прерывания attachInterrupt, или , что много лучше, используйте "родные" прерывания Atmega328, тогда точно такого рода сюрпризов не будет. Это функции

Вы объявляете, по каким пинам будет прерывание обрабатываться, у меня это С0-С2
  EICRA = 0x00; //  INT0 INT1 Type didn't matter
  EIMSK = 0x00; //       INT0 INT1 disabled

  PCMSK0 = 0x00;
  PCMSK1 = 0x07; // Pin change mask pins C0 C1 C2 ENABLE any change
  PCMSK2 = 0x00;
  PCIFR = 0x02; //PCINT 14-8 Flag   clear
  PCICR = 0x02; //Pins C0 - C5 interruptions enable

 

и считаете в функции обработки прерывания
ISR (PCINT1_vect)// pin change interrupt for A0 to A5

 

Rus-12
Offline
Зарегистрирован: 27.03.2019

Я так глубоко, вот штоп с векторами и всё такое в программирование пока не погрузился . Но с внешними прерыванием я могу. Попробую. 

Мне кажется мои закомментаренные строчки кода, из библиотеки, они как раз по внешнему прерыванию работают. Взято отсюбда https://github.com/xkam1x/Arduino-PWM-Reader

Onkel
Offline
Зарегистрирован: 22.02.2016

ua6em пишет:

Я читаю два канала ШИМ вот так:

У меня тоже пульт, но с 3 каналами, так что использовал родную функцию прерывания.

SLKH
Offline
Зарегистрирован: 17.08.2015

Rus-12 пишет:

дык а какая тут схема? Пин 11 с Uno - проводок - пин 2 на Нано. Земля Uno - проводок - земля Нано. Я не умею схему проводка рисовать )

всяко бывает. для меня вот это "перекинул с PWM выхода проводок на другой выход, который отдает импульсы на драйвер шагового двигателя" звучит дико. 

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Onkel пишет:

ua6em пишет:

Я читаю два канала ШИМ вот так:

У меня тоже пульт, но с 3 каналами, так что использовал родную функцию прерывания.

Это как?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Rus-12 пишет:
С кодом проблем нет, но не работает )
Класс!!!

«Неважно, что что-то идёт неправильно. Возможно, это хорошо выглядит» — Первый закон Скотта

Onkel
Offline
Зарегистрирован: 22.02.2016

ua6em: Это как?

Выходы RC приемника подключены к пинам А0-А2, в мк они С0-С2, настраиваем прерывания на сработку от любого изменения состояний пинов С0-С2

  EICRA = 0x00; //  INT0 INT1 Type didn't matter
  EIMSK = 0x00; //       INT0 INT1 disabled

  PCMSK0 = 0x00;
  PCMSK1 = 0x07; // Pin change mask pins C0 C1 C2 ENABLE any change
  PCMSK2 = 0x00;
  PCIFR = 0x02; //PCINT 14-8 Flag   clear
  PCICR = 0x02; //Pins C0 - C5 interruptions enable

потом в прерывании считаем микросекунды (сделано для школьников, поэтому использовал ардуинскую ф-ю micros();

ISR (PCINT1_vect)// pin change interrupt for A0 to A5
{

  if (  ( (PINC & 0x01) == 0 )     && ((OldC & 0x01) == 1)      )   //  C0 cпад- считаем время импульса Turn- это поворот
   
    Turn= int(micros()-Time0 )-1500;
  

  if (  ( (PINC & 0x01) == 1 )     && ((OldC & 0x01) == 0)      )  // Фронт импульса на C0 - фиксим таймер в мкс
   
    Time0=micros();
 

   if (  ( (PINC & 0x02) == 0 )     && ((OldC & 0x02) == 2)      ) // cпад импульса C1- cчитаем время импульса С1
    {
    Speed= 1500-int(micros()-Time1 ) ;
 
    }

  if (  ( (PINC & 0x02) == 2 )     && ((OldC & 0x02) == 0)      )  //   Фронт импульса на C1 - фиксим таймер в переменной Time1
  {
    Time1=micros();
  }

  if (  ( (PINC & 0x04) == 0 )     && ((OldC & 0x04) == 4)      )// cпад импульса C2- cчитаем время импульса С2
    
    Mode= int(micros()-Time2 )-1500;
    

  if (  ( (PINC & 0x04) == 4 )     && ((OldC & 0x04) == 0)      ) //   Фронт импульса на C2 - фиксим таймер в переменной Time2
 
    Time2=micros();
  
  

  OldC = PINC;
}

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Onkel пишет:

ua6em: Это как?

Выходы RC приемника подключены к пинам А0-А2, в мк они С0-С2, настраиваем прерывания на сработку от любого изменения состояний пинов С0-С2

  EICRA = 0x00; //  INT0 INT1 Type didn't matter
  EIMSK = 0x00; //       INT0 INT1 disabled

  PCMSK0 = 0x00;
  PCMSK1 = 0x07; // Pin change mask pins C0 C1 C2 ENABLE any change
  PCMSK2 = 0x00;
  PCIFR = 0x02; //PCINT 14-8 Flag   clear
  PCICR = 0x02; //Pins C0 - C5 interruptions enable

потом в прерывании считаем микросекунды (сделано для школьников, поэтому использовал ардуинскую ф-ю micros();

ISR (PCINT1_vect)// pin change interrupt for A0 to A5
{

  if (  ( (PINC & 0x01) == 0 )     && ((OldC & 0x01) == 1)      )   //  C0 cпад- считаем время импульса Turn- это поворот
   
    Turn= int(micros()-Time0 )-1500;
  

  if (  ( (PINC & 0x01) == 1 )     && ((OldC & 0x01) == 0)      )  // Фронт импульса на C0 - фиксим таймер в мкс
   
    Time0=micros();
 

   if (  ( (PINC & 0x02) == 0 )     && ((OldC & 0x02) == 2)      ) // cпад импульса C1- cчитаем время импульса С1
    {
    Speed= 1500-int(micros()-Time1 ) ;
 
    }

  if (  ( (PINC & 0x02) == 2 )     && ((OldC & 0x02) == 0)      )  //   Фронт импульса на C1 - фиксим таймер в переменной Time1
  {
    Time1=micros();
  }

  if (  ( (PINC & 0x04) == 0 )     && ((OldC & 0x04) == 4)      )// cпад импульса C2- cчитаем время импульса С2
    
    Mode= int(micros()-Time2 )-1500;
    

  if (  ( (PINC & 0x04) == 4 )     && ((OldC & 0x04) == 0)      ) //   Фронт импульса на C2 - фиксим таймер в переменной Time2
 
    Time2=micros();
  
  

  OldC = PINC;
}

а то же самое на пинах 2,3 и 12 можно сделать?

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ЕвгенийП пишет:

Rus-12 пишет:
С кодом проблем нет, но не работает )
Класс!!!

«Неважно, что что-то идёт неправильно. Возможно, это хорошо выглядит» — Первый закон Скотта

Ну да, библиотека не эталон точности. но тележка и на ней ездит )))

Интересно, а Вашу библиотеку TimeMeasure.h можно использовать для этих целей?

Onkel
Offline
Зарегистрирован: 22.02.2016

а то же самое на пинах 2,3 и 12 можно сделать?

 

Конечно можно. При этом Вы можете оставить свои ардуиновские функции внешнего прерывания, а добавить только подсчет времени импульса по пину 12, это вроде В4 в мк, и разрешить прерывания только по этому пину, не запрещая прерываний по пинам 2 и 3
вроде этого
 

  PCMSK0 = 0x10;
  PCMSK1 = 0x00;  
  PCMSK2 = 0x00;
  PCIFR = 0x01;  
  PCICR = 0x01;  

и считать время в функции ISR (PCINT0_vect)

 

Ну или можно все функции переписать, тогда нужно будет разрешать прерывания по d2,d3 и b4.

Rus-12
Offline
Зарегистрирован: 27.03.2019

Вобщем победил. Всем спасибо, при помощи таки pulseIn. Возможно какой-то мусор оставался на плате после теста вотчдога на ней, или предыдущих скетчей с прерыванием по таймеру, или что, непонятно. Явным образом указываю таймаут в функции pulseIn, после этого можно не указывать, она ставит по умолчанию, все встает на свои места. 

И если кому интересно - отказался от идеи передавать число через PWM )) Неточно. Непропорционально увеличивается ширина импульса. Подстраиваешь коэффициент пропрциональности под малую скважность, врет на большой и наоборот. Немного, но неприятно.

Использовал свободную ось Z. Изобразил какбе асинхронную передачу на ней. По ножке, которая указывает направление вращение шпинделя, передаю единичку(командой "вращать по часовой стрелке") и по внешнему прерыванию начинаю читать импульсы, которые GRBL командой "проедь по оси Z столько-то" отдает в ось Z. Потом передаю смену направления вращения шпинделя, получатель видит нолик,  заканчивает прием и смотрит сколько импульсов пришло. Получается не слишком быстро, десятые секунды, но мне этого достаточно. Зато диапазон передаваемых значений практически неограничен. Ну и точно, импульс потерять это надо постараться ))

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Rus-12 пишет:

Вобщем победил.

Победил - это когда удалось реализовать поставленную задачу, а всего-то надо было воспользоваться библиотекой от Евгения Петровича, точность измерения - десятые доли микросекунд )))

#include	"TimeMeasure.h"

void setup() {
	Serial.begin(57600);
	initTimeMeasuring();
}

//
//	Если готов результат измерения, печатаем
//
void loop() {
	const uint16_t res = measureResult();
	if (res) Serial.println(res);
}

 

Rus-12
Offline
Зарегистрирован: 27.03.2019

Точность измерения - это хорошо. Но я не уверен в точности отправителя. Получается так: я  говорю контроллеру отправителю "вкл шпиндель на 200 об", тот выдает некий pwm. Я читаю ширину импульса,  запоминаю соотношение, потом шлю команду "1000 об", читаю ширину импульса, делю на запомненное соотношение и результат - 1006. Некритично, но некультурно. Если опять дать 200, прочитается точно 200. Опять 1000, опять 1006. То есть неточность не в канале, неточно , а точнее нелинейно во всем диапазоне, делает pwm именно отправитель, в работу которого я не могу вмешаться.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Rus-12 пишет:

Точность измерения - это хорошо. Но я не уверен в точности отправителя. Получается так: я  говорю контроллеру отправителю "вкл шпиндель на 200 об", тот выдает некий pwm. Я читаю ширину импульса,  запоминаю соотношение, потом шлю команду "1000 об", читаю ширину импульса, делю на запомненное соотношение и результат - 1006. Некритично, но некультурно. Если опять дать 200, прочитается точно 200. Опять 1000, опять 1006. То есть неточность не в канале, неточно , а точнее нелинейно во всем диапазоне, делает pwm именно отправитель, в работу которого я не могу вмешаться.

для начала загрузите правильную программу, а потом можно о чём-то говорить, ваш метод имеет точность 4 микросекунды и таки да, после этого составляете в приёмнике массив оборотов и всё, берём из массива

Rus-12
Offline
Зарегистрирован: 27.03.2019

Что такое "правильная"? Чем GRBL 0.9 "неправильный"? И каким извиите образом, в него грузить "массив". Составить свою таблицу...и имея в голове эти поправки отправлять g коды, можно наверно. Но это гемморой. Получилось все проще и без выкрутасов.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Rus-12 пишет:

Что такое "правильная"?

я о точности применительно к пульсеин