Неправильно работает тахометр
- Войдите на сайт для отправки комментариев
Добрый день. Я пытаюсь собрать устройство, которое поддерживает обороты двигателя ВАЗ 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]
У Вас есть осцилограф? Есть чем посмотреть уровень помех на входе? :) И не пропускает оно прерывани, а ловит шум и даёт 59 тыс. оборотов в минуту. :)
К сожалению осцилографа нет. Я не настолько продвинут. :) Вы имеете в виду шум на входе или питании? но разве в случае шумов прерывания не будут происходить чаще, а следовательно обороты меньше. Что можно предпринять чтобы исключить шумы - экранировать сигнальный провод?
Могут быть связаны неправильные обороты с резисторами? например они замедляют переход от 0 к 1 и ардуина не считает это фронтом импульса? Или в коде, что-то выполняется и запрещает прерывание пока оно не выполнится?
conrod, проблема чисто аппаратная. Прерывания INT0 и INT1 срабатывают буквально от любого шороха - любой помехи по питанию или на любом входе. Либо исправляйте аппаратные косяки, либо считайте обороты таймером через вход ICP.
Резисторы 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, хоть и пишут проблема чисто аппаратная, грабли разложены и программные
Выкинь из прерывания любые вычисления, оставь только
micros_prev и micros_sp объяви волатильными; В loop() запрети прерывания на время доступа к этим переменным.
RC фильт можно выполнить и программно и на том же очень чувствительном к шорохам прерывании: в процедуре обработки прерывания проверять время, прошедшее после предыдущего прерывания и, если оно меньше того, что требуется на один оборот при максимальной частоте вращения, вываливаться из прерывания ничего не делая. Но делитель на входе всё равно лучше сделать потяжелее, снизив сопротивление в 5-10 раз.
Добрый день. Доработал код согдасно рекомендациям. припаял конденсатор на вход.
Все равно, неправильно считает обороты со штатного датчика холла, хотя появилась большая стабильность обороты стали от19000 до 35000. :-)
Попробовал поставить отдельный индуктивный китайский датчик LJ12A3-4-Z/BY и репер на маховик. Видимо чувствительность датчика небольшая и он не успевает отреагировать на метку при вращении маховика. Но я заметил, при работе двигателя, когда в линии сигнала датчика 0, Ардуино начинает выводить значения не существующих оборотов. Когда в линии 1, обороты стабильно равны 0. Т.е. помехи по сигналу. Причем если поднести сигнальный кабель датчика к высоковольтным элементам ДВС катушке и ВВ проводам. Обороты определяемые ардуиной становятся стабильными и более-менее правильными. Вопрос - как избавиться от наводок высоковольтной части ДВС?
Я не программист но знаю что, датчик холла, это устройство реагирующее на магнитное поле. А в Вашем авто, стоит магнитоэлектрический датчик, имеющий своё магнитное (я так думаю, это датчик полжения колечатого вала) и меняется оно в момент прохождение металла через его мегнитное поле, там самым создавая сигнал и ЭДС (сам вырабатывает напряжение). Может в этом проблема?
Экранированные провода и конденсаторы.
Без него это мучения методом тыка. Я и с осцилографом еще не все помехи отловил которая моя Волга дает на ардуинку.
Это как?
Я не программист но знаю что, датчик холла, это устройство реагирующее на магнитное поле. А в Вашем авто, стоит магнитоэлектрический датчик, имеющий своё магнитное (я так думаю, это датчик полжения колечатого вала) и меняется оно в момент прохождение металла через его мегнитное поле, там самым создавая сигнал и ЭДС (сам вырабатывает напряжение). Может в этом проблема?
Экранированный провод может не помочь.
Я бы делитель делал не на резисторах, а на стабилитроне. И ловил бы импульсы без прерываний, а как на кнопках, с программным антидребезгом.