Delicka PWM signalu
#1
Potreboval by som urobit zapojenie ktore znizi duty cycle o 5%. (nemusi to byt presne 5, +- par percent hore dole nevadi)

Napada niekoho ako? existuje nejake jednoduche a elegantne riesenie? Nejake jednoduche RC znie lakavo ale podla mna nebude fungovat dobre, pretoze len oreze hranu signalu a znepresni pwm. Programovat MCU som sa chcel vyhnut ale mozno to inak nepojde? Mozno existuje nejaky cmos co to dokaze? nieco ako delicka pre frekvenciu Thinking ale na duty... cosi som vymyslal s 555kou cez trigger ale akonahle chcem menit duty ma to fixne nastavene casy a s tym to asi nepojde. Mate nejaky napad ako na to?

Mam pwm signal (cca 25kHz) ktoreho frekvenciu nechcem menit a jeho duty cycle sa dynamicky casto meni. (regulacia ventilatora) z tohto pwm chcem vytvorit novy pwm signal rovnakej frekvencie ale jemne znizeneho duty cycle.
Citovat
#2
Co na to řekne AI, když se jí zeptáš? Odečíst určitý pevný čas ti nestačí?
Citovat
#3
ai je z elektro blba jak tago...

jardag69 napsal:Odečíst určitý pevný čas ti nestačí?


nechapem co tym myslis, ved ano odcitat / znizit duty, ale nie pevny cas, chcem to dynamicke. Chcem to univerzalne, aby to fungovalo aj pri 20k aj pri 30k pwmku, a ci to pwm bude 90 alebo 10... stale minus 5
Citovat
#4
Jasně. Prostě -5% z délky signálu. Na to jsem sám zvědavej. I kdyby se to řešilo pomocí nějakého chytrého obvodu, tak to asi nebude v reálu. Pokud se to PWM nemění nijak rychle, tak by asi nevadilo, že by se to o jeden impulz zpozdilo. Ale byla by to pakárna. Obvod by změřil délku impulzu, provedl by přepočet a s příchodem dalšího pulzu, by vygeneroval pulz o těch 5% kratší.
Měl by stačit https://www.kondik.cz/io-atmega328p-au/?...hXBKFw2GzG
Copilot mi i napsal program :o)
Ale asi to chce brat s rezervou :o)

// ATmega328P: měření PWM na PD2 (INT0), výstup zkráceného pulzu na PB1 (OC1A, Arduino D9)
// Předpoklad: F_CPU = 16 MHz
#define F_CPU 16000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdint.h>
#include <util/delay.h>

volatile uint16_t start_ticks = 0;
volatile uint16_t measured_ticks = 0;
volatile uint16_t new_ticks = 0;
volatile uint8_t have_new_ticks = 0;
volatile uint8_t waiting_to_generate = 0;

int main(void) {
// Pin setup
DDRB |= (1 << PB1); // PB1 (OC1A, Arduino D9) jako výstup
PORTB &= ~(1 << PB1); // výstup LOW

// INT0 (PD2) jako vstup (default), zapnout interní pull-up pokud chceš:
// PORTD |= (1 << PD2);

// Timer1: normal mode, prescaler = 1 (no prescaling)
TCCR1A = 0x00;
TCCR1B = (1 << CS10); // prescaler = 1
// necháme Timer1 běžet volně (TCNT1)

// INT0: trigger on any logical change (ISC01=0, ISC00=1)
EICRA |= (1 << ISC00);
EICRA &= ~(1 << ISC01);
EIFR |= (1 << INTF0);
EIMSK |= (1 << INT0);

// Disable compare interrupt initially
TIMSK1 &= ~(1 << OCIE1A);

sei();

while (1) {
// hlavní smyčka může být prázdná; vše řeší ISR
// případně sem můžeš přidat diagnostiku, LED, atd.
_delay_ms(1000);
}
return 0;
}

// INT0 ISR: detekce náběhu i sestupu na PD2
ISR(INT0_vect) {
uint8_t pin = PIND & (1 << PD2);
uint16_t now = TCNT1;

if (pin) {
// rising edge: začátek pulzu
start_ticks = now;

// Pokud máme spočtenou new_ticks z předchozího pulzu, vygenerujeme zkrácený pulz nyní
if (have_new_ticks) {
// nastav výstup HIGH
PORTB |= (1 << PB1);
// naplánuj compare na (now + new_ticks)
uint16_t target = now + new_ticks;
OCR1A = target;
// povolit compare interrupt
TIMSK1 |= (1 << OCIE1A);
// označit, že jsme použili new_ticks
have_new_ticks = 0;
}
} else {
// falling edge: konec pulzu -> změřit délku
measured_ticks = now - start_ticks;
// spočítat 95%
uint32_t tmp = (uint32_t)measured_ticks * 95UL;
tmp = tmp / 100UL;
if (tmp == 0) tmp = 1; // zajistit alespoň 1 tick
new_ticks = (uint16_t)tmp;
have_new_ticks = 1;
}
}

// Timer1 Compare A ISR: vypnout výstup
ISR(TIMER1_COMPA_vect) {
// clear output
PORTB &= ~(1 << PB1);
// disable compare interrupt until next pulse
TIMSK1 &= ~(1 << OCIE1A);
}
Citovat
#5
jo cez procesor s ai programom to mi tiez napadlo ale az ako posledna moznost
Citovat