Вызов micros/millis ломает программу. Нужен совет чуть более опытных нежеля я людей.

plotter1

✩✩✩✩✩✩✩
24 Ноя 2021
20
1
Предыстория. Есть индуктивный датчик который считывает скорость первичного вала кпп. Т.к. шестерня с которой эта скорость считывается изменена, возникла потребность преобразовать сигнал одной частоты в сигнал немного другой частоты. Блочно программа разделена на 2 части: генератор сигнала на таймере 1, и дешифратор входящего сигнала на компараторе. Входящий сигнал ограничивается стабилитроном по верхнему срезу и шотки по нижнему (т.к. индуктивный датчик очень даже может выдать переменное напряжение в 7-8В). Выход управляет драйвером шаговика, который в данном сетапе работает как генератор модифицированной синусоиды.
Имеется следующий код (не обращайте внимание на некоторые рудименты, они ни на что не влияют и компилятором отсекаются. Просто переписывал его уже раз 10):
C++:
#include <directADC.h>
#include <GyverTimers.h>
void setup() {
  pinMode(9, OUTPUT);
  pinMode(A0, INPUT);
  TCCR1A = 0;
  TCCR1B = 0;
  OCR1A = 65500; // первичный период счетчика
  TCCR1B |= (1 << WGM12);//Сброс по совпадению
  TCCR1B |= (1 << CS10);//Предделитель 1
  digitalWrite(9, !digitalRead(9));
  TIMSK1 |= (1 << OCIE1A);
  ADC_disable(); // если используем мультиплексор для компаратора - обяательно выключаем ацп
  ACOMP_attachInterrupt(func, FALLING_TRIGGER);
 
}
volatile uint32_t tmr0;
uint32_t tmr1, tmr3, tmr4;
uint16_t sum;
volatile bool flag = false;
bool flag1;

ISR(TIMER1_COMPA_vect)
{

  PINB |= bit(1);
}
void func() {
  tmr0 = micros();
  flag = true;
}

uint32_t tmr2;
void loop() {
  static byte var;
  if (flag) {
    sum = (((tmr0 - tmr1) * 562) >> 8) - 1;
    tmr1 = tmr0;
    tmr3 = sum + tmr3;
    var = var + 1;
    flag = false;
  }
  if (var >= 255) {
    if (tmr3 >= 864359)OCR1A = ((tmr3 >> 8))+335;// корректур холостого хода
    else if (tmr3 >= 432180 && tmr3 < 864359) OCR1A = (tmr3 >> 8); // после 1000 начинаем ступенчато снижать период
    else if (tmr3 >= 288120 && tmr3 < 432180) OCR1A = (tmr3 >> 8) -25;
    else if (tmr3 < 288120) OCR1A = (tmr3 >> 8)-20;
    tmr3 = 0;
    var = 0;
  }
}
Этот код отлично работает, но есть нюанс. Если коробка перестаёт вращаться, то эбу ожидает остановки импульсов, а как видно, генератор на таймере в этой программе будет долбить последнюю прилетевшую с компаратора частоту. Для исправления этого я решил в самый конец лупа добавить строчку:
C++:
if (micros()- tmr0 >= 4096) OCR1A = 65500;
С точки зрения эбу это обороты на которые уже можно не обращать внимания и кпп для него как бы уже остановилась. Но тут вылезает странность, если залить такой код:
C++:
#include <directADC.h>
#include <GyverTimers.h>
void setup() {
  pinMode(9, OUTPUT);
  pinMode(A0, INPUT);
  TCCR1A = 0;
  TCCR1B = 0;
  OCR1A = 65500; // первичный период счетчика
  TCCR1B |= (1 << WGM12);//Сброс по совпадению
  TCCR1B |= (1 << CS10);//Предделитель 1
  digitalWrite(9, !digitalRead(9));
  TIMSK1 |= (1 << OCIE1A);
  ADC_disable(); // если используем мультиплексор для компаратора - обяательно выключаем ацп
  ACOMP_attachInterrupt(func, FALLING_TRIGGER);
 
}
volatile uint32_t tmr0;
uint32_t tmr1, tmr3, tmr4;
uint16_t sum;
volatile bool flag = false;
bool flag1;

