Programowanie AVR cz. 4: ATtiny2313 + PCF8583P + AT24C04 + I2C,czyli... zabrakło pamięci, ale jest zegar nastawiany "w locie".
Kontynuując zabawę z magistralą I2C (patrz: poprzedni artykuł o programowaniu AVR) i grzebanie w elektronicznym złomie, natknąłem się na niepozorny układ scalony PCF8583P, zamontowany wraz z - jak się domyśliłem - odpowiednim oscylatorem kwarcowym na prehistorycznej płytce uruchomieniowej, jeszcze chyba z czasów AT89C4051. Układ ten to zegar czasu rzeczywistego (RTC) wraz z kalendarzem i obsługa alarmów, zarządzany (programowanie, odczyt) poprzez magistralę I2C. Nie zastanawiając się długo postanowiłem dołączyć ten układ do systemu z poprzedniego wpisu, żeby stworzyć wypasiony zegar, kalendarz, budzik... Niestety, szybko okazało się, że mój ulubiony mikrokontroler ATtiny2313 ma zbyt mało pamięci FLASH, żeby pomieścić finezyjny kod, który zaczął mi wychodzić (żaliłem się już w moim streamie Google+). Dlatego też ograniczyłem program demonstracyjny do samego zegara - jedyny ficzer, jaki się pojawił, to nastawianie godziny i minuty "w locie" za pomocą dwóch przycisków. Oznacza to, że każda zmiana godziny czy minuty (zmiana w górę, czyli inkrementacja) powoduje natychmiastową aktualizację ustawień zegara PCF8583P. Oczywiście aktualny czas jest wyświetlany na jednowierszowym LCD.
Początkowo program działał dziwnie, udało mi się jednak - częściowo w oparciu o analizę, częściowo metodą doświadczalną - zapanować nad tą niestabilnością i teraz wszystko jest OK. Zachęcam do przejrzenia kodu źródłowego, mimo, że nie zawiera jakichś specjalnych wodotrysków, ech...
Całość uruchamiana była w układzie zawierającym na magistrali I2C również wspomnianą pamięć EEPROM, a ponieważ PCF8583 jest poniekąd modyfikacją pamięci z dołożoną ekstra funkcjonalnością (posiada np. taką samą jak AT24C04, zaszytą "preambułę" adresu), musiałem ustalić na nowo adresy sprzętowe slave'ów. Być może powodem niestabilnego działania układu (w pewnych warunkach) było zachwianie parametrów elektrycznych magistrali, nie pozwalające na poprawną transmisję danych? Nie wgłębiałem się, więc jest to sprawa do zbadania.
Poniżej schemat całego układu demonstracyjnego. Niestety, nie udało się zaprogramować i wykorzystać wszystkich jego możliwości - chyba pora przerzucić się na którąś z ATmeg...
Na koniec krótka konkluzja. Chcąc zbudować zegarek na ATtiny2313 nie musimy angażować do tego celu specjalizowanych układów, których programowa obsługa zaśmieci niepotrzebnie cenną pamięć mikrokontrolera - mamy przecież w naszym procesorku timer, który może generować przerwanie co jedną sekundę... ;-) Jednak zaletą zastosowania oddzielnego układu jest to, że zapewniając mu zasilanie (podtrzymanie) bateryjne, możemy mieć ciągły pomiar czasu nawet po wyłączeniu zasilania systemu mikroprocesorowego. Rozwiązanie takie zastosował kolega dołączając do RaspberryPi moduł zegara bazujący na bliźniaczym układzie PCF8563P - opis znajdziemy na jego blogu.
ERRATA:
Proszę koniecznie zajrzeć do wpisu: Programowanie AVR cz. 4,5: Poprawki związane z drobnym przeoczeniem.
Początkowo program działał dziwnie, udało mi się jednak - częściowo w oparciu o analizę, częściowo metodą doświadczalną - zapanować nad tą niestabilnością i teraz wszystko jest OK. Zachęcam do przejrzenia kodu źródłowego, mimo, że nie zawiera jakichś specjalnych wodotrysków, ech...
This file contains hidden or 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 i zegar czasu rzeczywistego PCF8583P | |
$regfile = "attiny2313.dat" | |
$crystal = 4000000 | |
$hwstack = 40 | |
$swstack = 16 | |
$framesize = 32 | |
' UWAGA: | |
' Fragment programu dotyczący komunikacji z pamięcią szeregową AT24C04C został | |
' usunięty ze względu na zbyt duży rozmiar kodu wynikowego (został przekroczony | |
' maksymalny rozmiar pamięci Flash - 2048B) | |
' Zostały tylko definicje stałych związanych z adresami pamięci. | |
' Pamięć 24c04 (SLAVE): | |
' - wyprowadzenie A1 podłączone do masy, stąd adresy jak niżej. | |
' Pierwsze 256 bajtów - bank 1 (bit P0 = 0) | |
Const Addrw_eep_p0 = 168 | |
Const Addrr_eep_p0 = 169 | |
' Drugie 256 bajtów - bank 2 (bit P0 = 1) | |
Const Addrw_eep_p1 = 170 | |
Const Addrr_eep_p1 = 171 | |
' Zegar czasu rzeczywistego PCF8583P (SLAVE): | |
' - wyprowadzenie A0 podłączone do masy | |
Const Addrw_rtc = 160 | |
Const Addrr_rtc = 161 | |
Config Submode = New | |
' 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 przyciski ustawiania zegara | |
Config Portd = &B1110011 | |
Portd = &B0001100 | |
' Timer0 zgłasza przerwanie co ok. 16 ms - następuje wtedy odczyt czasu i daty z RTC | |
' oraz konwersja z BCD na format dziesiętny | |
Config Timer0 = Timer , Prescale = 1024 | |
'Włączenie obsługi przerwań i - w szczególności - przerwania timera 0 | |
Enable Interrupts | |
Enable Timer0 | |
On Timer0 Show_date_time | |
Dim Value As Byte , Value1 As Byte , Value2 As Byte | |
Dim Hours As Byte , Minutes As Byte , Seconds As Byte | |
Dim Change As Boolean | |
Dim Send As Boolean | |
Dim Time_str As String * 9 | |
Dim Hour_str As String * 3 | |
Dim Minute_str As String * 3 | |
Dim Second_str As String * 3 | |
Portd.5 = 0 ' dioda czerwona | |
Portd.4 = 0 ' dioda niebieska | |
Portd.3 = 1 ' przycisk minut | |
Portd.2 = 1 ' przycisk godzin | |
Cursor Off | |
Cls | |
Change = 1 | |
Do | |
If Change = 1 Then | |
Hour_str = Str(hours) | |
Minute_str = Str(minutes) | |
Second_str = Str(seconds) | |
If Hours < 10 Then | |
Time_str = "0" + Hour_str | |
Else | |
Time_str = Hour_str | |
End If | |
If Minutes < 10 Then | |
Time_str = Time_str + ":0" + Minute_str | |
Else | |
Time_str = Time_str + ":" + Minute_str | |
End If | |
If Seconds < 10 Then | |
Time_str = Time_str + ":0" + Second_str | |
Else | |
Time_str = Time_str + ":" + Second_str | |
End If | |
Locate 1 , 1 | |
Lcd Time_str | |
Change = 0 | |
End If | |
Debounce Pind.3 , 0 , Incr_min , Sub | |
Debounce Pind.2 , 0 , Incr_hour , Sub | |
If Send = 1 Then | |
' Opóźnienie konieczne ze względu na prawidłową pracę magistrali I2C | |
Waitms 25 | |
Gosub Send_time | |
Start Timer0 | |
Send = 0 | |
End If | |
Loop | |
End | |
' Zapis czasu do PCF8583P | |
Sub Write_stream_3b(byval Adres As Byte , Value As Byte , Value1 As Byte) | |
I2cstart | |
I2cwbyte Addrw_rtc | |
I2cwbyte Adres | |
I2cwbyte 0 | |
I2cwbyte Value | |
I2cwbyte Value1 | |
I2cstop | |
' Konieczny jeszcze jeden bit stopu (bez niego problemy ze stabilnością) | |
I2cstop | |
End Sub | |
' Odczyt czasu z PCF8583P i konwersja BCD->DEC | |
Sub Read_stream_3b(byval Adres As Byte) | |
I2cstart | |
I2cwbyte Addrw_rtc | |
I2cwbyte Adres | |
I2cstart | |
I2cwbyte Addrr_rtc | |
I2crbyte Value , Ack | |
I2crbyte Value1 , Ack | |
I2crbyte Value2 , Nack | |
I2cstop | |
Seconds = Makedec(value) | |
Minutes = Makedec(value1) | |
Hours = Makedec(value2) | |
End Sub | |
' Wyłączanie/włączanie odmierzania czasu przez PCF8583P | |
Sub Toggle_pcf_timer(byval Pcf_timer As Byte) | |
I2cstart | |
I2cwbyte Addrw_rtc | |
I2cwbyte 0 | |
If Pcf_timer = 0 Then | |
I2cwbyte 128 | |
Else | |
I2cwbyte 0 | |
End If | |
I2cstop | |
End Sub | |
' Zapis zmienionych ustawień zegara; sekundy zerowane | |
Send_time: | |
Value = Makebcd(minutes) | |
Value1 = Makebcd(hours) | |
Write_stream_3b 2 , Value , Value1 | |
Toggle_pcf_timer 1 | |
Return | |
' Podprogram obsługi przerwania timera 0 | |
' - odczyt i dekodowanie czasu z PCF8583P | |
Show_date_time: | |
Read_stream_3b 2 | |
Change = 1 | |
Return | |
' Nastawianie zegara - inkrementacja minut | |
Incr_min: | |
Stop Timer0 | |
Toggle_pcf_timer 0 | |
Minutes = Minutes + 1 | |
If Minutes >= 60 Then | |
Minutes = 0 | |
End If | |
Send = 1 | |
Return | |
' Nastawianie zegara - inkrementacja godzin | |
Incr_hour: | |
Stop Timer0 | |
Toggle_pcf_timer 0 | |
Hours = Hours + 1 | |
If Hours >= 24 Then | |
Hours = 0 | |
End If | |
Send = 1 | |
Return |
Całość uruchamiana była w układzie zawierającym na magistrali I2C również wspomnianą pamięć EEPROM, a ponieważ PCF8583 jest poniekąd modyfikacją pamięci z dołożoną ekstra funkcjonalnością (posiada np. taką samą jak AT24C04, zaszytą "preambułę" adresu), musiałem ustalić na nowo adresy sprzętowe slave'ów. Być może powodem niestabilnego działania układu (w pewnych warunkach) było zachwianie parametrów elektrycznych magistrali, nie pozwalające na poprawną transmisję danych? Nie wgłębiałem się, więc jest to sprawa do zbadania.
Poniżej schemat całego układu demonstracyjnego. Niestety, nie udało się zaprogramować i wykorzystać wszystkich jego możliwości - chyba pora przerzucić się na którąś z ATmeg...
Na koniec krótka konkluzja. Chcąc zbudować zegarek na ATtiny2313 nie musimy angażować do tego celu specjalizowanych układów, których programowa obsługa zaśmieci niepotrzebnie cenną pamięć mikrokontrolera - mamy przecież w naszym procesorku timer, który może generować przerwanie co jedną sekundę... ;-) Jednak zaletą zastosowania oddzielnego układu jest to, że zapewniając mu zasilanie (podtrzymanie) bateryjne, możemy mieć ciągły pomiar czasu nawet po wyłączeniu zasilania systemu mikroprocesorowego. Rozwiązanie takie zastosował kolega dołączając do RaspberryPi moduł zegara bazujący na bliźniaczym układzie PCF8563P - opis znajdziemy na jego blogu.
ERRATA:
Proszę koniecznie zajrzeć do wpisu: Programowanie AVR cz. 4,5: Poprawki związane z drobnym przeoczeniem.
Komentarze
Prześlij komentarz