Генератор Arduino с регулировкой частоты и скважности по двум каналам.

5335
Offline
Зарегистрирован: 10.03.2016

скетч arduino nano генератора на два канала с регулировкой частоты и скважности с библиотекой PWM.h.

Библиотека позволяет начинающему без особых танцев с бубном вокруг регистров выдать по двум каналам регулируемую частоту с регулируемым ШИМом.

Теперь вопрос:

Как сделать, чтобы фронты начала сигналов 1 и второго каналов совпадали по фазе?

 

 

// генератор сигналов с регулировкой частоты и скважности по двум каналам.
// частота от 0 до 100 кГц, ШИМ от 0 до 255
//

//подключение библиотек *********************************************************************
#include <PWM.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd (2, 12, 4, 5, 6, 7);                      // назначение пин LCD (rs, enable, d4, d5, d6, d7)
//********************************************************************************************

//определение пинов **************************************************************************
#define OK_PIN    8                                         // кнопка ОК (можно любой пин)
#define OUT_1_PIN 9                                         // пин для генератора сигналов (не менять)
#define OUT_2_PIN 10                                        // пин для генератора сигналов (не менять)
#define LEFT_PIN  A0                                        // кнопка ЛЕВО (можно любой пин)
#define RIGHT_PIN A1                                        // кнопка ПРАВО (можно любой пин) 
//*********************************************************************************************

//объявление переменных ***********************************************************************
int PWM_1 = 200;                                            // стартовое значение ШИМ_1 от 0 до 255
int PWM_2 = 50;                                             // стартовое значение ШИМ_2 от 0 до 255
int32_t frequency = 10000;                                  // стартовое значение частоты в Гц
byte hag = 0;                                               // стартовое значение выбора режима
int mnog = 1;                                               // стартовое значение коэф. частоты
int flag = 0;                                               // стартовое флага
//*********************************************************************************************

// ********************************************************************************************
void setup()
{
  InitTimersSafe();                                         // инициализация таймеров

  //инициализация lcd *************************************************************************
  lcd.begin(16, 2);
  lcd.clear(); lcd. noCursor();
  //*******************************************************************************************
  
  // назначение портов ************************************************************************
  pinMode(OUT_1_PIN, OUTPUT);
  pinMode(OUT_2_PIN, OUTPUT);
  pinMode(LEFT_PIN, INPUT);
  pinMode(RIGHT_PIN, INPUT);
  pinMode(OK_PIN, INPUT);
  // ******************************************************************************************
  
  bool success_1 = SetPinFrequencySafe(OUT_1_PIN, frequency);                 // первоначальная установка частоты на первом выходе
  delay(50);
  bool success_2 = SetPinFrequencySafe(OUT_2_PIN, frequency);                 // первоначальная установка частоты на втором выходе
  delay(50);
  pwmWrite(OUT_1_PIN, PWM_1);                                                 // первоначальная установка ШИМ на первом выходе
  pwmWrite(OUT_2_PIN, PWM_2);                                                 // первоначальная установка ШИМ на втором выходе
  
  // вывод на экран *****************************************************************************
  lcd.setCursor(0, 0); lcd.print(frequency); lcd.print("Hz *   "); lcd.setCursor(15, 0); lcd.print(mnog);
  lcd.setCursor(0, 1);
  lcd.print("1PWM"); lcd.setCursor(4, 1); lcd.print(PWM_1);
  lcd.setCursor(9, 1);
  lcd.print("2PWM"); lcd.setCursor(13, 1); lcd.print(PWM_2);
}
  // ********************************************************************************************

 // основной цикл программы **********************************************************************
void loop()
{
  if ((digitalRead(LEFT_PIN) == HIGH) || (digitalRead(RIGHT_PIN) == HIGH)     // если нажата любая кнопка
      || (digitalRead(OK_PIN) == HIGH))
  {
    key();                                                                    // то вызов подпрограммы опроса кнопок
  }

  bool success_1 = SetPinFrequencySafe(OUT_1_PIN, frequency);                 // установка частоты на первом выходе
  delay(10);
  bool success_2 = SetPinFrequencySafe(OUT_2_PIN, frequency);                 // установка частоты на втором выходе
  delay(10);
  pwmWrite(OUT_1_PIN, PWM_1);                                                 // установка ШИМ на первом выходе
  pwmWrite(OUT_2_PIN, PWM_2);                                                 // установка ШИМ на втором выходе
}
//*************************************************************************************************

