#1 2025-10-04 23:24:53

James_Pont
Учасник
Зареєстрований: 2025-10-04
Повідомлень: 8

Кухонний комбайн на базі ардуїно. Потрібна допомога.

Доброго дня. Дістався мені непоганий кухонний комбайн profi cook pc km 1004 але з нюансом згоріла плата керування. Так з'явилася ідея відновити з допомогою ардуїно нано. За базу вирішив взяти код від ПІТ регулятора так як вже з заводу двигун має датчик холла.

const int obMin = 200;          //ввести минимальные обороты
const int obMax = 9000;         //ввести максимальные обороты
const int kImp = 60;          //ввести кол-во импульсов на 10 оборотов
const int minzn = 120;           //  минимальное значение симмистора на котором начинается вращение.
const int ogrmin =  70 ;         // ограничение симистора на минимальных оборотах.
const int mindimming = 80;        //значение симистора при закллинившем станке (первоначальный импульс)
const int dopusk =  200 ;         //допуск оборотов в минус и плюс

int AC_LOAD = 3;    // пин управления симистором
volatile int dimming = 130;  // время задержки от нуля   7 = максимально, 130 = минимально
volatile unsigned long time; // время в микросекундах срабатывания датчика нуля
unsigned long tims;           // переменная показаний времени


int holl = 0;    //переменная  срабатываня датчика
int pR;                  // показания регулятора
int ogr ;                 //переменная ограничений симистора натекущих оборотах
volatile int sp = 0;           //переменная суммы срабатываний датчика
volatile int prOb ;   //предвар реальн обороты
volatile int rOb ;    // реальные обороты

volatile unsigned int int_tic;    //переменные для подсчёта времени между импульсами.
volatile unsigned long tic;
volatile int t = 0;               //минимальное время импульсов +1
int val ;
void setup()
{
  
  t = (15000 / ( obMin * (kImp / 10))) * 2; //высчитываем минимальное время импульсов +1
  pinMode(AC_LOAD, OUTPUT);        // назначаем выходом
  attachInterrupt(0, zero_crosss_int, RISING);  // прерывание по пину 2
Serial.begin(9600);

  pinMode (8, INPUT); // вход сигнала ICP( №8 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
  tic = ((uint32_t)int_tic << 16) | ICR1 ; //подсчёт тиков
  ICR1 = 0; int_tic = 0; TCNT1 = 0;
  sp = sp + 1 ; // для подсчёта оборотов в минуту.
  holl = holl + 1;
}   // после каждого срабатывания датчика холл+1


ISR (TIMER1_OVF_vect) { //прерывание для счёта по переполнению uint
  int_tic++; //считать переполнения через 65536 тактов
  if (int_tic > t) {
    tic = 0;  //если на входе пусто более минимального времени то обнулить счётчики
    int_tic = 0;
  }
  if (int_tic > 500) {
    dimming = 130; // если стоим 2 секунды, то сбрасываем напряжение.
  }
}

// the interrupt function must take no parameters and return nothing
void zero_crosss_int()  // function to be fired at the zero crossing to dim the light
{
  time = micros();

}

void loop()  {


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

  if (val > 0) {                                       //   если регулятор больше 0
    if ( holl >= 1) {                                  // если сработал датчик
      prOb = 60000000 / ((tic * 0.0625 ) * kImp / 10); //Высчитываем обороты по показаниям датчика
      if ( prOb >= 0) {                                //проверяем на соответствие.
        rOb = prOb ;                                   //если нормально, записываем в реальные обороты
      }
     
      ogr = map(val, 0, 1023, ogrmin, 7);              //исходя из показаний регулятора узнаём на сколько может быть открыт симистор.
      
      dimming = map(rOb, (pR - dopusk), (pR + dopusk), ogr, minzn); //рассчитываем управление симистором.
      holl = 0;                                                       // обнуляем срабатывание датчика
    }
    
    if (tic == 0) {                                    // если двигатель не вращается
      dimming = mindimming ;                          //  время задержки равно первоначальному импульсу
    }
    dimming = constrain(dimming, ogr, minzn) ;       //  Следим чтоб время задержки было не меньше ограничения и не больше минимального значения
  }
  else {
    dimming = 130;                                   //Если регулятор на 0 то время задержки 130
   
  }


  int dimtime = (75 * dimming);               // For 60Hz =>65
  tims = micros();                            // считываем время, прошедшее с момента запуска программы
  if (tims >= (time + dimtime)) {             //если время больше или равно времени срабатывания нуля + время задержки

    digitalWrite(AC_LOAD, HIGH);              // открываем симистор
    delayMicroseconds(10);                   // задержка 10 микросекунд (для 60Hz = 8.33)
    digitalWrite(AC_LOAD, LOW);              // выключаем сигнал на симистор.
  }
  else {}
}

