Спидометр на Arduino

Denchik200401
Offline
Зарегистрирован: 17.07.2016

Знаю, что все это неоднократно обсуждалось, но поскольку я новичок, мне это непонятно. Есть геркон, есть магнит на спице колёса, и нужно посчитать сколько раз замкнется геркон за 2 сек. Читал, что нужно использовать прерывания, но у меня что-то не очень получается.

Использовал вот этот код:http://arduino.ru/forum/programmirovanie/podschet-impulsov-za-1-sekundu#comment-87317

Заранее спасибо!

a5021
Offline
Зарегистрирован: 07.07.2013

А не проще считать время между замыканиями, а не ждать 2 сек?

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

А еще лучше не заниматься херней с прерываниями. А просто посчитать количество импульсов (спадов или подьемов) за 2 сек. Да и геркон это механический контакт , так что есть дребезг.

Максим скорость 30км/час или 8,3 м/сек . Если взять колесо 500 мм то его периметр чуть больше 1,5 метра. Так что геркон отработает с частотой максимум 5 Гц.

Denchik200401
Offline
Зарегистрирован: 17.07.2016

Считать нужно подъёмы. А как это правильно реализовать, через таймер?

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

Вот вариант. Но константы надо подбирать по месту.

/ Счет оборотов колеса велосипеда с помощью геркона

// ---класс велосчетчик---
class qw_counter/ {
  public:
    qw_counter(int pin); 
    int out();
    int go();
  private:
    int _pin; // вывод датчика
    int _N;  // сколько циклов loop() надо сделать что бы было 2 сек
    boolean _P,_P_old ; // состояние изм вывода текущее и старое
    int _K ; // сколько импульсов произошло на датчике 
    int _K1; // данные на индикацию
};
qw_counter::qw_counter(int pin){
  _pin= pin;
  pinMode(_pin, INPUT);
  _P = digitalRead(_pin);
  _N = 2000/50; // 2 сек делить на 0.05 сек длит цикла   _N = 2000/50;   
  _K =0;
}

int qw_counter::go(){
      _P_old=_P;
      _P = digitalRead(_pin);
      if ((_P_old == 0)&&(_P == 1)) _K++; // счет по отпусканию геркона _|-
      _N--; if (_N != 0) return 1;
      _N = 2000/50; // 2 сек делить на 0.05 сек длит цикла 
      _K1 = _K; 
      _K = 0 ;
      return 0;
}
int qw_counter::out(){
  return _K1;
}

//---- программа ----

qw_counter counter(2);// здесь 2 это нога на которой стоит геркон подкл. на землю
void setup() {
   Serial.begin(9600);
}

void loop() {
  delay (50); //  0.05 сек длит цикла 
 if (counter.go() == 0) Serial.println(counter.out());
}

 

a5021
Offline
Зарегистрирован: 07.07.2013

Бред. Алгоритм ведь проще пареной репы: случилось замыкание -- запоминаем  чего возвращает millis(). Случилось следующее, от текущего millis() отнимаем запомненное. Это время, за которое колесо сделало круг. Делим длину окружности колеса на время, получаем скорость. И подбирать ничего не нужно.

Denchik200401
Offline
Зарегистрирован: 17.07.2016

А не могли бы вы это хоть каким-нибудь кусочком кода показать как это делается?

Denchik200401
Offline
Зарегистрирован: 17.07.2016

Т.е. _pin это пин к которому подключен вывод геркона?

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

Вот возьмем резистор 1к Ом.(SMD102)  Вот это будет примерно как класс. 

А вот уже R1,R2 Это уже представители класса резисторов в 1кOм. Разумеется есть классы резисторов в 2кОма,классы диодов, микросхем.

qw_counter counter(2);

Вот это строка делает счетчик counter  по описанию qw_counter на 2 ноге. Так что _pin это то что внутри, как бы "программная микросхема".

У этой микросхемы есть 2 программные функции.

counter.go() и counter.out()