// подпрограмма опроса кнопок и установки частоты и скважности ************************************
void key()
{

  if (digitalRead(OK_PIN) == HIGH)                                          // если нажата кнопка ОК - перебор коэф. для частоты и ШИМ
  {
    switch (hag)
    {
      case 0:                                                               // выбор множителя частоты (1)
        lcd.setCursor(12, 0);
        lcd.print("   1");
        mnog = 1;
        flag = 0;
        break;

      case 1:                                                               // выбор множителя частоты (10)
        lcd.setCursor(12, 0);
        lcd.print("  10");
        mnog = 10;
        flag = 0;
        break;

      case 2:                                                               // выбор множителя частоты (100)
        lcd.setCursor(12, 0);
        lcd.print(" 100");
        mnog = 100;
        flag = 0;
        break;

      case 3:                                                              // выбор множителя частоты (1000)
        lcd.setCursor(12, 0);
        lcd.print("  1K");
        mnog = 1000;
        flag = 0;
        break;

      case 4:                                                              // выбор множителя частоты (5000)
        lcd.setCursor(12, 0);
        lcd.print("  5K");
        mnog = 5000;
        flag = 0;
        break;

      case 5:                                                              // выбор 1 канала для регулировки ШИМ
        lcd.setCursor(12, 0);
        lcd.print("1PWM");
        flag = 1;
        break;

      case 6:                                                               // выбор 2 канала для регулировки ШИМ
        lcd.setCursor(12, 0);
        lcd.print("2PWM");
        flag = 2;
        break;

      case 7:                                                                // перебор параметров по кругу
        flag = 0;
        break;
    }
    hag = hag + 1; delay(100);                                               // приращение счетчика 
    if (hag == 8) hag = 0;
  }

  if (flag == 0)                                                            // флаг выборов режима настройки ШИМ или частоты (по умолчанию флаг =0 - настройка частоты)
  {
    if (digitalRead(LEFT_PIN) == HIGH)                                      // если нажата кнопка ЛЕВО 
    {
      frequency = frequency - mnog;                                         // то уменьшение частоты на выбранный коэф.

      if (frequency < 0)                                                    // если частота меньше 0 
      {
        frequency = 0;                                                      // то частота =0
      }
      delay(100);                                                           // защита от дребезга
    }

    if (digitalRead(RIGHT_PIN) == HIGH)                                     // если нажата кнопка ПРАВО 
    {
      frequency = frequency + mnog;                                         // то увеличение частоты

      if (frequency  >= 99999)                                              // если частота больше 99 999 
      {
        frequency = 99999;                                                  // то частота = 99 999
      }
      delay(100);                                                           // защита от дребезга
    }
    lcd.setCursor(0, 0);                                                    // вывод на экран частоты
    lcd.print(frequency); lcd.print("Hz *   ");                             // вывод на экран
  }

  if (flag == 1)                                                            // флаг выборов режима настройки ШИМ 1
  {

    if (digitalRead(LEFT_PIN) == HIGH)                                       // если нажата кнопка ЛЕВО 
    {
      PWM_1 = PWM_1 - 5;                                                     // то уменьшение ШИМ на 5

      if (PWM_1 < 10)                                                        // если ШИМ меньше 10 
      {
        PWM_1 = 10;                                                          // то ШИМ = 10
      }
      delay(100);                                                            // защита от дребезга
    }

    if (digitalRead(RIGHT_PIN) == HIGH)                                      // если нажата кнопка ПРАВО то приращение ШИМ на 5
    {
      PWM_1 = PWM_1 + 5;

      if (PWM_1 > 255)                                                       // если ШИМ больше 255 
      {
        PWM_1 = 255;                                                         // то ШИМ = 255
      }
      delay(100); //Serial.print("PWM1= "); Serial.println(PWM_1);           // защита от дребезга
    }
  }

  if (flag == 2)                                                              // флаг выбора режима настройки ШИМ 2
  {

    if (digitalRead(LEFT_PIN) == HIGH)                                        // аналогично ШИМ первого канала
    {
      PWM_2 = PWM_2 - 5;
      if (PWM_2 < 10)
      {
        PWM_2 = 10;
      }
      delay(100);
    }

    if (digitalRead(RIGHT_PIN) == HIGH)
    {
      PWM_2 = PWM_2 + 5;
      if (PWM_2 > 255)
      {
        PWM_2 = 255;
      }
      delay(100);
    }
  }
  // вывод на экран ШИМ 1,2 ***************************************************************************
  lcd.setCursor(4, 1);
  if (PWM_1 < 100)
  {
    lcd.print("0"); lcd.print(PWM_1);
  }
  else
  {
    lcd.print(PWM_1);
  }

  lcd.setCursor(13, 1);
  if (PWM_2 < 100)
  {
    lcd.print("0"); lcd.print(PWM_2);
  }
  else
  {
    lcd.print(PWM_2);
  }
  //***************************************************************************************************
}

 

