Неправильно работает тахометр

conrod
Offline
Зарегистрирован: 10.05.2016

Добрый день. Я пытаюсь собрать устройство, которое поддерживает обороты двигателя ВАЗ 1111 (ОКА) на заданном уровне. Пока моделировал и проверял на столе все шло хорошо. Когда поставил на двигатель появились непонятки. Ардуино не верно считает обороты. такое ощущение, что пропускает прерывания. Сигнал для тахометра я беру со штатного датчика Холла на двигателе он там от ВАЗ 2108. Подключил его через делитель напряжения на резисторах номиналом 2,2К и 4,7К , потому что на выходе датчика около 7В. В итоге на вход приходит 4В. питание Ардуино и серводвигателя раздельное на LM2596 серва и MP1584 ардуино

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

1200   1200   1200   4800   4800   1200   1200   59000   59000   59000   1200   1200  и т.д.

Какой либо закономерности я не заметил. Может кто-нибудь знает где искать?  заранее спасибо всем откликнувшимся.  Работа с прерываниями и определениями частоты вращения в 61-79 и 135-140 строках кода.

 

[code]
#include <EEPROM.h>
#include <TM1637Display.h>;
#include <Servo.h>

// контакты для подключения и объявления дисплея//
int CLK=A2;
int DIO=A3;
int i=0;//просто переменная//
int i1=0;//просто переменная//
TM1637Display display(CLK, DIO);//объявление дисплея//

//цоколевка для тахомера//
int RPMin=2;
int Key_up=11;  // выводы 9,10 - входы кнопок
int Key_down=10;
int ledpin=13;
int RPMout=3;
int RPM_tar=0;//поддерживаемые обороты

int servopin=9;
int pos = 0; //позиция серводвигателя
int delta = 0; //разница в падении приращении оборотов
float deltamod = 0; //разница в падении приращении оборотов
int deltapos = 0;//разница в падении приращении оборотов
int DrMAX=154; //значене позиции серводвигателя при открытом дросселе
int DrMIN=74;//значене позиции серводвигателя при закрытом дросселе
Servo myservo; 

//переменные для счетчика оборотов
volatile unsigned long micros_sp = 0;
volatile unsigned long micros_prev = 0;
volatile byte sz = 0; //счетчик обнуления
volatile unsigned int RPM = 0; //обороты


void setup() {
//EEPROM.write(0,1200/100); // запись целевых оборотов в ЕЕПРОМ , записать 1раз потом закомментировать
//EEPROM.write(1,1200%100);

RPM_tar=(EEPROM.read(0)*100+EEPROM.read(1)); //считываем обороты которые нужно поддерживать
  
display.setBrightness(0x0f); //яркость дисплея//
Serial.begin(9600);
myservo.attach(servopin);  // attaches the servo on pin 9 to the servo object

pinMode(Key_up, INPUT);  // объявление кнопок up и down
digitalWrite(Key_up, HIGH);
pinMode(Key_down, INPUT);
digitalWrite(Key_down, HIGH);

pinMode(RPMin, INPUT);
digitalWrite(RPMin, HIGH);

pinMode(ledpin, OUTPUT);
digitalWrite(ledpin, LOW);

//генератор импульсов для теста
//pinMode(RPMout, OUTPUT); // генератор сигнала 20 Гц = 1200об/мин после отладки можно закомментировать//
//tone(RPMout, 60);

myservo.write(100); //установка серводвигателя в начальное положение
delay(1000); 
attachInterrupt(0, RPMmetr, FALLING); //прерывание оборотов по спаду импульса
}

