Тахометр для двигателя

skyspirit
Offline
Зарегистрирован: 27.02.2015

Кто нибуть реализововал тахометр на ардуино, если да то подскажите в какую сторону копать:)

Gippopotam
Gippopotam аватар
Offline
Зарегистрирован: 12.09.2014

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

Seth
Offline
Зарегистрирован: 01.02.2014

Ну я себе в семерку делал.

Что сказать-то? Берете ардуину и датчик холла(есть штатные) и через прерывания считаете.

skyspirit
Offline
Зарегистрирован: 27.02.2015

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

 

Gippopotam
Gippopotam аватар
Offline
Зарегистрирован: 12.09.2014

skyspirit пишет:

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

Seth пишет:

Берете ардуину и датчик холла и через прерывания считаете.

skyspirit
Offline
Зарегистрирован: 27.02.2015

Датчик хола не подойдет нужно импульсы с генератора считывать

 

Seth
Offline
Зарегистрирован: 01.02.2014

А при чем тут генератор? Пусть тс сначала напишет чего он хочет, а потом может ему подскажут. Видишь, уже выясняется что на мотоцикл ему нужно. Пусть скажет на какой ещё.

skyspirit
Offline
Зарегистрирован: 27.02.2015

Идея чтоб на любой двигатель считать обороты коленвала, а хоть мотоцыкл хоть машына, бензопила 

Coolerr
Offline
Зарегистрирован: 30.06.2014

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

Gippopotam
Gippopotam аватар
Offline
Зарегистрирован: 12.09.2014

skyspirit пишет:

Датчик хола не подойдет нужно импульсы с генератора считывать

 

1. почему не пойдет?

2. какая разница откуда импульсы считать?

Puhlyaviy
Puhlyaviy аватар
Offline
Зарегистрирован: 22.05.2013

Да вы вообще тупите со своими датчиками и импульсами.. самый верный путь определение оборотов по звуку двигателя!!!
На дисплее делаем пиктограммы
1. Растроеный смайл. Обороты низкие
2. Веселый смайл. Обороты рев на квартал
3. Телки бьются в оргазме от звука вашего мотоцикла!

skyspirit
Offline
Зарегистрирован: 27.02.2015

вижу тут не специалисты а любители по..з...ть :)

Doozer
Offline
Зарегистрирован: 30.07.2015

skyspirit пишет:

вижу тут не специалисты а любители по..з...ть :)

 

Вам ответили на два бессмысленных вопроса, что вы ещё хотите?

Seth пишет:

Ну я себе в семерку делал.

Что сказать-то? Берете ардуину и датчик холла(есть штатные) и через прерывания считаете.

 

P.S. Вы задали тон теме, на себя и пеняйте.

Puhlyaviy
Puhlyaviy аватар
Offline
Зарегистрирован: 22.05.2013

У меня есть глупый вопрос.
ЗАЧЕМ? Зачем тахометр? Когда вы вообще смотрели на тахометр последний раз?

skyspirit
Offline
Зарегистрирован: 27.02.2015

Уточняю тему так как неправильно задал . Кто делал тахометер для двигателя? если делали поделитесь схемкой и прошивкой?

Coolerr
Offline
Зарегистрирован: 30.06.2014
skyspirit
Offline
Зарегистрирован: 27.02.2015

это уже видел неподходят, там в основном с датчиками хола а нужно импульсы напряжения считать с генератора 

Coolerr
Offline
Зарегистрирован: 30.06.2014

Я выше спрашивал какие импульсы у генератора?

Gippopotam
Gippopotam аватар
Offline
Зарегистрирован: 12.09.2014

А я выше спрашивал - какая разница, какие импульсы считать?

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

А у вас импульсный генератор  или что?
Если мотоцикл не дизельный ;) то импульсы можно брать с катушки зажигания ( или магнето)

Puhlyaviy
Puhlyaviy аватар
Offline
Зарегистрирован: 22.05.2013

А я выше спрашивал - нафига весь этот геморой? Вы когда едите типа тахометр разглядываете?

Seth
Offline
Зарегистрирован: 01.02.2014

Ну хочет человек тахометр. Пусть делает. Вам то что, не вам же городит.
Только универсальных решений нет. ТС так и не сказал, что за мотоцикл у него. И какие импульсы в постоянном токе генератора.

Puhlyaviy
Puhlyaviy аватар
Offline
Зарегистрирован: 22.05.2013

Seth пишет:
Ну хочет человек тахометр. Пусть делает. Вам то что, не вам же городит.
Только универсальных решений нет. ТС так и не сказал, что за мотоцикл у него. И какие импульсы в постоянном токе генератора.

