Ta strona używa ciasteczek (cookies), dzięki którym możliwe jest między innymi poprawne wyświetlanie elementów strony, zapamiętywanie sesji użytkowników. Dodatkowo na stronie znajduje się skrypt Google Analytics oraz PIWIK (statystyki oglądalności). Znajdują się również skrypty przycisków serwisów społecznościowych Facebook, Twitter i Google+ oraz YouTube, które również mogą zapisywać ciasteczka.

Sterownik oświetlenia do kuchni

Jedną z prostszych rzeczy jaką mogłem zbudować aby pokazać że nauka nie idzie w las, był sterownik oświetlenia w kuchni. Nie tego głównego znajdującego się na suficie, ale dodatkowego które mam zamontowane pod szafkami. W moim przypadku są to dwie taśmy LED, plus trzecia zamontowana w witrynie. Pomysł na sterownik powstał też z chęci wprowadzenia odrobiny automatyzacji w mieszkaniu jak i dla wygody. Każdy kto zrywa się wcześnie rano i musi zapalić światło, wie jaki to ból dla oczu gdy od razu świeci ono pełną mocą. O wiele przyjemniej jest gdy światło powoli się rozjaśnia a nasze oczy mają czas na przystosowanie się. Druga sprawa to nie zawsze jest potrzeba włączania głównego światła. Czasami się przecież tylko wpada i wypada z kuchni. Nie wspominając już o tym ile to razy człowiek zapomni wyłączyć światło wychodząc z kuchni.

Tak więc padło na sterownik który by kontrolował załączanie i wyłączanie światła.

Główną zaletą sterownika miała być ciągła kontrola ruchu w pomieszczeniu. Dopóki czujka PIR wykrywa ruch, dopóty światło się nie wyłącza. A nie jak to mam miejsce w większości dostępnych układów, gdzie światło się pali przez określoną ilość czasu a potem gaśnie. Nie jest to mój autorski pomysł, ale kolegi który już jakiś czas temu taki sterownik zbudował i oprogramował w Bascomie. Teraz ja miałem zamiar zaimplementować tą funkcję w swoim sterowniku.

Od strony programistycznej nie ma wielkich wyzwań. Każdy kto opanował sterowanie diodami poprzez PWM, obsługę przycisków i wykorzystywanie timerów programowych powinien bez problemu poradzić sobie z napisaniem programu do obsługi sterownika. Przynajmniej w podstawowej funkcjonalności, czyli rozjaśniania i ściemniania światła.

Oczywiście zrobienie sterownika tylko z tą podstawową funkcją było by pójściem na łatwiznę. Dlatego dodałem obsługę przycisku którym mogę włączyć światło na dłuższy czas, bez względu na to czy czujnik PIR wykryje ruch czy też nie. Dodatkowo sterownik również kontroluje zapalanie się światła w witrynie. Ostatnią przydatną funkcją którą zawarłem w programie, to kontrola natężenia światła w pomieszczeniu. Jak jest jasno w kuchni to sterownik nie włączy automatycznie światła pod szafkami pomimo wykrytego ruchu.

Sam sterownik jest zbudowany w oparciu o mikrokontroler ATMega48. Elementem odpowiedzialnym za wykrywanie ruchu jest czujnik PIR HC_SR501, tani i ogólnie dostępny. Zasada działania czujnika jest banalnie prosta, w momencie wykrycia ruchu, na pinie wyjściowym HC_SR501 pojawia się stan wysoki. Można to wykorzystać do wyzwalania przerwania w mikrokontrolerze zboczem np narastającym. Kolejnym elementem mającym wpływ na działanie sterownika jest fototranzystor. Został wybrany tylko dlatego że taki miałem na stanie, akurat żadnego fotorezystora nie posiadałem. Do elementów sterujących można jeszcze dodać przycisk którym załącza się światło na dłuższy czas, oraz krańcówkę zamontowaną w witrynie. Jako elementy wykonawcze zostały użyte dwa popularne tranzystory BUZ11, odseparowane od mikrokontrolera transoptorami. W celu ułatwienia ustawiania progu czułości fototranzystora, wykorzystany został jeden wyświetlacz siedmiosegmentowy na którym jest prezentowana wartość pomiaru ADC.

Opiszę po krótce jak działa program i co robią funkcje umieszczone w pętli głównej. Pierwszą funkcją jest SuperDebounce() p.Kardasia, odpowiada ona za wejście w funkcję set_sensitivy_foto(), która to umożliwia ustawienie progu czułości fototranzystora. Funkcje które znajdują się w jedynym warunku "if" są bezpośrednio odpowiedzialne za kontrolę oświetlenia. Pierwsza dokonuje pomiaru ADC z fototranzystora i porównuje go z wartością zapisaną przez użytkownika. Wartość ta jest przechowywana w pamięci EEPROM więc nie ma potrzeby ustawiania jej po ewentualnym zaniku napięcia. Kolejne funkcje sprawdzają czy zmienne przekazywane jako ich argumenty, spełniają warunki zapisane w ciele funkcji. Nie będę teraz szczegółowo opisywał działania tych funkcji, zajęło by to za dużo miejsca. Dla zainteresowanych szczegółami, na końcu artykułu jest link do pobrania w którym są pliki main.c, common.c i common.h, gdzie zasady działania funkcji są dokładnie opisane w komentarzach.