Тільки залишилось додати п'ять кнопок з вілповідними програмамми, але щось не виходить.

//константы
const int obMin = 200;          //ввести минимальные обороты
const int obMax = 9000;         //ввести максимальные обороты
const int kImp = 60;          //ввести кол-во импульсов на 10 оборотов
const int minzn = 120;           //  минимальное значение симмистора на котором начинается вращение.
const int ogrmin =  70 ;         // ограничение симистора на минимальных оборотах.
const int mindimming = 80;        //значение симистора при закллинившем станке (первоначальный импульс)
const int dopusk =  200 ;         //допуск оборотов в минус и плюс
//переменные 
int AC_LOAD = 3;    // пин управления симистором
volatile int dimming = 130;  // время задержки от нуля   7 = максимально, 130 = минимально
volatile unsigned long time; // время в микросекундах срабатывания датчика нуля
unsigned long tims;           // переменная показаний времени

//unsigned long currentTime;     //временные переменные для таймера экрана
//unsigned long loopTime;

int holl = 0;    //переменная  срабатываня датчика
int pR;                  // показания регулятора
int ogr ;                 //переменная ограничений симистора натекущих оборотах
volatile int sp = 0;           //переменная суммы срабатываний датчика
volatile int prOb ;   //предвар реальн обороты
volatile int rOb ;    // реальные обороты

volatile unsigned int int_tic;    //переменные для подсчёта времени между импульсами.
volatile unsigned long tic;
volatile int t = 0;               //минимальное время импульсов +1
int val ;

unsigned char mode;
boolean flag = 0;
boolean btn_flag = 0;
boolean btnState;
unsigned long btnTimer = 0;

#define button_manual 4
#define button_mixing 5
#define button_egg_milk 6
#define button_fruit_juice 7
#define button_grinding 9

#define led_manual A1
#define led_mixing A2
#define led_egg_milk A3
#define led_fruit_juice A4
#define led_grinding A5
void setup() {
  Serial.begin(9600);
  pinMode(button_manual, INPUT_PULLUP);
  pinMode(led_manual, OUTPUT);
  pinMode(button_mixing, INPUT_PULLUP);
  pinMode(led_mixing, OUTPUT);
  pinMode(button_egg_milk, INPUT_PULLUP);
  pinMode(led_egg_milk, OUTPUT);
  pinMode(button_fruit_juice, INPUT_PULLUP);
  pinMode(led_fruit_juice, OUTPUT);
  pinMode(button_grinding, INPUT_PULLUP);
  pinMode(led_grinding, OUTPUT);

 t = (15000 / ( obMin * (kImp / 10))) * 2; //высчитываем минимальное время импульсов +1
  pinMode(AC_LOAD, OUTPUT);        // назначаем выходом
  attachInterrupt(0, zero_crosss_int, RISING);  // прерывание по пину 2
Serial.begin(9600);


 pinMode (8, INPUT); // вход сигнала ICP( №8 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
  tic = ((uint32_t)int_tic << 16) | ICR1 ; //подсчёт тиков
  ICR1 = 0; int_tic = 0; TCNT1 = 0;
  sp = sp + 1 ; // для подсчёта оборотов в минуту.
  holl = holl + 1;
}   // после каждого срабатывания датчика холл+1


ISR (TIMER1_OVF_vect) { //прерывание для счёта по переполнению uint
  int_tic++; //считать переполнения через 65536 тактов
  if (int_tic > t) {
    tic = 0;  //если на входе пусто более минимального времени то обнулить счётчики
    int_tic = 0;
  }
  if (int_tic > 500) {
    dimming = 130; // если стоим 2 секунды, то сбрасываем напряжение.
  }
}

void zero_crosss_int()  // function to be fired at the zero crossing to dim the light
{
  time = micros();

}

