Еще раз мигаем светодиодом без Delay

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

Вы каждый раз проверяете сигнал. Т.е. смотрите, двигатель включён. Доехали до концевика, увидели на нём сигнал, поехали обратно. Вот тут бы Вам ехать две секунды не обращая внимания на сигнал, и остановитья, но Вы продолжаете его (сигнал) проверять. В итоге, как только вы чуть-чуть отехали обратно, сигнал оказывается потерян и Вы опять дрыгаетесь вперёд.

Поятно? Не слишком запутанно?

vinam
Offline
Зарегистрирован: 19.03.2016

По Вашему описанию все понятно, но что-то не получается у меня реализовать программно.....

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

Ну, думайте. Если никак, то показывайте.

vinam
Offline
Зарегистрирован: 19.03.2016

Я просто не пойму, что не так в коде, что в 100 посте... Ведь вроде бы все просто сигнал есть - включи вперед на 2 сек и сбрось управление, нет - на 2 сек назад и опять сбрось управление. Этот концевик независим от двигателя. Пробовал добавлять флаги - не помогает....

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Тяжело в деревне без нагана.Motor_lib.ino

/*Motor_lib.ino
#1 моторы
Мотор правый  ENA,IN1,IN2 ->5,4,3  скорость,вперед,назад
Мотор левый   ENA,IN1,IN2 ->9,8,7  скорость,вперед,назад
*/
// #1 моторы
#include "Cl_Motor.h"
Cl_Motor M1(5, 4, 3, 255); // создать мотор 1 (ENA=5,N1=4,N2=3,SPEED=255) 255 максимальная скорость
Cl_Motor M2(9, 8, 7, 255); // создать мотор 2 (ENA=9,N1=8,N2=7,SPEED=255) 255 максимальная скорость
void setup() {
  // #1 моторы
  M1.in_setup();// инициализировать мотор 1
  M2.in_setup();// инициализировать мотор 2
  // движение вперед
  M1.FORWARD();
  M2.FORWARD();
  delay (60000); // пауза 1 минута
  // движение назад
  M1.BACKWARD();
  M2.BACKWARD();
  delay (60000); // пауза 1 минута
  // вращение на месте
  M1.FORWARD();
  M2.BACKWARD();
  delay (60000); // пауза 1 минута
  // остановка
  M1.STOP();
  M2.STOP();
  delay (60000); // пауза 1 минута
}

void loop() {
  // #1 моторы

}

Cl_Motor.h

// Cl_Motor.h
#ifndef Cl_Motor_h
#define Cl_Motor_h

#include "Arduino.h"

class Cl_Motor {
  public:
    Cl_Motor(byte _1pin, byte _2pin, byte _3pin, byte _speed); // конструктор
    void in_setup(); // функцию засунуть в setup() программы
    void FORWARD(); // запустить мотор вперед
    void BACKWARD(); // запустить мотор вперед
    void STOP();// остановить мотор
  private:
    byte ENA_pin; // пин  ENA
    byte N1_pin; // пин  N1
    byte N2_pin; // пин  N2
    byte Speed; // скорость мотора
    byte Motor;// 1 мотор вращается вперед/2 мотор вращается назад / 0 нет

};
#endif // Cl_Motor.h

Cl_Motor.cpp

// Cl_Motor.cpp

#include "Arduino.h"
#include "Cl_Motor.h"

Cl_Motor::Cl_Motor(byte _1pin, byte _2pin, byte _3pin, byte _speed) { // конструктор
  ENA_pin = _1pin; // пин  ENA
  N1_pin = _2pin; // пин  N1
  N2_pin = _3pin; // пин  N2
  Speed = _speed; // скорость мотора
}
void Cl_Motor::in_setup() { // функцию засунуть в setup() программы
  Motor = 0;
  analogWrite (ENA_pin, Speed);
  pinMode (N1_pin, OUTPUT);
  digitalWrite(N1_pin, 0);
  pinMode (N2_pin, OUTPUT);
  digitalWrite(N2_pin, 0);
}
void Cl_Motor::FORWARD() { // запустить мотор вперед
  if (Motor != 1) {
    Motor = 1;
    digitalWrite(N1_pin, 1);
    digitalWrite(N2_pin, 0);
  }
}
void Cl_Motor::BACKWARD() { // запустить мотор назад
  if (Motor != 2) {
    Motor = 2;
    digitalWrite(N1_pin, 1);
    digitalWrite(N2_pin, 0);
  }
}
void Cl_Motor::STOP() { // остановить мотор
  if (Motor != 0) {
    Motor = 0;
    digitalWrite(N1_pin, 0);
    digitalWrite(N2_pin, 0);
  }
}

 

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