Сама идея считать обороты двигателя кроме как на коленвале мне видится сложно выполнимой. Ибо всякие тама передаточные ремни или шестерни и прочее... тоска в общем

skyspirit
Offline
Зарегистрирован: 27.02.2015

trembo пишет:

А у вас импульсный генератор  или что?
Если мотоцикл не дизельный ;) то импульсы можно брать с катушки зажигания ( или магнето)

Да можно с катушки брать, главно чтоб считало.

 

 

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011
Gippopotam
Gippopotam аватар
Offline
Зарегистрирован: 12.09.2014
bsdshneg
Offline
Зарегистрирован: 21.10.2014

Салют, товарищам!

Подниму тему, дабы не плодить много однообразных (поправьте, если я не прав)!

Есть копейка 73 года, нужен и спидометр и тахометр - про него-то и пойдёт речь. Для считывания оборотов можно на ВВ провод идущий от катушки намотать медный провод (пару десятков витков) и по количеству импульсов считать обороты - вот вопрос: "Как правильно подать их на ардуинку?" ... как я понимаю - на аналоговый вход? и считать количество отклонений от нуля? ... т.е. я понимаю, что и как надо считать, но не совсем понимаю как увязать всё это на ардуину (просьба не закидывать помидорами, все мы когда-то в чём-то задавали глупые вопросы)...

 

встречал тут вот такую схему, но это при подключении к управляющему катушкой проводу

или принцип тот же, только без резисторов?

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

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

http://avtopulsar.ru/wp-content/uploads/2013/01/49.jpg

звездочку с магнитом и датчик холла. данные будут лучше

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

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

Примерная их форма здесь, должны легко фильтроваться стабилитроном и РЦ цепочкой с учётом небольшой их частоты.
6000 оборотов  в минуту, 100 в секунду, две искры на оборот (при четырёх горшках) 200 Герц.....

https://www.google.ru/search?q=%D1%81%D0%B8%D0%B3%D0%BD%D0%B0%D0%BB+%D1%...

bsdshneg
Offline
Зарегистрирован: 21.10.2014

jeka_tm

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

bsdshneg
Offline
Зарегистрирован: 21.10.2014

trembo

т.е. я правильно тебя понимаю, что если намотать медный провод на ВВ провод от катушки, я таки получу правильные импульсы?

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

А "провод намотанный на провод" это конденсатор небольшой ёмкости.
Но он может иметь любую полярность.
Поэтому лучше брать сигнал с первичной обмотки
Картинки гляньте..... Там форма выбросов на первичке

bsdshneg
Offline
Зарегистрирован: 21.10.2014

trembo Спасибо!))) Буду пробовать по схеме делать, по результату напишу!

Да, я так понимаю, что ему нужно стабилизировать напряжение, и L7812 должен справиться с этой задачей ...

bsdshneg
Offline
Зарегистрирован: 21.10.2014

На данный момент код вот такой

int Tahometr_impulse_count;
byte TahometrPin = 2;
int RPM;
unsigned long Check_time ;

void setup() {
  Serial.begin(9600);
  pinMode(TahometrPin, INPUT);
  digitalWrite(TahometrPin, HIGH);
  Check_time = millis();
  attachInterrupt(0, TahometrImpulse_on, RISING);
}

void loop() {
  delay(500); // произвольное время, чем реже зовем калькулятор РПМ, тем усредненее значение.
  Calc_RPM();
  Serial.println (RPM);
}

//**********************************************************************
void Calc_RPM() {

  detachInterrupt(0); // запретили считать, на всякий случай, шоб не рыпался
  float Taho_ChekTime = millis() - Check_time; // время между снятиями показаний счетчика
  if (Taho_ChekTime > 0) { // проверка на переполнение "милиса" ну вдруг больше 50 дней ))
    if (Tahometr_impulse_count > 0) { // и наличия насчитанных импульсов (на нолик делить не желательно.. будут запредельные значения в RPM)
      RPM = (1000/Taho_ChekTime)*(Tahometr_impulse_count*30); // (1000/Taho_ChekTime) - вычисляем множитель (1 секунду делим на наше "замерочное" время) и умножаем на (Tahometr_impulse_count*30) - тут можно было написать *60/2 (* 60 секунд, т.к. у нас есть количество вспышек катушки в секунду и / на 2 т.к. на 1 оборот коленвала 2 искры для 4ёх цилиндрового дрыгателя), но к чему эти сложности
    } else {
      RPM = 0;            // если нет импульсов за время измерений  то  RPM=0
    }
  }

  Tahometr_impulse_count = 0; //сбросили счетчик.
  Check_time = millis(); // новое время
  attachInterrupt(0, TahometrImpulse_on, FALLING); // разрешили считать
}
//**********************************************************************

