Тахометр

cherison
Offline
Зарегистрирован: 24.12.2020

Доброго времени суток дорогие форумчане !!!
Есть огромное желание сделать динамическую подсветку на приборку своего авто. Нашел провод идущий с компа на тахометр, осциллографом замерил частоту импульсов при разных оборотах, и остальные параметры импульса.
Приступил к программированию.Arduino UNO. Вопрос собственно возник при подсчете частоты импульсов,
.частоту решил находить через период. Подключаю генератор импусов на 1кГц ко входу int0 (2пин), в мониторе ком порта выдает непонятные результаты.Вот собственно мой код , прошуне судить строго:

int pin = 2;
unsigned long time_prev=0; //время предыдущее
unsigned long f ; //частота

int b=0;

void setup()
{

Serial.begin(9600);
pinMode(pin, INPUT);
attachInterrupt(0, taho, RISING );

pinMode(2, INPUT_PULLUP); //подтягивающий резистор

}

void loop()

{

}

void taho()
{

b++;

if(b==1)
{
cli(); //запрещаю прерывания

f= 1000000/(micros()-time_prev); // 1сек/период между импульсами
time_prev = micros();
Serial.println(long(f));
b=0;
sei(); //разрешаю прерывания

}

}

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017
cherison
Offline
Зарегистрирован: 24.12.2020

не нахожу как вообще отредактировать свое первое сообщение

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

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

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

cherison пишет:

не нахожу как вообще отредактировать свое первое сообщение

Нулевое сообщение редактировать не получится. Но кто мешает правильно разместить код в последующих?

cherison
Offline
Зарегистрирован: 24.12.2020
int pin = 2;
unsigned long time_prev=0; //время предыдущее
unsigned long f ; //частота

int b=0;

void setup()
{

Serial.begin(9600);
pinMode(pin, INPUT);
attachInterrupt(0, taho, RISING );

pinMode(2, INPUT_PULLUP); //подтягивающий резистор

}

void loop()

{

}

void taho()
{

b++;

if(b==1)
{
cli(); //запрещаю прерывания

f= 1000000/(micros()-time_prev); // 1сек/период между импульсами
time_prev = micros();
Serial.println(long(f));
b=0;
sei(); //разрешаю прерывания

}

}

 

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

1 строки 31 и 37 не нужны (хоть и не мешают) это делается автоматически при входе/выходе из прерывания

2 Использовать  Serial.println в прерывании крайне не рекомендуется. Делайте это в loop() 

Какой диапазон частот приходит с датчика? Может стоит лучше считать импульсы вместо измерения периода?

 

cherison
Offline
Зарегистрирован: 24.12.2020

asam пишет:

1 строки 31 и 37 не нужны (хоть и не мешают) это делается автоматически при входе/выходе из прерывания

2 Использовать  Serial.println в прерывании крайне не рекомендуется. Делайте это в loop() 

Какой диапазон частот приходит с датчика? Может стоит лучше считать импульсы вместь измерения периода?

 

Спасибо за ответ, буду исправлять. Еще интересует такой момент, как подтягивающий резистор. Нужен ли он при при прерываниях по восходящему фронту импульса?

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

cherison пишет:

Спасибо за ответ, буду исправлять. Еще интересует такой момент, как подтягивающий резистор. Нужен ли он при при прерываниях по восходящему фронту импульса?

Зависит от датчика. Кстати, что там за напряжение на "проводе идущий с компа на тахометр" ?

cherison
Offline
Зарегистрирован: 24.12.2020

asam пишет:

cherison пишет:

Спасибо за ответ, буду исправлять. Еще интересует такой момент, как подтягивающий резистор. Нужен ли он при при прерываниях по восходящему фронту импульса?

Зависит от датчика. Кстати, что там за напряжение на "проводе идущий с компа на тахометр" ?

Я пока пробую с генератором импульсов, 1кГц, примерно 3,3В.

На авто с компа 12В, буду делать делитель напряжения, или какую нибудь опторазвязку.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

cherison пишет:

Еще интересует такой момент, как подтягивающий резистор. Нужен ли он при при прерываниях по восходящему фронту импульса?

Без схемы этот вопрос лишен смысла. А схему Вы забыли опубликовать.

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

Валяется у меня в загашнике такой код

unsigned long micros_sp;
volatile int sz; //счетчик обнуления
volatile int sp; //скорость

void setup() {
  // put your setup code here, to run once:
  attachInterrupt(0, speedometr, RISING); //прерывание спидометра по фронту импульса на пине D2
}

void loop() {
  (sz > 0) ? sz-- : sp = 0;
  delay(50);
}

//измеряем частоту на входе спидометра по прерыванию
void speedometr() {
  sp = (600000.0 / (micros() - micros_sp));
  micros_sp = micros();
  sz = 30;
}

/*
   Переменная  "sz" служит для обнуления значения скорости,
   если с момента прихода последнего импульса блок "void loop()"
   выполнился 30 раз, то есть если скорость равна нулю и новые
   импульсы не приходят. Для некоторых датчиков прерывание по
   фронту (RISING) может не корректно обрабатываться. В этом случае
   следует использовать прерывание по спаду(FALLING).
*/