vinam пишет:

Я просто не пойму, что не так в коде, что в 100 посте... Ведь вроде бы все просто сигнал есть - включи вперед на 2 сек и сбрось управление, нет - на 2 сек назад и опять сбрось управление. Этот концевик независим от двигателя. Пробовал добавлять флаги - не помогает....

Нет, ну Вы смотрите на код-то.

Давайте по шагам. Вот Вы в первый раз включили двигатель (строки 39-40). При этом Вы не стали запоминать время включения, а сразу стали сравнивать текущий милли с previousMillis, который у Вас 0. Влетели в блок 41-45 и выключили двигатель.

Может разумнее в момент включения двигателя запоминать время включения, чтоб от него, а не от нуля отсчитывать 2 сек?

Кроме того, в течение этих 2 секунд двигатель отъедет от концевика и стало быть условие в строке 38 перестанет выполняться. Значит, сравнивать время (в процессе ожидания 2 сек) надо где-то снаружи, а не внутри блока 38-46.

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

qwone пишет:

Тяжело в деревне без нагана.

Хорошо попразновали вчера? Даже завидно. Скорость у Вас задана раз и навсегда? Таким наганом только застрелиться!

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
/*
#1 кнопки
кнопка 1 -> 10 (btn_LF_pin) левый вперед 0 нажата / 1 нет
кнопка 2 -> 11 (btn_LB_pin) левый назад 0 нажата / 1 нет
кнопка 3 -> 12 (btn_RF_pin) правый вперед 0 нажата / 1 нет
кнопка 4 -> 13 (btn_RB_pin) правый назад 0 нажата / 1 нет
#2 моторы
Мотор правый  ENA,IN1,IN2 ->5,4,3  скорость,вперед,назад
Мотор левый   ENA,IN1,IN2 ->9,8,7  скорость,вперед,назад
*/
// #1 кнопки
const int btn_LF_pin = 10;
bool btn_LF;
const int btn_LB_pin = 11;
bool btn_LB;
const int btn_RF_pin = 12;
bool btn_RF;
const int btn_RB_pin = 13;
bool btn_RB;
// #2 моторы
#include "Cl_Motor.h"
Cl_Motor M1(5, 4, 3, 255); // создать мотор 1 (ENA=5,N1=4,N2=3,SPEED=255) 255 максимальная скорость
Cl_Motor M2(9, 8, 7, 255); // создать мотор 2 (ENA=9,N1=8,N2=7,SPEED=255) 255 максимальная скорость
void setup() {
  // #1 кнопки
  pinMode(btn_LF_pin, INPUT_PULLUP);
  pinMode(btn_LB_pin, INPUT_PULLUP);
  pinMode(btn_RF_pin, INPUT_PULLUP);
  pinMode(btn_RB_pin, INPUT_PULLUP);
  // #2 моторы
  M1.in_setup();// инициализировать мотор 1
  M2.in_setup();// инициализировать мотор 2
}

void loop() {
  // #1 кнопки
  btn_LF = digitalRead(btn_LF_pin);
  btn_LB = digitalRead(btn_LB_pin);
  btn_RF = digitalRead(btn_RF_pin);
  btn_RB = digitalRead(btn_RB_pin);
  // #2 моторы
  if (! btn_LF && btn_LB) M1.FORWARD();// движение вперед левого мотора
  else if ( btn_LF && ! btn_LB) M1.BACKWARD(); // движение назад левого мотора
  else M1.STOP(); // остановка левого мотора
  
  if (! btn_RF && btn_RB) M2.FORWARD();// движение вперед правого мотора
  else if ( btn_RF && ! btn_RB) M2.BACKWARD(); // движение назад правого мотора
  else M2.STOP(); // остановка правого мотора
}

 

