Корректор спидометра

klialex
Offline
Зарегистрирован: 26.05.2020

Доброго времени суток. Дабы не разводить длинное повествование:
-пилю для себя корректор, свапнул мотор, датчик скорости СОВСЕМ другой, спидометр безбожно врёт
-полноценной платы Ардуино жалко, да и не нужна оня сжечь, я "щитаю". Тем более под руками оказалась attiny85 в составе digispark

Доброго времени суток. Дабы не разводить длинное повествование:
-пилю для себя корректор, свапнул мотор, датчик скорости СОВСЕМ другой, спидометр безбожно врёт
-полноценной платы Ардуино жалко, да и не нужна оня сжечь, я "щитаю". Тем более под руками оказалась attiny85 в составе digispark

В чем вопрос: не поддерживает стабильный множитель в диапазоне частот преобразования 0-200Гц. Выходная частота при множителе, к примеру 3.5, плавает от 2.8 до 4. Но это в протеусе. В железе нет возможности померять, в условиях гаража отсутствуют приборы. Если есть у кого возможность собрать на стенде и померять, буду благодарен
Код:

#include
//********************************************************************
unsigned long freq = 0; // Время срабатывания датчика
unsigned long t_time = 0; // буферная переменная
const byte divider = 128; // Делитель прескалера
const float factor = 3.5; // Множитель частоты
const int redraw = 100; // Период обновления показаний

#define PIN_OUTPUT 1
//********************************************************************
void setup(){
attachInterrupt(0, sense, RISING); //прерывание по фронту импульса
TinySoftPwm_begin(divider, 0);}
//********************************************************************
void loop(){
static uint32_t StartUs = micros();
static uint32_t StartMs = millis();

if ((micros() - StartUs) >= freq) {

TinySoftPwm_process();
StartUs = micros();}

if ((millis()-StartMs) >= redraw) {// Обновляем показания
StartMs = millis();
if (freq <= 5000) TinySoftPwm_analogWrite(PIN_OUTPUT, 128);
else TinySoftPwm_analogWrite(PIN_OUTPUT, 0);}}
//********************************************************************
void sense(){ //измеряем длину периода импульса на входе по прерыванию
freq = (micros()- t_time)/(divider*factor);
t_time = micros();}

-NMi-
Offline
Зарегистрирован: 20.08.2018

klialex пишет:

Выходная частота при множителе, к примеру 3.5, плавает от 2.8 до 4. Но это в протеусе. В железе нет возможности померять, в условиях гаража отсутствуют приборы. Если есть у кого возможность собрать на стенде и померять, буду...

ан@хер тагда пр@теуз, ежли всиравно вжилезе сабирать?)))

Он для того и создан, чтобы была возможность СИМУЛИРОВАТЬ всё без паяльников и стендов!!!

рука_лицо_(((

klialex
Offline
Зарегистрирован: 26.05.2020

Спасибо за содержательный ответ. 

-NMi-
Offline
Зарегистрирован: 20.08.2018

Вслушайся в свои-же пейсанины - ты придлагаешь к@му-то сАбрать за тебя стенд для проверки??? ты в своём уме??? жаль, я не курю такое дерьмо, мошт с слава_богу, шо никурю...   ))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))

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

klialex можете обьяснить, что у вас в коде происходит? Вы правда рассчитываете на основе PWM сделать спидометр?

Все делается куда проще - по прерыванию считаете входные импульсы и транслируете их на выход в нужном отношении... PWM-у в этом алгоритме места нет

klialex
Offline
Зарегистрирован: 26.05.2020

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

klialex
Offline
Зарегистрирован: 26.05.2020

-NMi- пишет:

Вслушайся в свои-же пейсанины - ты придлагаешь к@му-то сАбрать за тебя стенд для проверки??? ты в своём уме??? жаль, я не курю такое дерьмо, мошт с слава_богу, шо никурю...   ))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))


Если у кого-то на столе валяется digistump, есть под рукой генератор меандра и частотомер - дел на пару минут. У меня этого сейчас нет, в самоизоляции сидим. Потому и прошу помощи. Или подсказать где ошибся в кодах. А вы с вашей "пейсаниной" застряли где-то в Олбании 2007 года

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

