pl:avrc:mp:mp0
Differences
This shows you the differences between two versions of the page.
pl:avrc:mp:mp0 [2012/09/29 13:39] – created mkucia | pl:avrc:mp:mp0 [2012/11/17 20:06] (current) – mkucia | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ====== Zamek szyfrowy z tarczą telefoniczną ====== | ||
+ | |||
+ | |||
+ | Projekt ten ma na celu pokazanie jak powinno się realizować mały projekt. | ||
+ | |||
+ | ====== Założenia ====== | ||
+ | Bardzo ważna jeżeli nie najważniejsza część, zauważyłem że bardzo często wręcz pomijana przez kolegów. Jak można pracować nie wiedząc o się chce zrobić? W założeniach powinny się znaleźć: | ||
+ | * Cel | ||
+ | * Wymagania | ||
+ | * Dostępne środki (koszty i czas) | ||
+ | Wypisując założenia warto zaczynać od najważniejszych zagadnień. Planując projekt trzeba pamiętać o własnych umiejętnościach, | ||
+ | |||
+ | W moim przypadku założenia wyglądają tak: | ||
+ | | ||
+ | * Chcę zrealizować zamek szyfrowy | ||
+ | * Wprowadzanie kombinacji jest realizowane za pomocą tarczy telefonicznej | ||
+ | * Urządzenie powinno posiadać wyświetlacz | ||
+ | * Koszty: żadne: wykorzystanie dostępnych części, budowa na płytce prototypowej | ||
+ | * Czas wykonania: 2 dni | ||
+ | * Funkcja edukacyjna | ||
+ | |||
+ | ====== Projektowanie ====== | ||
+ | Kiedy już wiadomo co się chce zrobić trzeba zastanowić się jak to zrobić. | ||
+ | ===== Wyświetlacz ===== | ||
+ | Informacja o stanie w jakim znajduje się urządzenie będzie przekazywana za pomocą prostego wyświetlacza [[integra: | ||
+ | <code c>// Tablica znaków 7 seg | ||
+ | const char chartab[] = {252, | ||
+ | 62, | ||
+ | 0, | ||
+ | 2,114, | ||
+ | 8, | ||
+ | ===== Tarcza ===== | ||
+ | Tarcze telefoniczną dostałem od kolegi. Posiada ona 3 wyprowadzenia. Po odkręceniu tylnej obudowy ukazał się skomplikowany układ mechaniczny. Jeden z przewodów był przewodem wspólnym dla 2 styków. Tarcza generuje 2 sygnały: | ||
+ | * Impulsy wybieranego numeru | ||
+ | * Ciągły sygnał aktywny w momencie obracania się tarczy | ||
+ | |||
+ | Początkowo planowałem wykorzystanie obu sygnałów, jednak zrezygnowałem z drogiego ponieważ same impulsy wystarczą do poprawnego odczytu stanu tarczy. Elektrycznie przewód wspólny jest podłączony do dodatniej szyny zasilania natomiast przewód sygnału impulsów jest podciągnięty pod masę przez rezystor 10k. Zastosowałem również kondensator 100nF podłączony pomiędzy linią sygnału a masą w celu debouncingu styków tarczy. | ||
+ | ===== Stany ===== | ||
+ | Następnym krokiem jest zaprojektowanie zachowania programu, rozrysowałem stany w jakich może się znajdować program.\\ | ||
+ | {{: | ||
+ | Urządzenie po resecie i inicjalizacji peryferiów wchodzi do punktu Reset gdzie są zerowane wszystkie znaczące zmienne, wyświetlacz i dioda. Następnie urządzenie może znajdować się w stanach: | ||
+ | * Idle: stan bezczynności - na wyświetlaczu miga znak zachęty. | ||
+ | * Rotating - występuje w momencie obracania się tarczy, na wyświetlaczu pojawia się zliczana liczba | ||
+ | * Locked - po zliczeniu implulsów liczba zostaje wczytana | ||
+ | * Ridle - bezczynność ale z oczekiwaniem na kolejne cyfry kombinacji | ||
+ | * Locked pattern - wszystkie cyfry kombinacji zostały wprowadzone | ||
+ | * Fail - cyfry kombinacji nie zgadzają się z zaszytym wzorem | ||
+ | * Success - cyfry kombinacji zgadzają się z wzorem | ||
+ | Schemat pozwala zaplanować logiczne przejścia i możliwe stany urządzenia. | ||
+ | ====== Schemat ideowy ====== | ||
+ | {{: | ||
+ | Na schemacie nie zaznaczyłem kondensatorów na szynie zasilania. | ||
+ | ====== Program ====== | ||
+ | < | ||
+ | #include " | ||
+ | #include " | ||
+ | |||
+ | //PORTY | ||
+ | #define DISPP PORTC | ||
+ | #define DISPD DDRC | ||
+ | #define LED_DIR DDRD | ||
+ | #define LED PORTD | ||
+ | |||
+ | #define forever for(;;) | ||
+ | |||
+ | // Tablica znaków 7 seg | ||
+ | const char chartab[] = { 252, 144, 234, 186, 150, 62, 126, 152, 254, 190, 0, 2, | ||
+ | 114, 8, 128 + 8, 16 + 8 + 128, 32 + 8 + 16 + 128, 64 + 32 + 8 + 16 | ||
+ | + 128, 4 + 64 + 32 + 8 + 16 + 128 }; | ||
+ | |||
+ | //STAN | ||
+ | enum STATUS { | ||
+ | st_reset, | ||
+ | st_idle, | ||
+ | st_ridle, | ||
+ | st_rotating, | ||
+ | st_locked, | ||
+ | st_lockpattern, | ||
+ | st_fail, | ||
+ | st_success | ||
+ | }; | ||
+ | volatile enum STATUS status = st_reset; | ||
+ | |||
+ | //GLOBALS | ||
+ | const uint8_t codetab[6] = { 1, 2, 3, 4, 5, 6 }; | ||
+ | volatile uint8_t counter = 0; | ||
+ | uint8_t numpos = 0; | ||
+ | uint8_t numtab[6]; | ||
+ | |||
+ | //TIMER | ||
+ | volatile uint8_t divider = 0; | ||
+ | volatile uint8_t blinker = 0; | ||
+ | volatile uint8_t timeout = 0; | ||
+ | // | ||
+ | ISR(TIMER1_COMPA_vect) | ||
+ | { | ||
+ | if (divider++ == 10) | ||
+ | { | ||
+ | blinker ^= 1; | ||
+ | divider = 0; | ||
+ | } | ||
+ | |||
+ | if (timeout < 0xFF) | ||
+ | timeout++; | ||
+ | } | ||
+ | |||
+ | //INT | ||
+ | // | ||
+ | ISR (SIG_INTERRUPT1) | ||
+ | { | ||
+ | //Tylko w tych 3 stanach sygnał z tarczy jest oczekiwany | ||
+ | if ((status == st_rotating) || (status == st_idle) || (status == st_ridle)) | ||
+ | { | ||
+ | status = st_rotating; | ||
+ | timeout = 0; // resetujemy | ||
+ | counter++; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | int main() | ||
+ | { | ||
+ | int i; | ||
+ | |||
+ | //IO Settings | ||
+ | LED_DIR = (1 << 5) | (1 << 6); | ||
+ | LED = 0; | ||
+ | DISPD = 0xFF; | ||
+ | |||
+ | // | ||
+ | TCCR1B |= (1 << WGM12); // Timer1 w trybie CTC | ||
+ | TIMSK |= (1 << OCIE1A); // Włączam przerwanie CTC | ||
+ | OCR1A = 868; // Ustawiam wartość do porównania | ||
+ | TCCR1B |= ((1 << CS10) | (1 << CS12)); // Ustawiam preskaler Fcpu/1024 | ||
+ | |||
+ | //Tylko zbocze rosnące aktywuje INT1 | ||
+ | MCUCR |= (1 << ISC11) | (1 << ISC10); | ||
+ | |||
+ | // | ||
+ | sei(); | ||
+ | |||
+ | //Main loop | ||
+ | forever | ||
+ | { | ||
+ | switch (status) | ||
+ | { | ||
+ | case st_reset: | ||
+ | // | ||
+ | timeout = 0; | ||
+ | counter = 0; | ||
+ | numpos = 0; | ||
+ | LED &= ~((1 << 5) | (1 << 6)); | ||
+ | // | ||
+ | GICR |= (1 << INT1); | ||
+ | status = st_idle; | ||
+ | break; | ||
+ | |||
+ | case st_idle: | ||
+ | //nic sie nie dzieje | ||
+ | |||
+ | //prompt | ||
+ | DISPP = chartab[11 - ((blinker ? 1 : 0))]; | ||
+ | |||
+ | //tutaj można dopisać jakis kod do uspienia MCU dla oszczednosci energii | ||
+ | // | ||
+ | break; | ||
+ | |||
+ | case st_rotating: | ||
+ | // impulsy sa teraz zliczane przez przerwanie | ||
+ | |||
+ | // | ||
+ | DISPP = chartab[counter % 10]; | ||
+ | |||
+ | //nowych impulsow dawno nie bylo wiec numer jest wczytywany | ||
+ | if (timeout > 10) | ||
+ | status = st_locked; | ||
+ | break; | ||
+ | |||
+ | case st_locked: | ||
+ | //numer wpisany | ||
+ | numtab[numpos++] = counter; | ||
+ | counter = 0; | ||
+ | timeout = 0; | ||
+ | |||
+ | // | ||
+ | _delay_ms(150); | ||
+ | |||
+ | //Czy to juz wszystkie cyfry? | ||
+ | if (numpos >= 6) | ||
+ | status = st_lockpattern; | ||
+ | else | ||
+ | status = st_ridle; | ||
+ | |||
+ | break; | ||
+ | |||
+ | case st_ridle: | ||
+ | // | ||
+ | |||
+ | //Po pewnym czasie wyswietlacz zaczyna migać sygnalizujac uplywajacy czas | ||
+ | if ((timeout > 50) && (divider % 5)) | ||
+ | LED |= (1 << 5); | ||
+ | else | ||
+ | LED &= ~(1 << 5); | ||
+ | |||
+ | // | ||
+ | DISPP = chartab[12 + numpos]; | ||
+ | |||
+ | //jezeli za dlugo nie wpisujemy kodu to resetujemy wszystko | ||
+ | if (timeout > 100) | ||
+ | status = st_reset; | ||
+ | break; | ||
+ | |||
+ | case st_lockpattern: | ||
+ | //kod wpisany | ||
+ | |||
+ | // | ||
+ | GICR &= ~(1 << INT1); | ||
+ | |||
+ | _delay_ms(150); | ||
+ | |||
+ | status = st_success; | ||
+ | // | ||
+ | for (i = 0; i < 6; i++) | ||
+ | if (numtab[i] != codetab[i]) | ||
+ | { | ||
+ | status = st_fail; | ||
+ | break; | ||
+ | } | ||
+ | break; | ||
+ | DISPP = 0; | ||
+ | |||
+ | case st_fail: | ||
+ | // | ||
+ | |||
+ | //migam szybko czerwona dioda | ||
+ | if (divider % 5) | ||
+ | LED |= (1 << 5); | ||
+ | else | ||
+ | LED &= ~(1 << 5); | ||
+ | |||
+ | if (timeout > 50) | ||
+ | status = st_reset; | ||
+ | |||
+ | break; | ||
+ | |||
+ | case st_success: | ||
+ | //sukces | ||
+ | |||
+ | //migam zielona dioda | ||
+ | if (blinker == 0) | ||
+ | LED |= (1 << 6); | ||
+ | else | ||
+ | LED &= ~(1 << 6); | ||
+ | |||
+ | //tutaj mozna zalaczyc jakis przekaznik otwierajacy np drzwi | ||
+ | // | ||
+ | |||
+ | // | ||
+ | if (timeout > 100) | ||
+ | status = st_reset; | ||
+ | break; | ||
+ | |||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | </ | ||
+ | ====== Upgrade ====== | ||
+ | W projekcie można by zmienić kilka rzeczy. Po pierwsze zamek nie otwiera niczego, w kodzie jest komentarz w którym momencie można włączyć np. przekaźnik. Ponieważ zawieszenie się programu (które może zostać spowodowane np. zakłóceniami) spowodowałoby odcięcie możliwości otwarcia zatrzasku sterowanego przez ten zamek szyfrowy dobrym pomysłem byłoby zaimplementowanie [[integra: | ||