Первая должна обязательно присутсвовать один раз в цикле loop(). Некий псевдодрайвер.Как 2000/50 раз к ней обратились. Так и результат по counter.out() получили.

В принципе подгружаемые библиотеки на классах и постороены. Но народ похоже про это тупо забывает. 

a5021
Offline
Зарегистрирован: 07.07.2013

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

_N--; if (_N != 0) return 1;

Нафиг в одной строке два действия? Если хотите, чтобы накануне сравнения _N декрементировалась, так и пишите

if (--_N != 0) return 1;

Только из за дебильных имен выглядит все, как птичья азбука.

Клапауций 232
Offline
Зарегистрирован: 05.04.2016

Denchik200401 пишет:

А не могли бы вы это хоть каким-нибудь кусочком кода показать как это делается?

класс титановый велосипед StopWatch.

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

a5021 Вот свистеть не надо. Программа у меня простая. 

//---- программа ----

qw_counter counter(2);// здесь 2 это нога на которой стоит геркон подкл. на землю
void setup() {
   Serial.begin(9600);
}

void loop() {
  delay (50); //  0.05 сек длит цикла 
 if (counter.go() == 0) Serial.println(counter.out());
}

Вот где вы птичий код нашли? А туда куда вы показывали, так это закулисы. Если вы развернете то что в include в .h и .cpp , то мое написание будет ясно как образец лаконичности.  Вас убивает, что две команды в одной строке. Но зачем усложнять то просто идет как упрощеный пример. А то можно шифрануть так, что без бухла и консультации со стороны не разбраться.

 

a5021
Offline
Зарегистрирован: 07.07.2013

qwone пишет:

А туда куда вы показывали, так это закулисы. Если вы развернете то что в include в .h и .cpp , то мое написание будет ясно как образец лаконичности.  Вас убивает, что две команды в одной строке. Но зачем усложнять то просто идет как упрощеный пример. А то можно шифрануть так, что без бухла и консультации со стороны не разбраться.

Переведите мне кто-нибудь.

Клапауций 232
Offline
Зарегистрирован: 05.04.2016

a5021 пишет:

Переведите мне кто-нибудь.

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

и, вообще - delay (50); //  0.05 сек длит цикла

Denchik200401
Offline
Зарегистрирован: 17.07.2016

Т.е. чтобы узнать скорость м/с нужно длину окружности колёса поделить на noDelay_01.tick?

gena
Offline
Зарегистрирован: 04.11.2012

 Denchik200401.   Вы в школе (на уроках физики) изучали связь пути, времени и скорости?

Denchik200401
Offline
Зарегистрирован: 17.07.2016

Если бы у меня эта физика была... Начнётся только с первого сентября.

James
Offline
Зарегистрирован: 26.02.2016

V=S/t
вот тебе и вся физика, где V -Скорость S-расстояние t-время

gena
Offline
Зарегистрирован: 04.11.2012

Уточню:

           V [км/ч] = S [км] / t [ч]          --->   V [км/ч] = 0,001 * S [м] / ( t [c] *(1/3600))

 

Дальше преобразуйте формулу самостоятельно. 

Denchik200401
Offline
Зарегистрирован: 17.07.2016

Ну теория это конечно хорошо, но мне бы знать, в вашем решении, Клапауцый, noDelay_01.tick обозначает время между двумя замыкании геркона?

 

П.с. это и все что мне нужно было знать, формулы эти изучаются во 2-ом классе.

Denchik200401
Offline
Зарегистрирован: 17.07.2016

Хотя я был неправ(перечитал код, понял), можно было и повежливее я всё-таки ребёнок!

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

Цитата:перевожу - он считает, что является автором оригинального стиля форматирования кода.

Берите выше - оригинального стиля программирования в среде Ардуино.

void setup() {
}

void loop() {
delay (50); //  0.05 сек длит цикла
// код исполнения
}