5335
Offline
Зарегистрирован: 10.03.2016

собрал схему в симуляторе PROTEUS. все работет. если надо приложу к теме.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

5335 пишет:

...генератора на два канала с регулировкой частоты и скважности...

...выдать по двум каналам регулируемую частоту...

Теперь вопрос:

Как сделать, чтобы фронты начала сигналов 1 и второго каналов совпадали по фазе?

Это принципиально невозможно.

При различной частоте фаза между сигналами неизбежно будет меняться.

 

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

5335
Offline
Зарегистрирован: 10.03.2016

частота у обоих каналов одна. и регулируется сразу для обоих каналов.

можно сдвинуть фазу второго канала жесткой логикой, но не хочется огород городить

5335
Offline
Зарегистрирован: 10.03.2016

 

 

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

[/quote]

а как  брать сигнал не с разных, а с одного и того же таймера? необходимо лезть в библиотеку?

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

Можно вообще без библиотеки. Прямо таймер запрограмировать. Как раз два канала. 

5335
Offline
Зарегистрирован: 10.03.2016

nik182 пишет:

Можно вообще без библиотеки. Прямо таймер запрограмировать. Как раз два канала. 

а как таймер без танцев запрограмировать? чтоб 2 канала регулировать по частоте и ШИМу?

этож надо матчасть учить. староват я.

с библиотекой получилось просто. не обладая знаниями работы конроллера.

вопрос только один - как только сдвинуть фронт второго канала?

подозреваю что надо копать бибилиотеку (менять условия сравнения таймеров)

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

5335 пишет:

Библиотека позволяет начинающему без особых танцев с бубном вокруг регистров выдать по двум каналам регулируемую частоту с регулируемым ШИМом.

[cut]

Как сделать, чтобы фронты начала сигналов 1 и второго каналов совпадали по фазе?

Выкинуть библу на помойку. Запрограммировать таймер в FAST-PWM режим.

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

5335 пишет:

частота у обоих каналов одна. и регулируется сразу для обоих каналов.

можно сдвинуть фазу второго канала жесткой логикой, но не хочется огород городить

сразу так и подумалось - решить аппаратно

5335
Offline
Зарегистрирован: 10.03.2016

судя по всему то да. аппаратно

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

5335, а что вы сможете аппаратно сделать? Точка отсчёта (т.е. синхронизации)  в "Phase Correct"  режиме всегда в середине ипульсов, и время, на которое нужно двигать один импульс относительно второго зависит от разницы их скважности, т.е. эта величина не постоянная. Что бы реализовать аппаратно сие придёться делать автоматическую подстройку фазы, а это уже серьёзное устройство. Ну или просто научиться программировать таймеры :)

5335
Offline
Зарегистрирован: 10.03.2016

спасибо добрый человек.

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

dimax, Phaze Correct - далеко не единственный режим работы таймера. Раз уж надо привязать фронты друг к другу, целесообразно использовать какой-то из режимов, осуществляющих счет по "пиле", а не "треугольнику".

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

andriano, если вы не заметили, то в #7 я именно про это и написал :) По "пиле" всего два режима. В СТС нет возможности регулировать скважность, остаётся один вариант -FastPWM

5335
Offline
Зарегистрирован: 10.03.2016

andriano пишет:

dimax, Phaze Correct - далеко не единственный режим работы таймера. Раз уж надо привязать фронты друг к другу, целесообразно использовать какой-то из режимов, осуществляющих счет по "пиле", а не "треугольнику".

5335
Offline
Зарегистрирован: 10.03.2016

вот по этой диаграмме "железо - углерод"?

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

Посмотрите в интернете. Множество статей например

https://embedderslife.wordpress.com/2012/04/02/%D0%BA%D1%80%D0%B0%D1%82%...

и в даташите. Ничего сложного. Реально четыре строчки в setup и три в loop.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Не так просто.