klialex пишет:
Возможно я не с той стороны зашёл. Считать надо не по аппаратному внешнему прерыванию, по таймеру с определенной частотой дискретизации проверять вход и с этой же частотой на основе множителя формировать выходной сигнал.

не, это тупик, первый вариант лучше. Считаешь прерыванием число входящих импульсов и транслируешь их на выход с нужным делителем.

Только в случае прерывания нужно боротся с дребезгом и наводками. Во-первых, подтянуть вход к плюсу или к минусу, поставить конденсатор параллельно входу. Если частота низкая. можно и программно дребезг подавлять, как на кнопке

klialex
Offline
Зарегистрирован: 26.05.2020

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

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

а частоты какие, примерно?

klialex
Offline
Зарегистрирован: 26.05.2020

Диапазон входных частот 0 - 200Гц. На 100Гц оно должно показывать 60км/ч Соответственно мой датчик работает на пониженной частоте, и ее надо увеличить.

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

klialex пишет:
Диапазон входных частот 0 - 200Гц. На 100Гц оно должно показывать 60км/ч

при таких частотах никакие прерывания вовсе не нужны. просто обрабатываете как нажатие кнопки.

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

klialex
Offline
Зарегистрирован: 26.05.2020

Множитель не должен плавать. Период и частота следования импульсов могут быть и не целыми.

Komandir
Offline
Зарегистрирован: 18.08.2018

Как врет спидометр сейчас ?

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

klialex
Offline
Зарегистрирован: 26.05.2020

;) Но мне же не важно количество импульсов на один оборот. Я не считаю абсолютных значений скорости. У меня задача увеличить частоту импульсов в определенное число раз. А частота входящих импульсов может быть и не целыми числом, но период их следования да. Я не считаю число импульсов, а измеряю время между импульсами, вернее их положительными фронтами прерыванием, делю на коэффициент и формирую выходной сигнал с вычисленным периодом. Так вот частота выходного сигнала плавает. Не могу понять либо это протеус прикалывается, либо на таких частотах уже не хватает времени процессора. Сейчас на скорости 70км/ч показывает 20км/ч. Т.е. если на входе 10Гц, на выходе должно быть 35Гц, если на входе 100Гц, соответственно на выходе 350Гц. Но у меня не так, нелинейно умножает.

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

Вы считаете частоту, устанавливаете скважность, а после этого у вас МК виноват? Китайцы проклятые? Америка и Обама лично?

Я такое делал чисто на таймерах человеку одному - даже в ардуине килогерцы нормально масштабировались. Но всякие миллисы уже не канают.

Morroc
Offline
Зарегистрирован: 24.10.2016

Тут на форуме был универсальный генератор. Я бы взял за основу, прикрутил счетчик с этим множителем и загонял как параметр в функцию того скетча. По крайней мере на выходе будет заданная частота и само плавать не будет. Но вообще что то не пойму проблемы - можно прям в одном цикле замерять период, умножать на коэффициент и тут же формировать сигнал на выходе с новым периодом, считать можно в любых попугаях, наверное даже тупо счетчиком цикла.

Komandir
Offline
Зарегистрирован: 18.08.2018

3.5 раза ? Очень странно !

и разве 

static uint32_t StartUs = micros();
static uint32_t StartMs = millis();

не должны быть вне loop ?

Green
Offline
Зарегистрирован: 01.10.2015

Так статик же ж! Кто ж их выносит.)
Волатильными должны быть переменные используемые в прерывании.

Komandir
Offline
Зарегистрирован: 18.08.2018

тогда для чего эта строка

