Плавный старт электродвигателя

Vlad1m1r
Vlad1m1r аватар
Offline
Зарегистрирован: 08.06.2019

#34

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Что бы опустить шим к нулю лучше сделать не 

analogWrite, а вот так :

pinMode(3,OUTPUT);
digitalWrite(3,LOW);

 

Vlad1m1r
Vlad1m1r аватар
Offline
Зарегистрирован: 08.06.2019
bool btnState = !digitalRead(2);
static bool runState = false;
if (btnState && !flag) {  // обработчик нажатия
  flag = true;
  //Serial.println("press");
}
if (!btnState && flag) {  // обработчик отпускания
  flag = false;
  //Serial.println("release");
}
if (!btnState && flag == true){
   runState=!runState;    
}
if (runState) {
   //... 
} else {
   digitalWrite(3,LOW); 
}

 

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Ну я же не так написал. В этом случае вам нужны именно две строчки. Поскольку analogWrite перенастраивает выход, я не вникал как перенастраивает, может и будет работать ваша конструкция, но я бы использовал всегда две строчки сначала настройка как цифровой выход, а потом значение этого выхода.

if (runState) {
   //... 
} else {
   pinMode(3,OUTPUT);
   digitalWrite(3,LOW); 
}

 

Vlad1m1r
Vlad1m1r аватар
Offline
Зарегистрирован: 08.06.2019

в коде #53 после обработчика отпускания флаг сбрасывается и дальнейшие условия не работают

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Полностью выложите ваш код.

Vlad1m1r
Vlad1m1r аватар
Offline
Зарегистрирован: 08.06.2019
#define obMin 500         //  минимальные обороты двигателя, меньше не але
#define obMax 6000      //  максимальные обороты двигателя
#define kImp 8          //  количество импульсов на 1 оборот тахо
#define PWMpin 3        //  пин выхода ШИМ D3
int16_t poten;           //  переменная регулятора скорости (потенциометра)
int16_t rpmzad;     //  показания регулятора скорости (потенциометра)
int16_t rpm;        //  переменная оборотов
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
volatile uint16_t int_tic;
volatile uint32_t tic;
bool flag = false;
const uint32_t accelTime = 5000;     // *** время разгона

void setup() {
  Serial.begin(9600);
  lcd.init(); // Turn on the blacklight and print a message.
  lcd.backlight();
  lcd.clear();
  lcd.setCursor(0, 0); lcd.print("ob/min:");

  pinMode(2, INPUT_PULLUP);
  pinMode(3, OUTPUT); // настройка D3 на выход
  pinMode(8, INPUT);  // вход сигнала ICP( D8 only для atmega328)

  //настройка 16 бит таймера-счётчика 1
  TCCR1B = 0;
  TCCR1A = 0;
  TCNT1 = 0;
  TIMSK1 = (1 << ICIE1) | (1 << TOIE1); //создавать прерывание от сигнала на пине ICP1
  TCCR1B = (1 << ICNC1) | (1 << ICES1) | (1 << CS10); //div 1
}

ISR (TIMER1_CAPT_vect) { //прерывание захвата сигнала на входе ICP1
  TCNT1 = 0;
  if (TIFR1 & (1 << TOV1)) {
    TIFR1 |= 1 << TOV1;
    if (ICR1 < 100) {
      int_tic++;
    }
  }
  tic = ((uint32_t)int_tic << 16) | ICR1 ; //подсчёт тиков
  int_tic = 0;
}

ISR (TIMER1_OVF_vect) { //прерывание для счёта по переполнению uint
  int_tic++; //считать переполнения через 65536 тактов
  if (int_tic > 244) //если на входе пусто более секунды
  {
    tic = 0;  //то обнулить счётчики
    int_tic = 0;
  }
}

