[uquote="СКАЗОЧНИК",url="/forum/viewtopic.php?p=3801490#p3801490"]Короче, идея простая. Для СВАПа. Поменяли двигатель или коробку или колеса в машине, а спидометр/тахометр врать начинают. Вот и надо устройство, которое может плавно подстраивать входящие импульсы в обе стороны. Примерно от 1 к 1 до 1 к 10.
З.Ы. Естественно, входящий сигнал может меняться в зависимости от частоты вращения агрегата.[/uquote]
Очень похожую решал знакомому задачу для тахометра. Только на простеньком pic12f683, хватило с головой. Надо было увеличивать длительность импульсов на 1/3. Но это по-умолчанию, а переменником на АЦП это дело еще регулировалось от 1/5 до 1 вроде. Вход делал захватом, выход после захвата одного периода измененный выдавался. Просто с захваченными цифрами пересчитывал их настраивал ими другой таймер на выход. Один период задержки вполне устраивал, реакция на изменения тоже за глаза получалась. Завтра гляну код, что я там писал точно не помню уже, а сегодня уже некогда.
EDIT: Поправил цифры в абзаце выше после заглядывания в код.
Добавлено after 13 minutes 43 seconds:
Залез всё-таки в код - захват делал на 16-битном таймере, выводил на 8-битном. Считал вообще через float, т.к. плавно по АЦП менялось когда надо было. У меня двойной буфер был - сначала считал значение после захвата, если оно изменилось, как посчитал выходное значение - если оно отличается от прошлого, то тогда обновляем его и поднимаем флаг, что параметры выходного таймера надо обновить и всё. Математика на тех частотах сигнала всегда за один период всё успевала посчитать. Выходной 8-битный таймер в прерывании "эмулировал" 16-битный с дополнительной переменной кол-ва переполнений просто, выход банальном там же ногодрыгом. Как-то так:
Код: Выделить всё
uint16_t get_outval(uint16_t in) {
float ratio = 1.33;
if (flag.adcmd && adcval >= ADC_MIN && adcval <= 1024)
ratio = ((float)adcval / 1024) + 1;
return (uint16_t)((in / 2) * ratio);
}
...
void interrupt isr() {
static volatile uint8_t t0ovfcnt = 0;
if (T0IF && T0IE) {
t0ovfcnt++;
// overflow count == high byte of outval
if (t0ovfcnt == outval.byte[1])
// Preload Timer0 with low byte
TMR0 = (uint8_t)(255 - outval.byte[0]);
// Last overflow condition
if (t0ovfcnt > outval.byte[1]) {
OUT = ~OUT; // invert output
t0ovfcnt = 0;
// input value was updated, need to copy new
if (flag.ccpup) {
outval.word = outval_tmpbuf.word;
flag.ccpup = false;
}
TMR0 = 0;
}
T0IF = 0;
}
// Input capture
if (PIR1bits.CCP1IF) {
if (!flag.t1ovf) {
inval.word = CCPR1;
flag.inrun = true;
}
else
flag.t1ovf = false;
TMR1 = 0;
CCP1IF = 0;
}
...
Добавлено after 23 minutes 20 seconds:
Но мне как видно только умножать длительность нужно было. Смещение из-за ногодрыга и нескольких условий в прерывании даже МК на 8МГц несколько тиков - совсем несущественно было для тахометра и тех частот в несколько сотен Гц.
С делением... программно больше заморочек будет, хотя тем же макаром с ногодрыром по таймеру - почему бы и нет? Вам же для показометров этих не нужна 100% точность по частоте, несколько тиков МК погоды не сделают, если у вас там и правда меандр около 4 Гц.