void TahometrImpulse_on() {
  Tahometr_impulse_count++;
}

код в принципе почти весь отсюда, с несколькипи изменениями, а именно:

1. изменены типы переменных, для расчётов

2. сам расчёт мне показался немного странным (как минимум не совсем прозрачным, короче я не въехал), ну собственно у меня он и не заработал и поэтому он был переделан

Пока что оно считает  импульсы от функции tone(), а вечером или завтра я опробую на машине, ну и отпишусь чего да как.

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

да странноват. float зачем непонятно. unsigned long по идее должен быть

50 дней ну нереально. никто столько не проедет подряд

#define  TahometrPin  2 

unsigned long Check_time=0;
unsigned long Taho_ChekTime=0;

int Tahometr_impulse_count;
int RPM;


void setup() {
  Serial.begin(9600);
  pinMode(TahometrPin, INPUT_PULLUP);
  Check_time = millis();
  attachInterrupt(0, TahometrImpulse_on, RISING);
}

void loop() {
  delay(500); // произвольное время, чем реже зовем калькулятор РПМ, тем усредненее значение.
  Calc_RPM();
  Serial.println (RPM);
}

//**********************************************************************
void Calc_RPM() {
  detachInterrupt(0); // запретили считать, на всякий случай, шоб не рыпался
  Taho_ChekTime = millis() - Check_time; // время между снятиями показаний счетчика
  if (Tahometr_impulse_count > 0) {
    RPM = (1000/Taho_ChekTime)*(Tahometr_impulse_count*30); // (1000/Taho_ChekTime) - вычисляем множитель (1 секунду делим на наше "замерочное" время) и умножаем на (Tahometr_impulse_count*30) - тут можно было написать *60/2 (* 60 секунд, т.к. у нас есть количество вспышек катушки в секунду и / на 2 т.к. на 1 оборот коленвала 2 искры для 4ёх цилиндрового дрыгателя), но к чему эти сложности
  } 
  else {
    RPM = 0;            // если нет импульсов за время измерений  то  RPM=0
  }


  Tahometr_impulse_count = 0; //сбросили счетчик.
  Check_time = millis(); // новое время
  attachInterrupt(0, TahometrImpulse_on, RISING);
}
//**********************************************************************

void TahometrImpulse_on() {
  Tahometr_impulse_count++;
}

 

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

Хватит пугать народ переполнением миллиса!

Лешак уже два года назад как доказал на пальцах и примерах что при правильном написании выражения
при переполнении разница    (  millis()- PreviousMillis )  выдаёт истинное значение.

Читайте ветку:  http://arduino.ru/forum/programmirovanie/eshche-raz-migaem-svetodiodom-b...

bsdshneg
Offline
Зарегистрирован: 21.10.2014

если ставить unsigned long, то он отказывался считать вот это (Taho_ChekTime/1000), но это было заблуждением (я вчера на свадьбе был, пузырьки ощущаю до сих пор, так что мне простительно)))))), а тип я исправить забыл :)

а про 50 дней - да, согласен, но сначала хотел проверить на машине, а потом уж начну отметать лишнее, но спасибо за поправки!!! )))

С исправлениями вот

#define TahometrPin 2

unsigned long Check_time = 0;
unsigned long Taho_ChekTime = 0;

int Tahometr_impulse_count;
int RPM;

void setup() {
  Serial.begin(9600);
  pinMode(TahometrPin, INPUT_PULLUP);
  Check_time = millis();
  attachInterrupt(0, TahometrImpulse_on, RISING); // RISING или FALLING - определяется на месте, с чем стабильней
}

void loop() {
  delay(500); // произвольное время, чем реже зовем калькулятор РПМ, тем усредненее значение.
  Calc_RPM();
  Serial.println (RPM);
}

