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:
- Microcontroleur ATmega328p
- NMOS IRLZ34N
- Diode 1N5819
- Moteur CC générique MOT2N (velleman)
Galerie:
