Эмуляция сигнала ДПКВ 60-2

Приветствую. На работе осцил.снял сигнал. На большом экране видно как повторяются “неправильные импульсы“: широкий импульс перед пропущенным, потом 58 импульсов пропущенный зуб, снова 58 импульсов и опять широкий импульс перед пропущенным. И дальше так по кругу. Широкий импульс появляется строго через раз. Не спонтанно , не хаотично. Если не получится устранить , то Бог с ним.

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

#include <TM1637.h>
// Определяем пины для подключения дисплея TM1637
#define CLK         8
#define DIO         9

#define wheel_len   240
#define pt_pin      A0
#define out1_pin    2
#define out2_pin    3
#define timeout     500

uint32_t tick_delay, FREQ = 5500;        //rpm
uint32_t pt, mill;
volatile uint8_t index = 0;

// Создаем объект дисплея TM1637
TM1637 tm1637(CLK, DIO);

const char Table1[wheel_len] = {
  0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
};

void setup() {

  DDRD |= (1 << PD2);
  DDRD |= (1 << PD3);

  PORTD &= ~(1 << PD2);
  PORTD &= ~(1 << PD3);

  // Настройка режима CTC Timer1
  TCCR1A &= ~((1 << WGM10) | (1 << WGM11));
  TCCR1B &= ~((1 << WGM13));
  TCCR1B |= (1 << WGM12);

  // Настройка предделителя на 8 Timer1
  TCCR1B |= (1 << CS11);
  TCCR1B &= ~((1 << CS12) | (1 << CS10));

  // Разрешаем прерывание по совпадению с OCR1A
  TIMSK1 |= (1 << OCIE1A);

  pt = analogRead(pt_pin);

  FREQ = map(pt, 0, 1024, 300, 5500);

  // Устанавливаем значение для сравнения
  tick_delay = ((120000000UL / FREQ) / wheel_len) * 2;
  OCR1A = tick_delay;

  // Глобально разрешаем прерывания
  sei();
}



void loop() {

  if (millis() - mill > timeout) {

    mill = millis();
    pt = analogRead(pt_pin);

    FREQ = map(pt, 0, 1024, 300, 5500);

    tick_delay = ((120000000UL / FREQ) / wheel_len) * 2;
    OCR1A = tick_delay;

    // Разбиваем на отдельные цифры
    int8_t digits[] = {0, 0, 0, 0};
    digits[0] = FREQ / 1000;        // тысячи (десятки км/ч)
    digits[1] = (FREQ / 100) % 10;  // сотни (единицы км/ч)
    digits[2] = (FREQ / 10) % 10;   // десятки (десятые км/ч)
    digits[3] = FREQ % 10;          // единицы (сотые км/ч)

    // Отображаем скорость на дисплее
    tm1637.point(false);
    tm1637.display(0, digits[0]);
    tm1637.point(false);
    tm1637.display(1, digits[1]);
    tm1637.point(false);  // Включаем точку для разделения целой и дробной части
    tm1637.display(2, digits[2]);
    tm1637.point(false);
    tm1637.display(3, digits[3]);
  }
}

ISR(TIMER1_COMPA_vect) {

  if (Table1[index] == 0) {
    PORTD &= ~(1 << PD2);
    PORTD |= (1 << PD3);
  } else {
    PORTD |= (1 << PD2);
    PORTD &= ~(1 << PD3);
  }

  if (index++ >= wheel_len) {
    index = 0;
  }
}

У меня с ним нет никаких проблем:

Сейчас попробую “проблемы” в основном цикле устроить и посмотреть.

Вот, устроил огромную задержку в теле цикла, проблем не вижу:

Код:

#include <TM1637.h>
// Определяем пины для подключения дисплея TM1637
#define CLK         8
#define DIO         9

#define wheel_len   240
#define pt_pin      A0
#define out1_pin    2
#define out2_pin    3
#define timeout     500

uint32_t tick_delay, FREQ = 5500;        //rpm
uint32_t pt, mill;
volatile uint8_t index = 0;