ТС частоту тоже надо регулировать, а значит есть сложности с использование ДВУХ каналов сравнения у таймера. Частотой придется управлять, используя прерывание переполнения таймера, по которому инициализировать начальное значение таймера не в 0, а в то, что нужно для точной частоты.

Этот подход - самый верный, но требует от программиста аккуратности в обработке граничных случаев. Иначе будет непредсказуемое поведение.

5335
Offline
Зарегистрирован: 10.03.2016

ну все. добили меня.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

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

Ну и, в конце концов, кое-где на таймер приходится по 3 канала сравнения.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

wdrakula, не пугайте Т.С.,  не всё так страшно, "Mode 14" 16-битного таймера в меге позволяет крутить плавно  и общую частоту, и скважность для каждого канала без прерываний и хитростей.

5335
Offline
Зарегистрирован: 10.03.2016

dimax пишет:

wdrakula, не пугайте Т.С.,  не всё так страшно, "Mode 14" 16-битного таймера в меге позволяет крутить плавно  и общую частоту, и скважность для каждого канала без прерываний и хитростей.

А можно поподробнее с этого момента?

5335
Offline
Зарегистрирован: 10.03.2016

Только на меге?

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

5335 пишет:

Только на меге?

да, на 328 (уно, нано, мини) нет такой фичи.

только на 2560 и ее линейке (1280, 640).

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

5335 пишет:

dimax пишет:

wdrakula, не пугайте Т.С.,  не всё так страшно, "Mode 14" 16-битного таймера в меге позволяет крутить плавно  и общую частоту, и скважность для каждого канала без прерываний и хитростей.

А можно поподробнее с этого момента?

мастер класс :)

Похоже на вашу картинку?  Умеючи работы на 5 минут.. :) Скетч для меги328

void setup() {
pinMode(9,OUTPUT);
pinMode(10,OUTPUT);
TCCR1A=(1<<COM1A1)|(1<<COM1B1)|(1<<WGM11);
TCCR1B=(1<<WGM13)|(1<<WGM12)|(1<<CS10); //mode14 FastPwm
ICR1=799;
OCR1A=200;
OCR1B=600;
}

void loop() {}

 

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

5335 пишет:

вот по этой диаграмме "железо - углерод"?

Да, по этой диаграмме ушли в область чугунов, мой приятель делал аналогичное на жёсткой логике, вытянуть два сигнала на передний фронт

Увидел решение Дмитрия! Красиво!!!

bwn
Offline
Зарегистрирован: 25.08.2014

5335 пишет:

вот по этой диаграмме "железо - углерод"?

Не, по Шеффлера.))))

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

bwn пишет:

5335 пишет:

вот по этой диаграмме "железо - углерод"?

Не, по Шеффлера.))))

Надо же, сие прошло мимо меня, хоть узнал, что и такое есть)))

Ферриты и аустениты )))

А мне импонировали ледебуриты )))

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

ua6em пишет:

Увидел решение Дмитрия! Красиво!!!

Оно вам ничего не напомнило? :)

5335
Offline
Зарегистрирован: 10.03.2016

 

мастер класс :)

Похоже на вашу картинку?  Умеючи работы на 5 минут.. :) Скетч для меги328

[/quote] 

вах! Промежгородняя!

как во всем этом благолепии менять частоту и скважность?

OCRой или ICRой?

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

5335,  ICR -длительность периода в тактах МК. Или  герцах = F_CPU/(ICR+1) ;    OCR -длительность лог "1" (импульса) на выходе в тактах МК, то бишь скважность. Отсюда сразу главное правило - OCR не должен  быть больше чем ICR.   Ну и скважность в проценты самостоятельно пересчитаете.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

dimax пишет:

Похоже на вашу картинку?  Умеючи работы на 5 минут.. :) Скетч для меги328

void setup() {
pinMode(9,OUTPUT);
pinMode(10,OUTPUT);
TCCR1A=(1<<COM1A1)|(1<<COM1B1)|(1<<WGM11);
TCCR1B=(1<<WGM13)|(1<<WGM12)|(1<<CS10); //mode14 FastPwm
ICR1=799;
OCR1A=200;
OCR1B=600;
}

void loop() {}

 

Мой косяк!  Просто я плохо искал.

Так что на любом  есть. Я - наврал. Сорри.

Единственно, что все регистры у таймера1 - по 16 бит и их советуют в скобках cli/sti изменять.

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