vinam
Offline
Зарегистрирован: 19.03.2016

Евгений, вот вынес я сравнение времени наружу и еще добавил флаги, а толка нет (проверяю в Протеусе), теперь пропала остановка по времени.

Уже перепробовал разные варианты, пересмотрел подобные примеры на форуме...

// Функция левого двигателя
void LeftMotorOn()	{
	static unsigned long previousMillis = 0;	// Храним время последнего переключения
	static unsigned long flagLow = 0;	// Флаг выполненного действия при отсутствии сигнала
	static unsigned long flagHigh = 0;	// Флаг выполненного действия при наличии сигнала

	if(digitalRead(LeftGerkon) == LOW || digitalRead(LeftGerkon) == HIGH)	{
		previousMillis = millis();
	}

	if(digitalRead(LeftGerkon) == LOW && flagLow == 0)	{ // Если нет сигнала и флаг == 0, то -
		digitalWrite(LeftWheelForward, HIGH);		// Вкл. мотор вперед
		digitalWrite(LeftWheelBack, LOW);		// Выкл. мотор незад
			if(millis() - previousMillis > TimeOpCl)	{	// Если проошло 2 сек
				digitalWrite(LeftWheelForward, LOW);	// Выкл. мотор вперед
				digitalWrite(LeftWheelBack, LOW);	// Выкл. мотор незад
				flagLow = 1;
				flagHigh = 0;	
			}
	}

	else if(digitalRead(LeftGerkon) == HIGH && flagHigh == 0)	{// Иначе, если есть сигнал и флаг == 0, то -
		digitalWrite(LeftWheelForward, LOW);	// Выкл. мотор вперед
		digitalWrite(LeftWheelBack, HIGH);		// Вкл. мотор незад
			if(millis() - previousMillis > TimeOpCl)	{// Если проошло 2 сек
				digitalWrite(LeftWheelForward, LOW);	// Выкл. мотор вперед
				digitalWrite(LeftWheelBack, LOW);	// Выкл. мотор незад
				flagHigh = 1;
				flagLow = 0;
		}
	}
}

 

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

Да, нет, ничего Вы не вынесли. Строки 14-19 и 25-30 как были внутри других условия, так и остались.

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

Для начала выписываем все состояния в котором бывает Ваш автомат. например:

1. Стоит
2. Едет влево (до упора)
3. Едет вправо (до упора)
4. Откатывается назад влево (2 сек)
5. Откатывается назад вправо (2 сек)

Выпишите все состояния, какие бывают, наверняка у Вас там ещё есть.

Дальше выпишите логику работы автомата в терминах состояний и переходов между ними. например.

ЕСЛИ состояние == 1
    Сгенерировать случайное число R от 0 до 1
    ЕСЛИ R < 0,25 { поехать вправо; перейти в состояние 3; }
    ИНАЧЕ ЕСЛИ R < 0,5 { поехать влево; перейти в состояние 2; }
ИНАЧЕ ЕСЛИ состояние == 2
    ЕСЛИ достигнут концевик { поехать вправо; запомнить время_0; перейти в состояние 5; }
ИНАЧЕ ЕСЛИ состояние == 3
    ЕСЛИ достигнут концевик { поехать влево; запомнить время_0; перейти в состояние 4; }
ИНАЧЕ ЕСЛИ состояние == 4
    ЕСЛИ тек.время - время_0 >= 2 сек { остановиться; перейти в состояние 1; }
ИНАЧЕ ЕСЛИ состояние == 5
   ЕСЛИ тек.время - время_0 >= 2 сек { остановиться; перейти в состояние 1; }

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

Когда Вы это распишете, проверьте всё внимательно и если логика правильная, то пишите программу.

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

vinam
Offline
Зарегистрирован: 19.03.2016

Евгений, спасибо Вам, - все получилось!!!

Извиняюсь, что не в тему, может кому понадобится - это управление автоматическими порогами на авто.