//**********************************************************************
void Calc_RPM() {
  
  detachInterrupt(0); // запретили считать, на всякий случай, шоб не рыпался
  Taho_ChekTime = millis() - Check_time; // время между снятиями показаний счетчика

  if (Tahometr_impulse_count > 0) { // и наличия насчитанных импульсов (на нолик делить не желательно.. будут запредельные значения в RPM)
    RPM = (1000 / Taho_ChekTime) * (Tahometr_impulse_count * 30); // (1000/Taho_ChekTime) - вычисляем множитель (1 секунду делим на наше "замерочное" время) и умножаем на (Tahometr_impulse_count*30) - тут можно было написать *60/2 (* 60 секунд, т.к. у нас есть количество вспышек катушки в секунду и / на 2 т.к. на 1 оборот коленвала 2 искры для 4ёх цилиндрового дрыгателя), но к чему эти сложности
  } else {
    RPM = 0;            // если нет импульсов за время измерений  то  RPM=0
  }
  
  Tahometr_impulse_count = 0; //сбросили счетчик.
  Check_time = millis(); // новое время
  attachInterrupt(0, TahometrImpulse_on, RISING); // разрешили считать, RISING или FALLING - определяется на месте, с чем стабильней
  
}
//**********************************************************************

void TahometrImpulse_on() {
  Tahometr_impulse_count++;
}

Теперь главное, чтоб заработало на авто!

bsdshneg
Offline
Зарегистрирован: 21.10.2014

trembo

Спасибо за ссылочку!

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

а где исправления? не увидел разницы

bsdshneg
Offline
Зарегистрирован: 21.10.2014

изменён тип Taho_ChekTime и убрана проверка на переполнение millis()

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

так это же я сделал))) про разницу я говорил с кодом который я подкорректированный выложил

bsdshneg
Offline
Зарегистрирован: 21.10.2014

так я же написал, что с твоими корректировками код ))))))

 

Теперь пока на машине не испробую - корректировать нечего)))

bsdshneg
Offline
Зарегистрирован: 21.10.2014

А нееееет, float Taho_ChekTime = 0;

В противном случае наш множитель равен только целому числу!

#define TahometrPin 2

unsigned long Check_time = 0;
float Taho_ChekTime = 0;

int Tahometr_impulse_count;
int RPM;

void setup() {
  Serial.begin(9600);
  pinMode(TahometrPin, INPUT_PULLUP);
  Check_time = millis();
  attachInterrupt(0, TahometrImpulse_on, RISING); // RISING или FALLING - определяется на месте, с чем стабильней
}

void loop() {
  delay(200); // произвольное время, чем реже зовем калькулятор РПМ, тем усредненее значение.
  Calc_RPM();
  Serial.println (RPM);
}

//**********************************************************************
void Calc_RPM() {
  
  detachInterrupt(0); // запретили считать, на всякий случай, шоб не рыпался
  Taho_ChekTime = millis() - Check_time; // время между снятиями показаний счетчика

  if (Tahometr_impulse_count > 0) { // и наличия насчитанных импульсов (на нолик делить не желательно.. будут запредельные значения в RPM)
    RPM = (1000 / Taho_ChekTime) * (Tahometr_impulse_count * 30); // (1000/Taho_ChekTime) - вычисляем множитель (1 секунду делим на наше "замерочное" время) и умножаем на (Tahometr_impulse_count*30) - тут можно было написать *60/2 (* 60 секунд, т.к. у нас есть количество вспышек катушки в секунду и / на 2 т.к. на 1 оборот коленвала 2 искры для 4ёх цилиндрового дрыгателя), но к чему эти сложности
  } else {
    RPM = 0;            // если нет импульсов за время измерений  то  RPM=0
  }
  
  Tahometr_impulse_count = 0; //сбросили счетчик.
  Check_time = millis(); // новое время
  attachInterrupt(0, TahometrImpulse_on, RISING); // разрешили считать, RISING или FALLING - определяется на месте, с чем стабильней
  
}
//**********************************************************************

void TahometrImpulse_on() {
  Tahometr_impulse_count++;
}

 

Olm
Offline
Зарегистрирован: 09.10.2014

Можно захват импульса делать на прерывании по захвату на таймере1. это  пин PB1 по моему.

Очень удобно и точное время получается,  я тахометр делал на оптопаре . Но это уже не стандартные ардуиновские функции получаются.

 

bsdshneg
Offline
Зарегистрирован: 21.10.2014

Olm пишет:

Можно захват имльса делать на прерывании по захвату на таймере1. это  пин PB1 по моему.

Очень удобно и точное время получается,  я тахометр делал на оптопаре . Но это уже не стандартные ардуиновские функции получаютя.

 

а можно про захват на таймере1 по подробней?.. хочется рассмотреть все варианты :)

да, и можно код Вашего тахометра посмотреть? :)

Olm
Offline
Зарегистрирован: 09.10.2014

У меня для atmega 8 код, ошибся -пин PB0  режим ICP1. 

Мой код редактировать надо,  там мусора много чтоб тут публиковать.