if ((micros() - StartUs) >= freq) {

? Только что присвоили static uint32_t StartUs = micros(); и сразу сравниваем ...

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

Komandir пишет:

тогда для чего эта строка

if ((micros() - StartUs) >= freq) {

? Только что присвоили static uint32_t StartUs = micros(); и сразу сравниваем ...

не ожидал от вас :)

строчка static uint32_t StartUs = micros(); выполняется один раз при первом прогоне loop()... на то оно и static

Komandir
Offline
Зарегистрирован: 18.08.2018

не проснулся видимо ещё ...

надо будет кстати глянуть - во что static выливается в выходном коде ...

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

klialex,

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

Ошибок в коде много. Я бы сказал, что это сплошная ошибка, начиная с негодного подхода. Вы копите погрешности везде, где только можете, в прерывании используете неволатильные переменные, а потом удивляетесь, что оно плавает.

Кроме того, сформулируйте (в первую очередь, для себя) кратко, чётко, и в одном месте чётко задачу. Диапазон частот! Коэффициент? Кстати, Вы уверены, что он одинаковый на всём диапазоне частот? Или он сам по себе ещё от частоты зависит?

В общем, давайте чёткую формулировку задачи и правильно выложенный код.

Komandir
Offline
Зарегистрирован: 18.08.2018

вижу такой алгоритм:

в переменной pp храним длительность выходного полупериода

в основном цикле просто ждем когда проходит время pp и инвертируем состояние выхода

в прерывании вычисляем период входных импульсов, делим его на 3.5*2 и сохраняем в pp

можно,но не обязательно - ещё продумать ситуацию когда импульсов нет или мало - авто стоит или ОЧЕНЬ медленно едет

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Komandir пишет:

можно,но не обязательно - ещё продумать 

Думать всегда обязательно.

При Вашем алгоритме оно НИКОГДА не покажет 0 просто потому, что после последнего импульса, она будет продолжать долбить каждые pp, в ожидании нового импульса.

Komandir
Offline
Зарегистрирован: 18.08.2018

ЕвгенийП для спидометра это не очень важно -очень инерционная хрень, а вот одометр будет медленно наращивать показания

klialex
Offline
Зарегистрирован: 26.05.2020

Прошу прощения. Был в гараже, открыл тему с телефона, кнопочек {code} не нашел. Сейчас и в дальнейшем исправлюсь.

Постановка задачи проста - увеличить частоту импульсов на выходе относительно входной в заданное число раз. Множитель необязательно целочисленный. Форма сигнала - меандр. За основу брал статью с https://fanclub-vw-bus.ru/forum/viewtopic.php?t=25745

Собственно код из топика:

#include <TinySoftPwm.h>
//********************************************************************
unsigned long freq      = 0;        // Время срабатывания датчика
unsigned long t_time    = 0;        // буферная переменная 
const byte    divider   = 128;      // Делитель прескалера
const float   factor    = 3.5;      // Множитель частоты
const int     redraw    = 100;      // Период обновления показаний

#define PIN_OUTPUT        1
//********************************************************************
void setup(){
    attachInterrupt(0, sense, RISING); //прерывание по фронту импульса
    TinySoftPwm_begin(divider, 0);}
//********************************************************************
void loop(){
static uint32_t StartUs  =  micros();
static uint32_t StartMs  =  millis(); 

if  ((micros() - StartUs) >= freq) {
    
    TinySoftPwm_process();
    StartUs  =  micros();}
   
if  ((millis()-StartMs) >= redraw) {// Обновляем показания
    StartMs  =  millis();
    if (freq <= 5000)  TinySoftPwm_analogWrite(PIN_OUTPUT, 128);
    else               TinySoftPwm_analogWrite(PIN_OUTPUT,   0);}}
//********************************************************************
void sense(){ //измеряем длину периода импульса на входе по прерыванию
     freq = (micros()- t_time)/(divider*factor);
     t_time = micros();}

Пробовал еще и так:

 

//********************************************************************
volatile unsigned long freq    = 0;          //Время срабатывания датчика
volatile unsigned long t_time    = 0;        //Буфер Время срабатывания датчика
volatile boolean       flag     = false;    //Флаг триггера
volatile float         divider = 3.5;
volatile boolean       state = 0;

#define PIN_SENSE         2
#define PIN_OUTPUT        1
//********************************************************************
void setup(){
attachInterrupt(0, tacho_time, RISING); //прерывание спидометра по фронту импульса
pinMode (PIN_OUTPUT, OUTPUT); 
}
//********************************************************************
void loop(){
static uint32_t        timer = micros();
if (micros()-timer >= freq/(divider*2))
  {
    timer = micros();
    digitalWrite(PIN_OUTPUT, state);
    state=!state;
   }
}
//********************************************************************
void tacho_time(){                      //измеряем длину периода импульса на входе спидометра по прерыванию
   freq = micros()- t_time;
   t_time = micros();
  }

 

 

Komandir
Offline
Зарегистрирован: 18.08.2018

в 18 строке у вас каждый проход деление и умножение на МК, в котором ни того ни другого нет !

деление умножение надо перенести в 27 строку, убрать FLOAT и делить на 7

21 и 22 надо заменить на прямое обращение к порту 

и что данный код не работает ? в автомобиле надо ещё простейший фильтр RC припаять на вход - там очень "шумно" ...

klialex
Offline
Зарегистрирован: 26.05.2020

Спасибо. Не могу только понять как для digispark прямое обращение к порту реализуется

И до машины пока не дошло, в протеусе уже некрасиво выглядит, а машина пока не ездит, дальше работы ведутся

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

Komandir пишет:

и что данный код не работает ? в автомобиле надо ещё простейший фильтр RC припаять на вход - там очень "шумно" ...

думаю из-за шумов и не работает. Шумный сигнал +прерывание = ступор, шуиы на входе способны полностью заморозить этот код

klialex
Offline
Зарегистрирован: 26.05.2020

Какие шумы в протеусе?

Komandir
Offline
Зарегистрирован: 18.08.2018

b707 когда круиз-контроль себе делал - то же столкнулся с шумами на сигнале от датчика скорости.

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

klialex пишет:

Какие шумы в протеусе?

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

Сначала залейте в протеус вот это и посмотрите

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

klialex пишет:

Спасибо. Не могу только понять как для digispark прямое обращение к порту реализуется

даташит в помощь, раздел называется "GPIO toogle" или как-то похоже

Komandir
Offline
Зарегистрирован: 18.08.2018

стр 53 

writing a logic one to a bit in the PINx Register, will result in a toggle in the corresponding bit in the Data Register

Komandir
Offline
Зарегистрирован: 18.08.2018

Нашел причину того что на разных частотах ТС видит разный результат :-) ...