dimax пишет:

ua6em пишет:

Увидел решение Дмитрия! Красиво!!!

Оно вам ничего не напомнило? :)

конечно напомнило, скетч написан, опробован, потом перевёл с ШИМа на ЦАП, но затею не похоронил, есть проблемы с оцифровкой датчика тока, шумы 50 милливольт, избавляюсь

5335
Offline
Зарегистрирован: 10.03.2016

dimax пишет:

5335,  ICR -длительность периода в тактах МК. Или  герцах = F_CPU/(ICR+1) ;    OCR -длительность лог "1" (импульса) на выходе в тактах МК, то бишь скважность. Отсюда сразу главное правило - OCR не должен  быть больше чем ICR.   Ну и скважность в проценты самостоятельно пересчитаете.

вот спасибо!

а мне мне говорили, что программисты народ конкретный.

дадут совет настолько точный, насколько бесполезный!

ан нет, есть порох в пороховницах и Дробь в ягодицах.

если что кому что отковать,  милости просим

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

5335 пишет:

а мне мне говорили, что программисты народ конкретный. дадут совет настолько точный, насколько бесполезный!

Совершенно верно говорили!  У меня готовой шаблон был, поэтому нетрудно было. Иначе бы ограничился фразой из #7.

5335
Offline
Зарегистрирован: 10.03.2016

Пересобрал скетч - все заработало как надо. Миллиард благодарностей. 

Аппаратно тоже можно. Отрезается левая часть сигнала TTL логикой 2 элемента И-НЕ и 2 элемента ИЛИ-НЕ. Но не так красиво

5335
Offline
Зарегистрирован: 10.03.2016

а как тоже самое сделать на MEGE 2560?

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

5335 пишет:

а как тоже самое сделать на MEGE 2560?

а зачем?

5335
Offline
Зарегистрирован: 10.03.2016

Собрал на 2-х nano электроэрозионный станочек: одна управляет приводом, вторая - генератор - куча соединительных связей между платами наводки от силовых ключей ловит

хочется на одной меге все сделать

Kakmyc
Offline
Зарегистрирован: 15.01.2018

Можно мне тоже генератор ардуино ?
А то я как дурак их у китайцев покупаю.

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

Kakmyc пишет:
Можно мне тоже генератор ардуино ?

Можно, разрешаем.

5335
Offline
Зарегистрирован: 10.03.2016

смотря для чего генератор. для эрозионки нужно 2 канала с одной частотой и разной скважностью. 1 - на поджиг дуги. 2-й на горение.

таких китайцы не делают

5335
Offline
Зарегистрирован: 10.03.2016

Так можно или нет на меге?

5335
Offline
Зарегистрирован: 10.03.2016

Или на stm

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

5335, конечно можно. Но не думаю, что кто-то будет писать код за вас :)

5335
Offline
Зарегистрирован: 10.03.2016

А проверить смогут.?

5335
Offline
Зарегистрирован: 10.03.2016

вижу форум превратился - сделай сам.

KestGts
Offline
Зарегистрирован: 15.06.2018

Я бы по генератору электроэрозии пообщался где то в ЛС (KestGts@GMAIL.COM)

gal
Offline
Зарегистрирован: 08.06.2018
Два канала, можно добавить еще два
STM32F103

HardwareTimer pwmtimer3(3);
void setup() {
  pinMode(PA7, PWM);
  pinMode(PB0, PWM);
  pwmtimer3.pause();
  pwmtimer3.setPrescaleFactor(1);       // Timer input clock Prescaler = 1 
  pwmtimer3.setOverflow(100-1);            // PWM Period width for 720kHz 
  pwmtimer3.setCompare(TIMER_CH3, 50);  // PWM High Pulse width is 50% duty (1:1)
  pwmtimer3.setCompare(TIMER_CH2, 20);
  pwmtimer3.refresh();
  pwmtimer3.resume();

 
}

void loop() {
}

 

5335
Offline
Зарегистрирован: 10.03.2016

4 канала - излишне

2 - нормально

1 канал формирует сигнал для включения высоковольтного транзистора- поджиг дуги

2 канал формирует сигнал включения низковольтного транзистора но с большей скважностью

оба канала формируют так называемый стульчик для EDM

 

Vlad6511
Offline
Зарегистрирован: 22.02.2018

Здравствуйте уважаемые коллеги. 

Помогите разобраться по этому генералу на 2 канала. Спасибо.