Вот неплохая статья http://radioparty.ru/prog-avr/program-c/548-ispolzovanie-tajmera-v-rezhime-zakhvata-izmerenie-shiriny-skvazhnosti-i-chastoty-signala

bsdshneg
Offline
Зарегистрирован: 21.10.2014

ммм, это как раз для реализации ещё одной задумки )))))) там как раз нужно знать ширину и частоту сигнала)))

Спасибо!!!

Olm
Offline
Зарегистрирован: 09.10.2014

Вот тут слегка причесал код, остальное лень редактировать.

Это тахометр с четырехразрядным семисегментником на динамической индикации


// сегменты PORTD
//_PD0____
//|      |
//PD1    | PD2
//|__PD3_|
//|      |
//|PD7   |PD4
//|______|
//   PD6    dp- pd5


#include <avr/wdt.h> //вачдог потом зацепить на 1 секунду к примеру

volatile byte screen[4]; //изображения цифр которые копируем в порт чтоб показать цифру
volatile static byte number[15] = {//изображения цифр и некоторых букв
  0b11010111, // 0
  0b00010100,   // 1
  0b11001101,    // 2
  0b01011101,   // 3
  0b00011110,    // 4
  0b01011011,   // 5
  0b11011011,     // 6
  0b00010101,     // 7
  0b11011111,    // 8
  0b01011111,    // 9
  0b00001000,//minus
  0b11000011,// С
  0b11010111, //А
  0b10010111//П
  //0~9,A,b,C,d,E,F,"-"," "
}; //изображения цифр и некоторых букв

volatile uint8_t countershiftanode = 0; // для динамичексой индикации счетчик
volatile uint8_t shiftanode = B00000001; //для динамической индикации

volatile uint8_t scan_number=0;// щетчик оборотов для усреднения
volatile uint8_t TIMER1_OVF_counter=0;// щетчик количества срабатываний таймера1 по переполнению
volatile uint8_t TIMER1_OVF_counter_final=0;// сюда сохраняем при насткплении прерывания по захвату щетчик TIMER1_OVF_counter
volatile uint16_t icr1_filal=0;// сюда сохраняем регистр захвата по наступлению прерывания по захвату

volatile boolean data_available=false;// когда 0 то данные захвата готовы и можно считать количество оборотов и выводить на экран
volatile uint32_t final_rpm;// расчитанное значение количества оборотов в минуту