при старте freq = 0 и пока пройдёт первый период на входе - цикл выдаёт "мешок" сигналов на выход и потом начинает нормально считать

на разной частоте этот "мешок" разного размера ..

пока не измерен период входного сигнала (не прошло два прерывания) - нельзя начинать генерацию на выходе

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Komandir пишет:

ЕвгенийП для спидометра это не очень важно -очень инерционная хрень, 

Что значит "не важно"? Она ведь не "медленно будет до нуля сползать", а никогда не сползёт - остановится на последнем показании. Начали Вы достаточно резко тормозить - последний раз было зафиксировано, скажем, 20, а до следующего импульса машина уже стала - так он Вам будет вечно 20 показывать!

Komandir
Offline
Зарегистрирован: 18.08.2018

Мы же каждый импульс мониторим - если случилось что скорость упала с 20 до нуля за один импульс, то вы куда то воткнулись.

Jeka_M
Jeka_M аватар
Онлайн
Зарегистрирован: 06.07.2014

Komandir пишет:

если случилось что скорость упала с 20 до нуля за один импульс, то вы куда то воткнулись.

Во, так это не баг, а фича получается - показывает последнюю зафиксированную скорость до втыкания.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Не воткнулся, а просто резко тормозил. ТС пишет о частотах в единицы герц (10 упоминал) - при хорошем торможении ... делов-то. По-любому это неправильно, Вы это уже поняли, так чего спорить - переделывать надо алгоритм.

klialex
Offline
Зарегистрирован: 26.05.2020

При этом этот счётный алгоритм у других людей работает. Не в точности, но очень похожий. Выше давал ссылку

klialex
Offline
Зарегистрирован: 26.05.2020

Да, я видел такое на старте. Пакет мусора, но дальше счёт идёт нормально. Только набегает погрешность

Komandir
Offline
Зарегистрирован: 18.08.2018

Авто спидометры изначально завышают скорость на 10 % ...

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

klialex пишет:
При этом этот счётный алгоритм у других людей работает. Не в точности, но очень похожий. Выше давал ссылку

так сейчас-то в чем проблема, решили же все вроде