Проблема с увеличением ШИМ с течением времени

Первый пост здесь. Итак, у меня есть проблема, которую я определил, но я не совсем уверен, как ее исправить. Я был бы очень признателен за некоторые входные данные и предложения. Я понимаю, что проблема в моем "pwmDelta", но не знаю, что делать, чтобы исправить это.

Я пытаюсь написать программу, которая будет увеличивать значение вывода 3 в течение заданного промежутка времени линейным образом, начиная с моей нижней точки и заканчивая в моей высшей точке.

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

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

int motor1 = 3;         //контакт для выхода ШИМ на двигатель
float t = 0;            //Переменная для отслеживания времени
int tLim = 30;          // Лимит времени для рампы
float lowLim = 21;      //Нижний предел, в рабочем цикле %
float highLim = 65;     // Верхний предел, в рабочем цикле %
float motorPWM = 53.55; //Начальное значение ШИМ, в битах
float pwmDelta = ((255/100)*(highLim-lowLim))/(tLim); //Дельта-уравнение, чтобы рассчитать, насколько изменится значение ШИМ при каждом его увеличении
float motorDelta;       //Переменная для записи значения на выход двигателя

void setup() {
  pinMode(motor1, OUTPUT);
  analogWrite(motor1, 53.55); //запустить двигатель с начальным значением на 20 секунд до начала рампы
  delay(20000);
  Serial.begin(9600);
}

void loop() {
  motorDelta = motorPWM + pwmDelta; // увеличение выходного значения на основе дельта-уравнения
  motorPWM = motorDelta; //Установка нового увеличенного значения равным старому значению, поэтому увеличение можно продолжить

  if (t <= tLim) {  // Проверяем, что время <= лимит времени
    analogWrite(motor1, (motorDelta)); // записываем увеличенное значение на выходной контакт
    delay(1000);  // ждем 1 секунду, увеличиваем t, чтобы следить за временем
    t++;
  }
  else {
    analogWrite(motor1, motorPWM = 165.75); //устанавливаем вывод на высокое значение на 60 секунд, затем устанавливаем на 0
    delay(60000);
    analogWrite(motor1, motorPWM = 0);
  }
  Serial.print(motorDelta);
  Serial.println();
  Serial.print(t);
  Serial.println();
}

, 👍2

Обсуждение

подумайте об этом.... какой еще параметр можно варьировать?, @jsotola

@jsotola 255/100 должно быть постоянным, так как это дает мне 2,55 бита на 1 процент рабочего цикла. Любой из других параметров в _pwmDelta_ можно изменять, и он предназначен для этого. Поэтому, когда он будет завершен, пользователь может ввести нижний / верхний предел в % рабочего цикла и время, и выход будет увеличиваться линейным образом в течение этого периода времени. Если вы имеете в виду другие параметры за пределами этого уравнения, я думаю, я не понимаю., @gfritz25


4 ответа


2
float pwmDelta=((255/100)*(highLim-lowLim))/(tLim);

Эта строка должна быть:

float pwmDelta=((255.0/100)*(highLim-lowLim))/(tLim);

Добавление .0 сообщает компилятору, что нужно выполнить эту математику, используя числа с плавающей запятой, и вы получите 2,55. Без него математика выполняется с помощью int, и результат равен 1, что вам не нужно.

analogWrite(motor1, 53.55); 

Просто напишите 54. AnalogWrite принимает только целые значения.

analogWrite(motor1, motorPWM=165.75);

Вы действительно должны сделать это двумя строками, заданием и аналоговой записью. Такой способ приводит к запутанному коду. Кроме того, AnalogWrite принимает только целые значения, поэтому ваши десятичные числа также бесполезны.

,

analogWrite(motor1, 53.55) выводит 53: преобразование числа с плавающей запятой в целое число не округляется, оно просто усекает дробную часть., @Edgar Bonet

Ты прав. Но я подумал, что 54 будет ближе к тому, что он на самом деле хотел, потому что я округлил. Я предлагал ему использовать 54, а не то, что AnalogRead будет рассматривать его поплавок как 54., @Delta_G


0

Вы пытаетесь плавно увеличить значение ШИМ с 21 % до 65 % в течение 30 секунд с интервалом в 1 секунду, что не очень хорошо работает, поскольку значение ШИМ должно быть байтом.

Это означает, что значение, записанное в регистр ШИМ, изменится с 21*255/100 на 65*255/100, то есть с 53,55 на 165,75.

Используйте значения 53 и 166, что даст разницу в 113.

Ваш код написан для обновления значения ШИМ каждые 1000 мс, что дает 30 шагов, большинство из которых не являются целыми числами.

Вместо этого увеличьте значение ШИМ на 113 шагов. Каждый шаг будет целым числом, и каждый шаг будет иметь длину 265 486 мкс.

,

0

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

  • Вместо использования delay() вы можете управлять временем с помощью millis(). Это сделает рампу более плавной, и вы сможете добавьте код в цикл, если это необходимо, который не будет заблокирован задержки.
  • Сохранение времени в миллисекундах и значения ШИМ в естественном виде. единицы (а не проценты) упрощают код.
  • Удалите лишние переменные, такие как motorDelta, которые одинаковы как MotorPWM.
  • Последовательный отступ и удаление лишних скобок помогают читабельность.

Вот моя попытка реализовать эти предложения:

const int motor1 = 3;  // контакт для выхода ШИМ на двигатель
const unsigned long tLim = 30000;  // продолжительность рампы ШИМ
const float PWM_unit = 255.0/100;  // преобразовать проценты в шкалу ШИМ
const float lowLim = PWM_unit * 21;
const float highLim = PWM_unit * 65;
const float PWM_rate = (highLim-lowLim) / tLim;

unsigned long start_time;  // начало рампы
int previousPWM = 0;

void setup() {
    pinMode(motor1, OUTPUT);
    analogWrite(motor1, round(lowLim));
    delay(20000);
    Serial.begin(9600);
    Serial.println(" t   PWM");
    Serial.println("--------");
    start_time = millis();
}

void loop() {
    unsigned long t = millis() - start_time;

    if (t >= tLim) {  // мы закончили
        analogWrite(motor1, round(highLim));
        delay(60000);  // держать на highLim в течение 60 с
        analogWrite(motor1, 0);  // затем останавливаемся
        exit(0);
    }

    int motorPWM = round(lowLim + t * PWM_rate);
    if (motorPWM != previousPWM) {
        analogWrite(motor1, motorPWM);
        Serial.print(t / 1000.0);
        Serial.print("  ");
        Serial.println(motorPWM);
        previousPWM = motorPWM;
    }
}
,

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


0

Происходит следующее: вы записали дробь таким образом, что компилятор интерпретирует ее как целочисленную математику. C/C++ усекает дроби, поэтому 255/100 — это всего лишь 2 (и если какие-либо из остальных являются целыми числами, они также вызывают усечение). Что вам нужно сделать, так это сделать какое-то число в этом вычислении десятичным — не имеет значения, какое именно — или преобразовать входные данные в число с плавающей запятой с (float) somevariable.

Пока все это находится в одной строке, все задействованные вычисления (за исключением порядка операций, поэтому приведите одну из разделяемых переменных к числу с плавающей запятой, если они указаны в отдельных терминах в скобках) будут быть с плавающей запятой. Обратите внимание, что если вы зададите здесь значение целого числа, оно будет усечено только после точных математических вычислений, так что это более правильно.

float pwmDelta = ((255/100)*(highLim-lowLim))/(tLim);

Должно быть:

float pwmDelta = 2,55*(highLim-lowLim)/(float)tLim; (Это также делает все это одним термином.)

,