int main(void) {


  // initialize the digital pin as an output.ATMEGA8
  DDRD = B11111111;        // +назначает выводы Arduino 0-7 выходными ПОРТ ДАННЫХ D это сегменты
  PORTD= 0;// НЕ ГОРЯТ НА СТАРТЕ СЕГМЕНТЫ 

  DDRC = B00001111;        //-- аноды выходы PC0-PC3
  PORTC=PORTC | B00011111;// ВЫХОДЫ УСТАНАВЛИВАЕМ В HIGH- ЭТО НЕ ГОРИТ   , А LOW- ГОРИТ. ОСТАЛЬНЫЕ ПИНЫ ОСТАЮТСЯ ВХОДАМИ С ПОДТЯЖКОЙ

  DDRB=0;// ВСЕ ВХОДЫ
  PORTB= PORTB | B00111111;// PB0 У НАС ВХОД РЕГИСТРА ЗАХВАТА, ОСТАЛЬНЫЕ С ПОДТЯЖКОЙ
  //---------------------------------------------------------------------------------------






  // НАСТРАИВАЕМ ПРЕРЫВАНИЕ ДЛЯ ДИНАМИЧЕСКОЙ ИНДИКАЦИИ НА ТАЙМЕРЕ 0
  // Timer/Counter 0 initialization
  // Clock source: System Clock
  // Clock value: 62,500 kHz  4.096 МС   244 КАДРА ПОЛУЧАЕТСЯ, НОРМАЛЬНО
  TCCR0=(1<<CS02) | (0<<CS01) | (0<<CS00);
  TCNT0=0x00;//---------------------------------------------------------------------------------







  // НАСТРАИВАЕМ ТАЙМЕР 1 НА ПРЕРЫВАНИЕ ПО ПЕРЕПОЛНЕНИЮ И ПО ЗАХВАТУ ICR ПОРТА PB0
  // Timer/Counter 1 initialization
  // Clock source: System Clock
  // Clock value: 2000,000 kHz
  // Mode: Normal top=0xFFFF
  // OC1A output: Disconnected
  // OC1B output: Disconnected
  // Noise Canceler: On
  // Input Capture on Rising Edge
  // Timer Period: 32,768 ms
  // Timer1 Overflow Interrupt: On
  // Input Capture Interrupt: On
  // Compare A Match Interrupt: Off
  // Compare B Match Interrupt: Off
  TCCR1A=(0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (0<<WGM11) | (0<<WGM10);
  TCCR1B=(1<<ICNC1) | (1<<ICES1) | (0<<WGM13) | (0<<WGM12) | (0<<CS12) | (1<<CS11) | (0<<CS10);
  TCNT1=0;
  //TCNT1H=0x00;
  //TCNT1L=0x00;
  ICR1=0;
  //ICR1H=0x00;
  //ICR1L=0x00;
  OCR1AH=0x00;
  OCR1AL=0x00;
  OCR1BH=0x00;
  OCR1BL=0x00;//----------------------------------------------------------------------------------


  // Timer(s)/Counter(s) Interrupt(s) initialization
  TIMSK=(0<<OCIE2) | (0<<TOIE2) | (1<<TICIE1) | (0<<OCIE1A) | (0<<OCIE1B) | (1<<TOIE1) | (1<<TOIE0);
  // разрешены прерывания TICIE1- по захвату
  //                      TOIE1- по переполнению таймера 1
  //                      TOIE0- по переполнению таймера 0           


    // Watchdog Timer initialization 1second
  wdt_enable(WDTO_1S);

  sei(); 


  // the loop routine runs over and over again forever:
  //void loop() {
  while(1){
    //ATMEGA8------------------------------------------------------------------
    // тут рассчитываем количество оборотов если данные для расчета  готовы



    if (data_available==true)// если данные для расчета
    {
      //расчет  формула
      // (TIMER1_OVF_counter_final *65535)+ icr1_filal   -  это у нас сколько занял 1 оборот  в тиках таймера.   используем переменную uint32_t
      //1 тик таймера равен 1/2000000 равно = 0.0000005 секунды 5 десятимиллионных секунды. 1 секунда/ 0.0000005 = 2000000 значит 60 секуднд =120000000
      // uint32_t  более 4х миллиардов

      final_rpm=((TIMER1_OVF_counter_final*65536)+ icr1_filal);
      final_rpm= 240000000/final_rpm;//  так как замер длительности оборотов у нас на основе 2х оборотов то  240000000 иначе 120000000



      //разложим получившиеся обороты на числа

      //rasklad(final_rpm);
      if(final_rpm>9999){
        final_rpm=0;
      }
      data_available= false;
    }// конец data_available== true

      //rasklad (TIMER1_OVF_counter_final);
    rasklad(final_rpm);

    // ЧТОБ ЭКРАН ОБНОВЛЯЛСЯ НЕ ЧАЩЕ 5 РАЗ В СЕКУНДУ, СДЕЛАЕМ ЗАДЕРЖКУ 200 МС
    delay_mss(200);
    wdt_reset();

  }// конец--------------------------------------

}//main(void) КОНЕЦ---------------------------------------------------------------








ISR(TIMER0_OVF_vect) {//динамическая индикация----------------------------244 прерываний в секунду

  // ЗДЕСЬ НАДО ВКЛЮЧИТЬ ПРЕРЫВАНИЯ ЧТОБ МОГЛИ СРАБОТАТЬ ДРУГИЕ ВЛОЖЕННЫЕ ПРЕРЫВАНИЯ И ДИНАМИЧЕСКАЯ ИНДИКАЦИЯ НЕ ТОРМОЗИЛА ПОДСЧЕТ ВРЕМЕНИ И
  //СРАБАТЫВАНИЯ ТАЙМЕРА ПО ЗАХВАТУ.
  sei();   // Reinitialize Timer2 value

  PORTD = screen[countershiftanode]; //ЗАКИНУЛИ ЦИФРУ
  PORTC = PORTC | B00001111; // В АНОДЫ ПИШЕМ ЕДИНИЦЫ - ЭТО РАВНО ЗАНУЛЕНИЮ pc0 pc3- занулили

  PORTC = PORTC & ( ~ shiftanode ); // НАЛОЖИЛИ СООТВЕТСТВУЮЩУЮ МАСКУ АНОДА ИНВЕРТИРОВАВ ЕЁ - ЭТИМ ВКЛЮЧАЕМ 0 , ОСТАЛЬНЫЕ ЕДИНИЦЫ ВЫКЛЮЧЕНЫ РАЗРЯДЫ
  countershiftanode++;
  shiftanode = (shiftanode << 1);
  if (countershiftanode == 4) {
    countershiftanode = 0;
    shiftanode = B00000001;
  }
} //----------------------------------------------------------------------------








// если таймер переполняется и наступает прерывание то ПРОШЛО 32.768 МИЛИСЕКУНД И ПЛЮСУЕМ TIMER1_OVF_counter ПОКА НЕ ДОСТИГНЕТ 100
// ЭТО ОЗНАЧАЕТ ЧТО двигатель ВРАЩАЕТСЯ МЕДЛЕННЕЕ ЧЕМ 18 ОБОРОТОВ В МИНУТУ, ЧЕГО БЫТЬ НЕ МОЖЕТ 
ISR(TIMER1_OVF_vect) {

  TIMER1_OVF_counter++;// количество переполнений 1 байт переменная


  if (TIMER1_OVF_counter>150){// двигатель стоит, обнуляем щетчики------
    TIMER1_OVF_counter_final=0;// двигатель стоит - обнуляем щетчик
    TCNT1=0;//ОБНУЛЯЕМ СЧЕТНЫЙ РЕГИСТР
    icr1_filal=0;// финальное содержимое регистра захвата тоже равно нулю
    TIMER1_OVF_counter=0; 
    data_available=false;
    final_rpm=0;
  }//


}//    это будет происходить раз в 32.2768 секунды или меньше 18 ти оборотов







//ПРИШЕЛ ВОСХОДЯЩИЙ ФРОНТ СИГНАЛА С ФОТОДАТЧИКА. СРАБОТАЛО ПРЕРЫВАНИЕ И ЗАПОМНИЛО ВРЕМЯ. ТЕПЕРЬ НАДО СКОПИРОВАТЬ ЭТО ВРЕМЯ В ПЕРЕМЕННУЮ
//И ВЫЧИСЛЯТЬ ПОЛНУЮ ДЛИТЕЛЬНОСТЬ ИМПУЛЬСА

//если во время выполнения прерывания по захвату происходит переполнение то захват произошел раньШе и мы  всеравно обнуляем TCNT1  И ОТМЕНЯЕМ ПРЕРЫВАНИЕ ПО
//ПЕРЕПОЛНЕНИЮ СБРОСОМ ФЛАГА ЗАПИСЬЮ 1 В ЭТОТ ФЛАГ
ISR(TIMER1_CAPT_vect) {
  // ЕЩЕ МАЛЕНЬКАЯ ЗАЩИТА ОТ  ПОМЕХ - ПРОИЗОШЛО ПРЕРЫВАНИЕ ПО RISING, МЫ ДОЛЖНЫ ПРОЧЕСТЬ HIGH C PB0
  if((PINB & B00000001)>0)// ЕСЛИ HIGH ТО ВЫПОЛНЯЕМ, ИНАЧЕ ВЫХОДИМ   
  { 
    if((PINB & B00000001)>0)// ЕСЛИ HIGH ТО ВЫПОЛНЯЕМ, ИНАЧЕ ВЫХОДИМ   
    {// ЕЩЕ РАЗПРОВЕРЯЕМ НА ДРЕБЕЗГ, И ЕСЛИ УШЛО ТО ВЫХОДИМ, ИНАЧЕ СИГНАБ РЕАЛЬНЫЙ
      if (scan_number==0){
        // нифига не делаем, просто выходим из прерывания, а щетчик щитает дальше второй оборот. Далее на основе 2х оборотов будем считать
        //среднее значение
        scan_number=1;
       
      }
      else //если равно 1
      { 
        TCNT1=0;//ОБНУЛЯЕМ СЧЕТНЫЙ РЕГИСТР ДЛЯ НОВОГО СЧЕТА НОВОГО ОБОРОТА
        icr1_filal=ICR1;// копируем содержимое регистра захвата
        TIMER1_OVF_counter_final = TIMER1_OVF_counter;// ЩЕТЧИК КОЛИЧЕСТВА ПЕРЕПОЛНЕНИЙ КОПИРУЕМ В ФИНАЛЬНУЮ ПЕРЕМЕННУЮ
        TIMER1_OVF_counter=0; // ОБНУЛЯЕМ ЩЕТЧИК КОЛИЧЕСТВА ПЕРЕПОЛНЕНИЙ
        // тут сбросим прерывание по переполнению если оно удруг уже произошло пока мы в обработчике прерывания по захвату, так как счет длительности оборота
        // начинается снова
        //Регистр флагов прерываний таймеров-счетчиков - TIFR  Флаг TOV1 сбрасывается аппаратно при переходе на соответствующий вектор прерывания. 
        //Альтернативно, флаг TOV1 сбрасывается путем записи в него лог. 1.
        //OCF2 TOV2 ICF1 OCF1A OCF1B TOV1 – TOV0   //TIFR
        TIFR=TIFR | B00000100;// СБРОСИЛИ ЕСЛИ БЫЛо прерывание
        scan_number=0;
        data_available=true;//
      }

    }
  }

}//ISR(TIMER1_CAPT_vect) 






void rasklad (int16_t decimal) {// расклад числа -------------------------------------------------------------------------------
  byte rasklad_temp[4];

  int decimaltemp = decimal;
  rasklad_temp[1] = decimal / 1000; // сотни
  decimal = decimal %= 1000; //остаток от деления на 1000  (сотни)
  rasklad_temp[2] = decimal / 100; // сотни
  decimal = decimal %= 100; //остаток от деления на 100  (десятки)
  rasklad_temp[3] = decimal / 10; // десятки
  rasklad_temp[0] = decimal %= 10; // остаток  еденицы


  if (decimaltemp < 1000) {
    screen[3] = 0; // если меньше 1000 то ничего не рисуем PC3
  }
  else {
    screen[3] = number[rasklad_temp[1]];
  }



  if (decimaltemp < 100) {
    screen[1] = 0; // если меньше 100 то ничего не рисуем PC1
  }
  else {
    screen[1] = number[rasklad_temp[2]];
  }

  if (decimaltemp < 10) {
    screen[2] = B00000000; // если меньше 100 то ничего не рисуем кроме точки PC2
  }
  else  {
    screen[2] = (number[rasklad_temp[3]]) ; // рисуем цифру с точкой
  }

  screen[0] = number[rasklad_temp[0]];
} // конец расклада числа в screen имеем печатаемые цифры--------------------------------------------------------------------------------------------------





//**************Delay****************************
void delay_mss(uint16_t tic_ms)
{
  while (tic_ms)
  {
    delay_us(999);
    tic_ms--;
  }
}

void delay_us(uint16_t tic_us)
{
  tic_us *= 4; //1us = 4 цикла
  __asm__ volatile
    (
  "1: sbiw %0,1" "\n\t" //; вычесть из регистра значение N
  "brne 1b"
: 
    "=w" (tic_us)
: 
    "0" (tic_us)
    );
}

 

bsdshneg
Offline
Зарегистрирован: 21.10.2014

фигасе ... к такому я ещё не готов ))) avr для меня пока тёмный лес ... Но спасибо!!! Для ознакомления и разбора кода самое то)))