void loop() {
  lcd_print_screen();
  rpm = (((float)F_CPU / tic) * 60) / kImp;
  /* tic-количество тактов процессора, совершенных за 1 период входного сигнала.
    если tic*(1/F_CPU) то будет время периода в секундах.
    если F_CPU/tic - будет частота в герцах. Как пример: Hz = (float)F_CPU / tic;
  */

  poten = analogRead(A0);                         //  потенциометр на пине А0
  rpmzad = map(poten, 0, 1023, obMin, obMax);     //  Приводим показания регулятора к минимальным и максимальным оборотам

  bool btnState = !digitalRead(2);
  static uint32_t accelTimer = 0;      // *** таймер разгона
  static bool runState = false;
  if (btnState && !flag) {  // обработчик нажатия
    accelTimer = millis();             // *** при нажатии засекаем время старта разгона
    flag = true;
    //Serial.println("press");
  }
  if (!btnState && flag) {  // обработчик отпускания
    flag = false;
    //Serial.println("release");
  }
  if (!btnState && flag == true) {
    runState = !runState;
  }
  if (runState) {
    uint32_t delta = millis() - accelTimer; // ***
    if (delta < accelTime) {            // *** пока время разгона
      rpmzad = delta * rpmzad / accelTime; // *** изменяем скорость исходя из прошедшего времени и установки резистора
    }
    // (вход, установка, п, и, д, период в секундах, мин.выход, макс. выход)
    analogWrite(3, computePID(rpm, rpmzad, 0.03, 0.01, 0.03, 0.03, 0, 255));
    // Serial.println("work");
  } else {
    pinMode(3, OUTPUT);
    digitalWrite(3, 0);
  }
}

// функция пид
int computePID(float input, float setpoint, float kp, float ki, float kd, float dt, int minOut, int maxOut) {
  float err = setpoint - input;
  static float integral = 0, prevErr = 0;
  integral = constrain(integral + (float)err * dt * ki, minOut, maxOut);
  float D = (err - prevErr) / dt;
  prevErr = err;
  return constrain(err * kp + integral + D * kd, minOut, maxOut);
}

void lcd_print_screen() { // вывод переменных на lcd_2004
  static uint32_t lcdTimer;
  if (millis() - lcdTimer > 350) {
    lcdTimer = millis();
    lcd.setCursor(7, 0);
    lcd.print(rpm);
    lcd.print("   ");
  }
}

 

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Да, точно, ошибся я.... Счаз...

 

   bool btnState = !digitalRead(2);
   static bool runState = false;
   if (btnState && !flag) {  // обработчик нажатия
     flag = true;
     runState=!runState;
     Serial.println("press");
   }
   if (!btnState && flag) {  // обработчик отпускания
     flag = false;
     Serial.println("release");
   }
   if (runState) {
      //... 
   } else {
      pinMode(3,OUTPUT);
      digitalWrite(3,LOW); 
   }

Инверсия признака работы мотора нужна только в момент нажатия, а я что то стал ей мигать в процессе работы :)

и вот в районе 86 строчки , лучше сделать так:

    if (delta < accelTime) {            // *** пока время разгона
      rpmzad = delta * rpmzad / accelTime; // *** изменяем скорость исходя из прошедшего времени и установки резистора
    } else {
        accelTimer=millis()-accelTime-1;
    }

 

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Надо полагать - заработало....

Vlad1m1r
Vlad1m1r аватар
Offline
Зарегистрирован: 08.06.2019

Brokly, я сейчас с телефона, поэтому код текстом вставлю. Вставил как надо. 

bool flag = false;
bool btnState = !digitalRead(2); // состояние кнопки
if (btnState && flag == false) { // нажал кнопку
flag = true;
accelTimer = millis();
}
if (!btnState && flag == true) { // отпустил кнопку
flag = false;
btnPress = btnPress + 1;
if (btnPress == 2) btnPress = 0;
}
if (btnPress == 0) { // повторное нажатие
sbi(TCCR2A, COM2B1);
OCR2B = 0; // установить на D3 PWM=0
//pinMode(3, OUTPUT);
//digitalWrite(3, LOW);
//Serial.println("stop");
}
if (btnPress == 1) { // первое нажатие
uint32_t delta = millis() - accelTimer; // ***
if (delta < accelTime) { // *** пока время разгона
rpmzad = delta * rpmzad / accelTime; // *** изменяем скорость исходя из прошедшего времени и установки резистора
}
cbi(TCCR2A, COM2B1); // эта и нижняя строчка аналог analogWrite(3, computePID(rpm, rpmzad, 0.03, 0.01, 0.03, 0.03, 0, 255));
OCR2B = computePID(rpm, rpmzad, 0.03, 0.01, 0.03, 0.03, 0, 255); // computePID(вход, установка, п, и, д, период в секундах, мин.выход, макс. выход)
//Serial.println(OCR2B);
}

 

Vlad1m1r
Vlad1m1r аватар
Offline
Зарегистрирован: 08.06.2019

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

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Ну количество путей решений в си бесконечно, на то он и си . Работает, и хорошо.

Vlad1m1r
Vlad1m1r аватар
Offline
Зарегистрирован: 08.06.2019

Большое спасибо за помощь

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Не за что. Вы сам все делали.

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

brokly пишет:

Надо полагать - заработало....

Конечно заработал, вот сколько за эти два дня ТС написал? и поблагодарил и окончательный код выложил.