void loop() {


  // читаем инвертированное значение для удобства
 btnState = !digitalRead(4);
  if (btnState && !flag && millis() - btnTimer > 200) {
    flag = true;
    btnTimer = millis();
  }
  if (btnState && flag && millis() - btnTimer > 500) {
    btnTimer = millis();
    mode = 1;
  flag =!flag;
  }
  if (!btnState && flag && millis() - btnTimer > 500) {
    flag = false;
    btnTimer = millis();
  }

  btnState = !digitalRead(button_mixing);                            // режим миксер
  if (btnState == 1 && btn_flag == 0 && millis() - btnTimer > 200) {
    btn_flag = 1;
    btnTimer = millis();
flag =!flag;
mode = 2;
    // digitalWrite(led, flag);
  }  
  if (btnState == 0 && btn_flag == 1) {
    btn_flag = 0;
    }
     else if (btnState == 1 && flag == 1 && mode > 0) {
   mode = 0;
    }
      btnState = !digitalRead(button_egg_milk);                        // режим сливки
  if (btnState == 1 && btn_flag == 0 && millis() - btnTimer > 200) {
    btn_flag = 1;
    btnTimer = millis();
flag =!flag;
mode = 3;
    // digitalWrite(led, flag);
  }  
  if (btnState == 0 && btn_flag == 1) {
    btn_flag = 0;
    }
     else if (btnState == 1 && flag == 1 && mode > 0) {
   mode = 0;
    }
      btnState = !digitalRead(button_fruit_juice);                       //  режим блендер
  if (btnState == 1 && btn_flag == 0 && millis() - btnTimer > 200) {
    btn_flag = 1;
    btnTimer = millis();
   flag =!flag;
   mode = 4; 
    // digitalWrite(led, flag);
  }  
  if (btnState == 0 && btn_flag == 1) {
    btn_flag = 0;
    }
     else if (btnState == 1 && flag == 1 && mode > 0) {
   mode = 0;
    }

      btnState = !digitalRead(button_grinding);                        // режим мясорубка
  if (btnState == 1 && btn_flag == 0 && millis() - btnTimer > 200) {
    btnTimer = millis();
    btn_flag = 1;
   flag =!flag;
   mode = 5;
    // digitalWrite(led, flag);
  }  
  if (btnState == 0 && btn_flag == 1) {
    btn_flag = 0;
    }
   else if (flag == 1 && mode == 5 ) {
   mode = 0;
    }

 switch(mode){
  case 0:
digitalWrite(led_manual, LOW);
digitalWrite(led_mixing, LOW);
digitalWrite(led_egg_milk, LOW);
digitalWrite(led_fruit_juice, LOW);
digitalWrite(led_grinding, LOW);
Serial.println("stop");
  break;
  case 1: 
  
  val = analogRead(A0);
  pR = map(val, 0, 1023, obMin, obMax); //Приводим показания регулятора к минимальным и максимальным оборотам

  if (val > 0) {                                       //   если регулятор больше 0
    if ( holl >= 1) {                                  // если сработал датчик
      prOb = 60000000 / ((tic * 0.0625 ) * kImp / 10); //Высчитываем обороты по показаниям датчика
      if ( prOb >= 0) {                                //проверяем на соответствие.
        rOb = prOb ;                                   //если нормально, записываем в реальные обороты
      }
     
      ogr = map(val, 0, 1023, ogrmin, 7);              //исходя из показаний регулятора узнаём на сколько может быть открыт симистор.
      
      dimming = map(rOb, (pR - dopusk), (pR + dopusk), ogr, minzn); //рассчитываем управление симистором.
      holl = 0;                                                       // обнуляем срабатывание датчика
    }
    
    if (tic == 0) {                                    // если двигатель не вращается
      dimming = mindimming ;                          //  время задержки равно первоначальному импульсу
    }
    dimming = constrain(dimming, ogr, minzn) ;       //  Следим чтоб время задержки было не меньше ограничения и не больше минимального значения
  }
  else {
    dimming = 130;                                   //Если регулятор на 0 то время задержки 130 
  }
  int dimtime = (75 * dimming);               // For 60Hz =>65
  tims = micros();                            // считываем время, прошедшее с момента запуска программы
  if (tims >= (time + dimtime)) {             //если время больше или равно времени срабатывания нуля + время задержки

    digitalWrite(AC_LOAD, HIGH);              // открываем симистор
    delayMicroseconds(10);                   // задержка 10 микросекунд (для 60Hz = 8.33)
    digitalWrite(AC_LOAD, LOW);              // выключаем сигнал на симистор.
  }
  else {}

Serial.println("manual");
digitalWrite(led_manual, HIGH);
digitalWrite(led_mixing, LOW);
digitalWrite(led_egg_milk, LOW);
digitalWrite(led_fruit_juice, LOW);
digitalWrite(led_grinding, LOW);
   break;
   case 2: mixing(); break;
    case 3:egg_milk();break;
     case 4:fruit_juice(); break;
      case 5:grinding(); break;
 } 

}
void grinding(){
Serial.println("grinding");
digitalWrite(led_manual, LOW);
digitalWrite(led_mixing, LOW);
digitalWrite(led_egg_milk, LOW);
digitalWrite(led_fruit_juice, LOW);
digitalWrite(led_grinding, HIGH);
}
void manual(unsigned long tm, unsigned int ho){

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

  if (val > 0) {                                       //   если регулятор больше 0
    if ( ho >= 1) {                                  // если сработал датчик
      prOb = 60000000 / ((tic * 0.0625 ) * kImp / 10); //Высчитываем обороты по показаниям датчика
      if ( prOb >= 0) {                                //проверяем на соответствие.
        rOb = prOb ;                                   //если нормально, записываем в реальные обороты
      }
     
      ogr = map(val, 0, 1023, ogrmin, 7);              //исходя из показаний регулятора узнаём на сколько может быть открыт симистор.
      
      dimming = map(rOb, (pR - dopusk), (pR + dopusk), ogr, minzn); //рассчитываем управление симистором.
      ho = 0;                                                       // обнуляем срабатывание датчика
    }
    
    if (tic == 0) {                                    // если двигатель не вращается
      dimming = mindimming ;                          //  время задержки равно первоначальному импульсу
    }
    dimming = constrain(dimming, ogr, minzn) ;       //  Следим чтоб время задержки было не меньше ограничения и не больше минимального значения
  }
  else {
    dimming = 130;                                   //Если регулятор на 0 то время задержки 130  
  }
  int dimtime = (75 * dimming);               // For 60Hz =>65
  tims = micros();                            // считываем время, прошедшее с момента запуска программы
  if (tims >= (tm + dimtime)) {             //если время больше или равно времени срабатывания нуля + время задержки

    digitalWrite(AC_LOAD, HIGH);              // открываем симистор
    delayMicroseconds(10);                   // задержка 10 микросекунд (для 60Hz = 8.33)
    digitalWrite(AC_LOAD, LOW);              // выключаем сигнал на симистор.
  }
  else {}

Serial.println("manual");
digitalWrite(led_manual, HIGH);
digitalWrite(led_mixing, LOW);
digitalWrite(led_egg_milk, LOW);
digitalWrite(led_fruit_juice, LOW);
digitalWrite(led_grinding, LOW);
}
void mixing(){
Serial.println("mixing");
digitalWrite(led_manual, LOW);
digitalWrite(led_mixing, HIGH);
digitalWrite(led_egg_milk, LOW);
digitalWrite(led_fruit_juice, LOW);
digitalWrite(led_grinding, LOW);

  pR = 9000; // режи з постійними обертами 

  if (val > 0) {                                       //   если регулятор больше 0
    if ( holl >= 1) {                                  // если сработал датчик
      prOb = 60000000 / ((tic * 0.0625 ) * kImp / 10); //Высчитываем обороты по показаниям датчика
      if ( prOb >= 0) {                                //проверяем на соответствие.
        rOb = prOb ;                                   //если нормально, записываем в реальные обороты
      }
     
      ogr = map(val, 0, 1023, ogrmin, 7);              //исходя из показаний регулятора узнаём на сколько может быть открыт симистор.
      
      dimming = map(rOb, (pR - dopusk), (pR + dopusk), ogr, minzn); //рассчитываем управление симистором.
      holl = 0;                                                       // обнуляем срабатывание датчика
    }
    
    if (tic == 0) {                                    // если двигатель не вращается
      dimming = mindimming ;                          //  время задержки равно первоначальному импульсу
    }
    dimming = constrain(dimming, ogr, minzn) ;       //  Следим чтоб время задержки было не меньше ограничения и не больше минимального значения
  }
  else {
    dimming = 130;                                   //Если регулятор на 0 то время задержки 130
   
  }


  int dimtime = (75 * dimming);               // For 60Hz =>65
  tims = micros();                            // считываем время, прошедшее с момента запуска программы
  if (tims >= (time + dimtime)) {             //если время больше или равно времени срабатывания нуля + время задержки

    digitalWrite(AC_LOAD, HIGH);              // открываем симистор
    delayMicroseconds(10);                   // задержка 10 микросекунд (для 60Hz = 8.33)
    digitalWrite(AC_LOAD, LOW);              // выключаем сигнал на симистор.
  }
  else {}


}
void egg_milk(){
Serial.println("egg");
digitalWrite(led_manual, LOW);
digitalWrite(led_mixing, LOW);
digitalWrite(led_egg_milk, HIGH);
digitalWrite(led_fruit_juice, LOW);
digitalWrite(led_grinding, LOW);
}
void fruit_juice(){
Serial.println("fruit_juice");
digitalWrite(led_manual, LOW);
digitalWrite(led_mixing, LOW);
digitalWrite(led_egg_milk, LOW);
digitalWrite(led_fruit_juice, HIGH);
digitalWrite(led_grinding, LOW);
}

