Uruchomiłem kanały sterowane z odbiornika i zaczęła się magia. Można tu przestawić
drążek, a w modelu coś się dzieje. Niestety nie dzieje się dobrze. Silnik główny
pobiera taki prąd, że napięcie zasilania spada do 5V i serwa głupieją. Będę musiał
zmienić silnik główny na trochę słabszy. A to pociąga za sobą zmianę przekładni,
wału Cardana i łoża silnika. Do Zjazdu mogę nie zdążyć, ale będę próbował.
Teraz opiszę coś, z NASA. Jak za pomocą jednego timera obsłużyć trzy kanały
z aparatury i kontrolować stery głębokości.
Telegram z odbiornika wygląda tak, że co 20milisekund przychodzą (na kolejnych
liniach odbiornika) impulsy o długościach od 1 do 2 milisekund. Impulsy te
przychodzą bez żadnego odstępu, to znaczy odstęp jest niemierzalny
za pomocą procesora z kwarcem 16MHz. Trzy z czterech kanałów są podłączone
do procesora tak, aby pojawiały się przerwania przy pojawianiu się impulsów.
Cały czas chodzi timer z częstotliwością 250 kHz. Timer z tą częstotliwością
zwiększa swój licznik, który może być w dowolnej chwili odczytany.
Licznik timera zmienia się od 0 do 65535 po czym generowane jest przerwanie.
Przeliczenie od 0 do 65535 trwa około 0.26 sekundy.
Pierwsze dwa impulsy z aparatury generują przerwanie na zboczu narastającym, trzecie generuje
przerwanie na zboczu narastającym, a obsługa przerwania przestawia je tak, aby
następne przerwanie było na zboczu opadającym impulsu. Z kolei to przerwanie
na zboczu opadającym przestawia siebie tak, aby następne było na zboczu narastającym
impulsu i system jest gotów do obsługi następnego telegramu RC.
Pierwsze przerwanie ustawia licznik timera na zero (pomysł Gury – mocno uprościł obsługę
przerwań). Drugie przerwanie odczytuje stan timera i zapamiętuje go jako długość impulsu
z pierwszego kanału a następnie zeruje timer. Trzecie przerwanie na zboczu narastającym
odczytuje timer i zapisuje go jako długość impulsu z kanału drugiego i zeruje timer.
Na zboczu opadającym odczytuje timer i zapisuje go jako długość impulsu trzeciego kanału.
Następnie ustawia timer tak, że następne przerwanie z timera zostanie wygenerowane za
2 milisekundy. Zakładam, że przez 2 milisekundy zdążę wypracować sygnał dla sterów
głębokości.
Przerwanie timera ustawia siebie tak, aby następne było wygenerowane po czasie trwania
impulsu dla sterów głębokości. Po upływie tego czasu timer powraca do liczenia od 0 do
65535 i czekania na impulsy z aparatury. Całość obsługi zajmuje max 3*2 + 2 + 2 = 10ms
i powtarza się z częstotliwością wysyłania telegramu przez odbiornik RC.
A oto stosowny kawałek programu :
Kod: Zaznacz cały
// Aparatura RC sygna│y z aparatury
//====================================================
// Przerwania przychodza po kolei. Pierwsze przerwanie na zbocze
// narastajace.
// Pomiedzy zboczami moze byc co najwyzej 3 ms przerwy
// Pomiar czasu dokonywany jest poprzez zapamietanie TCNT1 zmieniane co 1/250ms
// CH1 - lewo prawo - bezposrednio na serwo
// CH2 - silnik glowny INT1
// CH3 - zanurzenie INT2
// CH4 - ster glebokosci INT0
// Kolejnosc impulsow jest taka jak kolejnosc kanalow
volatile unsigned char cKanal;
// W jednostkach 0.004 ms czyli 250 na 1 ms
// 375 - to zero
volatile unsigned int iRCDlugImpSilnikaGlownego;
volatile unsigned int iRCDlugImpSteruGlebokosci;
volatile unsigned int iRCDlugImpZanurzenia;
unsigned char cNaZboczuNarastajacym = 1;
// Silnik glowny
// Przerwanie pojawia sie przy narastajacym
SIGNAL( SIG_INTERRUPT1 )
{
TCNT1 = 0;
}
// Zanurzenie
// przerwanie jest tylko przy narastajacym zboczu
SIGNAL( SIG_INTERRUPT2 )
{
iRCDlugImpSilnikaGlownego = TCNT1;
TCNT1 = 0;
}
// Ster glebokosci
// Przerwanie pojawia sie przy narastajacym a potem jest przelaczane na opadajace zbocze
SIGNAL( SIG_INTERRUPT0 )
{
if ( cNaZboczuNarastajacym )
{
iRCDlugImpZanurzenia = TCNT1;
TCNT1 = 0;
// Przeprogramowanie na zbocze opadajace
MCUCR = 0b00001110;
cNaZboczuNarastajacym = 0;
}
else
{
iRCDlugImpSteruGlebokosci = TCNT1;
MCUCR = 0b00001111;
cNaZboczuNarastajacym = 1;
TCNT1 = 0xFFFF - 500; // Przerwanie TIMER1 OVERFLOW za 2 ms
cCtrlTimer1 = 1;
}
}
i obsługa timera :
Kod: Zaznacz cały
//--------------------------------------------------
// Przerwanie od Timer1
// Zmienne ustawiane w przerwaniu
//--------------------------------------------------
volatile unsigned char cCtrlTimer1 = 0;
// w 1/250 czesciach milisekundy
volatile unsigned int DlugImpulsuNaSterGlebokosci;
//******************************************************************************
SIGNAL(SIG_OVERFLOW1)
{
// TCNT1 musi byc przeladowywany
// Timer tyka zgodnie z zaprogramowanymi wartosciami
// Przy kazdym tyknieciu zwieksza TCNT1.
// Przy osiagnieciu 0xFFFF generowane jest to przerwanie
// TCNT1 = 0xFFFF - 5000; // przerwanie co 20ms
switch ( cCtrlTimer1 )
{
case 0 : // normalna praca
break;
case 1:
TCNT1 = 0xFFFF - DlugImpulsuNaSterGlebokosci;
PORTD |= _BV( SterGlebPWM );
++cCtrlTimer1;
PORTB |= _BV( LED_TEST );
break;
case 2:
PORTD &= ~_BV( SterGlebPWM );
PORTB &= ~_BV( LED_TEST );
cCtrlTimer1 = 0;
break;
default:
break;
}
}
Z ukłonami
Andrzej Korycki