Olm
Offline
Зарегистрирован: 09.10.2014

это код для атмега 8 на 16мгц. В среде ардуины компилируется:))

на атмега 328 только инициализацию таймеров  надо поменять вроде

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 62,500 kHz
// Mode: Normal top=0xFF
// OC0A output: Disconnected
// OC0B output: Disconnected
// Timer Period: 4,096 ms
TCCR0A=(0<<COM0A1) | (0<<COM0A0) | (0<<COM0B1) | (0<<COM0B0) | (0<<WGM01) | (0<<WGM00);
TCCR0B=(0<<WGM02) | (1<<CS02) | (0<<CS01) | (0<<CS00);
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 2000,000 kHz
// Mode: Normal top=0xFFFF
// OC1A output: Disconnected
// OC1B output: Disconnected
// Noise Canceler: On
// Input Capture on Rising Edge
// Timer Period: 32,768 ms
// Timer1 Overflow Interrupt: On
// Input Capture Interrupt: On
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=(0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (0<<WGM11) | (0<<WGM10);
TCCR1B=(1<<ICNC1) | (1<<ICES1) | (0<<WGM13) | (0<<WGM12) | (0<<CS12) | (1<<CS11) | (0<<CS10);
TCNT1=0x00;
ICR1=0x00;
OCR1A=0x00;
OCR1B=0x00;




// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=(0<<OCIE0B) | (0<<OCIE0A) | (1<<TOIE0);

// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=(1<<ICIE1) | (0<<OCIE1B) | (0<<OCIE1A) | (1<<TOIE1);



 

 

bsdshneg
Offline
Зарегистрирован: 21.10.2014

то что AVR в среде ардуины нормально себя чувствует я знаю, просто ардуина сама по себе (язык) расслабляет и делает "себя" более общедоступным и "без заморочек" нежели AVR или STM ... при этом прекрасно понимаю, что надо всё же пробовать осваиватть либо AVR либо STM, а лучше сразу обои два, но в виду малого количества свободного времени это сложно сделать ... вот тут-то как раз ардуина и выигрывает ))))))