Суть в тому що в першому випадку двигун працює ідеально, а в другом де я додав кнопок двигун починає сіпатись. Розуміє що десь натупив, а не рузумію де. Чи не може хтось допогти ? Шкода викидквати гарну річ smile

Остання редакція James_Pont (2025-10-04 23:27:15)

Неактивний

#2 2025-10-05 10:58:18

jokeer
Гість

Re: Кухонний комбайн на базі ардуїно. Потрібна допомога.

Ви якось дивно управляєте симістором. Було б логічно ловити interrupt по переходу через 0 , запускати таймер,  і по interrupt від таймера запускати симістор. Всередині loop там що завгодно може вилізти.

#3 2025-10-05 11:21:49

dimich
Учасник
Зареєстрований: 2023-12-01
Повідомлень: 634

Re: Кухонний комбайн на базі ардуїно. Потрібна допомога.

В логіку коду не вчитувався, бо він сумбурний і ледь структурований. Сумнівають, що воно навіть скомпілиться. Але як мінімум, у вас неатомарні звернення до змінних, які оновлюються в обробниках переривань. ПЗ для вбудованих систем так не пишеться.
Наскільки критичний той таймінг керування симістором? 10 мкс співрозмірне з часом виконання обробників переривань. Не очікуйте, що та затримка буде завжди 10 мкс. А якщо важлива не тільки тривалість імпульсів, а й тривалість пауз між ними, то тільки analogRead() дає затримку більше 100 мкс.