Правда, он для спидометра, но принцип тот же - на выходе имеем частоту следования импульсов

ЗЫ: код не мой, и я его нигде не применял ))

sadman41
Offline
Зарегистрирован: 19.10.2016

Фрагмент кода потенциально бажный.

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

Сильно не вникал, но для самообразования - где может быть затык? 

sadman41
Offline
Зарегистрирован: 19.10.2016
v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

Вот так?

#include <util/atomic.h>

unsigned long micros_sp;
volatile int sz; //счетчик обнуления
volatile int sp; //скорость

void setup() {
  // put your setup code here, to run once:
  attachInterrupt(0, speedometr, RISING); //прерывание спидометра по фронту импульса на пине D2
}

void loop() {
  ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
    (sz > 0) ? sz-- : sp = 0;
  }
  delay(50);
}

//измеряем частоту на входе спидометра по прерыванию
void speedometr() {
  sp = (600000.0 / (micros() - micros_sp));
  micros_sp = micros();
  sz = 30;
}

/*
   Переменная  "sz" служит для обнуления значения скорости,
   если с момента прихода последнего импульса блок "void loop()"
   выполнился 30 раз, то есть если скорость равна нулю и новые
   импульсы не приходят. Для некоторых датчиков прерывание по
   фронту (RISING) может не корректно обрабатываться. В этом случае
   следует использовать прерывание по спаду(FALLING).
*/

 

sadman41
Offline
Зарегистрирован: 19.10.2016

Типа того. Только, полагаю, sz в данном случае можно вообще не вытаскивать в луп, сделав всё в обработчике прерывания. А атомик натравить только на sp, который, быть может, станет выводится в Serial в пределах loop();

rkit
Offline
Зарегистрирован: 23.11.2016

Скорость не нужно считать в прерывании совсем. Считать в лупе по max(предыдущий интервал, время с последнего фронта).

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

sz - это обнулятор )) - уменьшается, если нет импульсов и при нуле скорость тоже приравнивается к нулю. Соответственно, если обрабатывать его только в прерываниях, то получить нулевую скорость не получится - нет импульсов, нет обнуления. 

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

ЗЫ: брал где-то на драйве

rkit
Offline
Зарегистрирован: 23.11.2016

А если совсем хорошо, то вместо прерывания по каждому фронту, нужно использовать аппаратный счетчик.

cherison
Offline
Зарегистрирован: 24.12.2020

andriano пишет:

cherison пишет:

Еще интересует такой момент, как подтягивающий резистор. Нужен ли он при при прерываниях по восходящему фронту импульса?

Без схемы этот вопрос лишен смысла. А схему Вы забыли опубликовать.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

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

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

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

cherison
Offline
Зарегистрирован: 24.12.2020

andriano пишет:

В схеме не указаны характеристики импульсов

Почитайте внимательно выше, 12В, частота импульсов приблизительно от 47Гц (холостой ход), до 200Гц (отсечка). 12В от 50 до 200 Гц. Импульсы прямоугольные.

cherison
Offline
Зарегистрирован: 24.12.2020

andriano пишет:

 поэтому нельзя сказать, рабочая она или нет.

Пробую считать импульсы нижеприведенным кодом, считает правильно:

long a;

void setup() 
 {
  Serial.begin(9600);
  attachInterrupt(0, f , RISING);
 }

void loop() {
  a = 0; // сбрасываем счетчик и ждем.
  delay(1000); 
  Serial.print(" a= ");                              
  Serial.print(a);
 
}

void f()
 {
     a++;
 }

 

cherison
Offline
Зарегистрирован: 24.12.2020

cherison пишет:

andriano пишет:

 поэтому нельзя сказать, рабочая она или нет.

Пробую считать импульсы нижеприведенным кодом, считает правильно:

long a;

void setup() 
 {
  Serial.begin(9600);
  attachInterrupt(0, f , RISING);
 }

void loop() {
  a = 0; // сбрасываем счетчик и ждем.
  delay(1000); 
  Serial.print(" a= ");                              
  Serial.print(a);
 
}

void f()
 {
     a++;
 }

 

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

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

cherison пишет:

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

Ну так сделайте аналогично blink without delay.

Но для десятков-сотен Гц лучше, конечно, измерять период а не число импульсов.

cherison
Offline
Зарегистрирован: 24.12.2020

Может считать не период, а частоту ?

cherison
Offline
Зарегистрирован: 24.12.2020

andriano пишет:

Ну так сделайте аналогично blink without delay.

Но для десятков-сотен Гц лучше, конечно, измерять период а не число импульсов.

Уберу тогда с кода все лишнее, пока измерю пока период.

cherison
Offline
Зарегистрирован: 24.12.2020

Считаю период, а он равен 1 миллисекунде ( 1кГц подаю), в монитор ком порта выводит непонятные значения:

Ниже код, с помощью которого я считаю период:


