sterowanie przez podczerwień

To forum jest dla wszystkich pasjonatów mikrokontrolerów AVR Atmela. Wymiana doświadczeń i pomoc dla początkujących w pisaniu programów zarówno w C, Asemblerze jak i BASCOM. Zapraszam znawców tematu, aby pomogli wszystkim początkującym!
ODPOWIEDZ
maxxxior
Użytkownik
Posty: 210
Rejestracja: 19 mar 2010, 21:27
Lokalizacja: Skierniewice

sterowanie przez podczerwień

Post autor: maxxxior » 05 gru 2012, 19:13

Witam, poniżej wklejam swój program i opiszę o co mi chodzi. Za pomocą tego programu chcę sterować pojazdem (pojazd na atmega32 + mostekH + 2silniki DC + serwomechanizm do skręcania) Jest to program odbiornika, czyli pojazdu. I teraz, jak wyślę komendę 3 to serwo skręca w lewo, jest ok, jak wcisnę na pilocie przycisk 2 to silnik kręci sie do przodu- jest OK. Tylko, nawet jak puszczę przycisk, to silnik kręci się dalej. Chcę zrobić tak, aby silnik kręcił się tylko wtedy kiedy trzymam przycisk. Jak to zrealizować? ma ktoś jakiś pomysł?

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;
}

Awatar użytkownika
kayron
Użytkownik
Posty: 2088
Rejestracja: 21 wrz 2008, 12:53
Lokalizacja: Poland
Kontakt:

Post autor: kayron » 05 gru 2012, 19:25

Musisz śledzić bit Toggle komendy z pilota, ale szczerze nigdy tego nie używałem, i nie bardzo rozumiem jego działanie, chyba jak jest ustawiony na 1, to znaczy że przycisk w pilocie jest przytrzymany.

maxxxior
Użytkownik
Posty: 210
Rejestracja: 19 mar 2010, 21:27
Lokalizacja: Skierniewice

Post autor: maxxxior » 05 gru 2012, 19:53

tzn, bit toggle zmienia swoją wartość na przeciwną za każdym razem naciśnięcia przycisku kombinowałem teraz trochę z tym bitem toggle, lecz nic nie udało mi się zrobić...

Awatar użytkownika
tom5555
Użytkownik
Posty: 625
Rejestracja: 23 sty 2008, 1:20
Lokalizacja: Zabrze
Kontakt:

Post autor: tom5555 » 05 gru 2012, 22:13

Nie siedzę w C, ale myślę że trzeba to zrobić tak: to co dałeś w "else" wyrzuć jeden poziom wyżej, tzn. jeżeli odebrano komendę to wykonuje się kod programu po "if (cmd != -1) { ", a jeżeli nie odebrano komendy to serwo na zero i port C=0.

maxxxior
Użytkownik
Posty: 210
Rejestracja: 19 mar 2010, 21:27
Lokalizacja: Skierniewice

Post autor: maxxxior » 05 gru 2012, 22:21

ok, zrobiłem tak, i mniej więcej działa:

Kod: Zaznacz cały

while (1) {
		OCR1A = wypelnienie; //określenie czasu impylsu

		// Wykrywa i dekoduje polecenie pilota RC5
		cmd = detect();
		PORTC = 0x00;
		wypelnienie = 1500;
		// Jeśli odebrano komendę
		if (cmd != -1) {

			// skrec w lewo
			if (cmd == 3) {

				wypelnienie += 300;

			}
			// skrec w prawo
			else if (cmd == 5) {

				wypelnienie -= 300;

				// jedz do przodu
			} else if (cmd == 2) {

				PORTC |= (1 << PC5);

			}
			// jedz do tylu
			else if (cmd == 4) {

				PORTC |= (1 << PC4);

			}

		}
	}
silnik się kręci TYLKO wtedy jeśli trzymam silnik, gorzej z serwem, bo przechyla się tylko o określony kąt. Wiem dlaczego tak się dzieje, ale myślę że z tym już sobie poradzę...

ODPOWIEDZ