так что команда delay (50); Это нормировка длительности всего цикла loop(). Аналог педали газ-тормоз автомобиля, что бы сделать среднюю длительность цикла. Да и программирование программы становится "горизонтальным". События- обработчик события и псевдо-драйвера.

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

qwone пишет:

 

void setup() {
}

void loop() {
delay (50); //  0.05 сек длит цикла
// код исполнения
}

так что команда delay (50); Это нормировка длительности всего цикла loop(). Аналог педали газ-тормоз автомобиля, что бы сделать среднюю длительность цикла. 

ШТА? С каких это пор тупая задержка нормирует длительность всего цикла? Тем более - как-то там "усредняет"? Что будет, если в loop после строчки "код исполнения" вставить код, который выполняется 200 мс? Ваш delay тоже "отнормирует" длительность цикла?

Клапауций 232
Offline
Зарегистрирован: 05.04.2016

qwone пишет:

так что команда delay (50); Это нормировка длительности всего цикла loop(). Аналог педали газ-тормоз автомобиля, что бы сделать среднюю длительность цикла. Да и программирование программы становится "горизонтальным". События- обработчик события и псевдо-драйвера.

трамблёр

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

Вы программируете в привычном стиле, который я называю "вертикальный". Для "вертикального" программирования подразумевается, что loop() это аналог main(). То есть программа решается в один проход цикла loop() сверху - вниз. Понятно что loop() зацикливает программу и она выполняется вновь и вновь.

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

Вот представим 2 ситуации. Есть задача и мы ее выполняем и день и ночь . Если нет материала , то сидим ждем пока его не завезут и не идем домой. Это "вертикальное" программирование.

Вторая ситуация . Каждый день после работы (или учебы) мы возвращаемся домой и смотрим, если возможность сделать что то для себя по своему плану. Если есть возможность делаем, нет откладываем на завтра. Здесь 1 проход цикла это один день. В этот день мы должны 1 раз опросить датчики, их проанализировать и дать 1 ответ.  2 раза опрашивать датчик не надо. И если нет условий для выдачи ответа его не давать. Какая длительность цикла в loop() задается в цикле самим программистом. Разумеется никаких циклов и циклических структур при горизонтальном программировании быть не должно, кроме самого loop().

Клапауций 232
Offline
Зарегистрирован: 05.04.2016

qwone пишет:

Вы программируете

расскажи нам про трамблёр.

a5021
Offline
Зарегистрирован: 07.07.2013

Denchik200401 пишет:
можно было и повежливее я всё-таки ребёнок!

2004.01 -- это дата рождения? Если так, то прости нас всех. На форуме не видно, кому сколько лет.

Обод колеса (шины) имеет длину. Ее можно измерить рулеткой или "сантиметром", которым пользуются любители домашнего шитья. Предположим, что имеется некий  небольшой велосипед, где длина окружности колеса равняется одому метру. Дальше мы закпрепляем геркон неподвижно на вилке, а магнит на спицах или ободе. В этом случае, при движении велосипеда, магнит будет замыкать контакты геркона один раз за оборот колеса.  Замыкание контактов будет происходить всякий раз, когда велосипед пройдет один метр (длина обода). Если же измерить время, которое проходит между замыканиями геркона, то мы получим вторую величину, необходимую для вычисления скорости. Предположим, что едущий велосипед замыкает геркон через каждые 600 миллисекунд или 0.6 секунды. Разделив длину окружности на время между замыканиями геркона, получим скорость: 1 метр / 0.6 секунды = 1.67 м/с. Скорость обычно считают в км/ч, т.ч. полученное значение нужно умножить на 3600 (секунд в часе) и разделить на 1000 (метров в километре). Скорость нашего воображаемого велосипеда таким образом составит 6 км/ч.

int reedSwitch = 10; // пин, куда присоединен геркон
float cLen = 1.0;    // длина обода в метрах

void setup() {
  pinMode(reedSwitch, INPUT_PULLUP); // режим входа с подтяжкой к плюсу
  Serial.begin(9600); // включаем вывод в последовательный порт
}

