Почему 'плавают' показатели датчика оборотов.

rula
Offline
Зарегистрирован: 27.09.2019

Использую щелевой датчик оборотов на lm393. В системе кроме датчика и двигателя никого нет. Считаю обороты через разницу во времени которую получаю в прерывании, там кроме разницы ничего нет.  Обороты(показатель с датчика) плавают в тысячу раз. При этом если просто считывать сигнал с датчика и когда он есть, моргать светодиодом на ардуине, моргает синхронно со светодиодом на датчике. Т.е. Датчик, вроде, рабочий. В этой же системе другой датчик, на датчике холла, работает корректно. Что и как проверить, чтоб выяснить кто виноват, дребезг(подтягивал, ставил проверку), датчик или прерывания. 

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

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

nik182
Offline
Зарегистрирован: 04.05.2015

На прерывании всегда так. Любой чих в системе и прерывание срабатывает. Попробуйте на pulseIn сделать. Намного устойчивее работает.

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

Если подключено через Ж то и pulseIn будет фигню выдавать. А если подключено нормально, то и прерывания будут нормально работать.

nik182
Offline
Зарегистрирован: 04.05.2015

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

rula
Offline
Зарегистрирован: 27.09.2019

Вывод после pulseIn
Диск на 100 прорезей, но и с 2-мя лопастями поведение тоже нестабильное.

57:53.151 -> frequency 8239
09:57:53.224 -> frequency 8283
09:57:53.262 -> frequency 6966
09:57:53.299 -> frequency 7376
09:57:53.336 -> frequency 9778
09:57:53.406 -> frequency 7790
09:57:53.479 -> frequency 10207
09:57:53.513 -> frequency 7818
09:57:53.587 -> frequency 9655
09:57:53.624 -> frequency 7492
09:57:53.694 -> frequency 8633
09:57:53.731 -> frequency 8891
09:57:53.768 -> frequency 7682
09:57:53.834 -> frequency 8132
09:57:53.871 -> frequency 7697
09:57:53.943 -> frequency 8277
09:57:53.979 -> frequency 8125
09:57:54.048 -> frequency 7104
09:57:54.082 -> frequency 9205
09:57:54.158 -> frequency 8082
09:57:54.194 -> frequency 7892
09:57:54.230 -> frequency 6456
09:57:54.297 -> frequency 6179
09:57:54.343 -> frequency 8369
09:57:54.409 -> frequency 6788
09:57:54.446 -> frequency 0
09:57:54.520 -> frequency 7646
09:57:54.556 -> frequency 6906
09:57:54.593 -> frequency 6690
09:57:54.664 -> frequency 6414
09:57:54.700 -> frequency 5402
09:57:54.774 -> frequency 5833
09:57:54.812 -> frequency 6106
09:57:54.850 -> frequency 5985
09:57:54.925 -> frequency 5185
09:57:54.995 -> frequency 6552
09:57:55.063 -> frequency 5743
09:57:55.100 -> frequency 5744
09:57:55.183 -> frequency 5417
09:57:55.210 -> frequency 5680
09:57:55.281 -> frequency 4752
09:57:55.354 -> frequency 5035
09:57:55.388 -> frequency 4024
09:57:55.422 -> frequency 3707
09:57:55.497 -> frequency 2767

int senserpin=2;
int sensordelay=1000; 
unsigned long duration;
float freq;



//мотор диск
int IN1 = 8; 
int IN2 = 9;
int ENB1 = 10;


void setup() {
  Serial.begin(9600);                

//pinMode (2, INPUT_PULLUP);
pinMode(senserpin,INPUT);



// мотор диск
 pinMode (ENB1, OUTPUT); 
 pinMode (IN1, OUTPUT);
 pinMode (IN2, OUTPUT);
digitalWrite (IN1, LOW); 
digitalWrite (IN2, HIGH);
analogWrite(ENB1,50);  

}

void loop() {

duration=pulseIn(senserpin, HIGH);
//freq= 1/(duration*1000000);
Serial.print("frequency ");
Serial.println(duration);


}

 

 

rula
Offline
Зарегистрирован: 27.09.2019

И обратил внимание, при выводе в порт в момент когда происходят резкие изменения, вывод "подтормаживает".

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

так ясное дело! Вы выводите строки по 15 байт. На скорости 9600 это порядка 15мс. А каждая новая строка формируется через 2-10мс. Буфер отправки заполняется и начинается работа в блокирующем режиме, что замедляет луп. В результате вызов pulseIn как попало ложится на импульс и меряет что попало.

rula
Offline
Зарегистрирован: 27.09.2019
12:23:19.707 -> 340       0.00
12:23:21.209 -> 197       0.00
12:23:22.711 -> 166       0.00
12:23:24.224 -> 157       0.00
12:23:25.697 -> 195       0.00
12:23:27.202 -> 200       0.00
12:23:28.727 -> 252       0.00
12:23:30.228 -> 44       0.00
12:23:31.720 -> 415       0.00
12:23:33.241 -> 467       0.00
12:23:34.722 -> 458       0.00
12:23:36.237 -> 765       0.00
12:23:37.723 -> 551       0.00
12:23:39.236 -> 520       0.00

Видимо без разницы, задержка 1500мс

byte n = 100;      // число лопастей



float r_speed, rev_time;
volatile unsigned long lastflash, flash, lastshow;
unsigned int RPM;
String spaces = "       ";