Один геркон на две двери (на каждую сторону). Открыли дверь - выдвинулся порог, закрыли - задвинулся. Так как защиты двигателей у меня нет, решил подавать питание на 1,5 - 2 сек. и сбрасывать его.

По ссылке файл для Proteus со схемой и программой.

http://my-files.ru/hnygkf

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

Не за что, с Победой!

StasOn
Offline
Зарегистрирован: 10.05.2017

Ребята, помогите разобраться с этим millis..

В общем ситуация такая, есть 2 реле, которые должны включатся отдельно друг от друга на разные периоды времени, которые задаются через переменные, а не объявляются сразу (задаются кнопками). В то время пока первое реле включено второе должно быть выключено и наоборот. Еще наверное нужно предусмотреть задержку (компенсацию) для включения и выключения реле чтобы они не сработали одновременно. 

Время вводил в секундах, не могу понять, как перевести все в миллс, т.е. вроде бы время * 1000 но как же добавить пресловутый UL?

Уже с дисплеем разобрался и с кнопками, а вот с реле никак не получается (((

 

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

StasOn пишет:

вроде бы время * 1000 но как же добавить пресловутый UL?

Большинство ларчиков открываются предельно просто: время * 1000ul

StasOn
Offline
Зарегистрирован: 10.05.2017

Блин, какая же приятная штука Delay, так все просто делается..

void loop() {
 digitalWrite(3,HIGH);
 delay (Zar*1000);
 digitalWrite(3,LOW);
 digitalWrite(5,HIGH);
 delay (Raz*1000);
 digitalWrite(5,LOW);
}

А вот с миллис разобраться не получается

int Zar; //время заряда
int Raz; //время разряда

void setup() {
  Zar=10;
  Raz=1;
  pinMode (3,OUTPUT);
  pinMode (5,OUTPUT);
  digitalWrite(3,HIGH);
//  Serial.begin(9600);
}
void up() {
  static unsigned long previousMillis = 0;
  static unsigned long tZar = Zar*1000UL; 
  while(millis() - previousMillis > tZar && digitalRead(5) == 0) {
    previousMillis = millis();
    digitalWrite(3,!digitalRead(3));
  }
}
void dw() {
  static unsigned long previousMillis1 = 0;
  static unsigned long tRaz = Raz*1000UL;
  while(millis() - previousMillis1 > tRaz && digitalRead(3) == 0) {
    previousMillis1 = millis();    
    digitalWrite(5,!digitalRead(5));
  }  
}

void loop() {
up();
dw();
}

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

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

Ну, Вы остудите голову (можно лёд приложить) и спокойно разберитесь чего Вы хотите. В первом скетче Вы их включаете по очереди, а во втором запустили мигать параллельно. Вот они параллельно и мигают. Нормально так все.

И, кстати, что делают while в строка 15 и 23? Оно у Вас всё равно исполняется только по одному разу, т.к. Вы previousMillis внутри цикла меняете. Тогда почему не использовать более простую конструкцию if?

Да, и ещё, если Вам реально нужно, чтобы светодиоды светились сменяя друг друга (один светится - второй - нет), это не так делается. Зачем для этого два пина? Вполне достаточно одного. Схема нужна?

evgta
Offline
Зарегистрирован: 02.09.2016

Вы так говорите что в delay есть что-то плохое?

если ненадо кнопки опрашивать или выполнять парралельные работы то в делей нет ничего плохого.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
const int Zar = 10; //время заряда
const unsigned long tZar = Zar * 1000UL;
const int Raz = 1; //время разряда
const unsigned long tRaz = Raz * 1000UL;
bool mode_zar = 1; // 1 заряд / 0 разряд
bool v3,v5;
void setup() {
  pinMode (3, OUTPUT);
  digitalWrite(3, v3 = 1);
  pinMode (5, OUTPUT);
  digitalWrite(5, v5 = 0);
}
void loop() {
  static unsigned long past = 0;
  if (mode_zar && millis() - past >= tZar) {
    past = millis();
    mode_zar = 0;
    digitalWrite(3, v3 =  !v3);
    digitalWrite(5, v5 = !v5);
  }
  if (!mode_zar && millis() - past >= tRaz) {
    past = millis();
    mode_zar = 1;
    digitalWrite(3, v3 =  !v3);
    digitalWrite(5, v5 = !v5);
  }
}

evgta пишет:

Вы так говорите что в delay есть что-то плохое?

если ненадо кнопки опрашивать или выполнять парралельные работы то в делей нет ничего плохого.

В delay() все плохо. Кажущая простота выключает мозг у новичков. Это как вы заявили: В ворах ничего плохого нет- они чистят подобно уборщикам ваши карманы.

StasOn
Offline
Зарегистрирован: 10.05.2017

Вы правильно меня поняли, нужно чтобы светодиоды светились сменяя друг друга (один светится - второй - нет). Время свечения задается переменными. А 2 пина используются потому, что вместо светодиодов будет другая нагрузка - реле или транзистор. Буду благодарен, если объясните или покажете как проще это реализовать.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

StasOn пишет:
Буду благодарен, если объясните или покажете как проще это реализовать.

Если вы в упор не увидели мой скетч, то я тут бессилен.

StasOn
Offline
Зарегистрирован: 10.05.2017

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

Скетч видел, попробовал, спасибо огромное, все работает. Буду теперь разбираться, Как он работает ))

evgta
Offline
Зарегистрирован: 02.09.2016

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

в цикл можно встроить опрос кнопок

for (time1 = millis(); time2 <=tmot; time2=millis()-time1)
{


}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

evgta пишет:

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

Паралельность, диагоналность. Понапридумывали всякой туфты. millis это банальные часы. а функция millis() -"узнать время" и все. Delay же это временная пробка. Процессор нихрена не делает , потому что он занят важной работой "нихрена не делать 1 секунду".

StasOn
Offline
Зарегистрирован: 10.05.2017

Да, видимо думаю я не как программист, мог бы и догадаться управлять обоими светодиодами из одного оператора как у qwone, а я уперся и пытался обрабатывать их разными.. Чего только не делал, и операторы менял, и разносил по разным функциям, придумывал новые условия.. А все проще оказалось ))

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