void loop() {
  while (digitalRead(reedSwitch) == HIGH); // ждем, пок геркон не будет замкнут
  uint32_t Time1 = millis(); // запоминаем время
  for (;;) {  // крутим "вечный" цикл
    delay(50); // ждем, пока магнит проедет мимо геркона
    while (digitalRead(reedSwitch) == HIGH); // опять ждем замыкания
    uint32_t Time2 = millis(); // берем текущее время
    float rTime = (Time2 - Time1) / 3600000;  // находим время полного оборота колеса в долях часа
    float bikeSpeed = (cLen / 1000) / rTime; // вычисляем скорость в км/ч
    Serial.print("Скорость равна: ");
    Serial.print(bikeSpeed);
    Serial.println(" км/ч.");
    Time1 = Time2; // запоминаем время для след. вычисления
  }
}

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

 
Denchik200401
Offline
Зарегистрирован: 17.07.2016

Спасибо вам огромное, это то, что было нужно!

 

П.с. 2004.01 это дата рождения.

James
Offline
Зарегистрирован: 26.02.2016
delay(50); // ждем, пока магнит проедет мимо геркона

с таким объяснением оно еще как-то выглядит, но это "костыль" своеобразный:), а вдруг скорость очень низкая и геркон не успеет разомкнуться? ну или если ехать больше 45 км/ч с длиной окружности 70 см?почему не проверить размыкание? 

Denchik200401
Offline
Зарегистрирован: 17.07.2016

Может это и костыль, но для личного использования сойдёт) ну 45км/ч при том что С = 70см это конечно слишком. Велосипеды с такими колесами врятли поедут столько... Но все это уже оффтоп

James
Offline
Зарегистрирован: 26.02.2016

это не оффтоп, вот ссылка http://bikehike.org/uhod-i-remont/kak-izmerit-diametr-kolesa.html почитай, 
наоборот шоссейные колеса больше в диаметре.

Denchik200401
Offline
Зарегистрирован: 17.07.2016

Что-то в мониторе порта тишина...

a5021
Offline
Зарегистрирован: 07.07.2013

Геркон как подключен?

 

a5021
Offline
Зарегистрирован: 07.07.2013

James пишет:
с таким объяснением оно еще как-то выглядит, но это "костыль" своеобразный:),

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

Denchik200401
Offline
Зарегистрирован: 17.07.2016

Один конец к +5 другой к D10

a5021
Offline
Зарегистрирован: 07.07.2013

И получается, что на D10 всегда стоит единица, независимо от того, замкнут геркон или разомкнут. Программа стопориться на первом цикле ожидания (строка 10). Вторым концом геркон должен быть посажен на землю.

Denchik200401
Offline
Зарегистрирован: 17.07.2016

Все равно молчит и на gnd и на +3.3 и на +5. Также analogread пробовал, результат 0.

ВН
Offline
Зарегистрирован: 25.02.2016

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

  т.е. такая цепь.  <+5v> r=300 Om +Vd1 <D10> gerkon <GND>

когда геркон замкнут на землю <GND> светодиод Vd1  горит.

James
Offline
Зарегистрирован: 26.02.2016

a5021 ,согласен, так делать можно, я за то что стоит учесть, что есть условия при которых будет работать неправильно. Так что при желании/необходимости "доработать напильником".

Denchik200401
Offline
Зарегистрирован: 17.07.2016

Пробовал при замыкании гори, писал код под замыкание геркона, чтобы если замкнут горел светодиод - работает, но стоит заменить код из digitalWrite на t1 = millis() , так сразу t = ничего

Denchik200401
Offline
Зарегистрирован: 17.07.2016

Набросал вот такой код:http://arduino.ru/forum/programmirovanie/millis Н в нем есть одна проблемма с millis(), там все описнно

a5021
Offline
Зарегистрирован: 07.07.2013

Покажите ваш код с герконом.

