A oto kod:
Kod: Zaznacz cały
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
// Odbiornik podczerwieni SFH5110 przyłączony do portu PB0
#define RC5_IN (PINB & (1<<0))
typedef unsigned char u8;
typedef unsigned int uint;
volatile u8 timerL;
volatile u8 timerH;
// konfiguracja timera, przerwanie powinno wystapic co 32us
void init_rc5() {
//atmega8
TCCR0 = (1 << CS00); // włącza Timer0
TIMSK = (1 << TOIE0); // włącza przerwanie "Timer0 Overflow"
sei();
}
// Procedura obsługi przerwania Timer0 Overflow
ISR(TIMER0_OVF_vect)
{
volatile static u8 inttemp;
// zmienna timerL zwiększa się co 32us
timerL++;
// zmienna timerH zwiększa się co 8.192ms (32us*256)
inttemp++;
if (!inttemp)
timerH++;
}
// detekcja komendy RC-5
uint detect() {
u8 temp;
u8 ref1;
u8 ref2;
u8 bitcnt;
uint command;
timerH = 0;
timerL = 0;
// Czeka na okres ciszy na linii wejścia uC trwający 3.5ms
// Jeśli nie wykryje takiego okresu ciszy w ciągu 131ms,
// to kończy działanie funkcji z błędem
while (timerL < 110) {
if (timerH >= 16)
return command = -1;
if (!RC5_IN)
timerL = 0;
}
// Czeka na pierwszy bit startowy.
// Jeśli nie wykryje bitu startowego w ciągu 131ms,
// to kończy działanie funkcji z błędem
while (RC5_IN)
if (timerH >= 16)
return command = -1;
// Pomiar czasu trwania niskiego poziom syganłu
// w pierwszym bicie startowym.
// Jeśli nie wykryje rosnącego zbocza sygnału w ciągu
// 1ms, to kończy działanie funkcji z błędem
// czas trwania jednego bitu - 1,788ms
timerL = 0;
while (!RC5_IN)
if (timerL > 34)
return command = -1;
//
temp = timerL;
timerL = 0;
// ref1 - oblicza 3/4 czasu trwania bitu
ref1 = temp + (temp >> 1);
// ref2 - oblicza 5/4 czasu trwania bitu
ref2 = (temp << 1) + (temp >> 1);
// Oczekuje na zbocze opadające sygnału w środku drugiego
// bitu startowego.
// Jeśli nie wykryje zbocza w ciągu 3/4 czasu trwania
// bitu, to kończy działanie funkcji z błędem
while (RC5_IN)
if (timerL > ref1)
return command = -1;
// W momencie wykrycia zbocza sygnału, synchronizuje
// zmieną timerL dla próbkowania bitu toggle
timerL = 0;
// Odczytuje dekoduje pozostałe 12 bitów polecenia rc5
for (bitcnt = 0, command = 0; bitcnt < 12; bitcnt++) {
// Czeka 3/4 czasu trwania bitu od momentu wykrycia
// zbocza sygnału w połowie poprzedniego bitu
while (timerL < ref1) {
};
// Próbkuje - odczytuje port we uC
if (!RC5_IN) {
// Jeśli odczytano 0, zapamiętuje w zmiennej
// "command" bit o wartości 0
command <<= 1;
// Oczekuje na zbocze rosnące sygnału w środku bitu.
// Jeśli nie wykryje zbocza w ciągu 5/4 czasu trwania
// bitu, to kończy działanie funkcji z błędem
while (!RC5_IN)
if (timerL > ref2)
return command = -1;
} else {
// Jeśli odczytano 1, zapamiętuje w zmiennej
// "command" bit o wartości 1
command = (command << 1) | 0x01;
// Oczekuje na zbocze opadające sygnału w środku bitu.
// Jeśli nie wykryje zbocza w ciągu 5/4 czasu trwania
// bitu, to kończy działanie funkcji z błędem
while (RC5_IN)
if (timerL > ref2)
return command = -1;
}
// W momencie wykrycia zbocza sygnału, synchronizuje
// zmieną timerL dla próbkowania kolejnego bitu
timerL = 0;
}
// Zwraca kod polecenia rc5
// bity 0..5 numer przycisku
// bity 6..10 kod systemu(urządzenia)
// bit 11 toggle bit
return command;
}
//---------------------------------------------------------------
// GLÓWNA FUNKCJA PROGRAMU
//---------------------------------------------------------------
int main(void) {
uint cmd;
u8 out;
// Konfiguracja portów Atmega8
// serwo podpiete pod pin PB1(OC1A), a mostek H, czyli silniki do pinów PC4 PC5
DDRD = 0x7f;
PORTD = 0x00;
DDRB |= (1 << 1);
PORTB |= (1 << 1);
DDRC = 0xFF;
PORTC = 0x00;
// Konfiguracja timera do obsługi serwomechanizmu
int wypelnienie = 1500;
TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11); //tryb pracy licznika(15), ustawienie prescalera na 8,
TCCR1B = (1 << CS11) | (1 << WGM12) | (1 << WGM13);
ICR1 = 20000; //ustawienie okresu na 20ms(czestotliwosc 50Mz)
// uruchamia Timer0 i przerwanie
init_rc5();
while (1) {
OCR1A = wypelnienie; //określenie czasu impylsu
// Wykrywa i dekoduje polecenie pilota RC5
cmd = detect();
// Jeśli odebrano komendę
if (cmd != -1) {
// skrec w lewo
if (cmd == 3) {
_delay_ms(80);
wypelnienie += 100;
}
// skrec w prawo
else if (cmd == 5) {
_delay_ms(80);
wypelnienie -= 100;
_delay_ms(80);
// jedz do przodu
} else if (cmd == 2) {
_delay_ms(100);
PORTC |= (1 << PC5);
_delay_ms(100 );
PORTC = 0x00;
}
// jedz do tylu
else if (cmd == 4) {
_delay_ms(80);
PORTC |= (1 << PC4);
}
// inaczej - pozostaw serwo w pozycji 0 i ustaw portC na 0
else {
wypelnienie = 1500;
PORTC = 0x00;
}
}
}
return 0;
}