Kodów proszę nie traktować jako wzorców do naśladowania i jako jedynych słusznych rozwiązań. Mam świadomość że mogłyby być napisane bardziej optymalnie, z wykorzystaniem zaawansowanych technik programowania. Podobnie sprawa ma się ze schematem układu sterownika. On również powstał w oparciu o stan mojej wiedzy w tym zakresie w czasie gdy go budowałem.

Proszę również mieć na uwadze to, że nie biorę odpowiedzialności za niepoprawne działanie programu i sterownika, który powstał pod konkretne warunki w mojej kuchni.

 

Sterownik_LED_PWM1
 * main.c
 *
 *  Created on: 1 sty 2014
 *      Author: Marcin Gibas
 *
 *  Sterownik oświetlenia LED. ATmega48P, zewnętrzny kwarc 8 MHz, czujnik PIR HC_SR501,
 *  fototranzystor L53P3C. Sterownik posiada możliwość regulacji czułości fototranzystora
 *  w celu ustawienia właściwego progu załączania światła.
 */

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "common.h"

int main(void){

	_delay_ms(4000);			/* zwłoka mająca na celu przeczekanie aż stan na pinie do którego jest podłączony czujnik PIR
								* osiągnie stan niski, ma to znaczenie dlatego że przerwanie z czujnika reaguje na zbocze narastające
								* na pinie i od razu ustawia sprzętową flagę przerwania, co w tej wersji oprogramowania
								* jest niepożądane, ze względu na warunki w funkcjach sprawdzającyh zarówno czujnik PIR jak i fototranzystor */

	// konfiguracja zewnętrznego przerwania na INT0 (czujnik PIR)
	DDR_PIR &= ~( PIR );					// kierunek - wejście
	EICRA |= (1 << ISC01 | 1 << ISC00);		// wyzwalanie przerwania zboczem narastającym na pinie INT0
	EIMSK |= (1 << INT0);					// odblokowanie przerwania na pinie INT0
	PORT_PIR &= ~( PIR );					// ustawienie stanu niskiego na pinie
	// koniec konfiguracji zewnętrznego przerwania na INT0

	// konfiguracja diody sygnalizującej pracę Timera zliczającego czas
	DDR_LED_TIMER |= ( LED_TIMER );			// kierunek - wyjście
	PORT_LED_TIMER &= ~( LED_TIMER );		// ustawienie stanu niskiego na pinie

	// konfiguracja diody sygnalizującej wystąpienie przerwania na INT0
	DDR_LED_INT0 |= ( LED_INT0 );			// kierunek - wyjście
	PORT_LED_INT0 &= ~( LED_INT0 );			// ustawienie stanu niskiego na pinie

	// konfiguracja wyświetlacza 7LED
	DDR_7LED_A |= ( A_7LED );					// kierunek - wyjście
	PORT_7LED_A |= ( A_7LED );					// ustawienie stanu wysokiego na pinie

	DDR_7LED_K |= (SEG_A | SEG_B | SEG_C);							// kierunek - wyjście
	DDR_7LED_K1 |= (SEG_D | SEG_E | SEG_F | SEG_G | SEG_DP);		// kierunek - wyjście
	PORT_7LED_K |= (SEG_A | SEG_B | SEG_C);							// ustawienie stanu wysokiego (segmenty wyłączone)
	PORT_7LED_K1 |= (SEG_D | SEG_E | SEG_F | SEG_G | SEG_DP);		// ustawienie stanu wysokiego (segmenty wyłączone)

	// konfiguracja wyjść do których są podłączone lampy pod szafkami oraz witryna
	DDR_LAMP |= (LAMP);		// kierunek - wyjście
	PORT_LAMP &= ~(LAMP);		// ustawienie stanu niskiego na pinie

	DDR_LAMP_W |= (W_LAMP);		// kierunek - wyjście
	PORT_LAMP_W &= ~(W_LAMP);		// ustawienie stanu niskiego na pinie

	// konfigurowanie przycisków
	DDR_KEY &= ~( KEY | KEY_S1 | KEY_S2 | W_KEY_OPEN | W_KEY_CLOSE);		// kierunek - wejście
	PORT_KEY |= ( KEY | KEY_S1 | KEY_S2 | W_KEY_OPEN | W_KEY_CLOSE);		// podciągnięcie pinu pod VCC

	// inicjalizacja przetwornika ADC
	ADCSRA |= (1 << ADEN);						// włączenie ADC
	ADCSRA |= (1 << ADPS2 | 1 << ADPS1);		// ustawienie preskalera (64)
	ADMUX |= (1 << REFS0 );						// ustawienie napięcia odniesienia na napięcie zasilania
	// koniec inicjalizacji przetwornika ADC

	// konfiguracja Timera0 używanego do zliczania czasu z rozdzielczością 10 ms
	TCCR0A |= (1 << WGM01);					// tryb CTC
	TCCR0B |= (1 << CS02 | 1 << CS00);		// prerskaler 1024
	OCR0A = 77;								// podział przez 77 (8000000 Hz / 1024 / 100 Hz) -1 = 10 ms
	TIMSK0 |= (1 << OCIE0A);				// zezwolenie na przerwanie Compare Match (A)
	// koniec konfiguracji Timera0

	// konfiguracja Timera1 używanego do PWM
	TCCR1A |= (1 << WGM10);				// tryb FastPWM 8-bit
	TCCR1B |= (1 << WGM12);				// tryb FastPWM 8-bit
	TCCR1B |= (1 << CS11);				// preskaler = 8 , częstotliwość 3,9kHZ  (częstotliwość zegara/preskaler/kroki = częstotliwość PWM)
	TCCR1A |= (1 << COM1A1);				// ustawienie bitu odpowiedzialnego za uaktywnienie PWM na wyjściu OCR1A
	TCCR1A |= (1 << COM1B1);
	OCR1A = light;						// przypisanie zmiennej "light" do pinu OCR1A (PWM)
	OCR1B = w_light;					// przypisanie zmiennej "w_light" do pinu OCR1B (PWM)

	/* koniec konfiguracji Timera1 PWM, w powyższej konfiguracji nie został ustawiony bit COM1B1 w rejestrze TCCR1A,
	 * jest on ustawiany w funkcji obsługującej załączanie światła w witrynie */

	// konfiguracja Timera2 uzywane do zliczania czasu z rozdzielczością 20 ms
	TCCR2A |= (1 << WGM21);								// tryb CTC
	TCCR2B |= (1 << CS22 | 1 << CS21 | 1 << CS20); 		// preskaler 1024
	OCR2A = 155;										// podział przez 155 (8000000 Hz / 1024 / 50 Hz) - 1 = 20ms
	TIMSK2 |= (1 << OCIE2A); 							// zezwolenie na przerwanie Compare Match (A)

	int0_flag = 0;	// wyzerowanie flagi przerwania zewnętrznego

	check_eeprom();	// sprawdzenie czy EEPROM jest pusty czy też zapisany

	_delay_ms(1000);		// musi być !!!

	sei();			// zezwolenie na globalne przerwania

	// pętla główna programu
	while(1)
	{
		SuperDebounce(&key_lock_s1,&PIND,KEY_S1,0,300,NULL,&enter_setup);

		set_sensitivy_foto(&setup, &set_foto);

		if (!setup){

			check_foto(&set_foto);

			light_ready(&int0_flag, &light, &dark);
	
			lamp_on(&int0_flag, &light, &time_off);

			lamp_off(&time_off, &light);

			w_lamp_on(&w_light);

			w_lamp_off(&w_light);

			key_press(&key_lock, &PIND, KEY);

			long_light(&key_cnt, &light);
	
			window_key(&key_lock_open, &key_lock_close, &PIND, W_KEY_OPEN, W_KEY_CLOSE);
		}

	}
}

