Железная дорога на Arduino

Старик Похабыч

★★★★★★★
14 Авг 2019
4,267
1,303
Москва
Я ж там написал:
Запоминаем время
время = millis();
если прошло (сколько там в делай):
if (millis()- время>время в делай) то следующее увеличение - уменьшение.
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,267
1,303
Москва
Понимаю. Для ознакомления:
 
  • Лойс +1
Реакции: mcvall

Arhat109

★★★★✩✩✩
9 Июн 2019
473
203
Ну или автор обновит или без него.. там в общем-то все тоже самое, только "в кино" ;)
 

mcvall

✩✩✩✩✩✩✩
15 Ноя 2020
33
3
Ну или автор обновит или без него.. там в общем-то все тоже самое, только "в кино" ;)
Очень сложно это всё. За неделю перечитал много информации, нужно переварить, применить, пощупать, моргнуть светодиодом;)
 

Arhat109

★★★★✩✩✩
9 Июн 2019
473
203
Это только кажется поначалу. Начнете пговобовать, придет понимание, что это проще чем "традиционно программирование с делай" ;)
Си - очень простой язык, только требует внимательного отношения к коду и глубокого понимания "указателя". Выстрелить себе в ногу в нем можно самыми разнообразными способами, хотя современные ИДЕ (не пользуйте родное от Ардуино) следят за вашим полетом мысли и пальцев достаточно пристально.
Рекомендую ИДЕ от JetBrain, лучше пока ничего не нашел, т.к. продукцией "мелкософта" не пользуюсь принципиально.
Плюсанутое Си, кмк, слишком дорого для программирования микроконтроллеров, где все-таки "объем имеет значение"... поэтому у меня только "православное Си" в коде. :)
 
Изменено:
  • Лойс +1
Реакции: mcvall

Arhat109

★★★★✩✩✩
9 Июн 2019
473
203
Баррон "Песня. Имя песни. Название песни. Имя названия песни." .. 1969 кажись. :)

На самом деле всё примитивно и просто: Переменная (песня) - ящик для хранения значений. Имя песни - адрес в памяти. Название песни - указатель на ее адрес (значение) .. Имя названия песни - адрес хранения значения указателя.. это не "одно и тоже". ;)

Ну и "указательная арифметика" (первый класс начальной школы).. ++ к адресу .. это скока? ;) Из "особенностей" .. это помнить что имя массива есть указатель, не более.
 
  • Лойс +1
Реакции: mcvall

mcvall

✩✩✩✩✩✩✩
15 Ноя 2020
33
3
@Старик Похабыч, Приветствую. Переделал код на millis. Создал отдельную функцию void MotorStart() и затем указал её в void loop() запуск без кнопки. После рестарта МК через секунду загораются 2 светодиода (заменил ими мотор) на 10 попугаев (из 255), далее через 3 секунды на 30 попугаев и через 5 секунд на 50 попугаев. Всё как мне нужно, ок. Но есть но!
1. Когда хочу запустить эту функцию нажатием кнопки, то при нажатии светодиоды горят на максимум, и далее ничего не происходит.
2. Почему эта функция после отработки не повторяется вновь, ведь она в цикле void loop()? Спасибо!

Код на Millis:
// Управление двигателем  PWM2

unsigned long last_time, last_time2, last_time3;
const int motor1Pin1 = 5;  // номер контакта для IN1 драйвера двигателя
const int motor1Pin2 = 18; // номер контакта для IN2 драйвера двигателя
const int buttonPin = 22;  // номер контакта для кнопки
int buttonState = 0;       // переменная для хранения статуса кнопки:

// задаем свойства ШИМ-сигнала:
const int freq = 5000;     // Частота
const int ledChannel = 0;  // Канал,генерирующий PWM-сигнал для motor1Pin2
const int ledChannel_1 = 1;// Канал,генерирующий PWM-сигнал для motor1Pin1
const int resolution = 8;  // Разрешение
int dutyCycle;
int dutyCycle_1;