//мотор диск
int IN1 = 8; 
int IN2 = 9;
int ENB1 = 10;


void setup() {
  Serial.begin(9600);                  
//  detachInterrupt(1);
pinMode (2, INPUT_PULLUP);
  attachInterrupt(0, sens, CHANGE);    

// мотор диск
 pinMode (ENB1, OUTPUT); 
 pinMode (IN1, OUTPUT);
 pinMode (IN2, OUTPUT);

}
void sens() {
  if (micros() - lastflash > 200){
  flash = micros() - lastflash;   
  lastflash = micros();           
}
}
void loop() {

digitalWrite (IN1, LOW);  
digitalWrite (IN2, HIGH);
analogWrite(ENB1,100);  
  
  if (micros() - lastflash > 10000000) { 
    RPM = 0;                            
    r_speed = 0;
  } else {
    rev_time = (float) flash / 1000000 * n;            
    RPM = (float) 60 / rev_time;                        
  }
if (millis() - lastshow > 1500) { 

    Serial.print(RPM);       

Serial.print("       ");  

    Serial.println(r_speed);  

    lastshow = millis(); 
 }
}

 

 

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

в строчке 45 всегда будет получаться ноль, потому что она считается в целых числах, а только потом результат (ноль) приводится к типу флоат

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

rula, попробуйте считать обороты таймером, как частоту. Пример.

nik182
Offline
Зарегистрирован: 04.05.2015

Чудак человек. Перед duration=pulseIn(senserpin, HIGH); нужно обязательно ставить пустой duration=pulseIn(senserpin, LOW); потом два раза duration1=pulseIn(senserpin, HIGH); duration2=pulseIn(senserpin, LOW);и сложить первое и второе измерение. Это и будет период. А с твоим лупом всегда будет плавать, потому что если выход HIGH то начала следующего HIGH ждать не будет и будет считать время с текущей случайной позиции. 

int senserpin=2;
int sensordelay=1000; 
unsigned long duration,duration1,duration2;
float freq;



//мотор диск
int IN1 = 8; 
int IN2 = 9;
int ENB1 = 10;


void setup() {
  Serial.begin(9600);                

//pinMode (2, INPUT_PULLUP);
pinMode(senserpin,INPUT);



// мотор диск
 pinMode (ENB1, OUTPUT); 
 pinMode (IN1, OUTPUT);
 pinMode (IN2, OUTPUT);
digitalWrite (IN1, LOW); 
digitalWrite (IN2, HIGH);
analogWrite(ENB1,50);  

}

void loop() {

duration=pulseIn(senserpin, LOW);
duration1=pulseIn(senserpin, HIGH);
duration2=pulseIn(senserpin, LOW);
//freq= 1/(duration*1000000);
duration=duration1+duration2;
Serial.print("frequency ");
Serial.println(duration);


}

 

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

nik182 пишет:

Чудак человек. Перед duration=pulseIn(senserpin, HIGH); нужно обязательно ставить пустой duration=pulseIn(senserpin, LOW); потом два раза duration1=pulseIn(senserpin, HIGH); duration2=pulseIn(senserpin, LOW);и сложить первое и второе измерение. Это и будет период. А с твоим лупом всегда будет плавать, потому что если выход HIGH то начала следующего HIGH ждать не будет и будет считать время с текущей случайной позиции.

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

Reads a pulse (either HIGH or LOW) on a pin. For example, if value is HIGHpulseIn() waits for the pin to go from LOW to HIGH, starts timing, then waits for the pin to go LOW and stops timing. Returns the length of the pulse in microseconds or gives up and returns 0 if no complete pulse was received within the timeout.

 

А ТС, скорее всего, с подключением датчика проблемы.

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

nik182 пишет:
Я бы не был столь категоричен. pulseIn иголку наводки с большой вероятностью пропустит, прерывание всегда сработает. Если на pulseIn показания более устойчивы, то надо искать откуда идут наводки. Если также плохо работает, то тогда поможет только осцилограф.

Внешние прерывания у Атмеги обрабатываются синхронно. Т.е. состояние пина считывается каждый такт. Если "иголка" проскочила между тактами, то ничего не сработает. PulsIn работает сходным образом, только помедленне, поскольку опрос пина происходит програмно. Та часть PulsIn-а, что следит за изменеием пина написана на ассембере и работает достаточно быстро. Я точно не считал, но по виду можно говорить про время реакции всего раз в 10 большие чем прерывания. То есть "иголки" длительностью в  несколько сотен наносекунд вполне себе  могут привести к сбоям в работе  PulsIn.

Я бы порекомендовал ТС взять скоп с полосой, хотя бы, 50 Мгц и посмотреть что у него там на выходе его датчика творится.

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

На ICR защитой от иголок является трехкратное считывание и только после этого райзинг прерывания, например...

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

sadman41 пишет:

На ICR защитой от иголок является трехкратное считывание и только после этого райзинг прерывания, например...

А еще керамикой пикофарад в 10 вход зашунтировать.

nik182
Offline
Зарегистрирован: 04.05.2015

Залез, посмотрел код. Действительно ждет окончания предыдущего, потом считает. Но вот считать только high или low не правильно. Нужна сумма low и high. Дырки могут быть разными. Там ещё есть что типа pulseInlong который сразу считает период, вот только у меня он не заработал как надо.