Denchik200401
Offline
Зарегистрирован: 17.07.2016
// задаем константы
const int buttonPin = 2;     // номер входа, подключенный к кнопке
const int ledPin =  13;      // номер выхода светодиода
 
// переменные
int buttonState = 0;         // переменная для хранения состояния кнопки
 int t1;
 int t2;
void setup() {
  Serial.begin(9600);
  // инициализируем пин, подключенный к светодиоду, как выход
  pinMode(ledPin, OUTPUT);     
  // инициализируем пин, подключенный к кнопке, как вход
  pinMode(buttonPin, INPUT); 
  
}
 
void loop(){
  // считываем значения с входа кнопки
  buttonState = digitalRead(buttonPin);
 
  // проверяем нажата ли кнопка
  // если нажата, то buttonState будет HIGH:
  if (buttonState == HIGH) {   
    // включаем светодиод   
   t1 = millis(); 
  }
  delay(70);
  if (buttonState == HIGH) {   
    // включаем светодиод   
    t2 = millis(); 
  }
  long counter = t2 - t1;
if (counter > 0 ) {
digitalWrite(ledPin, HIGH);
}
//Serial.print(counter);
}

Вот в этом коде проблема с millis()

Denchik200401
Offline
Зарегистрирован: 17.07.2016

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

ВН
Offline
Зарегистрирован: 25.02.2016

millis() -"Количество миллисекунд с момента начала выполнения программы. (unsigned long)"

проверить соответствие типов t1, t2

Denchik200401
Offline
Зарегистрирован: 17.07.2016

Теперь он выкидывает цифры 69 70 71... Даже без замыкания геркона

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Куда выкидывает? В скетче нигде нет вывода хоть куда-нибудь.

Denchik200401
Offline
Зарегистрирован: 17.07.2016

Раскоментируйте 37 строку

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Вы чего хотите сделать? Если кнопка нажата, чтобы светодиод загорался?

digitalWrite(lenPin,digitalRead(buttonPin));

Чтобы он загорался через 70 мс после того, как нажата кнопка?

byte state = digitalRead(buttonPin);
delay(70);
digitalWrite(lenPin,state);

Что именно вы хотите изобразить излишне запутанным кодом?

Denchik200401
Offline
Зарегистрирован: 17.07.2016
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
Adafruit_PCD8544 display = Adafruit_PCD8544(3, 4, 5, 6, 7);


// задаем константы
const int buttonPin = 8;     // номер входа, подключенный к кнопке
const int ledPin =  13;      // номер выхода светодиода
 
// переменные
int buttonState = 0;         // переменная для хранения состояния кнопки
 unsigned long t1;
 unsigned long t2;
void setup() {
  Serial.begin(9600);
  // инициализируем пин, подключенный к светодиоду, как выход
  pinMode(ledPin, OUTPUT);     
  // инициализируем пин, подключенный к кнопке, как вход
  pinMode(buttonPin, INPUT); 

  // инициализация и очистка дисплея
    display.begin();
    display.clearDisplay();
    display.display();
    
    display.setContrast(50); // установка контраста
    delay(1000);
    display.setTextSize(1);  // установка размера шрифта
    display.setTextColor(BLACK); // установка цвета текста
    display.setCursor(0,0); // установка цвета текста
}
 
void loop(){
  // считываем значения с входа кнопки
  buttonState = digitalRead(buttonPin);
 
 
  if (buttonState == LOW) {   
    
   t1 = millis(); 
  }
  delay(70);
  if (buttonState == LOW) {   
     
    t2 = millis(); 
  }
unsigned  long counter = t2 - t1;
if (counter > 0 ) {
digitalWrite(ledPin, HIGH);
}
Serial.print(counter);

display.println(counter);
    display.display();
}

Ну вот как-то так, и все равно беспорядочные числа

Denchik200401
Offline
Зарегистрирован: 17.07.2016

я хочу посчитать время между 1 и 2 замыканием геркона