int pin = 2;
long  time_prev=0; //время предыдущее
long  time_now=0; //время предыдущее

int a=0;
int b=0;
long T=0;



void setup()
{

  Serial.begin(9600);
  pinMode(pin, INPUT);
  attachInterrupt(0, taho, RISING );

}
 
void loop()
{

}
  
  
void taho()
{    
      Serial.println(int(b));
      b++; 
      
          if(b==1)  
               { 
                        time_now = micros();
                        T=(time_now-time_prev);
                        time_prev = micros();
                        Serial.print("Период=");
                        Serial.println(long(T));
                        b=0;      

               }

       
}

 

 

MaksVV
Offline
Зарегистрирован: 06.08.2015
volatile uint32_t Time[2];
volatile byte state=0;
int f;

void setup() 
{
  Serial.begin (9600);
  attachInterrupt(0, tic , RISING);
}

void loop() 
{
cli();
if (state==2) {f = 1000000/(Time[1] - Time[0]); state=0; } 
sei();

static uint32_t prevtime = 0;
if (millis()-prevtime>1000){Serial.println (f); prevtime = millis(); }
}

void tic()
{
 if (state<2)  { Time[state] = micros(); state++;}
}

 

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020
if (sost==0 || sost==1)

Прикольно ))

MaksVV
Offline
Зарегистрирован: 06.08.2015

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

MaksVV
Offline
Зарегистрирован: 06.08.2015

долго исполняется? 

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

Просто прикольно. А чем оно лучше (sost < 2) ? Ну так, для общего развития ))

MaksVV
Offline
Зарегистрирован: 06.08.2015

Ну можно и так, я сначала bool сделал, потом мне двух состояний не хватило) может поэтому так написал

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

cherison пишет:

Считаю период, а он равен 1 миллисекунде ( 1кГц подаю), в монитор ком порта выводит непонятные значения:

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

cherison
Offline
Зарегистрирован: 24.12.2020

v258 пишет:

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

Это я усвоил, убрал я с обработчика.Немного переделал код:

int pin = 2;
long  time_prev=0; //время предыдущее
long  time_now=0; //время настоящее
int a=0;
int b=0;
long T=0;

void setup()
  {
     Serial.begin(9600);
     pinMode(pin, INPUT);
     attachInterrupt(0, taho, RISING );
  }
 
void loop()
  {
      if(a==2)  
          { 
          T=time_now-time_prev;
          Serial.print("Период=");
          Serial.println(long(T));
          a=0;
          }
}
  
  
void taho()
 {    
    if(b==1)  
         { 
         time_now = micros();
         b=0; 
         a++;      
         }
                    
     else  { 
              time_prev = micros();
              b++; 
              a++; 
              }    
 }

 

В мониторе ком порта показывает нормальные значения, но эти значения через раз со знаком минус "-".

cherison
Offline
Зарегистрирован: 24.12.2020

cherison пишет:

В мониторе ком порта показывает нормальные значения, но эти значения через раз со знаком минус "-".

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

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

У таймеров есть счетный вход и система захвата значения...

Один таймер настроить дергать раз в секунду захват значения на другом таймере + проводок, а второй просто считает импульсы со счетного входа...

В прерывании по захвату второго таймера - обнулять счетчик и копировать значение из регистра захвата в переменную.

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

cherison
Offline
Зарегистрирован: 24.12.2020

Komandir пишет:

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

У таймеров есть счетный вход и система захвата значения...

Один таймер настроить дергать раз в секунду захват значения на другом таймере + проводок, а второй просто считает импульсы со счетного входа...

В прерывании по захвату второго таймера - обнулять счетчик и копировать значение из регистра захвата в переменную.

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

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

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

cherison пишет:

В мониторе ком порта показывает нормальные значения, но эти значения через раз со знаком минус "-".


Потому что тип должен быть не long, a unsigned long

MaksVV
Offline
Зарегистрирован: 06.08.2015

ТС , а код #30 чем тебе не зашёл? 

MaksVV
Offline
Зарегистрирован: 06.08.2015

Komandir пишет:
Гонять камень в прерывание на каждый импульс ???

У таймеров есть счетный вход и система захвата значения...

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

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Я считаю что надо по максимуму использовать аппаратные средства МК.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Komandir пишет:

Я считаю что надо по максимуму использовать аппаратные средства МК.

Зачем?

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Я не запрещаю помигать диодом через delay ...

b707
Offline
Зарегистрирован: 26.05.2017

Komandir пишет:

Один таймер настроить дергать раз в секунду захват значения на другом таймере + проводок, а второй просто считает импульсы со счетного входа...

В прерывании по захвату второго таймера - обнулять счетчик и копировать значение из регистра захвата в переменную.

зачем для этого два таймера? все отлично делается и на одном

Даже обе половинки сигнала ШИМ можно одним таймером померять и вывести не только частоту, но и заполнение. Обсуждали же...

http://arduino.ru/forum/pesochnitsa-razdel-dlya-novichkov/chtenie-shim-5-kgts?page=1#comment-522823