Неактивний

#4 2025-10-05 12:21:39

James_Pont
Учасник
Зареєстрований: 2025-10-04
Повідомлень: 8

Re: Кухонний комбайн на базі ардуїно. Потрібна допомога.

Добре. Спробую переписати з урахуванням ваших коментарів. Може що вийде, тоді відпишусь. Заодно думаю ще додати принципову схему.

Неактивний

#5 2025-10-05 12:53:02

jokeR
Учасник
Зареєстрований: 2024-12-12
Повідомлень: 162

Re: Кухонний комбайн на базі ардуїно. Потрібна допомога.

Із схемою теж непогано wink
Ще хороша ідея - синхронізувати все з частотою мережі. Піднімати прапорець по interrupt і крутити далі бізнес-логіку з кнопками і всим іншим. Тоді не треба запам"ятовувати мілісекунди для кнопок, можна рахувати 100-герцові тіки. І за analogread можна смикати рідше. Це ж регулятор обертів, так? Ви ж не крутите його 3000 обертів за хвилину?

Неактивний

#6 2025-10-06 19:32:17

James_Pont
Учасник
Зареєстрований: 2025-10-04
Повідомлень: 8

Re: Кухонний комбайн на базі ардуїно. Потрібна допомога.

Schematic_Arduino_2025-10-05.png

Неактивний

#7 2025-10-06 19:35:06

James_Pont
Учасник
Зареєстрований: 2025-10-04
Повідомлень: 8

Re: Кухонний комбайн на базі ардуїно. Потрібна допомога.

Швидко зробив, трохи було часу обмаль.

Неактивний

#8 2025-10-06 20:30:15

jokeer
Гість

Re: Кухонний комбайн на базі ардуїно. Потрібна допомога.

Ну, все правильно, питань ніт wink Всі рекомендації в силі. Конденсатори на живленні є, але на схемі не показані, правда? Ще непогано задіяти watchdog.

#9 2025-10-06 21:10:22

James_Pont
Учасник
Зареєстрований: 2025-10-04
Повідомлень: 8

Re: Кухонний комбайн на базі ардуїно. Потрібна допомога.

Так є. Не став заморочуватись

jokeer пише:

Ну, все правильно, питань ніт wink Всі рекомендації в силі. Конденсатори на живленні є, але на схемі не показані, правда? Ще непогано задіяти watchdog.

Неактивний

#10 2025-10-06 22:04:36

jokeer
Гість

Re: Кухонний комбайн на базі ардуїно. Потрібна допомога.

Хттпс://arduino.stackexchange.com/questions/83616/turn-off-timer1-timer1-one-shot
Здається те що вам потрібно

#11 2025-10-07 16:48:07

James_Pont
Учасник
Зареєстрований: 2025-10-04
Повідомлень: 8

Re: Кухонний комбайн на базі ардуїно. Потрібна допомога.

jokeer пише:

Хттпс://arduino.stackexchange.com/questions/83616/turn-off-timer1-timer1-one-shot
Здається те що вам потрібно

Дякую! Корисна інформація.

Неактивний

Швидке повідомлення

Введіть повідомлення і натисніть Надіслати

Підвал форуму