Skocz do zawartości

Zdobądź Proxxona FBS 240/E - #4 - Uniwersalna funkcja


Pomocna odpowiedź

html_mig_img
Zgodnie z rozpoczętym cyklem pora na kolejne zadanie. Stawka jest wysoka, bo do rozdania mam jeszcze 9  Proxxonów FBS 240/E.Dziś rusza następne zadanie, czyli okazja do zdobycia kolejnej szlifierko-wiertarki!

UWAGA, to tylko wstęp! Dalsza część artykułu dostępna jest na blogu.

Przeczytaj całość »

Poniżej znajdują się komentarze powiązane z tym wpisem.

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Treker, myślę, że tak. Generalnie wszystkie biblioteki arduino praktycznie są napisane typowo jako kasy - servo, stepper, serial. Napisałem ostatnio np. klasę do obsługi średniej kroczącej (zero sprzętu), wtedy po zaincludowaniu pliku .h kod wygląda tak:

deklaracja:

SMA average(L); //konstruujemy obiekt klasy SMA, parametrem konstruktora jest ilość próbek średniej

używanie:

average.add(probka); //dodajemy próbkę do bufora, reszta zostaje automatycznie przesunięta
zmienna = average.get(); //odczytujemy średnią z ostatnich L próbek

Sama średnia obsługuje na razie tylko twory mojej innej klasy, Cartesian, która to przechowuje współrzędne w układzie kartezjańskim, ale nic nie stoi na przeszkodzie, by oprzeć klasę o szablon - wtedy będzie mogła liczyć średnią z dowolnych zmiennych. Właśnie obiektowość w Arduino jest świetna - tak mi teraz przemknęło przez myśl, by napisać może jakiś odcinek kursu arduino o klasach właśnie. Pozwala to na nieporównywalnie prostszą względem czystego C skalowalność kody, staje się on też prostszy w wykorzystaniu na inne platformy (jeśli tylko znajdzie się dla nich kompilator C++, na przykład STMy).

Link do komentarza
Share on other sites

Chciałbym Wam przedstawić funkcję do obsługi przycisku (ang. switch) w przerwaniu INT0 na pinie PD2 portu D mikrokontrolera AVR firmy ATMEL ATmega8. Kod źródłowy napisany jest w języku C dla 8-bitowych mikrokontrolerów AVR. Podstawowe informacje o tym mikrokontrolerze można znaleźć w jego nocie katalogowej (ang. datasheet) wpisując w przeglądarkę internetową frazę "ATmega8 datasheet".

 

Takie rozwiązanie pozwala na użycie tegoż przycisku jako przycisk ON/OFF naszego robota lub innego urządzenia 🙂

 

Przedstawię teraz konfigurację przycisku i zmiennej globalnej do obsługi przerwania:

// Definiujemy przycisk, który znajduje się na pinie 2 portu D, czyli PD2.
#define Przycisk_PIN (1<<PD2)
#define Przycisk (PIND & Przycisk_PIN)

volatile int jazda = 0;

 

Teraz przechodzimy do "Głównej funkcji programu" i ustawiamy pin PD2 jako wejście, ponieważ będzie on odbierał sygnały, które "wygeneruje" przycisk (stan bliski VCC (+5V), czyli logiczna jedynka (1) lub stany bliskie GND, czyli logiczne zero (0)). Musimy też pamiętać, że aby korzystać z przerwań musimy włączyć globalne przerwania --> sei();

//--- Główna funkcja programu ---
int main(void) {
DDRD &= ~Przycisk_PIN;		// Wejcie - Przycisk
PORTD |= Przycisk_PIN;		// Pull-Up wewnętrzny (rezystor podciągający do VCC, dlatego nie trzeba stosować fizycznego rezystora podciągającego)

sei();						// Włączenie globalnych przerwań
}

 

Przejdźmy teraz do obsługi przerwania INT0 na pinie PD2:

//--- Obsługa przerwania z INT0 ---
ISR(INT0_vect) {

GICR &= ~(1<<INT0);	// Wyłączamy obsługę przerwania na PD2 - drgania styków spowodowałyby wielokrotne jego wywołanie

jazda ^= 1;			// Zmieniamy stan flagi

GICR |= (1<<INT0);	// Włączamy z powrotem obsługę przerwania
}

 