StasOn. Я тоже не программист. А то что я влегкую написал так. Так это результат долгого прохождения по швабрам, граблям гвоздям и прочей хр**ни. И в результате я могу сказать точно: я до сих пор не могу писать вменяемые программы.Но это секрет. :)

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

StasOn пишет:

А 2 пина используются потому, что вместо светодиодов будет другая нагрузка - реле или транзистор. Буду благодарен, если объясните или покажете как проще это реализовать.

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

Вот смотрите со светодиодом для начала:

Если Ваши светодиоды разных цветов, то, возможно, Вы захотите поставить им разные резисторы. Тогда можно так:

  

Ну, а с транзистором тоже самое. Я тут им нарисовал в качестве нагрузки лампочки накаливания - замените на реле или на что Вам там нужно.

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

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

qwone пишет:

Процессор нихрена не делает , потому что он занят важной работой "нихрена не делать 1 секунду".

Ну, так уж и ни хрена! Это ж Вам не POWER_DOWN режим! Он честно крутится в цикле и добросовестно осваивает бюджет перерабатывает электроэнергию в тепло :)

StasOn
Offline
Зарегистрирован: 10.05.2017

За схемы спасибо! С одним пином на 2 светодиода хитро, но не подходит. Сначала я сделаю управление до конца, потом возьмусь за питание ,а потом за высоковольтную часть (нагрузка будет 15в и от 0,1 до 5 А, еще не решил что лучше, реле - громкие, медленные, зато есть и подключать не сложно, или транзисторы - тихие, быстрые, но надо вникать, схемотехника посложнее). А зачем пины экономить? Я конечно понимаю, что можно сэкономить на памяти и на ресурсах, но пока всего хватает.

Еще хотел спросить qwone можно ли в его скетче предусмотреть задержку между включениями диодов? Т.к. от танцев с миллис пока далек ))

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

Нельзя реле прямо на пин - транзисторы по-любому.

