Проблемы с библиотекой TimerOne (работает не так, как ожидалось)
- Войдите на сайт для отправки комментариев
Добрый всем день. Это первый мой пост на этом форуме, так что прошу сильно не пинать, если что..
Задачу себе придумал такую: сделать корректор показаний спидометра для мотоцикла. Дело в том, что на некоторых мотоциклах сейчас датчик скорости стоит на вторичном валу коробки и при изменении передаточного числа (просто заменили ведущую или (и) ведомую звезду на другую, с другим количеством зубьев, спидометр начинает врать). Буржуи продают устройства коррекции (SpeedoHealer). Но коробочка стоит совсем не гуманно, плюс доставка. В общем не интересно. Сенсор скорости видимо представляет собой датчик холла, который генерит импульсы напрямую в приборку. Нужно определить частоту (или длину одного импульса) и подкорректировав, передать на приборку. В сервис-мануале на мотоцикл, в разделе проверки датчика скорости, сказано, что при вращении вторичного вала, на таком то контакте (всего их 3) должен появляться сигнал 5 В. Ну как бы ардуино напрашивается сама собой. Посидел с бумажкой и карандашом и выходит, что минимальная частота, которую нужно будет генерить ~ 1.5 Гц. Поэтому по рекомендации гугла, решил использовать библиотеку TimerOne. Для моделирования собрал макет из трехпроводного кулера, пьезопищалки и китайской ардуины UNO. (картинка не моя и к сожалению, не понял, как убрать картинку под спойлер)
пищалку подключил на 9-й пин.
#include <TimerOne.h> const byte fqPin = 2; // Номер пина для получение аппаратного прерывания const byte outPin = 9; // Номер пина для генерации выходного сигнала volatile unsigned long counter; // Количество отсчётов. volatile unsigned long mks; // Время последнего отсчёта. unsigned long oldTime; // Время последнего отсчёта в предыдущем вычислении. unsigned long previousMillis = 0; // храним время последнего измерения const long interval = 100; // интервал между измерениями в миллисекундах (0.1 сек) // Функция для обработки прерывания. void myISR() { mks = micros(); // Момент последнего отсчёта counter++; // Количество отсчётов } void setup() { unsigned long rpm; unsigned long currentMillis; unsigned long tmr; unsigned long cnt; pinMode(outPin, OUTPUT); Timer1.initialize(8000000); Timer1.pwm(9, 8); //Serial.begin(115200); // Подключаем функцию myISR на прерывание по появлению сигнала на ноге fqPin. attachInterrupt(digitalPinToInterrupt(fqPin), myISR, RISING); // Для подсчета импульсов в минуту // Начинаем бесконечный цикл while (true) { currentMillis = millis(); // текущий момент времени (для организации паузы вместо delay()) // Если с момента прошлого измерения прошло уже больше, чем 0.65 секунды // т.е. стоим на месте или скорость меньше 1 км/ч if (currentMillis - previousMillis > 650) { previousMillis = currentMillis; // Получаем данные. noInterrupts(); oldTime = mks; counter = 0; interrupts(); Timer1.setPeriod(0); //rpm = 0 //Serial.println( "interval > 0.65" ); } // Если с момента прошлого измерения прошло меньше 0.65 секунды, else { //Serial.println( counter ); // Если с момента прошлого измерения прошло больше, чем interval, // и за это время счетчик увеличился на 2 и больше отсчетов if ((currentMillis - previousMillis > interval) && (counter > 1)) { previousMillis = currentMillis; // Получаем данные. noInterrupts(); cnt = counter; counter = 0; tmr = mks; interrupts(); // Рассчитываем среднюю длительность одного импульса в микросекундах rpm = ((tmr - oldTime) / cnt);//*150/100 // Таким образом можем пересчитать длину импульса на выходе Timer1.setPeriod(rpm); oldTime = tmr; //Serial.println( rpm ); } } } } void loop() { }
Изначально, в строке 26 стояло Timer1.pwm(9, 512); Т.е. с заполнением 50%.
В принципе все работает, пищалка пищит , при торможении двигателя рукой частота звука соответственно меняется, НО! На некоторых оборотах щелчки пропадали совсем, тормозишь крыльчатку еще сильнее, звук появляется, даешь разогнаться, то же с какой то скорости звук появляется. Методом научного тыка выяснилось, что если уменьщить коэффициент заполнения до ~ 8 пищалка пищит во всем диапазоне от 0 до ~3000 об мин.
Для опыта написал еще тестовый скетч:
// Имитируется воспроизведение данных, полученных с датчика скорости мотоцикла // при равномерном разгоне/торможении мотоцикла // С ускорением а // От скорости vStart // До скорости vFinish // С интервалом между замерами tInterval (миллисекунды - float) // Данные по частотам предварительно собираются в массив, затем с помощью // библиотеки TimerOne на 9 пине генерятся прямоугольные импульсы с переменной частотой. #include <TimerOne.h> // Глобальные константы const float a = 9.0; // Задаем ускорение (м/с2) const float vStart = 0.0; // Начальная скорость (км/ч) const float vFinish = 180.0; // Конечная скорость (км/ч) const float tInterval = 100.0; // Интервал между измерениями (миллисекунды) const float roundOfWheel = 1.956; // Длина окружности колеса const float gearRatio = 2.733; // Передаточное число колесо -> вторичный вал коробки const float numberOfPulsesPerRevolution = 4.0; // Количество импульсов на один оборот вала void setup() { unsigned long currentMillis; // для организации паузы вместо delay() unsigned long previousMillis = 0; // храним время последнего измерения bool myDirection = true; // увеличиваем (истина) или уменьшаем (ложь) значение адреса массива i unsigned long rpm; // Предварительная подготовка массива float vStartMS = vStart * 1000.0 / 3600.0; // Начальная скорость в м/с float vFinishMS = vFinish * 1000.0 / 3600.0; // Конечная скорость в м/с float vTMP = vStartMS; // Текущая скорость в м/с Serial.begin(115200); // Сначала подсчитаем каким будет размер массива int j = 0; while (vTMP <= vFinishMS) { vTMP = vTMP + a * tInterval / 1000.0; // Новая скорость в м/с ч/з tInterval миллисекунд j++; } // Создаем массив для данных размером j long arrayPeriod[j]; // Заполняем массив данными vTMP = vStartMS; j = 0; while (vTMP <= vFinishMS) { float newV = vTMP + a * tInterval / 1000.0; // Новая скорость в м/с ч/з tInterval миллисекунд float sTMP = (newV * newV - vTMP * vTMP)/(2.0 * a); // Путь в м, пройденный за tInterval миллисекунд float numberOfPulses = sTMP / roundOfWheel * gearRatio * numberOfPulsesPerRevolution; // Количество импульсов, сгенерированных за интервал tInterval long lengthOfImpuls = long(1000.0 / (numberOfPulses / tInterval)); // Средняя длина одного импульса в интервале (в микросекундах) Serial.println( lengthOfImpuls ); arrayPeriod[j] = lengthOfImpuls; vTMP = newV; // Запомнили новую скорость j++; } //Serial.println( "===========" ); // И запоминаем количество элементов в массиве int i = j; // Начинаем пищать в пищалку pinMode(9, OUTPUT); Timer1.initialize(8000000); Timer1.pwm(9, 8); // Коэффициент заполнения ~0.78%, при большем коэффициенте заполнении на некоторых частотах звук в пищалке пропадает ??? j = 0; unsigned long longInterval = long(tInterval); while (true) { currentMillis = millis(); if (currentMillis - previousMillis > longInterval) { previousMillis = currentMillis; rpm = arrayPeriod[j]; //Serial.println( rpm ); Timer1.setPeriod(rpm); if (j == (i - 1)) { // Последний элемент массива, меняем направление на обратное ("тормозим") myDirection = false; } if (j == 0) { // Первый элемент массива, меняем направление на прямое ("разгоняемся") myDirection = true; } if (myDirection) { j++; } else { j--; } } } } void loop() { }
Упс, вместо того, что бы продолжить редактирование, я пост сохранил. А редактировать можно?
Ладно, продолжу.
При работе второго скетча на мой слух, есть некие ступеньки при воспроизведении. Т.е. частота меняется не плавно, как по идее должна бы, а .. неплавно что ли. И если поставить коэфф. заполнения достаточно большим, звук пропадает.
Ну собственно вопросы:
1) Почему пропадает звук?
2) Почитав этюды для начинающих (Блинк без делэй и т.д...), понял, что можно воспроизводить не любую частоту а вполне определенный набор. хоть и достаточно большой. Как библиотека выбирает, что воспроизвести (длительность периода 397696 или 397568) если я попрошу ее воспроизвести 397700? В исходник библиотеки смотрел. Но как с чтением книги на казахском языке: вроде буквы все знакомые а смысл ускользает :)
3) И можно ли в этом случае использовать эту библиотеку для ЭТОЙ задачи?
Оценить качество воспроизводимого сигнала сам не могу, т.к. из инструментов только мультиметр.