void setup() {
  ledcSetup(ledChannel, freq, resolution); // настраиваем ШИМ-сигнал согласно свойствам, заданным выше
  ledcSetup(ledChannel_1, freq, resolution);

  pinMode(motor1Pin1, OUTPUT);
  pinMode(motor1Pin2, OUTPUT);
  pinMode(buttonPin, INPUT);

  ledcAttachPin(motor1Pin1, ledChannel_1); // где: motor1Pin1 - контакт для вывода PWM, ledChannel - канал,генерирующий PWM-сигнал для motor1Pin1
  ledcAttachPin(motor1Pin2, ledChannel);

}


void loop(){
  buttonState = digitalRead(buttonPin);
  if (buttonState == HIGH) { 
  
MotorStart();

}
}

void MotorStart(){
   if (millis() - last_time > 1000) {
      last_time = millis();
      dutyCycle_1 = 10; // pin5
      dutyCycle = 10; // pin18
      ledcWrite(ledChannel_1, dutyCycle_1);
      ledcWrite(ledChannel, dutyCycle);
  }if (millis() - last_time2 > 3000) {
      last_time = millis();
      dutyCycle_1 = 30; // pin5
      dutyCycle = 30; // pin18
      ledcWrite(ledChannel_1, dutyCycle_1);
      ledcWrite(ledChannel, dutyCycle);
  }if (millis() - last_time3 > 5000) {
      last_time = millis();
      dutyCycle_1 = 50; // pin5
      dutyCycle = 50; // pin18
      ledcWrite(ledChannel_1, dutyCycle_1);
      ledcWrite(ledChannel, dutyCycle);
  }
}
 
Изменено:

Старик Похабыч