// Przerwanie zewnętrzne INT0
ISR(INT0_vect)
{
	int0_flag = 1;			// ustawienie programowej flagi przerwania zewnętrzngo
}

// Przerwanie od Timera0 co 10ms
ISR(TIMER0_COMPA_vect)
{
	ms_timer = TIMER;
	if (ms_timer)
	{
		TIMER = -- ms_timer;
	}

	// licznik czasu korzystający z Timera0
	ms_cnt ++;						// inkrementowanie zmiennej milisekund przy każdym wykonaniu przerwania, czyli co 10ms
	if (ms_cnt >= 99)				// jeżli zmienna milisekund osiągnie wartość 99, oznacza to że minęło 1000ms, czyli 1s
	{
		LED_TIMER_TOG;				// zmiana stanu diody co 1s
		sec_cnt ++;					// inkremenbtowanie zmiennej sekundowej
		ms_cnt = 0;					// zerowanie zmiennej milisekund w celu ponownego zliczania do 99
		if (sec_cnt >= 59)			// jeżli zmienna sekundowa osiągnie wartość 59, oznacza to że minęła 1 minuta
		{
			min_cnt ++;				// inkrementowanie zmiennej minutowej
			sec_cnt = 0;			// zerowanie zmiennej sekundowej w celu ponownego zliczania sekund do 59
			ms_cnt = 0;				// zerowanie zmiennej milisekund w celu ponownego zliczania milisekund do 99
			if (min_cnt >= 59)		// jeżli zmienna minutowa osiągnie wartość 59, czyli minęła godzina zerowane są wszystkie zmienne zliczające czas
			{
				ms_cnt = 0;
				sec_cnt = 0;
				min_cnt = 0;
			}
		}
	}
}

// Przerwanie od Timera2 co 20ms
ISR(TIMER2_COMPA_vect)
{
	ms_timer = TIMER1;
	if (ms_timer)
	{
		TIMER1 = -- ms_timer;
	}

	ms_timer = TIMER2;
	if (ms_timer)
	{
		TIMER2 = -- ms_timer;
	}
}

E-mail

Dodaj komentarz


Kod antyspamowy
Odśwież