// Создаем объект дисплея TM1637
TM1637 tm1637(CLK, DIO);

const char Table1[wheel_len] = {
  0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
};

void setup() {

  DDRD |= (1 << PD2);
  DDRD |= (1 << PD3);

  PORTD &= ~(1 << PD2);
  PORTD &= ~(1 << PD3);

  // Настройка режима CTC Timer1
  TCCR1A &= ~((1 << WGM10) | (1 << WGM11));
  TCCR1B &= ~((1 << WGM13));
  TCCR1B |= (1 << WGM12);

  // Настройка предделителя на 8 Timer1
  TCCR1B |= (1 << CS11);
  TCCR1B &= ~((1 << CS12) | (1 << CS10));

  // Разрешаем прерывание по совпадению с OCR1A
  TIMSK1 |= (1 << OCIE1A);

  pt = analogRead(pt_pin);

  FREQ = map(pt, 0, 1024, 300, 5500);

  // Устанавливаем значение для сравнения
  tick_delay = ((120000000UL / FREQ) / wheel_len) * 2;
  OCR1A = tick_delay;

  // Глобально разрешаем прерывания
  sei();
}



void loop() {

  if (millis() - mill > timeout) {

    mill = millis();
    pt = analogRead(pt_pin);

    FREQ = map(pt, 0, 1024, 300, 5500);

    tick_delay = ((120000000UL / FREQ) / wheel_len) * 2;
    OCR1A = tick_delay;

    // Разбиваем на отдельные цифры
    int8_t digits[] = {0, 0, 0, 0};
    digits[0] = FREQ / 1000;        // тысячи (десятки км/ч)
    digits[1] = (FREQ / 100) % 10;  // сотни (единицы км/ч)
    digits[2] = (FREQ / 10) % 10;   // десятки (десятые км/ч)
    digits[3] = FREQ % 10;          // единицы (сотые км/ч)

    // Отображаем скорость на дисплее
    tm1637.point(false);
    tm1637.display(0, digits[0]);
    tm1637.point(false);
    tm1637.display(1, digits[1]);
    tm1637.point(false);  // Включаем точку для разделения целой и дробной части
    tm1637.display(2, digits[2]);
    tm1637.point(false);
    tm1637.display(3, digits[3]);
  }

  for (uint32_t tt = 0; tt < 200000; tt++) {
    asm("nop");
  }
}

ISR(TIMER1_COMPA_vect) {

  if (Table1[index] == 0) {
    PORTD &= ~(1 << PD2);
    PORTD |= (1 << PD3);
  } else {
    PORTD |= (1 << PD2);
    PORTD &= ~(1 << PD3);
  }

  if (index++ >= wheel_len) {
    index = 0;
  }
}

Что-то тут “не то”. Да и как-то странно, что именно “через раз”. В коде нет ничего такого, что могло так действовать на выходные данные…

ЗЫ: Купи логический анализатор (типа такого), сильно помогает иногда…

Так и мелькает этот имульс - зараза)) .Да ну его. BOOM, сделаю на двух ардуинках. Ничего страшного.

Логический анализатор приобрету.