void loop() {  // put your main code here, to run repeatedly:

i1=0;
if (sz != 0){sz--;}else{RPM = 0;};
delta = RPM_tar-RPM;//расчет изменения текущего количества оборотов
if (delta<0) {deltamod=-1*delta;} else {deltamod=delta;} //делаем изменения оборотов положительными значениями 
deltapos = deltamod/RPM_tar*90; //расчет изменения текущего положения вала серводвигателя для восстановления заданных оборотов

//изменение позиции вала серовдвигателя с учетом ограничения углов дросселя
if (delta<0) {pos=pos-deltapos;}
if (delta>0) {pos=pos+deltapos;}
if (pos <= DrMIN) {pos=DrMIN;} 
if (pos >= DrMAX) {pos=DrMAX;} 
  myservo.write(pos);

//обработка кнопок прибавить и уменьшить обороты если они нажаты при необходимости запоминаем требуемые обороты
//к5нопка больше оборотов 
while (digitalRead(Key_up)==0){
    i1++;
   RPM_tar=RPM_tar+10;
  if (RPM_tar==6000){RPM_tar=0;}
  display.showNumberDec(RPM_tar,1,4,0);
  delay(1500/i1);
  if (digitalRead(Key_down)==0){
    EEPROM.write(0,RPM_tar/100); // запись целевых оборотов в ЕЕПРОМ , 
    EEPROM.write(1,RPM_tar%100);
    display.setBrightness(0x00);
    delay(500);
    display.showNumberDec(RPM_tar,1,4,0);
    display.setBrightness(0x0f);
  delay(1000);
    }
    }
//кнопка меньше оборотов
while (digitalRead(Key_down)==0){
   i1++;
   RPM_tar=RPM_tar-10;
   if (RPM_tar==0){RPM_tar=6000;}
    display.showNumberDec(RPM_tar,1,4,0);
   delay(1500/i1);
  if (digitalRead(Key_up)==0){
    EEPROM.write(0,RPM_tar/100); // запись целевых оборотов в ЕЕПРОМ 
    EEPROM.write(1,RPM_tar%100);
display.setBrightness(0x00);
delay(500);
    display.showNumberDec(RPM_tar,1,4,0);
    display.setBrightness(0x0f);
  delay(1000);
    }
    }
    
if (i>=20) {display.showNumberDec(RPM,1,4,0); // вывод на экран текущих оборотов 1ин раз за 20 циклов
i=0;}
else {i++;} 


Serial.println (RPM);

//генератор импульсов для теста
/*for (float i=35; i <= 125; i=i+0.5){
      tone(RPMout, i);
      //delay(20);
         }
  /* for (float i=125; i >= 35; i=i-0.5){
      tone(RPMout, i);
       //delay(20);
}*/
}

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


[/code]

 

faeton
faeton аватар
Offline
Зарегистрирован: 21.03.2016

У Вас есть осцилограф? Есть чем посмотреть уровень помех на входе? :) И не пропускает оно прерывани, а ловит шум и даёт 59 тыс. оборотов в минуту. :)

conrod
Offline
Зарегистрирован: 10.05.2016

К сожалению осцилографа нет. Я не настолько продвинут. :) Вы имеете в виду шум на входе или питании?  но разве в случае шумов прерывания не будут происходить чаще, а следовательно обороты меньше.  Что можно предпринять чтобы исключить шумы - экранировать сигнальный провод?

Могут быть связаны неправильные обороты с резисторами?  например они замедляют переход от 0 к 1 и ардуина не считает это фронтом импульса? Или в коде, что-то выполняется и запрещает прерывание пока оно не выполнится?

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

conrod, проблема чисто аппаратная. Прерывания INT0 и INT1 срабатывают буквально от любого шороха  - любой помехи по питанию или на любом входе. Либо исправляйте аппаратные косяки, либо считайте обороты таймером через вход ICP.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Резисторы 2.2к и 4.7к надо поставить как можно ближе ко входу дуньки, и дополнительно можно паралелльно 4.7к воткнуть керамический кондер небольшой емкости до 100нф, 10..33н вполне подойдет. Получится RC-фильтр, отсекающий помехи. Частота "отсечки" (ослабление в 2 раза) определяется постоянной времени RC-цепи = 2.2*R*C. Частота вашего двигателя всяко до 10тыс об/мин , или менее 170гц., часто и значительно. 1/170 = 2.2*R*C или Cmax = 1/(170 * 2.2 * 4700) (ф). Для удержания фронтов возьмите кондер в раз 100 меньше полученного значения.

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Arhat109-2 пишет:
Резисторы 2.2к и 4.7к надо поставить как можно ближе ко входу дуньки, и дополнительно можно паралелльно 4.7к воткнуть керамический кондер небольшой емкости до 100нф, 10..33н вполне подойдет. Получится RC-фильтр, отсекающий помехи. Частота "отсечки" (ослабление в 2 раза) определяется постоянной времени RC-цепи = 2.2*R*C. Частота вашего двигателя всяко до 10тыс об/мин , или менее 170гц., часто и значительно. 1/170 = 2.2*R*C или Cmax = 1/(170 * 2.2 * 4700) (ф). Для удержания фронтов возьмите кондер в раз 100 меньше полученного значения.
Не забываем про триггер шмитта после всего этого. Входы прерывания не любят пологие фронты.