Jeszcze napiszemy uproszczony kod źródłowy do obsługi tego przerwania:

// --- Pętla nieskończona programu ---
while(1) {

		if(jazda) {     	// Sprawdzamy czy "jazda" jest 1-ką lub 0-em
		_delay_ms(50);		// Eliminacja drgania styków
		if(jazda) {
			LED1_ON;     	// Dioda LED świeci
		}else{
			LED1_OFF;     	// Dioda LED nie świeci
		}
		}
}

 

Drgań styków możemy się jeszcze pozbyć sprzętowo, przez realizację podłączenia przycisku do mikrokontrolera. Mianowicie przez użycie odpowiednich rezystorów jak i kondensatorów - na Forum było to omawiane wiele razy (a nawet w #3 odsłonie tego konkursu).

 

Mam nadzieję, że ta prosta funkcja do obsługi przycisku w przerwaniu jako przycisk ON/OFF pozwoli wielu początkującym okiełznanie swojego robota 🙂

 

Pozdrawiam, Adam (aixI).

Link do komentarza
Share on other sites

W sumie jakby się tak dobrze zastanowić, to jeżeli mają to być jakieś dobre, pomocne funkcje, które mają nauczać początkujących i wpajać im od samego początku dobre nawyki, to jest to prawdą, że jednak nie powinno się stosować "delay'a" w przerwaniu - sam wiem, że się go tam nie powinno stosować, ale niestety nie usprawiedliwia mnie to. Poprawiłem i ustawiłem autodel.

Pozdrawiam,

Link do komentarza
Share on other sites

Nie chcę być namolny, ale usuwając tego delay'a i nie zastępując go inną metodą eliminacji drgań styków (a są takie 😉 ), problemu wcale się do końca nie pozbywasz. Owszem, kod staje się nieco poprawniejszy, ale inny problem powraca.

Link do komentarza
Share on other sites

Bobby, ok w takim razie dopuszczam również takie rozwiązania.

aixI, zwracam też uwagę, że to rozwiązanie nie do końca jest funkcją. Jest to kilka "rozrzuconych" kawałków kodu. Oczywiście rozumiem, że tutaj inaczej ciężko byłoby to rozwiązać, ale proszę, aby wszyscy pamiętali, że należy ograniczać takie rozdrabnianie.

aixI, piotreks-89, nie wygaszajcie postów, niech zostaną widoczne dla wszystkich.

Link do komentarza
Share on other sites

int8_t uchyb(uint8_t pomiary[], uint8_t czujniki, uint8_t prog)
{
static int8_t wagi[8];						//tablica zawierajaca wagi poszczególnych czujników
if (wagi[0] == 0)							//wyliczenie wag czujników przy pierwszym wywołaniu funkcji
{
	for (uint8_t i=0; i<(czujniki/2); i++)
	{
		wagi[i] = 1 << ((czujniki / 2) - i);
		wagi[czujniki-i-1] = -wagi[i];
	}
}

int8_t uchyb = 0;
uint8_t ile = 0;
for (uint8_t i=0; i<czujniki; i++)
{
	if (pomiary[i] < prog)					//kierunek znaku nierówności zależy od reakcji czujnika na kolor podłoża
	{										// < dla sytuacji gdy linia daje niskie wartości z ADC
		uchyb += wagi[i];					// > dla sytuacji gdy linia daje wysokie wartości z ADC
		ile++;
	}
}
if (ile>1)
	uchyb /= ile;
return uchyb;
}

Funkcja zwraca wartość uchybu dla regulatora P(ID) na podstawie tablicy z wartościami z przetwornika ADC.

Argumentu funkcji:

1. nazwa tablicy z pomiarami z ADC

2. liczba czujników

4. próg rozpoznawania kolorów

przyjąłem 2 założenia: 8-bitowy odczyt ADC i max. 8 czujników

Podaję też cały program wykorzystujący tę funkcję, a także z kodem do generowania tablicy z pomiarami ADC w przerwaniach.

Poniższy kod jest przeznaczony dla mikrokontrolerów ATmega innych niż: ATmega8, ATmega8A, ATmega128, ATmega406. Z oczywistych względów nie będzie działał tez na mikrokontrolerach, które nie są wyposażone w ADC.

#include <avr/io.h>
#include <avr/interrupt.h>

#define SENSORS	8		//liczba czujników [max. 8]

volatile uint8_t reading[SENSORS];   //tablica przechowująca odczyty ADC

void Init_ADC();
uint8_t potega(uint8_t podstawa, uint8_t wykladnik);
int8_t uchyb(uint8_t pomiary[], uint8_t czujniki, uint8_t prog);

int main(void)
{
Init_ADC();
int8_t error;
while (1)
{
	error = uchyb(reading, SENSORS, 128);
}
}

void Init_ADC()
{
ADMUX |= (1<<REFS0);				//VCC jako napięcie odniesienia z pinem AREF podłączonym do GND przez kondensator
ADMUX |= (1<<ADLAR);				//przesunięcie wyniku do lewej -> 8-bitowy odczyt wyniku
ADCSRA |= (1<<ADPS2) | (1<<ADPS1);	//prescaler = 64 -> przy 16MHz daje to 250kHz dla ADC
ADCSRA |= (1<<ADIE);				//włączenie przerwań od ADC
ADCSRA |= (1<<ADEN);				//włączenie przetwornika ADC
ADCSRA |= (1<<ADSC);				//start konwersji
sei();								//globalne zezwolenie na przerwania
}

ISR(ADC_vect)
{
static uint8_t i;					//
reading[i] = ADCH;
i++;
i%=SENSORS;
ADMUX = (ADMUX & 0b11111000) | i;
ADCSRA |= (1<<ADSC);
}

int8_t uchyb(uint8_t pomiary[], uint8_t czujniki, uint8_t prog)
{
static int8_t wagi[8];						//tablica zawierajaca wagi poszczególnych czujników
if (wagi[0] == 0)							//wyliczenie wag czujników przy pierwszym wywołaniu funkcji
{
	for (uint8_t i=0; i<(czujniki/2); i++)
	{
		wagi[i] = 1 << ((czujniki / 2) - i);
		wagi[czujniki-i-1] = -wagi[i];
	}
}

int8_t uchyb = 0;
uint8_t ile = 0;
for (uint8_t i=0; i<czujniki; i++)
{
	if (pomiary[i] < prog)					//kierunek znaku nierówności zależy od reakcji czujnika na kolor podłoża
	{										// < dla sytuacji gdy linia daje niskie wartości z ADC
		uchyb += wagi[i];					// > dla sytuacji gdy linia daje wysokie wartości z ADC
		ile++;
	}
}
if (ile>1)
	uchyb /= ile;
return uchyb;
}

@Edit 14-07-2015: poprawiłem potęgowanie ze znaku ^, który w języku C jest operacją XOR, na przesunięcie bitowe. Podziękowania dla Elvisa za wyłapanie błędu i propozycję rozwiązania.

Ja zaproponowałem funkcję liczącą potęgę jednak rozwiązanie Elvisa jest dużo prostsze.

uint8_t potega(uint8_t podstawa, uint8_t wykladnik)
{
if (wykladnik == 0)
	return 1;
else 
	return podstawa * potega(podstawa, (wykladnik - 1));
}

Warto zwrócić uwagę, że ta funkcja przyjmuje i zwraca zmienne 8-bitowe bez znaku, czyli wartości 0-255. Tak jak wykorzystana jest ona w funkcji głównej będzie działać poprawnie dla maks. 15 czujników.

Link do komentarza
Share on other sites

Hudyvolt, zamiast ciągle uruchamiać od nowa konwersję:

ADCSRA |= (1<<ADSC);

Można ustawić przetwornik w tryb 'Free run' (podczas jego inicjalizacji) poprzez ustawienie bitu 'ADFR', w taki sposób:

ADCSRA |= (1<<ADFR);
Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.