Эх, жаль… Загадка так и не будет раскрыта… (((

Еще раз спасибо за мастер класс :+1: По сути все получилось.

Я вот думаю… @Diagnost , а как ты две ардуино то увяжешь?

есть еще такой скетчик, можно выбирать количество зубов, градусы впадин и выступов , количество пропущенных зубов, и частоту грубовато (через терминал). работает на прерываниях , поэтому луп не влияет на выдаваемый сигнал

const uint16_t rpm_D = 1000;        // по дефолту  1000 об/мин 

const uint16_t tooth_quantity = 60; // выбираем количество зубчиков датчика коленвала

const uint16_t tooth_size  = 3;     // выбираем длину зуба    в градусах
const uint16_t hole_size = 3;       // выбираем длину впадины в градусах

//    зуб+впадина = 360/количество зубов (проверяем это) !!! 

const uint16_t missed_teeth = 2; // выбираем количество пропущенных зубьев

const bool CKPbeginLogic = 0;    // логика начала сигнала колена  (0 или 1)

#define CKPpin PB0               // пин коленвала (8 пин ардуино) можно менять


void setup() {
  Serial.begin(115200);
  if ((tooth_size+hole_size)*tooth_quantity!=360) Serial.println("Неправильно выбрано количество и/или размер зубьев!!!"); 
  Serial.print (rpm_D); Serial.println (" rpm");Serial.println();
  DDRB|= _BV(CKPpin); // пин дпкв на выход
  
  if (!CKPbeginLogic)PORTB |=_BV(CKPpin); // задаем начальный уровень сигнала дпкв
 
  //ниже настраиваем аппаратный таймер ардуино
  TCCR1A = 0;   
  TCCR1B = 8;
  TCCR1B |= 1;
  OCR1A = 2666666ul/rpm_D;  
  TIMSK1 |= (1<<OCIE1A);
}


void loop()  // луп в формированиим сигнала дпкв не участвует, здесь только задаются обороты коленвала через терминал
{

  
if (Serial.available() )
          {
    byte inbyte = Serial.read();
    if (inbyte >='1' && inbyte <='9')       // в консоль вводим от 1 до 9, чтоб выбрать обороты(без символов конца строки)
    {
      uint32_t rpm = (inbyte-'0')*1000;
      Serial.print (rpm); Serial.println (" rpm");
      OCR1A = 2666666UL/rpm;
    }
         }

}

ISR (TIMER1_COMPA_vect)// обрабочик таймера, сюда заходит раз в градус поворота коленвала

{
static byte countT = 0; // счетчик градусов зуба/впадины
static byte counttooth = 1; // счетчик зубов
static bool tooth_or_hole = 1; // флаг зуб/впадина

  countT++;  // прибавляем счетчик градусов зуба/впадины
  if ((tooth_or_hole && countT>=tooth_size) || (!tooth_or_hole && countT>=hole_size) ) // если по градусам достигли зуба или впадины
  {
    tooth_or_hole = !tooth_or_hole;  // меняем состояние зуб/впадина
    countT = 0;  // сбрасываем счетчик градусов зуба/впадины
    counttooth++; // увеличиваем номер текущего зуба
    if (counttooth>(tooth_quantity*2)) counttooth =1; // сбрасываем увеличение номера зуба в случае достижения максимума
    // ниже дергаем ногой (сигнал ДПКВ), если это не пропущенные зубья. 
    if (missed_teeth == 0 || (tooth_quantity*2 - counttooth) > (missed_teeth*2-1))PORTB ^= _BV(CKPpin);
  }
}
1 лайк

на самом деле ваш скетч не совсем 60-2 в классическом понимании. в вашем скетче в сигнале пропущен один выступ и одна впадина.

то есть в месте синхронизации проходят подряд три выступа и три впадины. Для блоков 60-2 такой сигнал может не подойти.

хотя наверное в скетче так сделали, чтобы прямоугольный сигнал с ардуины подсунуть в ЭБУ с индуктивным дпкв, сигнал которого представляет синусоиду. и чтобы пропуск зубьев был похож, так сделали .

1 лайк

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

в коде в массиве, где задается, зуб или впадина (нули и единицы), сделано 240 значений . Это видимо было сделано для полного цикла работы 4 тактного двс, где за два оборота коленвала весь цикл проходит. то есть имеем дпкв 60 импульсов, на каждом импульсе нужна впадина и выступ, то есть 120 значений , а так как оборота 2 за полный цикл, то поэтому массив имеет 240 значений .

но косяк в вашем скетче я нашел. Он возникает в конце массива, поэтому проблема возникает через раз (потому что один пропуск зубьев проходит в центре тела массива и тут косяк не влияет)

проблема тут . вместо

if (index++ >= wheel_len) {
    index = 0;}

надо

 index++;
  if (index >= wheel_len) {index = 0;}
1 лайк
#include <TM1637.h>
// Определяем пины для подключения дисплея TM1637
#define CLK         8
#define DIO         9

#define wheel_len   240
#define pt_pin      A0
#define out1_pin    2
#define out2_pin    3
#define timeout     500

uint32_t tick_delay, FREQ = 5500;        //rpm
uint32_t pt, mill;
volatile uint8_t index = 0;

// Создаем объект дисплея TM1637
TM1637 tm1637(CLK, DIO);

const char Table1[wheel_len] = {
  0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
};

void setup() {

  DDRD |= (1 << PD2);
  DDRD |= (1 << PD3);

  PORTD &= ~(1 << PD2);
  PORTD &= ~(1 << PD3);

  // Настройка режима CTC Timer1
  TCCR1A &= ~((1 << WGM10) | (1 << WGM11));
  TCCR1B &= ~((1 << WGM13));
  TCCR1B |= (1 << WGM12);

  // Настройка предделителя на 8 Timer1
  TCCR1B |= (1 << CS11);
  TCCR1B &= ~((1 << CS12) | (1 << CS10));

  // Разрешаем прерывание по совпадению с OCR1A
  TIMSK1 |= (1 << OCIE1A);

  pt = analogRead(pt_pin);

  FREQ = map(pt, 0, 1024, 300, 5500);

  // Устанавливаем значение для сравнения
  tick_delay = ((120000000UL / FREQ) / wheel_len) * 2;
  OCR1A = tick_delay;

  // Глобально разрешаем прерывания
  sei();
}



void loop() {

  if (millis() - mill > timeout) {

    mill = millis();
    pt = analogRead(pt_pin);

    FREQ = map(pt, 0, 1024, 300, 5500);

    tick_delay = ((120000000UL / FREQ) / wheel_len) * 2;
    OCR1A = tick_delay;

    // Разбиваем на отдельные цифры
    int8_t digits[] = {0, 0, 0, 0};
    digits[0] = FREQ / 1000;        // тысячи (десятки км/ч)
    digits[1] = (FREQ / 100) % 10;  // сотни (единицы км/ч)
    digits[2] = (FREQ / 10) % 10;   // десятки (десятые км/ч)
    digits[3] = FREQ % 10;          // единицы (сотые км/ч)

    // Отображаем скорость на дисплее
    tm1637.point(false);
    tm1637.display(0, digits[0]);
    tm1637.point(false);
    tm1637.display(1, digits[1]);
    tm1637.point(false);  // Включаем точку для разделения целой и дробной части
    tm1637.display(2, digits[2]);
    tm1637.point(false);
    tm1637.display(3, digits[3]);
  }
}

ISR(TIMER1_COMPA_vect) {

  if (Table1[index] == 0) {
    PORTD &= ~(1 << PD2);
    PORTD |= (1 << PD3);
  } else {
    PORTD |= (1 << PD2);
    PORTD &= ~(1 << PD3);
  }
index++;
  if (index >= wheel_len) {
    index = 0;
  }
}
1 лайк

Есть только одно “НО”…
У меня на логическом анализаторе проблема ТС не воспроизвелась, как бы я не старался (и осциллограмма соответствует первоначальной).

Дублирую скриншоты, если лень листать тему:

  1. Работа “в штатном режиме”:

  1. Устроил “проблемы” в основном цикле (loop()):

Возможно потому, что я тестировал на малых (низких) частотах.

1 лайк

А в этом есть “здравое зерно”…

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

Тем не менее, если у ТС есть желание проверить предположение - я только ЗА! Хочется ведь разобраться, а не “п#ськами мериться” )))

1 лайк

Только, наверное, более лаконичная такая запись будет:

#include <TM1637.h>
// Определяем пины для подключения дисплея TM1637
#define CLK         8
#define DIO         9

#define wheel_len   240
#define pt_pin      A0
#define out1_pin    2
#define out2_pin    3
#define timeout     500

uint32_t tick_delay, FREQ = 5500;        //rpm
uint32_t pt, mill;
volatile uint8_t index = 0;

// Создаем объект дисплея TM1637
TM1637 tm1637(CLK, DIO);

const char Table1[wheel_len] = {
  0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
};

void setup() {

  DDRD |= (1 << PD2);
  DDRD |= (1 << PD3);

  PORTD &= ~(1 << PD2);
  PORTD &= ~(1 << PD3);

  // Настройка режима CTC Timer1
  TCCR1A &= ~((1 << WGM10) | (1 << WGM11));
  TCCR1B &= ~((1 << WGM13));
  TCCR1B |= (1 << WGM12);

  // Настройка предделителя на 8 Timer1
  TCCR1B |= (1 << CS11);
  TCCR1B &= ~((1 << CS12) | (1 << CS10));

  // Разрешаем прерывание по совпадению с OCR1A
  TIMSK1 |= (1 << OCIE1A);

  pt = analogRead(pt_pin);

  FREQ = map(pt, 0, 1024, 300, 5500);

  // Устанавливаем значение для сравнения
  tick_delay = ((120000000UL / FREQ) / wheel_len) * 2;
  OCR1A = tick_delay;

  // Глобально разрешаем прерывания
  sei();
}



void loop() {

  if (millis() - mill > timeout) {

    mill = millis();
    pt = analogRead(pt_pin);

    FREQ = map(pt, 0, 1024, 300, 5500);

    tick_delay = ((120000000UL / FREQ) / wheel_len) * 2;
    OCR1A = tick_delay;

    // Разбиваем на отдельные цифры
    int8_t digits[] = {0, 0, 0, 0};
    digits[0] = FREQ / 1000;        // тысячи (десятки км/ч)
    digits[1] = (FREQ / 100) % 10;  // сотни (единицы км/ч)
    digits[2] = (FREQ / 10) % 10;   // десятки (десятые км/ч)
    digits[3] = FREQ % 10;          // единицы (сотые км/ч)

    // Отображаем скорость на дисплее
    tm1637.point(false);
    tm1637.display(0, digits[0]);
    tm1637.point(false);
    tm1637.display(1, digits[1]);
    tm1637.point(false);  // Выключаем точку для разделения целой и дробной части
    tm1637.display(2, digits[2]);
    tm1637.point(false);
    tm1637.display(3, digits[3]);
  }
}

ISR(TIMER1_COMPA_vect) {

  if (Table1[index++] == 0) {
    PORTD &= ~(1 << PD2);
    PORTD |= (1 << PD3);
  } else {
    PORTD |= (1 << PD2);
    PORTD &= ~(1 << PD3);
  }

  if (index >= wheel_len) {
    index = 0;
  }
}
1 лайк

Удлинение импульса это уже и есть проблема , ЭБУ это не понравится , и он будет срывать синхронизацию. Отключать форсунки , катушки и тд. Но и дополнительный всплеск перед пропуском зубьев , который у ТС возникает, 90 процентов по этой же причине происходит.

Кстати, а зачем таблица на 240 элементов, если вторые 120 элементов 1 в 1 совпадают с первыми 120ю? Думаю, можно вырезать половину совершенно спокойно.

там в изначальном скетче у ТС был еще один массив на датчик распредвала , а вот он уже должен быть 240 значений , поэтому и дпкв массив такой размер имеет. Так как ТС не нужен сигнал дпрв , у вы его убрали, то да, можно спокойно массив пополам порубить.

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

 if (++index>= wheel_len) {
    index = 0;
  }

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

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

byte index = 0 ; 

void setup() {
 Serial.begin (115200); 

  while (1)
  {
     if (index++>=240){Serial.print(index); break;}
   } 
}

void loop() {}

и

byte index = 0 ; 

void setup() {
 Serial.begin (115200); 

  while (1)
  {
     if (++index>=240){Serial.print(index); break;}
   } 
}

void loop() {}
2 лайка

а теперь увеличь в своем скетче с ошибкой массив до 241 значения (при этом размер массива в квадратных скобках пустым оставь), и последнее значение меняй 0 или 1 и увидишь , что в одном случае это удлинение импульса , а в другом - дополнительный неправильный импульс (в зависимости от того какой мусор был в памяти на этом месте) . в твоем слуае при замерах был вариант с удлинением импульса, а у ТС совпало так что дополнительный импульс был