Зачем экономить пины (кроме случая, когда их не хватает - там-то понятно) зависит от задачи. Например, если важно одно включить, а другое выключить строго одновременно - только одним пином (или двумя, но строго на одном порте и в этом случае надо забыть о digitalWrite, а делать всё одной операцией с портом). Если включаете и выключаете двумя операциями digitalWrite, то между этими операциями неминуема задержка. А когда на одном пине (или одной операцией с портом) - всё реально одновременно.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

StasOn пишет:

Еще хотел спросить qwone можно ли в его скетче предусмотреть задержку между включениями диодов? Т.к. от танцев с миллис пока далек ))

const int Zar = 10; //время заряда
const unsigned long tZar = Zar * 1000UL;
const int Raz = 1; //время разряда
const unsigned long tRaz = Raz * 1000UL;
const int Paz1 = 1; //время паузы 1
const unsigned long tPaz1 = Paz1 * 1000UL;
const int Paz2 = 1; //время паузы 2
const unsigned long tPaz2 = Paz2 * 1000UL;
byte mode = 0; // 0 заряд  /  1 пауза1 / 2 разряд / 3 пауза2
bool v3, v5;
void setup() {
  pinMode (3, OUTPUT);
  digitalWrite(3, v3 = 1);
  pinMode (5, OUTPUT);
  digitalWrite(5, v5 = 0);
}
void loop() {
  static unsigned long past = 0;
  if ((mode == 0) && millis() - past >= tZar) { // заряд
    past = millis();
    mode = 1;
    digitalWrite(3, v3 =  !v3);
    digitalWrite(5, v5 = !v5);
  }
  if ((mode == 1) && millis() - past >= Paz1) { // пауза 1
    past = millis();
    mode = 2;
  }
  if ((mode == 2) && millis() - past >= tRaz) { // разряд
    past = millis();
    mode = 3;
    digitalWrite(3, v3 =  !v3);
    digitalWrite(5, v5 = !v5);
  }
  if ((mode == 3) && millis() - past >= Paz2) { // пауза 2
    past = millis();
    mode = 0;
  }
}

ПС: Идеальным этот скетч не считаю. Это что бы быстрее разобрались

StasOn
Offline
Зарегистрирован: 10.05.2017

Спасибо большое! Нет на свете ничего идеального (( Раньше, давно, забавлялся программками на VBA, писал макросы для Exel, так вот, делал программу, распечатывал ее на принтере и оптимизировал код. Бывало, что размер сокращался в 10 раз )).

А вопрос по теме - вставил я ваш код в свою программу, запустил, смотрю вроде не работает, попробовал залить отдельным скетчем, все ок. Снова залил свою программу задержки выставил на 1 сек., подождал, работает. Правда светодиоды моргают с задержкой примерно в 5 секунд. Может ли это быть следствием большого объема программы или где-то ошибка? (кривые руки) 

Вообще дебаггер нужно поискать для ардуинки, а то что-то грустно методом тыка все.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Забудьте про большой объем программы. Это объяснение для нубов. Есть процессор. Он может выполнить определеное количество инструкций в секунду.  Если вы криво напишете программу, дикие повторы, лишние петли, ненужные циклы, то ваш процессор просто не будет успевать это делать за определеное время, а значит тормозить.  Возьмите общественный транспорт и такси. Расстояние одинаково но такси приходит быстрее не потому что маленькая, а потому что не делает кучу остановок на которых и еще и долго стоит. Ну да многие могут сказать, что в такси может сесть 5 человек, а в автобус 100. Значит автобус едет в 5 раз медленее.  И еще тупее высказывание: если в такси и в автобусе по 5 человек, то они будут ехать одинаково. 

StasOn
Offline
Зарегистрирован: 10.05.2017

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

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

StasOn.Надо смотреть вашу программу. Но я не могу. Точнее после меня вы не сможете понять, как программа функционирует, а значить модернизировать в дальнейшем. Что сразу отправит программу на мусор.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Наверное если промежутки должны быть точные то так?
 

