Есть тут на форуме кто уже сталкивался с измерением оборотов причем с большим диапазоном от 100 - 20 000 об/мин?
Например с помощью датчика холла или просто светоотражающей поверхности оптическим способом считывать с вала.
Мне пока нужен примитивный измеритель оборотов вентилятора 80X80X25 c таховыходом те что в компе стоят в блоках питания старых но что бы от 100 - 4500 об/мин умел мерить.
Примеры на С конечно нужны.
//Канал A PWM таймера 1 (вывод OC1A) используется для управления
//двигателем. На валу двигателя находится прерыватель оптического
//потока с количеством лопостей BLADES. Для стабилизации частоты
//прерывателя применяется PID-регулятор, который использует
//показания измерителя частоты прерывателя. Измеритель использует
//прерывание по захвату таймера 1 (вывод ICP) и прерывание по
//совпадению таймера 1. Когда измеритель находится в состоянии
//ST_INIT происходит захват таймера в переменную Tb, и начинается процесс
//измерение частоты ST_COUNT. Частота измеряется по количеству периодов
//входного сигнала, равному количеству лопастей прерывателя BLADES.
//Этим устраняется джиттер, вызванный неточностью изготовления прерывателя.
//Периоды считаются в переменной Nb. События совпадения таймера 1 считаются
//в переменной Tn. Когда проходит заданное количество периодов,
//происходит захват таймера в переменную Te, и процесс измерения частоты
//заканчивается (ST_DONE). После этого основная программа вычисляет
//длительность одного оборота Tcap = Te - Tb + Tn * (PWM_MAX + 1)
//и частоту прерывателя GetF = BLADES * F_CLK / Tcap.
//Длительность процесса измерения ограничена с помощью таймера FTimer
//значением FM_MAX. Если длительность оборота больше FM_MAX,
//частота прерывателя считается равной нулю.
#define FM_MAX 100 //максимальный измеряемый период вращения, мс
#define BLADES 8 //количество лопастей прерывателя
enum { ST_INIT, ST_COUNT, ST_DONE };
static char State; //состояние измерителя частоты прерывателя
static int Tn; //количество переполнений таймера
static int Tb, Te; //захваченные значения начала и конца интервала
static int GetF; //измеренная частота прерывателя
#pragma vector = TIMER1_CAPT_vect
__interrupt void Timer_Cap(void); //прерывание по захвату
#pragma vector = TIMER1_OVF_vect
__interrupt void Timer_Ovf(void); //прерывание по переполнению
void Meter_Init(void)
{
TCCR1A = (1 << COM1A1) | (1 << COM1A0) |
(1 << COM1B1) | (1 << COM1B0) |
(1 << WGM11) | (1 << WGM10);
TCCR1B = (1 << WGM12) | (1 << CS10);
TIFR = (1 << ICF1) | (1 << TOV1);
TIMSK |= (1 << TICIE1) | (1 << TOIE1);
GetF = 0; //обнуление измеренной частоты
State = ST_INIT; //запуск измерителя частоты
}
//Вызывать в основном цикле, t - флаг системного тика (1 мс)
void Meter_Exe(bool t)
{
static char FTimer = ms2sys(FM_MAX); //таймер максимального периода
if(t)
{
//обработка таймера максимального периода измерителя частоты:
if(FTimer) FTimer--;
}
//управление двигателем прерывателя:
if(State == ST_DONE || !FTimer) //измерение частоты закончено
{
if(FTimer) //если период измерения не превышен, вычисление частоты
{
long Tcap = Te - Tb + (long)Tn * (PWM_MAX + 1); //длительность оборота
GetF = (long)(BLADES * F_CLK * 1E6) / Tcap; //частота прерывателя
}
else //период превышен,
{
GetF = 0; //обнуление частоты
}
FTimer = ms2sys(FM_MAX); //перезагрузка таймера макс. периода
State = ST_INIT; //запуск нового измерения частоты
}
}
//------------------------- Прерывание по захвату: ---------------------------
#pragma vector = TIMER1_CAPT_vect
__interrupt void Timer_Cap(void)
{
static char Nb; //счетчик измеренных импульсов
switch(State)
{
case ST_INIT: //фаза начала измерения частоты
{
Tb = ICR1; //захват таймера в начале интервала
Tn = 0; //инициализация количества переполнений
if(Tb < 500 && (TIFR & (1 << TOV1)))
Tn--; //коррекция, если переполнение было до захвата
Nb = BLADES; //инициализация количества лопостей
State = ST_COUNT; //переход к фазе измерения частоты
break;
}
case ST_COUNT: //фаза измерения частоты
{
if(!--Nb) //счет лопостей, если измерены все, то
{
Te = ICR1; //захват таймера в конце интервала
if(Te < 500 && (TIFR & (1 << TOV1)))
Tn++; //коррекция, если переполнение было до захвата
State = ST_DONE; //измерение частоты закончено
}
break;
}
}
}
//----------------------- Прерывание по переполнению: ------------------------
#pragma vector = TIMER1_OVF_vect
__interrupt void Timer_Ovf(void)
{
if(State == ST_COUNT) Tn++; //подсчет переполнений для частотомера
}
AVT-28, за место того, что-бы копипастить всё подряд и пытаться скомпилировать неизвестно что, попытайтесь разобраться с принципом измерения частоты. Будет намного правильнее и быстрее. Это совет.
На этом форуме не раз подобное обсасывалось, причём недавно. Поищите.
Да сложно сразу освоить все! И С и С# и ассемблер и контроллер. Я ко всему приду постепенно. Щас просто голова пухнет.
А поскольку мне это просто интересно очень я это делаю.
С чем то разобрался, с чем то никак, частично понял как контроллер работает и так далее.
Еще пару тройку месяцев и думаю тут не буду народ жуткими вопросами мучить.
Часть примеров сохраню и можно вставлять куда то в следующие разработки.