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

 

Программный ШИМ на 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, ШИМ




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

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

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