void loop() {
  static unsigned long past = 0;
  if ((mode == 0) && millis() - past >= tZar) { // заряд

    past = past+tZar;

    mode = 1;
    digitalWrite(3, v3 =  !v3);
    digitalWrite(5, v5 = !v5);
  }
...

 

StasOn
Offline
Зарегистрирован: 10.05.2017

Скажите, а может тормозить из-за того, что в программе присутствует класс для кнопок, который тоже использует millis?

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

надо смотреть. Если это мои классы, то они не тормозят.Если конечно к ним не подключены тормознутые обработчики .:)

Pyotr
Offline
Зарегистрирован: 12.03.2014

ЕвгенийП пишет:

[

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

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

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

Pyotr пишет:

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

Да, спасибо, что заметили, но я теперь не могу удалить, т.к. Вы ответили на пост :(

Вообще, лучше не удалять, а исправить, но этого я теперь тоже не могу.

Исправлюсь здесь.

Вот работающая схема того же самого

Logik
Offline
Зарегистрирован: 05.08.2014

Pyotr пишет:

ЕвгенийП пишет:

[

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

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

Да. Для непонявших суть проблемы - рассмотрите ток из базы верхнего тр-ра в базу нижнего.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

[

ну да, базы разорвать, с баз в общую точку  два резитора и на управление, сэкономить один резистор не удастся

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

Спасибо, сделано уже в посте №139. Теперь бы ещё нашелся добрый админ и неправильные картинки удалил, чтобы никому мозги не пудрили. А, кстати, картинку я и сам кажется могу удалить. Щас попробую :)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

я тоже об этом подумал )))

Pyotr
Offline
Зарегистрирован: 12.03.2014

ЕвгенийП пишет:

В этой замечательной схеме, как говорилось, есть один момент. Когда пин находится в высокоимпедансном состоянии (Hi-Z), то светятся обе лампочки (или включены реле).

Если такое недопустимо, то нужно включить резисторы 220 Ом (навскидку номинал) между Б и Э каждого транз. В таком случае напряжение Б-Э при Hi-Z будет около 0.5 В и транз. будут закрыты.

В таком случае лампочки или не светятся или светится только одна из двух. Всего три состояния.

Чтобы получить 4 состояния, нужно схему подключить к пину, поддерживающий ШИМ, а параллельно лампочкам поставить конденсаторы по нескольку мкФ

1. обе светятся             analogWrite(pin, 128);
2. обе не светятся        pinMode(pin, INPUT); 
3. светится одна           analogWrite(pin, 0);
4. светится вторая        analogWrite(pin, 255);

StasOn
Offline
Зарегистрирован: 10.05.2017

Всем доброго дня! В общем проблема такая - в скетче есть класс обработки кнопок который использует millis(), есть функция которая использует millis()(мигание светодиодов), если в функции loop() я просто включаю функцию мигания светодиода, то все ОК, если же я добавляю обработчик кнопки, то время горения светодиодов увеличивается в 5 раз. 

Для мигания использовал скетч из сообщения #118 (пробовал другие)

Класс использовал http://arduino.ru/forum/programmirovanie/klass-titanovyi-velosiped-dlya-taktovoi-knopki (пробовал другие)

что не делал, пробема не уходит

Сейчас попробую вынести обработчик в отдельную функцию, посмотрю что получится, а всех, кто поможет дельным советом, как правильно выйти из этой ситуации, я заранее благодарю :)

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Если есть желпние, то покопайся в этом #1074

Вот еще пакет https://yadi.sk/d/RW5tQtw-3J5ENA

Головной файл из этого пакета 

