Senema!

Un circuit très simple juste pour démarrer lentement un moteur CC de 5V et imiter un métro.
Je l'ai programmé grace à mon RaspberryPi5 en utilisant avrdude.

Programme:

    
    #define F_CPU 1000000UL

    #include <avr/io.h>
    #include <util/delay.h>

    #define TARGET_PWM_FREQ 4440UL
    #define RAMP_STEP        1
    #define RAMP_DELAY_MS   100
    #define SHIFT_BACKSTEP  13         // ~5%
    #define SHIFT_INTERVAL  26         // ~10%
    #define SHIFT_RECOVER_MULTIPLIER  0.5

    void pwm_init()
    {
        DDRD |= (1 << PD6);  // OC0A (PD6) as output

        TCCR0A |= (1 << COM0A1) | (1 << WGM01) | (1 << WGM00);  // Fast PWM, non-inverting

        uint16_t prescaler_values[] = {1, 8, 64, 256, 1024};
        uint8_t prescaler_bits[] = {
            (1 << CS00),
            (1 << CS01),
            (1 << CS01) | (1 << CS00),
            (1 << CS02),
            (1 << CS02) | (1 << CS00)
        };

        uint8_t best_index = 0;
        uint32_t best_error = 0xFFFFFFFF;

        for (uint8_t i = 0; i < 5; i++) {
            uint32_t freq = F_CPU / (prescaler_values[i] * 256UL);
            uint32_t error = (freq > TARGET_PWM_FREQ) ? (freq - TARGET_PWM_FREQ) : (TARGET_PWM_FREQ - freq);
            if (error < best_error) {
                best_error = error;
                best_index = i;
            }
        }

        TCCR0B |= prescaler_bits[best_index];
        OCR0A = 0;
    }

    void ramp_up_with_gears()
    {
        uint8_t duty = 0;
        uint8_t next_shift = SHIFT_INTERVAL;

        while (duty <= 255) {
            OCR0A = duty;
            _delay_ms(RAMP_DELAY_MS);
            duty += RAMP_STEP;

            // Check if it's time to simulate a gear shift
            if (duty >= next_shift && duty <= 255) {
                uint8_t dip = (duty >= SHIFT_BACKSTEP) ? duty - SHIFT_BACKSTEP : 0;
                OCR0A = dip;
                _delay_ms(RAMP_DELAY_MS);  // Hold the "kick" briefly

                // Ramp back up to original duty, but 2x faster
                while (dip < duty) {
                    dip += RAMP_STEP;
                    if (dip > duty) dip = duty;
                    OCR0A = dip;
                    _delay_ms(RAMP_DELAY_MS * SHIFT_RECOVER_MULTIPLIER);  // 2x faster
                }

                next_shift += SHIFT_INTERVAL;
            }
        }
    }

    int main(void)
    {
        pwm_init();

        while (1) {
            ramp_up_with_gears();
            _delay_ms(1000);
            OCR0A = 0;
            _delay_ms(2000);
        }
    }
    
    

Composants:

Galerie:

Version 183b710 2025-06-06 21:18:23 +0200.