ISR(TIMER1_COMPA_vect)
{

  PINB |= bit(1);
}
void func() {
  tmr0 = micros();
  flag = true;
}

uint32_t tmr2;
void loop() {
  static byte var;
  if (flag) {
    sum = (((tmr0 - tmr1) * 562) >> 8) - 1;
    tmr1 = tmr0;
    tmr3 = sum + tmr3;
    var = var + 1;
    flag = false;
  }
  if (var >= 255) {
    if (tmr3 >= 864359)OCR1A = ((tmr3 >> 8))+335;// корректур холостого хода
    else if (tmr3 >= 432180 && tmr3 < 864359) OCR1A = (tmr3 >> 8); // после 1000 начинаем ступенчато снижать период
    else if (tmr3 >= 288120 && tmr3 < 432180) OCR1A = (tmr3 >> 8) -25;
    else if (tmr3 < 288120) OCR1A = (tmr3 >> 8)-20;
    tmr3 = 0;
    var = 0;
  }
if (micros()- tmr0 >= 4096) OCR1A = 65500;
}
то на выходе получаем только импульсы с с периодом 65500, не зависимо от того, что подаём на вход.
Более того, если вставить тупо такие строчки:
C++:
volatile uint32_t tmp; //volatile чтобы компилятор не оптимизировал и не удалил нафиг
if (micros()- tmp >= 1) tmp=tmp
то период импульсов по таймеру 1 становится другим!
Если вставить любое другое условие не содержащие millis/micros то всё работает как часики.
И собственно главный вопрос, почему вызов millis/micros в лупе влияет на то, на что по идее вообще никак влиять не должен?
 

Эдуард Анисимов

★★★★★★✩
23 Сен 2019
2,410
976
58
Марий-Эл
Всё нужно перевести на аппаратную часть.
Один таймер подсчитывает импульсы. Второй задаёт диапазон по времени для первого таймера, когда эти импульсы подсчитывать.
Далее можно или по прерыванию, или по глобальной переменной отслеживать окончание счёта и принимать решение.
Ещё лучше для этого использовать DMA. Тогда ядро будет почти не загружено.
 

plotter1

✩✩✩✩✩✩✩
24 Ноя 2021
20
1
Всё нужно перевести на аппаратную часть.
Это значит отказаться от компаратора. А на низких оборотах напряжение около 1В, что для таймерного входа маловато.

Один непонятно что спросил (очень путано).
Ну звиняйте, не блинк. Да.
Если кратко, то вызов микрос в лупе меняет скорость первого таймера. Сфига?
 

Bruzzer

★★★✩✩✩✩
23 Май 2020
472
134
@plotter1,
Вы задали вопрос попросив "не обращать внимание на рудименты", но что рудименты а что нет - знаете только вы.
Было бы понятней, если бы было два кода БЕЗ "рудиментов".
Вызов микрос меняет скорость - в какое место в скетче вы вставили код? С какого значения на какое он меняет?
Дополнение. Я не увидел, где вы настраиваете компаратор.
 

Сотнег

★★★★★★★
15 Янв 2020
4,369
1,496
@plotter1,
вы посмотрите исходник функции micros().
Может, тогда и вопрос отпадёт.
 

plotter1

✩✩✩✩✩✩✩
24 Ноя 2021
20
1
вы посмотрите исходник функции micros().
Может, тогда и вопрос отпадёт.
Вы про запрет прерываний?

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

Сотнег

★★★★★★★
15 Янв 2020
4,369
1,496
@plotter1,
запрет и вообще количество выполняемых операций.
Вам виднее должно быть. Вы в своём коде разбираетесь лучше случайных прохожих тут.