Programowanie AVR cz. 3: ATtiny2313, EEPROM AT24C04C i magistrala I2C. Oraz krótko o pewnej zapomnianej obietnicy.
000 wstęp
Głównym bohaterem tego posta jest magistrala I2C, zwana również interfejsem dwuprzewodowym (ang. Two-wire lub 2-wire interface). To proste łącze wykorzystywane jest w wielu ciekawych układach mogących współpracować z mikrokontrolerami i nie tylko. Można tu wspomnieć - żeby nie było, że użyłem słowa "wielu" bez pokrycia - choćby o układach pamięci, zegarach czasu rzeczywistego, przetwornikach AC/CA...
Co prawda "małe" mikrokontrolery nie mają dedykowanych linii dla I2C, ale dzięki środowiskom i bibliotekom dla programistów, zapewniającym pełną implementację m. in. protokołu I2C, mamy możliwość bezproblemowego wykorzystania dobrodziejstw tej magistrali posługując się uniwersalnymi liniami wejścia - wyjścia. Można też podjąć się samodzielnej implementacji obsługi tej magistrali - jeśli ktoś lubi takie wyzwania.
Na początek jednak warto przyjrzeć się samej idei i koncepcji magistrali I2C:
Dobrze by było też przeanalizować kartę katalogową układu AT24C04C (zakładam, że Tiny2313 już dość dobrze znamy):
Układ AT24C04C - jak sugeruje tytuł posta - to pamięć EEPROM. Nie jest to jednak kostka pamięci w klasycznym tego słowa rozumieniu, z wieloma liniami adresowymi i danych oraz liniami sterującymi - mówimy o tym układzie "pamięć szeregowa", ponieważ dostęp do jej zawartości uzyskujemy właśnie poprzez szeregową magistralę I2C. Taka konstrukcja pamięci pozwoliła przede wszystkim na zmniejszenie fizycznych rozmiarów układu do np. typowej kostki w obudowie DIP-8 (dwa rzędy po cztery wyprowadzenia), co sprzyja wykorzystaniu tego układu w małogabarytowych projektach.
Przy okazji przeglądania (analizy!) karty katalogowej AT24C04C, możemy się wiele dowiedzieć na temat samej magistrali, tym razem już konkretnie - głównie chodzi tu o protokół, sposób adresacji urządzeń itp. Ze względu zaś na prostotę operacji - bo w przypadku pamięci mamy wyłącznie zapis i odczyt bez dodatkowych czynności - AT24C04C jest rewelacyjnym środkiem dydaktycznym i znakomitym przykładem na początek przygody z naszą magistralą.
A dlaczego właśnie 24C04, a nie np. 24C08? Proste: taką kostkę akurat miałem...
No to zaczynamy!
001 przygotowanie układu
Trzeba pamiętać, że wiele układów cyfrowych przeznaczonych do współpracy z innymi układami za pomocą magistral, posiada wyjścia typu otwarty kolektor (otwarty dren). Żeby się nie rozpisywać - chodzi tutaj o "końcówkę mocy" wyjścia układu; jest ona niepełna, co daje możliwość dostosowania obciążenia układu w dużo większym zakresie, niż ma to miejsce w przypadku klasycznych wyjść cyfrowych. Dostosowanie obciążenia (to w pewnym sensie skrót myślowy - zainteresowanych odsyłam do literatury technicznej dotyczącej podstaw elektroniki) wykonuje się przy pomocy rezystorów podciągających, które stanowią uzupełnienie owego niekompletnego wyjścia układu. W przypadku I2C konieczne jest zastosowanie właśnie takich rezystorów dla obu linii (SCL i SDA); wartość tych rezystorów należy odpowiednio dobrać - w przypadku naszego układu będzie to 4,7kΩ. Oczywiście rezystor podciągający włączamy między zasilanie a linię magistrali. Dodatkowo linie I2C należy podłączyć do mikrokontrolera poprzez rezystory o wartości 300-330Ω.
Następnym krokiem w procesie przygotowania układu testowego jest ustalenie adresu sprzętowego dla kostki pamięci. Adresy urządzeń na magistrali I2C to liczby 7-bitowe. Ósmy bit (a w zasadzie pierwszy, bo na najmniej znaczącej pozycji) to znacznik kierunku transmisji - wartość "1" oznacza odczyt z urządzenia, "0" to zapis do urządzenia. Wynika z tego, że każde urządzenie ma dwa adresy 8-bitowe... Przeglądając dokumentację AT24C04 natkniemy się w którymś momencie właśnie na opis adresowania tego układu. Cztery najstarsze bity adresu 24C04 zawierają "zaszytą" sekwencję "1010", dalej brane są pod uwagę stany zadane na wyprowadzenia A2 i A1 układu (A0 jest ignorowane w przypadku 24C04), następnie mamy znacznik "banku" pamięci P0 i bit kierunku R/W. Co do znacznika banku pamięci - należy zwrócić uwagę, że układ 24C04 ma pojemność 4kb czyli 512B. Ponieważ przez magistralę I2C można przesyłać dane tylko w postaci paczek 8-bitowych, nie ma możliwości "płaskiego" adresowania całej zawartości pamięci - za pomocą liczby 8-bitowej jesteśmy w stanie zaadresować jedynie połowę zawartości tej pamięci, czyli 256B (24C04 ma organizację bajtową). Tutaj właśnie z pomocą przychodzi nam znacznik P0, który stanowi przełącznik dla owych połówek pamięci - np. dla P0=1 komórka pamięci o adresie 00h to tak naprawdę komórka o adresie 100h.
W naszym układzie testowym ustalamy wartość bitów A2 i A1 jako "0" (podłączamy do masy).
Jak się ostatecznie okazuje, nasz układ pamięci ma aż cztery adresy na magistrali I2C! Adresy te, już w postaci liczbowej dziesiętnej, znajdziecie w prezentowanym w dalszej części artykułu listingu programu.
Na koniec zerujemy wejście układu pamięci oznaczone jako WP (Write Protect), żeby zapewnić sobie możliwość swobodnego zapisu i odczytu.
Na poniższym schemacie widzimy już kompletny układ do testowania pamięci 24C04 i magistrali I2C:
Dodatkowo, w celu wizualizacji procesu poprawnego (lub nie) zapisu i odczytu pamięci, dołączyłem do układu testowego wyświetlacz LCD (na schemacie jest to wyświetlacz 16*2 - w rzeczywistości użyłem 16*1a) - klasyczny, na bazie układu kompatybilnego z HD44780 oraz dwie diody LED. Program (przedstawiony dalej) uruchamiany jest przyciskiem, który na schemacie widnieje pod postacią jumpera TEST J1 - tutaj też użyłem symbolu zastępczego (muszę uzupełnić biblioteki Eagle'a).
002 program
Żeby hardware był użyteczny, potrzebny jest software... Na listingu poniżej widnieje program testowy, którego zadaniem jest zapełnienie obu banków pamięci pewnymi wartościami (dla każdego banku jest to inna wartość), a następnie sprawdzenie, czy dane zostały prawidłowo zapisane - czyli odczytanie zawartości obu banków i porównanie liczby odczytanej z zakładaną wartością poprawną.
Polecam przeanalizowanie programu, ze szczególnym zwróceniem uwagi na to, jak elegancko zostały zaprojektowane funkcje BASCOMa operujące na magistrali I2C - odzwierciedlają one dość dokładnie "protokół" logiczny tej magistrali.
Należy zdać sobie sprawę, że sporą część kodu stanowią ozdobniki związane z wizualizacją operacji - stąd program po kompilacji zajmuje ok. 1,5kB. Same operacje komunikacji z I2C są tutaj w miarę lekkie.
Ktoś pomyśli: no ok, działa...
...ale jak sprawdzić, czy faktycznie? Bo każde następne uruchomienie spowoduje - w przypadku nieudanego zapisu - odczyt wcześniej zapisanych do pamięci danych, które są oczywiście poprawne. Sprawa jest prosta - trzeba przekompilować program z innymi wartościami Val_p0 i Val_p1. A jeśli ktoś chce sprawdzić, jak to jest z tymi rezystorami podciągającymi - zachęcam do wyjęcia jednego z nich (lub obu) w trakcie pracy układu. Efekty specjalne gwarantowane (spokojnie, jeśli nie zrobicie gdzieś jakiegoś zwarcia, nic się nie spali).
003 todo
Jeśli nic nie pomyliliśmy, to nasz układ do testowania I2C powinien działać bez problemów. Nie wiem, jak Wy, ale ja zwykle lubię troszkę podrążyć temat (sukces jest najlepszą zachętą) - proponuję więc przyjrzenie się układowi PCF8583P. Jest to zegar czasu rzeczywistego z kalendarzem - oczywiście obsługiwany poprzez I2C i umieszczony, podobnie jak AT24C04, w malutkiej obudowie ośmiowyprowadzeniowej. Podłączamy do niego oscylator (ok. 34kHz), kondensatorek 33pF, zapewniamy ciągły dostęp zasilania (można z baterii) i... Ale o tym być może wkrótce :) Zachęcam również do samodzielnych eksperymentów.
Postscriptum
Dawno temu obiecałem (tak, czego ja już na tym blogu nie obiecywałem...) program do przekształcenia ATtiny 2313 w układ sterowania linijką świetlną. Oto i on:
Jeżeli chodzi o elektronikę, do portu B mikrokontrolera podłączamy osiem diod LED poprzez rezystor 220Ω (podobnie jak na schemacie pokazanym wcześniej), zaś do wskazanych na listingu wyprowadzeń portu D - przyciski zwierające do masy. Do tego oczywiście oscylator 4MHz z dwoma kondensatorkami 33pF (również jak na wcześniejszym schemacie).
Po wgraniu programu można pobawić się efektami świetlnymi (proszę zwrócić uwagę, że efekt "spoczynkowy" jest generowany przez pracujący w tle timer, natomiast definicje efektów umieszczone są w wewnętrznej pamięci EEPROM mikrokontrolera).
Udanych eksperymentów zatem!
ERRATA czy też konieczny, acz zapomniany dopisek
Zagłębiając się w adresowanie układów na magistrali I2C i podłączanie ich do niej, zapomniałem o czymś, co wprawdzie łatwo można znaleźć w kodzie programu (pierwszy listing), ale co nie rzuca się specjalnie w oczy. A powinno.
Otóż jako wyjścia magistrali I2C mikrokontrolera ATtiny 2313 mogą zostać użyte dowolne dwie linie portów wejścia-wyjścia. U mnie, m. in. ze względu na konieczność podłączenia wyświetlacza, jako wyprowadzenia I2C "robią" linie (wyjścia) PORTB.1 (SCL) i PORTB.0 (SDA). Konfiguracji tych wyjść można dokonać z poziomu środowiska BASCOMa (Options -> Compiler -> I2C):
Dodatkowo zalecałbym wstawienie do kodu, przed deklaracjami zmiennych, dwóch linijek, których znaczenie jest to samo, jak powyższych ustawień środowiska dla I2C:
Głównym bohaterem tego posta jest magistrala I2C, zwana również interfejsem dwuprzewodowym (ang. Two-wire lub 2-wire interface). To proste łącze wykorzystywane jest w wielu ciekawych układach mogących współpracować z mikrokontrolerami i nie tylko. Można tu wspomnieć - żeby nie było, że użyłem słowa "wielu" bez pokrycia - choćby o układach pamięci, zegarach czasu rzeczywistego, przetwornikach AC/CA...
Co prawda "małe" mikrokontrolery nie mają dedykowanych linii dla I2C, ale dzięki środowiskom i bibliotekom dla programistów, zapewniającym pełną implementację m. in. protokołu I2C, mamy możliwość bezproblemowego wykorzystania dobrodziejstw tej magistrali posługując się uniwersalnymi liniami wejścia - wyjścia. Można też podjąć się samodzielnej implementacji obsługi tej magistrali - jeśli ktoś lubi takie wyzwania.
Na początek jednak warto przyjrzeć się samej idei i koncepcji magistrali I2C:
Dobrze by było też przeanalizować kartę katalogową układu AT24C04C (zakładam, że Tiny2313 już dość dobrze znamy):
Układ AT24C04C - jak sugeruje tytuł posta - to pamięć EEPROM. Nie jest to jednak kostka pamięci w klasycznym tego słowa rozumieniu, z wieloma liniami adresowymi i danych oraz liniami sterującymi - mówimy o tym układzie "pamięć szeregowa", ponieważ dostęp do jej zawartości uzyskujemy właśnie poprzez szeregową magistralę I2C. Taka konstrukcja pamięci pozwoliła przede wszystkim na zmniejszenie fizycznych rozmiarów układu do np. typowej kostki w obudowie DIP-8 (dwa rzędy po cztery wyprowadzenia), co sprzyja wykorzystaniu tego układu w małogabarytowych projektach.
Przy okazji przeglądania (analizy!) karty katalogowej AT24C04C, możemy się wiele dowiedzieć na temat samej magistrali, tym razem już konkretnie - głównie chodzi tu o protokół, sposób adresacji urządzeń itp. Ze względu zaś na prostotę operacji - bo w przypadku pamięci mamy wyłącznie zapis i odczyt bez dodatkowych czynności - AT24C04C jest rewelacyjnym środkiem dydaktycznym i znakomitym przykładem na początek przygody z naszą magistralą.
A dlaczego właśnie 24C04, a nie np. 24C08? Proste: taką kostkę akurat miałem...
No to zaczynamy!
001 przygotowanie układu
Trzeba pamiętać, że wiele układów cyfrowych przeznaczonych do współpracy z innymi układami za pomocą magistral, posiada wyjścia typu otwarty kolektor (otwarty dren). Żeby się nie rozpisywać - chodzi tutaj o "końcówkę mocy" wyjścia układu; jest ona niepełna, co daje możliwość dostosowania obciążenia układu w dużo większym zakresie, niż ma to miejsce w przypadku klasycznych wyjść cyfrowych. Dostosowanie obciążenia (to w pewnym sensie skrót myślowy - zainteresowanych odsyłam do literatury technicznej dotyczącej podstaw elektroniki) wykonuje się przy pomocy rezystorów podciągających, które stanowią uzupełnienie owego niekompletnego wyjścia układu. W przypadku I2C konieczne jest zastosowanie właśnie takich rezystorów dla obu linii (SCL i SDA); wartość tych rezystorów należy odpowiednio dobrać - w przypadku naszego układu będzie to 4,7kΩ. Oczywiście rezystor podciągający włączamy między zasilanie a linię magistrali. Dodatkowo linie I2C należy podłączyć do mikrokontrolera poprzez rezystory o wartości 300-330Ω.
Następnym krokiem w procesie przygotowania układu testowego jest ustalenie adresu sprzętowego dla kostki pamięci. Adresy urządzeń na magistrali I2C to liczby 7-bitowe. Ósmy bit (a w zasadzie pierwszy, bo na najmniej znaczącej pozycji) to znacznik kierunku transmisji - wartość "1" oznacza odczyt z urządzenia, "0" to zapis do urządzenia. Wynika z tego, że każde urządzenie ma dwa adresy 8-bitowe... Przeglądając dokumentację AT24C04 natkniemy się w którymś momencie właśnie na opis adresowania tego układu. Cztery najstarsze bity adresu 24C04 zawierają "zaszytą" sekwencję "1010", dalej brane są pod uwagę stany zadane na wyprowadzenia A2 i A1 układu (A0 jest ignorowane w przypadku 24C04), następnie mamy znacznik "banku" pamięci P0 i bit kierunku R/W. Co do znacznika banku pamięci - należy zwrócić uwagę, że układ 24C04 ma pojemność 4kb czyli 512B. Ponieważ przez magistralę I2C można przesyłać dane tylko w postaci paczek 8-bitowych, nie ma możliwości "płaskiego" adresowania całej zawartości pamięci - za pomocą liczby 8-bitowej jesteśmy w stanie zaadresować jedynie połowę zawartości tej pamięci, czyli 256B (24C04 ma organizację bajtową). Tutaj właśnie z pomocą przychodzi nam znacznik P0, który stanowi przełącznik dla owych połówek pamięci - np. dla P0=1 komórka pamięci o adresie 00h to tak naprawdę komórka o adresie 100h.
W naszym układzie testowym ustalamy wartość bitów A2 i A1 jako "0" (podłączamy do masy).
Jak się ostatecznie okazuje, nasz układ pamięci ma aż cztery adresy na magistrali I2C! Adresy te, już w postaci liczbowej dziesiętnej, znajdziecie w prezentowanym w dalszej części artykułu listingu programu.
Na koniec zerujemy wejście układu pamięci oznaczone jako WP (Write Protect), żeby zapewnić sobie możliwość swobodnego zapisu i odczytu.
Na poniższym schemacie widzimy już kompletny układ do testowania pamięci 24C04 i magistrali I2C:
Dodatkowo, w celu wizualizacji procesu poprawnego (lub nie) zapisu i odczytu pamięci, dołączyłem do układu testowego wyświetlacz LCD (na schemacie jest to wyświetlacz 16*2 - w rzeczywistości użyłem 16*1a) - klasyczny, na bazie układu kompatybilnego z HD44780 oraz dwie diody LED. Program (przedstawiony dalej) uruchamiany jest przyciskiem, który na schemacie widnieje pod postacią jumpera TEST J1 - tutaj też użyłem symbolu zastępczego (muszę uzupełnić biblioteki Eagle'a).
002 program
Żeby hardware był użyteczny, potrzebny jest software... Na listingu poniżej widnieje program testowy, którego zadaniem jest zapełnienie obu banków pamięci pewnymi wartościami (dla każdego banku jest to inna wartość), a następnie sprawdzenie, czy dane zostały prawidłowo zapisane - czyli odczytanie zawartości obu banków i porównanie liczby odczytanej z zakładaną wartością poprawną.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
' Obsługa pamięci EEPROM 24c04 | |
' - przykład + efekty specjalne | |
$regfile = "attiny2313.dat" | |
$crystal = 4000000 | |
$hwstack = 40 | |
$swstack = 16 | |
$framesize = 32 | |
' Liczby wpisywane do pamięci w banku 0 i 1 (bit P0 adresu urządzenia) | |
Const Val_p0 = 220 | |
Const Val_p1 = 225 | |
' Konfiguracja wyświetlacza | |
Config Lcd = 16 * 1a | |
' Porty mikrokontrolera (dwie linie portu B), które będą emulować wyprowadzenia magistrali I2C (mikrokontroler to MASTER) | |
Config Scl = Portb.1 | |
Config Sda = Portb.0 | |
' Do linii portu D podłączone są diody kontrolne oraz przycisk uruchamiający test zapisu i odczytu | |
Config Portd = &B1110111 | |
Portd = &B0001000 | |
' Pamięć 24c04 (SLAVE): | |
' - wyprowadzenia A2 i A1 podłączone do masy, stąd adresy jak niżej. | |
' Pierwsze 256 bajtów - bank 1 (bit P0 = 0) | |
Const Addrw_p0 = 160 | |
Const Addrr_p0 = 161 | |
' Drugie 256 bajtów - bank 2 (bit P0 = 1) | |
Const Addrw_p1 = 162 | |
Const Addrr_p1 = 163 | |
Dim Adres As Byte , Value As Byte | |
Dim Addrw As Byte , Addrr As Byte | |
Dim Tst_val As Byte | |
Declare Sub Write_eeprom(byval Adres As Byte , Byval Value As Byte) | |
Declare Sub Read_eeprom(byval Adres As Byte , Value As Byte) | |
Declare Sub Error | |
Declare Sub Read_bank_test(byval Bank_nr As Byte) | |
Declare Sub Write_bank_test(byval Bank_nr As Byte) | |
Portd.5 = 0 ' dioda czerwona | |
Portd.4 = 0 ' dioda niebieska | |
Portd.3 = 1 ' "przycisk" uruchamiający proces zapisu/odczytu | |
Cursor Off | |
Cls | |
Lcd "2404 test ready" | |
Do | |
If Pind.3 = 0 Then | |
'Zapis pierwszego banku pamięci (256 bajtów o wartości stałej Val_p0) | |
Write_bank_test 0 | |
Waitms 100 | |
'Zapis drugiego banku pamięci (256 bajtów o wartości stałej Val_p1) | |
Write_bank_test 1 | |
Cls | |
' Przerwa - sygnalizacja zmiany trybu testu na odczyt | |
For Adres = 0 To 2 | |
Waitms 50 | |
Portd.4 = 1 | |
Portd.5 = 1 | |
Waitms 50 | |
Portd.4 = 0 | |
Portd.5 = 0 | |
Next Adres | |
'Odczyt pierwszego banku pamięci | |
Read_bank_test 0 | |
Waitms 100 | |
'Odczyt drugiego banku pamięci | |
Read_bank_test 1 | |
Cls | |
Lcd "2404 test OK!" | |
Waitms 500 | |
Cls | |
Lcd "2404 test ready" | |
End If | |
Loop | |
End | |
' Zapis bajtu do pamięci 24c04 | |
Sub Write_eeprom(byval Adres As Byte , Byval Value As Byte) | |
Portd.4 = 1 | |
I2cstart | |
I2cwbyte Addrw | |
I2cwbyte Adres | |
I2cwbyte Value | |
I2cstop | |
Waitms 5 | |
Portd.4 = 0 | |
End Sub | |
' Odczyt bajtu z pamięci 24c04 | |
Sub Read_eeprom(byval Adres As Byte , Value As Byte) | |
Portd.4 = 1 | |
I2cstart | |
I2cwbyte Addrw | |
I2cwbyte Adres | |
I2cstart | |
I2cwbyte Addrr | |
I2crbyte Value , Nack | |
I2cstop | |
Waitms 5 | |
Portd.4 = 0 | |
End Sub | |
' Sygnalizacja błędu | |
Sub Error | |
Cls | |
Lcd "R/W error" | |
Portd.5 = 1 | |
Waitms 50 | |
Portd.5 = 0 | |
End Sub | |
' Podprogram odczytu i weryfikacji zawartości wskazanego banku pamięci | |
Sub Read_bank_test(byval Bank_nr As Byte) | |
If Bank_nr = 0 Then | |
Addrr = Addrr_p0 | |
Addrw = Addrw_p0 | |
Tst_val = Val_p0 | |
Else | |
Addrr = Addrr_p1 | |
Addrw = Addrw_p1 | |
Tst_val = Val_p1 | |
End If | |
Cls | |
Lcd "P0=" + Bank_nr + ",R,val=" + Tst_val | |
For Adres = 0 To 255 | |
Read_eeprom Adres , Value | |
Waitms 5 | |
If Value <> Tst_val Or Err <> 0 Then | |
Error | |
Cls | |
Lcd "P0=" + Bank_nr + ",R,val=" + Tst_val | |
End If | |
Next Adres | |
End Sub | |
' Podprogram zapisu zawartości wskazanego banku pamięci | |
Sub Write_bank_test(byval Bank_nr As Byte) | |
If Bank_nr = 0 Then | |
Addrw = Addrw_p0 | |
Tst_val = Val_p0 | |
Else | |
Addrw = Addrw_p1 | |
Tst_val = Val_p1 | |
End If | |
Cls | |
Lcd "P0=" + Bank_nr + ",W,val=" + Tst_val | |
For Adres = 0 To 255 | |
Write_eeprom Adres , Tst_val | |
Waitms 5 | |
If Err <> 0 Then | |
Error | |
Cls | |
Lcd "P0=" + Bank_nr + ",W,val=" + Tst_val | |
End If | |
Next Adres | |
End Sub |
Polecam przeanalizowanie programu, ze szczególnym zwróceniem uwagi na to, jak elegancko zostały zaprojektowane funkcje BASCOMa operujące na magistrali I2C - odzwierciedlają one dość dokładnie "protokół" logiczny tej magistrali.
Należy zdać sobie sprawę, że sporą część kodu stanowią ozdobniki związane z wizualizacją operacji - stąd program po kompilacji zajmuje ok. 1,5kB. Same operacje komunikacji z I2C są tutaj w miarę lekkie.
Ktoś pomyśli: no ok, działa...
...ale jak sprawdzić, czy faktycznie? Bo każde następne uruchomienie spowoduje - w przypadku nieudanego zapisu - odczyt wcześniej zapisanych do pamięci danych, które są oczywiście poprawne. Sprawa jest prosta - trzeba przekompilować program z innymi wartościami Val_p0 i Val_p1. A jeśli ktoś chce sprawdzić, jak to jest z tymi rezystorami podciągającymi - zachęcam do wyjęcia jednego z nich (lub obu) w trakcie pracy układu. Efekty specjalne gwarantowane (spokojnie, jeśli nie zrobicie gdzieś jakiegoś zwarcia, nic się nie spali).
003 todo
Jeśli nic nie pomyliliśmy, to nasz układ do testowania I2C powinien działać bez problemów. Nie wiem, jak Wy, ale ja zwykle lubię troszkę podrążyć temat (sukces jest najlepszą zachętą) - proponuję więc przyjrzenie się układowi PCF8583P. Jest to zegar czasu rzeczywistego z kalendarzem - oczywiście obsługiwany poprzez I2C i umieszczony, podobnie jak AT24C04, w malutkiej obudowie ośmiowyprowadzeniowej. Podłączamy do niego oscylator (ok. 34kHz), kondensatorek 33pF, zapewniamy ciągły dostęp zasilania (można z baterii) i... Ale o tym być może wkrótce :) Zachęcam również do samodzielnych eksperymentów.
Postscriptum
Dawno temu obiecałem (tak, czego ja już na tym blogu nie obiecywałem...) program do przekształcenia ATtiny 2313 w układ sterowania linijką świetlną. Oto i on:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
' 3 efekty świetlne na 8 LED-ów i mikrokontroler. | |
$regfile = "attiny2313.dat" | |
$crystal = 4000000 | |
$hwstack = 40 | |
$swstack = 16 | |
$framesize = 32 | |
' Poniższa dyrektywa musi być aktywna dla avrdude, stk500.exe oraz AVRStudio; | |
' Programator USBASP z poziomu Bascoma wymaga binarnego wsadu do EEPROM (domyślnie) | |
'$eepromhex | |
$eeprom | |
' Definicje efektów świetlnych | |
' 1 - Od lewej do prawej i z powrotem | |
Leftright: | |
Data 128 , 64 , 32 , 16 , 8 , 4 , 2 , 1 , 2 , 4 , 8 , 16 , 32 , 64 | |
' 2 - Od lewej do prawej czwórkami | |
Leftrightfour: | |
Data 129 , 66 , 36 , 24 , 36 , 66 | |
' 3 - Tylko do prawej | |
Toright: | |
Data 128 , 64 , 32 , 16 , 8 , 4 , 2 , 1 | |
' 4 - Tylko do lewej | |
Toleft: | |
Data 1 , 2 , 4 , 8 , 16 , 32 , 64 , 128 | |
$data | |
' Czas wyświetlania (dla efektu nie sterowanego timerem) | |
Const Lr4 = 16 | |
' Port B jako wyjścia | |
Config Portb = &B11111111 | |
' Stan spoczynkowy portu B to 0 | |
Portb = &B00000000 | |
' Bity 6, 5 i 4 portu D jako wejścia | |
Config Portd = &B1000111 | |
' Stan spoczynkowy portu D to 1 | |
Portd = &B1111111 | |
' Wyświetlaniem normalnej linijki będzie sterował timer0 - następna dioda zapalana co ok. 16ms | |
Config Timer0 = Timer , Prescale = 256 | |
' Włączamy obsługę przerwań i przerwanie timera 0 | |
Enable Interrupts | |
Enable Timer0 | |
' Ustawiamy podprogram obsługi przerwania timera 0 | |
On Timer0 Przesun_linijke | |
' Funkcja realizująca efekt świetlny (deklaracja) | |
' address - adres w EEPROM początku tablicy z definicją efektu | |
' maxcount - maksymalna wartość licznika pętli (liczba elementów w/w tablicy - 1) | |
Declare Sub Effect(address As Byte , Byval Maxcount As Byte) | |
Dim I As Byte , Tmp As Byte ' licznik pętli, zmienna pomocnicza do wyznaczania adresu w EEPROM | |
Dim Iters As Byte ' licznik pętli dla timera Timer0 | |
Dim Addr As Byte ' zmienna przechowująca adres początku tabeli w pamięci EEPROM | |
' Okazuje się, że port D nie od razu ma wartości spoczynkowe ustalone... | |
Portd.3 = 1 | |
Portd.4 = 1 | |
Portd.5 = 1 | |
Iters = 0 | |
Do | |
' W pętli sprawdzane są po kolei bity od najmłodszego do najstarszego, | |
' więc wyzerowanie kilku na raz będzie zinterpretowane jako naciśnięcie | |
' jednego (tego, który pierwszy został wyzerowany); może to sprawiać wrażenie | |
' losowości. | |
If Pind.3 = 0 Then ' efekt czwórek | |
Addr = Loadlabel(leftrightfour) | |
Effect Addr , 5 | |
Elseif Pind.4 = 0 Then ' efekt "do prawej" | |
Addr = Loadlabel(toright) | |
Effect Addr , 7 | |
Elseif Pind.5 = 0 Then ' efekt "do lewej" | |
Addr = Loadlabel(toleft) | |
Effect Addr , 7 | |
End If | |
Loop | |
End | |
' Funkcja realizująca efekt świetlny (definicja) | |
Sub Effect(address As Byte , Byval Maxcount As Byte) | |
Stop Timer0 | |
For I = 0 To Maxcount | |
Tmp = Address + I | |
Readeeprom Portb , Tmp | |
Waitms Lr4 | |
Next I | |
Start Timer0 | |
End Sub | |
' Podprogram obługi przerwania - bez pętli itp., maks. krótki | |
Przesun_linijke: | |
Addr = Loadlabel(leftright) | |
Tmp = Addr + Iters | |
Readeeprom Portb , Tmp | |
Iters = Iters + 1 | |
Iters = Iters Mod 14 | |
Return |
Jeżeli chodzi o elektronikę, do portu B mikrokontrolera podłączamy osiem diod LED poprzez rezystor 220Ω (podobnie jak na schemacie pokazanym wcześniej), zaś do wskazanych na listingu wyprowadzeń portu D - przyciski zwierające do masy. Do tego oczywiście oscylator 4MHz z dwoma kondensatorkami 33pF (również jak na wcześniejszym schemacie).
Po wgraniu programu można pobawić się efektami świetlnymi (proszę zwrócić uwagę, że efekt "spoczynkowy" jest generowany przez pracujący w tle timer, natomiast definicje efektów umieszczone są w wewnętrznej pamięci EEPROM mikrokontrolera).
Udanych eksperymentów zatem!
ERRATA czy też konieczny, acz zapomniany dopisek
Zagłębiając się w adresowanie układów na magistrali I2C i podłączanie ich do niej, zapomniałem o czymś, co wprawdzie łatwo można znaleźć w kodzie programu (pierwszy listing), ale co nie rzuca się specjalnie w oczy. A powinno.
Otóż jako wyjścia magistrali I2C mikrokontrolera ATtiny 2313 mogą zostać użyte dowolne dwie linie portów wejścia-wyjścia. U mnie, m. in. ze względu na konieczność podłączenia wyświetlacza, jako wyprowadzenia I2C "robią" linie (wyjścia) PORTB.1 (SCL) i PORTB.0 (SDA). Konfiguracji tych wyjść można dokonać z poziomu środowiska BASCOMa (Options -> Compiler -> I2C):
Dodatkowo zalecałbym wstawienie do kodu, przed deklaracjami zmiennych, dwóch linijek, których znaczenie jest to samo, jak powyższych ustawień środowiska dla I2C:
Dublowanie konfiguracji nie jest szkodliwe, a w tym przypadku wręcz pożądane (uniezależnimy się od konfiguracji środowiska - czasem po prostu możemy o niej zapomnieć).Config Scl = Portb.1Config Sda = Portb.0
Komentarze
Prześlij komentarz