Ну я же не так написал. В этом случае вам нужны именно две строчки. Поскольку analogWrite перенастраивает выход, я не вникал как перенастраивает, может и будет работать ваша конструкция, но я бы использовал всегда две строчки сначала настройка как цифровой выход, а потом значение этого выхода.
if (runState) {
//...
} else {
pinMode(3,OUTPUT);
digitalWrite(3,LOW);
}
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;
}
Для обработки кнопки я ввел переменную, которая считает количество нажатий. И вот по первому двигатель плавно разгоняется до установленных оборотов, благодаря вам. А по второму останавливается.
#34
Что бы опустить шим к нулю лучше сделать не
analogWrite, а вот так :
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); }Ну я же не так написал. В этом случае вам нужны именно две строчки. Поскольку analogWrite перенастраивает выход, я не вникал как перенастраивает, может и будет работать ваша конструкция, но я бы использовал всегда две строчки сначала настройка как цифровой выход, а потом значение этого выхода.
if (runState) { //... } else { pinMode(3,OUTPUT); digitalWrite(3,LOW); }в коде #53 после обработчика отпускания флаг сбрасывается и дальнейшие условия не работают
Полностью выложите ваш код.
#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(" "); } }Да, точно, ошибся я.... Счаз...
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, я сейчас с телефона, поэтому код текстом вставлю. Вставил как надо.
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); }Для обработки кнопки я ввел переменную, которая считает количество нажатий. И вот по первому двигатель плавно разгоняется до установленных оборотов, благодаря вам. А по второму останавливается.
Ну количество путей решений в си бесконечно, на то он и си . Работает, и хорошо.
Большое спасибо за помощь
Не за что. Вы сам все делали.
Надо полагать - заработало....
Конечно заработал, вот сколько за эти два дня ТС написал? и поблагодарил и окончательный код выложил.