Изменение частоты вывода ШИМ на Arduino Uno

Я пытаюсь изменить частоту выхода ШИМ с Arduino Uno R3 (использую контакт 9) на 200 Гц с рабочим циклом 20%. Это для ESC, который подключен к двигателю на 12 В, и я знаю, что ESC работает так, как если бы я вводил волну 200 Гц от генератора сигналов, который работает двигатель. Однако мне было трудно сделать то же самое с Arduino Uno, и я полагаю, что это связано с тем, что частота по умолчанию составляет 490 Гц, поэтому мне нужен способ изменить эту частоту на 200 Гц. Существуют ли какие-либо библиотеки или специальные способы сделать это?

Спасибо!

, 👍1

Обсуждение

пожалуйста, добавьте свой код в сообщение... форматируйте как "код", @jsotola

Еще не использовал библиотеку для этого, но вы можете найти многообещающие результаты в веб-поиске. Как [эта библиотека] (https://github.com/matzefriedrich/arduino-pwm-frequency-library), @chrisl


2 ответа


Лучший ответ:

2

Вы также можете использовать мою недавно созданную библиотеку AVR_PWM, чтобы защитить себя от работы с сложные аппаратные регистры

Например

#include "AVR_PWM.h"

#if ( PWM_USING_ATMEGA2560 )
  // Пины проверены в Mega
  //#define pinToUse 12 // Timer1B на Mega
  //#define pinToUse 11 // Timer1A на Mega
  //#define pinToUse 9 // Timer2B на Mega
  //#определить pinToUse 2 // Timer3B на Mega
  //#определить pinToUse 3 // Timer3C на Mega
  //#define pinToUse 5 // Timer3A на Mega
  //#define pinToUse 6 // Timer4A на Mega
  //#define pinToUse 7 // Timer4B на Mega
  #define pinToUse       8            // Timer4C на Mega
  //#define pinToUse 46 // Timer5A на Mega
  //#define pinToUse 45 // Timer5B на Mega
  //#define pinToUse 44 // Timer5C на Mega

#elif ( PWM_USING_ATMEGA_32U4  )
  // Пины проверены на 32u4.
  //#определить pinToUse 5 // Timer3A на 32u4
  #define pinToUse      9            // Timer1A на 32u4
  //#определить pinToUse 10 // Timer1B на 32u4

#else

  // Контакты проверены на Nano / UNO.
  #define pinToUse      9            // Timer1A на UNO, Nano и т. д.
  //#define pinToUse 10 // Timer1B на UNO, Nano и т. д.
  //#define pinToUse 5 // Timer0B на UNO, Nano, e
  //#define pinToUse 3 // Timer2B на UNO, Nano и т. д.
#endif

//создает экземпляр pwm
AVR_PWM* PWM_Instance;

float frequency;
float dutyCycle;

void setup()
{
  Serial.print(F("\nStarting PWM_Basic on "));
  Serial.println(BOARD_NAME);
  Serial.println(AVR_PWM_VERSION);

  //назначает частоту ШИМ 200 Гц и коэффициент заполнения 0%
  PWM_Instance = new AVR_PWM(pinToUse, 200, 0);
}

void loop()
{
  frequency = 200;
  dutyCycle = 20;

  PWM_Instance->setPWM(pinToUse, frequency, dutyCycle);

  delay(10000);
  dutyCycle = 90;

  PWM_Instance->setPWM(pinToUse, frequency, dutyCycle);

  delay(10000);
}
,

Это работает для меня, спасибо!, @wroex24


2

Если вы готовы использовать таймер 2 (контакт D3), этот код сделает это:

void setup() 
 {
  pinMode (3, OUTPUT);

  TCCR2A = bit (WGM20) | bit (WGM21) | bit (COM2B1); // быстрая ШИМ, сброс OC2B при сравнении
  TCCR2B = bit (WGM22) | bit (CS20) | bit (CS21) | bit (CS22); // прескалер 1024
  OCR2A =  77;    // относительный нуль
  OCR2B =  15;    // 20% рабочий цикл
  }  // конец настройки

void loop()
  {
  // делаем здесь другие вещи
  }

Подробнее о таймерах Atmega328P на моей странице о таймерах.

Цифра 77 получена из:

16000000 / 1024 / 78 = 200.32

Другими словами, пределитель 1024 делится на тактовую частоту 16 МГц, а затем мы считаем до 78, что дает результат чуть более 200. На самом деле я использую 77, потому что таймер относительно нуля (он считает от 0 до 77, что дает 78 счетов). Это означает, что частота немного отличается (она будет 200,32 Гц, а не 200, но этого может быть достаточно).


Вы также можете сделать это с таймером 1 (контакт D10), чтобы получить более точные результаты, например:

void setup() 
 {
  pinMode (10, OUTPUT);

  // режим 15
  TCCR1A = bit (WGM10) | bit (WGM11) | bit (COM1B1); // быстрый ШИМ, сброс OC1B при сравнении
  TCCR1B = bit (WGM12) | bit (WGM13) | bit (CS11);   // быстрый ШИМ, прескалер 8
  OCR1A = 10000 - 1;   // что считать
  OCR1B = 2000 - 1;    // рабочий цикл
  }  // конец настройки

void loop()
  {
  // делаем здесь другие вещи
  }

В этом случае я использовал предварительный масштаб 8 и значение счета 10000 следующим образом:

16000000 / 8 / 10000 = 200

В этом случае ответ ровно 200, что будет точнее, чем 200,32, полученное при использовании Таймера 2. Это связано с тем, что Таймер 1 является 16-битным таймером и имеет более высокое разрешение.

,