Pull to refresh

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

Reading time3 min
Views79K
Примерно год назад я начал разрабатывать блок управления автомобильным двигателем с нуля.
Позвольте рассказать, почему эта идея до сих пор кажется мне реалистичной.


Итак, старенькая Киа Прайд. Под капотом у неё есть вот такая штука, к которой подходит десяток проводов — это распределитель зажигания, в корпус которого заодно встроены датчики положения распредвала и катушка зажигания.



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



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



Эти два жестяных колеса сидят на валу, вращаются вместе с ним — и, о чудо, формируют в двух торчащих наружу проводах вот такой очень простой сигнал:



На этом наше везение не заканчивается: хотя мы и знаем, что аккумулятор в автомобиле обычно двенадцативольтовый — сигнальная электроника работает обычно на пяти вольтах! А это значит, что этот сигнал можно вот абсолютно как он есть подключить к например stm32f4discovery — это такая плата с микроконтроллером, в которой цена менее тысячи рублей сочетается с 32ых битным процессором частотой 168 МГц и даже арифметическим сопроцессором.



Если решить программировать это чудо с использованием ChibiOS/RT, хотя бы для упрощения интерфейсов работы с периферией, то вот таким несложным кодом мы получим в консоль работающий тахометр.

volatile int rpm = 0;
int lastInputEventTime = -10 * CH_FREQUENCY;

void icuWidthCallback(ICUDriver *driver) {
    int now = chTimeNow();
    int diff = now - lastInputEventTime;
    rpm = 60000 * TICKS_IN_MS * 2 / 4 / diff;
    lastInputEventTime = now;
}

ICUConfig wave_icucfg = { ICU_INPUT_ACTIVE_LOW, 100000, icuWidthCallback, NULL };

int main(void) {
    halInit();
    chSysInit();

    // this thread would blink one of the LEDs, that would look cool
    chThdCreateStatic(blinkingThreadStack, sizeof(blinkingThreadStack), NORMALPRIO, blinkingThread, NULL);

    // serial-over-usb initialization
    usb_serial_start();

    // configure input signal pin
    palSetPadMode(CRANK_INPUT_PORT, CRANK_INPUT_PIN, PAL_MODE_ALTERNATE(GPIO_AF_TIM2));

    // start input capture - we will handle input events and calculate RPM based on the timestamps
    icuStart(&CRANK_DRIVER, &wave_icucfg);
    icuEnable(&CRANK_DRIVER);

    while (TRUE) {
        // RPM value is updated by the input event handler
        chprintf(&SDU1, "rpm: %d\r\n", rpm);
        chThdSleep(100);
    }

    return 0;
}




По-моему, достаточно просто. Но, всё-таки одно дело — считать что-то с датчиков, и совсем другое дело — сгенерировать какой-то управляющий сигнал.
Давайте разберёмся, как же управляются форсунки?

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

Итак, берём блок управления и кладём его на стол.



Аккумулятор у нас в машине на 12 вольт? так и старый ATX блок питания — тоже на 12 вольт, его и используем для питания блока управления на время экспериментов.



Когда мы подключались к автомобильной проводке, мы видели там пятивольтовый сигнал — но сам датчик положения коленвала работает как открытый коллектор — т.е. провод датчика либо заземлён, либо ни к чему не подключён. Чтоб эмулировать такой датчик, нам будет нужен транзистор.



И немного кода для генерации сигнала.

static PWMConfig pwmcfg_slow = { 10000, 1000, NULL, { {
PWM_OUTPUT_DISABLED, NULL }, { PWM_OUTPUT_ACTIVE_LOW, NULL }, {
PWM_OUTPUT_DISABLED, NULL }, { PWM_OUTPUT_DISABLED, NULL } },
/* HW dependent part.*/
0 };

int main(void) {
    halInit();
    chSysInit();

    // this thread would blink one of the LEDs, that would look cool
    chThdCreateStatic(blinkingThreadStack, sizeof(blinkingThreadStack), NORMALPRIO, blinkingThread, NULL);

    // serial-over-usb initialization
    usb_serial_start();

    pwmStart(PWM_SLOW, &pwmcfg_slow);
    palSetPadMode(GPIOB, 7, PAL_MODE_ALTERNATE(2));
    pwmEnableChannel(PWM_SLOW, 1, 600);

    while (TRUE)
        chThdSleep(100);

    return 0;
}



Форсунки впрыска топлива управляются заземлением идущего к ним от блока управления провода. Чтоб интерпретировать такой сигнал от лежащего на столе блока, нам понадобятся один диод и один резистор:



Соберём это всё и запустим. И, опять чудо! Стандартный блок управления нам поверил, и на основании всего лишь одного эмулированного датчика — датчика положения распредвала — начал пытаться управлять форсунками!



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

www.youtube.com/watch?v=GcxLY697WwM


update: раз вопрос возник в комментариях и раз я ссылку уже дал в комментариях — я добавлю сюда тоже:
rusefi.com
rusefi.com/forum
sourceforge.net/projects/rusefi
Tags:
Hubs:
+67
Comments134

Articles

Change theme settings