★★★★★★★
14 Авг 2019
4,267
1,303
Москва
В данном случае работа управлением мотором идет только при нажатой кнопке.
Тут все верно?
C++:
...
if (millis() - last_time2 > 3000) {
    last_time = millis();
...  
  if (millis() - last_time3 > 5000) {
    last_time = millis();
Очень сомневаюсь.При таком раскладе со старта без кнопки все и будет работать. Так же будет работать если держать кнопку нажатой сразу, то тоже будет работать, А если спустя 5+ секунд, то сразу максимум сокрости.
 

mcvall

✩✩✩✩✩✩✩
15 Ноя 2020
33
3
В данном случае работа управлением мотором идет только при нажатой кнопке.
Тут все верно?
Да, верно. При нажатой набирает обороты. Отпускаю, обороты подают, нажимаю - то растут, то падают, хаотично.
Сейчас после последнего if установил } else {motorbreak();} в блоке кнопки. Motorbreak - отдельная функция торможения. Так теперь при старте МК стартует Motorbreak, т.к. кнопка выкл. Мне нужно вызывать старт мотора и торможения в любое время работы МК, а не только при старте МК.
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,267
1,303
Москва
Еще раз:
вот тут сравнивается с last_time2
if (millis() - last_time2 > 3000) {
А тут приравнивается last_time
last_time = millis();
т.е. last_time2 и last_time3 нигде не получают значений, то скорее всего они равны 0
 

mcvall

✩✩✩✩✩✩✩
15 Ноя 2020
33
3
Избыточное цитирование
Еще раз:
вот тут сравнивается с last_time2
if (millis() - last_time2 > 3000) {
А тут приравнивается last_time
last_time = millis();
т.е. last_time2 и last_time3 нигде не получают значений, то скорее всего они равны 0
Я так сразу и сделал, но оно вообще при старте без кнопки даже хаотично работало, поэтому везде установил last_time = millis();
 

bort707

★★★★★★✩
21 Сен 2020
3,066
914

@mcvall,
Вы не спорьте, а исправляйте. Если вы устанавливаете таймер значением last_time, а проверяете last_time2 - это в принципе не может работать правильно.
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,267
1,303
Москва
Ну дык что надо понять. Если кнопка не нажата, то надо все время менять last_time, last_time2 , last_time3. Вот таким образом: last_time2=millis();
Тогда при нажатии все проверки будут корректны по логике.
И еще очень хорошая практика - трассировать по строкам программу в уме, проверяя куда что пойдет. Можно использовать листок бумаги, для записи переменных в нее.
 

mcvall

✩✩✩✩✩✩✩
15 Ноя 2020
33
3
Избыточное цитирование
Вы не спорьте, а исправляйте.
Ни в коем случае;)
Ну дык что надо понять. Если кнопка не нажата, то надо все время менять last_time, last_time2 , last_time3. Вот таким образом: last_time2=millis();
Да, где-то мой косяк, буду исправлять. Спасибо.

Еще раз:
вот тут сравнивается с last_time2
if (millis() - last_time2 > 3000) {
А тут приравнивается last_time
last_time = millis();
т.е. last_time2 и last_time3 нигде не получают значений, то скорее всего они равны 0
Поправил код. Теперь что с зажатой кнопкой, что без (убрал кнопку из кода) хаотичные мигания светодиодами, стартует правильно с 10, затем быстрые скачки между тремя значениями в разное время.
Код на Millis:
// Управление двигателем  PWM2

unsigned long last_time, last_time2, last_time3;
const int motor1Pin1 = 5;  // номер контакта для IN1 драйвера двигателя
const int motor1Pin2 = 18; // номер контакта для IN2 драйвера двигателя
const int buttonPin = 22;  // номер контакта для кнопки
int buttonState = 0;       // переменная для хранения статуса кнопки:

// задаем свойства ШИМ-сигнала:
const int freq = 5000;     // Частота
const int ledChannel = 0;  // Канал,генерирующий PWM-сигнал для motor1Pin2
const int ledChannel_1 = 1;// Канал,генерирующий PWM-сигнал для motor1Pin1
const int resolution = 8;  // Разрешение
int dutyCycle;
int dutyCycle_1;

void setup() {
  ledcSetup(ledChannel, freq, resolution); // настраиваем ШИМ-сигнал согласно свойствам, заданным выше
  ledcSetup(ledChannel_1, freq, resolution);
 
  pinMode(motor1Pin1, OUTPUT);
  pinMode(motor1Pin2, OUTPUT); 
  pinMode(buttonPin, INPUT);
 
  ledcAttachPin(motor1Pin1, ledChannel_1); // где: motor1Pin1 - контакт для вывода PWM, ledChannel - канал,генерирующий PWM-сигнал для motor1Pin1
  ledcAttachPin(motor1Pin2, ledChannel); 
 
}


void loop(){
  //buttonState = digitalRead(buttonPin);
  //if (buttonState == HIGH) {
 
  MotorStart();


}

void MotorStart(){
   if (millis() - last_time > 1000) {
      last_time = millis();
      dutyCycle_1 = 10; // pin5
      dutyCycle = 10; // pin18
      ledcWrite(ledChannel_1, dutyCycle_1);
      ledcWrite(ledChannel, dutyCycle);
  }if (millis() - last_time2 > 3000) {
      last_time2 = millis();
      dutyCycle_1 = 30; // pin5
      dutyCycle = 30; // pin18
      ledcWrite(ledChannel_1, dutyCycle_1);
      ledcWrite(ledChannel, dutyCycle);
  }if (millis() - last_time3 > 5000) {
      last_time3 = millis();
      dutyCycle_1 = 50; // pin5
      dutyCycle = 50; // pin18
      ledcWrite(ledChannel_1, dutyCycle_1);
      ledcWrite(ledChannel, dutyCycle);
  }
}
 

Lumenjer

★★★✩✩✩✩
10 Дек 2020
220
112
@mcvall, делается ровно то, что вы написали. А теперь подумайте, у вас ТРИ независимых друг от друга таймера и каждый из них выставляет свою яркость)
Прошла секунда - загорелся первый таймер, ок, прошла еще секунда, первый таймер сбросился, прошла еще одна, первый таймер сбросился еще раз и за ним сработал второй (т.к. прошло три секунды), проходит еще одна секунда - срабатывает первый таймер и выставляет яркость на 10, проходит еще секунда, первый продолжает держать на 10, но срабатывает таймер на 5 секунд и значение уже 50, через секунду первый выставляет на 10 и сразу за ним второй на 30 (два раза по 3 секунды прошло), мне продолжать?)

***
То, что вы хотите сделать, надо делать на одном таймере.

C++:
  if (millis() - last_time > 5000) {
      last_time = millis();
      dutyCycle_1 = 50; // pin5
      dutyCycle = 50; // pin18
      ledcWrite(ledChannel_1, dutyCycle_1);
      ledcWrite(ledChannel, dutyCycle);
  } else if (millis() - last_time > 3000) {
      dutyCycle_1 = 30; // pin5
      dutyCycle = 30; // pin18
      ledcWrite(ledChannel_1, dutyCycle_1);
      ledcWrite(ledChannel, dutyCycle);
   } else if (millis() - last_time > 1000) {
      dutyCycle_1 = 10; // pin5
      dutyCycle = 10; // pin18
      ledcWrite(ledChannel_1, dutyCycle_1);
      ledcWrite(ledChannel, dutyCycle);
   }
 

mcvall

✩✩✩✩✩✩✩
15 Ноя 2020
33
3
То, что вы хотите сделать, надо делать на одном таймере.
Спасибо. Проверил. Что получается - Рестарт, 10 (2сек), 30 (2сек), 50 (примерно 0,5сек) и по новой.
Я правильно понимаю, что таймеры не должны пересекаться в моем случае?
 

Lumenjer

★★★✩✩✩✩
10 Дек 2020
220
112
@mcvall, Напишите, сколько секунд должен работать каждый из этих режимов?
Рестарт, прошла секунда и включилось 10 (длится 2 сек), потом 30 (тоже 2 сек), 50 (1 сек)

Я правильно понимаю, что таймеры не должны пересекаться в моем случае?
Не должны

Вот более правильная конструкция, что ли, которая вызывает ledcWrite() только когда сработает таймер, а не с каждым проходом loop()

C++:
static uint32_t last_time = 0;
static uint8_t time = 1;      // Эту переменную можем использовать как для таймера, так и для значения, стартовое значение 1
  if (millis() - last_time > time*1000) {     // проверяем, прошло ли time умноженное на 1000 миллисекунд (вначале 1 * на 1000, т.е. 1 сек)
    if (time <= 5) {                              // тут смотрим, не превышает ли time  наше максимальное значение (которое мы будем пихать в ledcWrite)
      dutyCycle_1 = time*10; // pin5           // тут присваиваем значение (time * 10, при первом проходе это 1 * 10, т.е. 10)
      dutyCycle = time*10; // pin18            // тоже самое
      ledcWrite(ledChannel_1, dutyCycle_1);  // теперь вызываем с нужным значением
      ledcWrite(ledChannel, dutyCycle);
    }
    time += 2;          // увеличиваем time на 2, т.е. при следующем проходе цикла time будет уже не 1, а 3, а после 3 уже будет 5
    if (time >  5)  {       // вот тут уже можем расписать нужные условия после того, как сработало значение 50 на ledcWrite(), нам надо еще  1 секунду, например, то присваиваем time 6
      if (time == 6)   // проверяем, равен ли он уже 6, чтобы сбросить таймер
         last_time = millis();
      time = 6;   // тут просто присваиваем 6 (итого еще 1 секунда на следующее срабатывание после 5)
    }
  }
 
Изменено:

mcvall

✩✩✩✩✩✩✩
15 Ноя 2020
33
3
Напишите, сколько секунд должен работать каждый из этих режимов?
По 2 секунды при удержании кнопки. Если я указал в unsigned long три времени, то со времени рестарта должен идти отсчёт, который я указал для каждого таймера. Без кнопки все работает.