цифровая электроника
вычислительная техника
встраиваемые системы

 

Программный ШИМ на Arduino с использованием функции millis

Автор: Mike(admin) от 18-06-2018, 04:05

Arduino Uno имеет шесть контактов, предназначенных для широтно-импульсной модуляции (ШИМ или PWM). ШИМ отлично подходит для аналогового управления скоростью двигателей или зажиганием светодиодов. Но что, если вы хотите контролировать более 6 устройств? Или что, если вы используете линии ШИМ для управления сервомоторами, но все же хотите вывести светодиод на 7-й вывод?


Программный ШИМ на Arduino с использованием функции millis

Один из вариантов – изменение платы. Например, вы можете перейти на Arduino Mega 2560. Но это означает, что вы берете более крупную плату, что сулит больше затрат, как и при использовании дополнительных шилдов расширения. Тем не менее, выход есть. Используя функции millis() и micros(), можно полностью реализовать ШИМ программным способом. В этом материале приводится код, с помощью которого вы можете, используя функции micros() и millis(), получить больше линий ШИМ на Arduino Uno, Nano или Pro Mini. Вероятно, эта техника будет работать на других платах экосистемы Arduino.


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



// макросы для состояния светодиодов
#define ON true
#define OFF false
 
// переменные для синхронизации паттернов
unsigned long currentMillis = millis();
unsigned long previousMillis = 0;
unsigned long millisInterval = 100;
 
// переменные для программного ШИМ
unsigned long currentMicros = micros();
unsigned long previousMicros = 0;
// это частота ШИМ
// частота = 1 / (2 * microInterval)
unsigned long microInterval = 250;
 
const byte pwmMax = 100;
 
// затухание (для времени)
int fadeIncrement = 1;
 
// для свойств каждого программного ШИМ-вывода
typedef struct pwmPins {
  int pin;
  int pwmValue;
  bool pinState;
  int pwmTickCount;
} pwmPin;
 
// создание линий программного ШИМ
// это могут быть любые линии ввода/вывода
// которые могут быть установлены на выход
const int pinCount = 8;
const byte pins[pinCount] = {2,3,5,6,9,10,11,12};
 
pwmPin myPWMpins[pinCount];
 
// функция для настройки состояний программных ШИМ-линий
// можно изменить под свои потребности
// это создает чередующиеся паттерны затухания
void setupPWMpins() {
  for (int index=0; index < pinCount; index++) {
    myPWMpins[index].pin = pins[index];
 
    // немного смешаем
    // изменяет начальный pwmValue на нечетный и четный
    if (index % 2)
      myPWMpins[index].pwmValue = 25;
    else
      myPWMpins[index].pwmValue = 75;
 
    myPWMpins[index].pinState = ON;
    myPWMpins[index].pwmTickCount = 0;
 
    // в отличие от analogWrite (), это необходимо
    pinMode(pins[index], OUTPUT);
  }
}
 
void pwmFadePattern() {
  // проходим через каждую линию ШИМ и увеличиваем значение программного ШИМ
  // это будет похоже на вызов analogWrite () на каждом выводе аппаратного ШИМ
  for (int index=0; index < pinCount; index++) {
    myPWMpins[index].pwmValue += fadeIncrement;
    if (myPWMpins[index].pwmValue > 100)
      myPWMpins[index].pwmValue = 0;
  }
}
 
void handlePWM() {
  currentMicros = micros();
  // проверяем, нужно ли нам еще увеличивать счетчики ШИМ
    if (currentMicros - previousMicros >= microInterval) {
    // Инкрементирование счетчика каждой линии
    for (int index=0; index < pinCount; index++) {
    // каждая линия имеет свой tickCounter
      myPWMpins[index].pwmTickCount++;
 
    // определить, будем рассчитываем мы время включения on или время выключения off
      if (myPWMpins[index].pinState == ON) {
        if (myPWMpins[index].pwmTickCount >= myPWMpins[index].pwmValue) {
          myPWMpins[index].pinState = OFF;
        }
      } else {
        // если это не включение, а выключение
        if (myPWMpins[index].pwmTickCount >= pwmMax) {
          myPWMpins[index].pinState = ON;
          myPWMpins[index].pwmTickCount = 0;
        }
      }
      // вероятно, может использовать некоторую побитовую оптимизацию здесь
      // digitalWrite () действительно замедляет работу после 10 линий.
      digitalWrite(myPWMpins[index].pin, myPWMpins[index].pinState);
    }
    // сбросить счетчик micros()
    digitalWrite(13, !digitalRead(13));
    previousMicros = currentMicros;
  }
}
 
void setup() {
  setupPWMpins();
  pinMode(13, OUTPUT);
}
 
void loop() {

  handlePWM();
 
  // проверить таймер для затухающего паттерна
  // это было бы то же самое, если бы мы использовали analogWrite()
  currentMillis = millis();
  if (currentMillis - previousMillis >= millisInterval) {
    pwmFadePattern();
 
    // установка таймера для следующего отсчета
    previousMillis = currentMillis;
  }
}



© digitrode.ru


Теги: Arduino, ШИМ



   Благодарим Вас за интерес к информационному проекту digitrode.ru.
   Если Вы хотите, чтобы интересные и полезные материалы выходили чаще, и было меньше рекламы,
   Вы можее поддержать наш проект, пожертвовав любую сумму на его развитие.


Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь.
Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.

Комментарии:

Оставить комментарий