Witam
Do pomiar prędkości obrotowej wentylatora z PC chciałem użyć sygnału z czujnika halla, całość podłączone jak na schemacie poniżej do wejścia atmegi 16 ICP1. Chciałem użyć również wbudowanej funkcji timera 1 do pomiaru okresu.
I teraz co nie działa... Pomiar jest mało dokładny i strasznie skacze - przy pomiarze prędkości obrotowej max (7200) wynik skacze od ok 4200-30000 przy zmniejszaniu prędkości obrotowej też są straszne skoki np wentylator się ledwo kręci i wynik skacze od 500-2200 obrotów.
W załączniku dołączam przebieg który wchodzi na atmege+spectrum sygnału. Jak dla mnie jest idealny :>
Co próbowałem i nie dało żadnego rezultatu:
1)zmiana oporności pull-upa do halotronu
2)włączenie usuwania zakłóceń z sygnału wejściowego opcjach timera
3)przepuszczanie sygnału przez bramkę NAND - aby uzyskać prostokąt bez zakłóceń
4)filtr RC o częstotliwości odcięcia 250 Hz - próbowałem też z wyższymi częstotliwościami, ale nie dało to rezultatu
5)zmiana trybu wyzwalania -> wykorzystanie analog comparatora
6)uśrednianie 4 pomiarów
Wszystko bez większych rezultatów... błąd pomiaru dalej się pojawia....
Zastanawiałem się jeszcze nad programowym usuwaniem błędów pomiarowych na zasadzie że wartości mocno odbiegające od wartości rzeczywistej pomijał w uśrednianiu... ale nie wiem czy jest to aż tak potrzebne, czy błąd nei leży gdzie indziej.
I ostania rzecz...czytałem kilka postów na forum na ten temat i wszędzie niby korzystają z bezpośredneigo odczytu z INT0 np, ale jak dla mnie to bez sensu ponieważ jest wbudowany częstotliwościomierz i dlaczego go nie wykorzystać ?
Kod programu:
Z góry dziękuje za wszelką pomoc.
![[AVR][C]pomiar obrotów- problem z pomiarem częstotliwości [AVR][C]pomiar obrotów- problem z pomiarem częstotliwości](https://obrazki.elektroda.pl/5_1257781123_thumb.jpg)
Do pomiar prędkości obrotowej wentylatora z PC chciałem użyć sygnału z czujnika halla, całość podłączone jak na schemacie poniżej do wejścia atmegi 16 ICP1. Chciałem użyć również wbudowanej funkcji timera 1 do pomiaru okresu.
I teraz co nie działa... Pomiar jest mało dokładny i strasznie skacze - przy pomiarze prędkości obrotowej max (7200) wynik skacze od ok 4200-30000 przy zmniejszaniu prędkości obrotowej też są straszne skoki np wentylator się ledwo kręci i wynik skacze od 500-2200 obrotów.
W załączniku dołączam przebieg który wchodzi na atmege+spectrum sygnału. Jak dla mnie jest idealny :>
Co próbowałem i nie dało żadnego rezultatu:
1)zmiana oporności pull-upa do halotronu
2)włączenie usuwania zakłóceń z sygnału wejściowego opcjach timera
3)przepuszczanie sygnału przez bramkę NAND - aby uzyskać prostokąt bez zakłóceń
4)filtr RC o częstotliwości odcięcia 250 Hz - próbowałem też z wyższymi częstotliwościami, ale nie dało to rezultatu
5)zmiana trybu wyzwalania -> wykorzystanie analog comparatora
6)uśrednianie 4 pomiarów
Wszystko bez większych rezultatów... błąd pomiaru dalej się pojawia....
Zastanawiałem się jeszcze nad programowym usuwaniem błędów pomiarowych na zasadzie że wartości mocno odbiegające od wartości rzeczywistej pomijał w uśrednianiu... ale nie wiem czy jest to aż tak potrzebne, czy błąd nei leży gdzie indziej.
I ostania rzecz...czytałem kilka postów na forum na ten temat i wszędzie niby korzystają z bezpośredneigo odczytu z INT0 np, ale jak dla mnie to bez sensu ponieważ jest wbudowany częstotliwościomierz i dlaczego go nie wykorzystać ?
Kod programu:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <inttypes.h>
#include <avr/pgmspace.h>
#include <stdlib.h>
#include "harddef.h"
#include "delay.h"
#include "delay.c"
#include "lcd.h"
#include "lcd.c"
uint8_t count_1s=0;
volatile uint16_t count_probe=0;
volatile uint16_t time_capture=100;
volatile uint16_t time_capture_1=100;
volatile uint16_t time_capture_2=150;
volatile uint16_t rpm=0;
volatile uint8_t flag_is_set=0;
volatile uint16_t rpm_time=0;
volatile uint16_t time_temp=0;
void LCDint(void);
void LCDcls(void);
void LCDcommand(uint8_t command);
void LCDdec(unsigned int val);
ISR(TIMER0_OVF_vect ) /*obłsuga systemu-> przerwanie co 32ms
prescaler 1024*/
{
if(count_1s==7){ /*pełna obsługa przerwania co 228 ms*/
TCCR0=0; /*wyłacz timer */
/*obsługa LCD*/
LCDcls();
LCDstr_P((prog_char*)PSTR("n="));
LCDcommand(LCDC_SHIFTL);
time_capture=time_capture_2-time_capture_1; /*oblicz okres trwania impulsu*/
rpm=(125000/time_capture)*30; /*przelicz na prędkość obrotową
rpm=((((8*10^6)/64)/czas_okresu)*60)/2
prędkość obrotowa=(((częstoliwość zegara w MHz)/prescaler)/czas okresu)/(2 impulsy na obrót) */
/*wyświetl prędkość obrotową i czas jednego okresu na wyswietlaczu 2x16*/
LCDdec(rpm);
LCDcommand(LCDC_DDA|0x40);
LCDstr_P((prog_char*)PSTR("t="));
LCDcommand(LCDC_SHIFTL);
LCDdec(time_capture);
LCDcommand(LCDC_DDA|0x00);
TIMSK&=~(1<<TOIE0); /*wyłącz przerwanei od timera 0*/
count_1s=0; /*zeruj smienną pomocniczą*/
time_capture_1=0; /*zerój zmienne do pomiaru czasu*/
time_capture_2=0;
flag_is_set=0; /*zerój flage peirwszego pomiaru*/
TCCR1B=(1<<CS10)|(1<<CS11); /*ustaw timer 1 prescaler 64*/
TIMSK|=(1<<TICIE1); /*załącz przerwanie od input capture unit
przerwanei występuje po pojawieniu się zbocza narastajacego
na wejściu ICP1 */
}else{
++count_1s;
}
}
ISR(TIMER1_CAPT_vect ){ /*pomiar okresu*/
if(flag_is_set==0){ /*pierwszy pomiar-> zapis do zmiennej 1
pierw przepisuje wartość młodszego rejestru
potem starszy rejestr-> manual atmegi 16 str 96*/
time_capture_1=ICR1L;
time_temp=ICR1H;
time_capture_1=time_capture_1|(time_temp<<8); /*przesuniećie bitowe i zpais do jednej zmiennej*/
time_temp=0; /*zerój zmienną pomocniczą*/
}
if(flag_is_set==1){
time_capture_2=ICR1L; /*to samo jak poprzedinio*/
time_temp=ICR1H;
time_capture_2=time_capture_2|(time_temp<<8);
time_temp=0;
TIMSK&=~(1<<TICIE1); /*wyłącz przerwanie od input capture*/
TCCR1B=0x00; /*wyłącz timer 1*/
TCNT1=0; /*zerój jego wartość*/
flag_is_set=0; /*zerój flagę*/
TCCR0=(1<<CS00)|(1<<CS02); /*włącz timer 0*/
TIMSK=(1<<TOIE0); /*załącz przerwanie główne*/
}else{
flag_is_set=1;
}
}
void main(void){
DDR(LCD_RSPORT)=(1<<LCD_E)|(1<<LCD_RS); /*porty do obłsugi wyswietlacza*/
DDR(LCD_DPORT)=(0x0f<<LCD_D4);
LCDint();
LCDcls();
TCCR0=(1<<CS00)|(1<<CS02); /*uruchom timer 0, prescaler 1024*/
TIMSK=(1<<TOIE0); /*załącz przerwanie -> timer overflow*/
sei(); /*załącz przerwania globaline*/
while(1){
}
}
Z góry dziękuje za wszelką pomoc.