conrod
Offline
Зарегистрирован: 10.05.2016

Большое спасибо за советы буду разбираться дальше.

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

conrod, хоть и пишут проблема чисто аппаратная, грабли разложены и программные

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

void RPMmetr(){
micros_prev = micros_sp;
micros_sp = micros();
}

micros_prev и micros_sp объяви волатильными; В loop() запрети прерывания на время доступа к этим переменным.

faeton
faeton аватар
Offline
Зарегистрирован: 21.03.2016

conrod пишет:
Большое спасибо за советы буду разбираться дальше.

RC фильт можно выполнить и программно и на том же очень чувствительном к шорохам прерывании: в процедуре обработки прерывания проверять время, прошедшее после предыдущего прерывания и, если оно меньше того, что требуется на один оборот при максимальной частоте вращения, вываливаться из прерывания ничего не делая. Но делитель на входе всё равно лучше сделать потяжелее, снизив сопротивление в 5-10 раз.

conrod
Offline
Зарегистрирован: 10.05.2016

Добрый день. Доработал код согдасно рекомендациям. припаял конденсатор на вход.
Все равно, неправильно считает обороты со штатного датчика холла, хотя появилась большая стабильность обороты стали от19000 до 35000. :-)

Попробовал поставить отдельный индуктивный китайский датчик LJ12A3-4-Z/BY и репер на маховик. Видимо чувствительность датчика небольшая и он не успевает отреагировать на метку при вращении маховика. Но я заметил, при работе двигателя, когда в линии сигнала датчика 0, Ардуино начинает выводить значения не существующих оборотов. Когда в линии 1, обороты стабильно равны 0. Т.е. помехи по сигналу. Причем если поднести сигнальный кабель датчика к высоковольтным элементам ДВС катушке и ВВ проводам. Обороты определяемые ардуиной становятся стабильными и более-менее правильными. Вопрос - как избавиться от наводок высоковольтной части ДВС? 

Владимир Север
Offline
Зарегистрирован: 04.10.2018

Я не программист но знаю что, датчик холла, это устройство реагирующее на магнитное поле. А в Вашем авто, стоит магнитоэлектрический датчик, имеющий своё магнитное (я так думаю, это датчик полжения колечатого вала) и меняется оно в момент прохождение металла через его мегнитное поле, там самым создавая сигнал и ЭДС (сам вырабатывает напряжение). Может в этом проблема?

Владимир Север
Offline
Зарегистрирован: 04.10.2018

Экранированные провода и конденсаторы.

sva_khv
Offline
Зарегистрирован: 19.12.2016

conrod пишет:
К сожалению осцилографа нет.

Без него это мучения методом тыка. Я и с осцилографом еще не все помехи отловил которая моя Волга дает на ардуинку.

conrod пишет:
  но разве в случае шумов прерывания не будут происходить чаще, а следовательно обороты меньше?

Это как? 

 

jdigreze
Offline
Зарегистрирован: 14.01.2018

Владимир Север пишет:

Я не программист но знаю что, датчик холла, это устройство реагирующее на магнитное поле. А в Вашем авто, стоит магнитоэлектрический датчик, имеющий своё магнитное (я так думаю, это датчик полжения колечатого вала) и меняется оно в момент прохождение металла через его мегнитное поле, там самым создавая сигнал и ЭДС (сам вырабатывает напряжение). Может в этом проблема?

Неа. Там именно датчик Холла стоит.

Экранированный провод может не помочь.

Я бы делитель делал не на резисторах, а на стабилитроне. И ловил бы импульсы без прерываний, а как на кнопках, с программным антидребезгом.