/* class_Led.ino 
  #1 светодиод ->13
  #2 кнопка 1 -> 4 вкл светодиод
  #3 кнопка 2 -> 5 выкл светодиод
  #4 кнопка 3 -> 6 светодиод мигает
*/
// #1 светодиод
#include "Cl_led.h"
const byte led1_pin = 13;
Cl_led *Led1 = new Cl_led(led1_pin, 1); // создать
// #2 кнопка
#include "Cl_do_btn.h"
const byte btn1_pin = 4;
const byte btn2_pin = 5;
const byte btn3_pin = 6;
void Do_Btn1() {
  Led1->ON();
}
void Do_Btn2() {
  Led1->OFF();
}
void Do_Btn3() {
  Led1->blink(500); // мигать 0.5 горит -0.5 нет
}
Cl_do_btn * Btn[] =  {
  new Cl_do_btn(btn1_pin, 0,    // пин кнопки, уровень при наж кнопки
  & Do_Btn1   ),                // какую функцию надо сделать
  new Cl_do_btn(btn2_pin, 0,    // пин кнопки, уровень при наж кнопки
  & Do_Btn2   ),                // какую функцию надо сделать
  new Cl_do_btn(btn3_pin, 0,    // пин кнопки, уровень при наж кнопки
  & Do_Btn3   )                 // какую функцию надо сделать
};
void setup() {
  Led1->setup();
  for (byte i = 0; i < 3; i++)
    Btn[i]->setup();
}

void loop() {
  Led1->loop();
  for (byte i = 0; i < 3; i++)
    Btn[i]->loop();
}

 

StasOn
Offline
Зарегистрирован: 10.05.2017

Победил я наконец эту мигалку с миллис:

const int Zar = 10; //время заряда
const unsigned long tZar = Zar * 1000UL;
const int Raz = 5; //время разряда
const unsigned long tRaz = Raz * 1000UL;
const int Paz = 1; //время паузы 1
const unsigned long tPaz = Paz * 1000UL;
byte mode = 0; // 0 заряд  /  1 пауза1 / 2 разряд / 3 пауза2
void setup() {
  pinMode (3, OUTPUT);
  digitalWrite(3, 0);
  pinMode (5, OUTPUT);
  digitalWrite(5, 0);
}
void loop() {
  static unsigned long past = 0;
  
  if ((mode == 0) && millis() - past >= tPaz) { // Кончилась первая пауза начался разряд
    past = millis();
    mode = 1;
    digitalWrite(3, LOW);
    digitalWrite(5, HIGH);
  }
  if ((mode == 1) && millis() - past >= tRaz) { // Кончился разряд началась вторая пауза
    past = millis();
    mode = 2;
    digitalWrite(3, LOW);
    digitalWrite(5, LOW);
  }
  if ((mode == 2) && millis() - past >= tPaz) { // Кончилась вторая пауза начался заряд
    past = millis();
    mode = 3;
    digitalWrite(3, HIGH);
    digitalWrite(5, LOW);
  }
  if ((mode == 3) && millis() - past >= tZar) { // Кончился заряд началась первая пауза
    past = millis();
    mode = 0;
    digitalWrite(3, LOW);
    digitalWrite(5, LOW);
  }
}

Всем Спасибо за помошь. Из обсуждения вынес много интересных и полезных вещей.)) Буду думать теперь над основной программой и оптимизацией. За любые советы и критику буду благодарен ))

alexbmd
Offline
Зарегистрирован: 15.01.2016

leshak пишет:

 

  static unsigned long previousMillis = 0;        // храним время последнего переключения светодиода
  if(millis() - previousMillis > INTERVAL) {
    previousMillis = millis();  
  }

получается у нас диод маргнет только один раз ? точнее потом начнет переключаться с частотой процессора т.к. после первого србатывания if мы присваиваем previousMillis = millis();  но как только начинаем новый круг loop натыкаемся настрочку previousMillis = 0; получается после первой 1000 миллис у нас всегда if будет срабатывать т.к. previousMillis = 0 а millis() к этому времени будет много больше 1000. или я упускаю из виду чтото?

negavoid
Offline
Зарегистрирован: 09.07.2016

Упускаете, слово static делает переменную "глобальной", и при новом заходе в loop она не будет переинициализирована нулём, в ней будет значение от предыдущего loop-а.

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

alexbmd пишет:

после первого србатывания if мы присваиваем previousMillis = millis(); но как только начинаем новый круг loop натыкаемся настрочку previousMillis = 0; получается после первой 1000 миллис у нас всегда if будет срабатывать т.к. previousMillis = 0 а millis() к этому времени будет много больше 1000. или я упускаю из виду чтото?

Упускаете то, что previousMillis описан как static.