Termostat do pieca gazowego (2)

Termostat do pieca gazowego (2)

Prezentowany w artykule projekt to uniwersalny, mikroprocesorowy termostat do pieca gazowego. W poprzedniej części opisu omówiliśmy konstrukcję i sposób montażu urządzenia. Tym razem zajmiemy się kwestiami związanymi z uruchomieniem oraz konfiguracją termostatu, przybliżymy także Czytelnikom najważniejsze zagadnienia programistyczne.

Podstawowe parametry:
  • konstrukcja oparta na mikrokontrolerze ATmega4808
  • pomiar temperatury otoczenia: czujnik DS18B20
  • dokładność pomiaru temperatury: ±0,5°C
  • sterowanie: enkoder obrotowy
  • wyświetlacz: LCD TFT 128×160 px
  • wyjścia przekaźnikowe: 2×DPDT 250 V/8 A
  • wbudowany zegar czasu rzeczywistego (DS3231) z podtrzymaniem (CR2032)

Uruchomienie i działanie układu

Uruchomienie układu zaczynamy od płytki zasilacza. Po podłączeniu sieci 230 V sprawdzamy obecność napięcia wyjściowego +5 V (wyprowadzenia 1 i 2 złącza P2) względem masy (wyprowadzenia 3 i 4 złącza P2). Jeżeli napięcie to jest prawidłowe, łączymy obie płytki złączami IDC. Napięcie na wyjściu stabilizatora U2 – umieszczonego na płytce sterownika – powinno wynosić +3,3 V. W następnym kroku do złącza J2 wpinamy programator umożliwiający zaprogramowanie mikrokontrolera Atmega4808 za pomocą jednej linii UPDI. Ja użyłem programatora MPLAB PICkit4 współpracującego ze środowiskiem projektowym MPLABX IDE. Po podłączeniu zewnętrznego czujnika DS18B20 do złącza P4 układ jest gotowy do weryfikacji działania oraz rozpoczęcia programowania ustawień.

Fotografia 4. Ekran główny termostatu

Po włączeniu zasilania pojawia się ekran główny podzielony na dwie strefy. W pierwszej z nich wyświetla się temperatura mierzona przez czujnik DS18B20. Wynik jest aktualizowany co 1 sekundę (co wynika z czasu potrzebnego na dokonanie pomiaru). W drugiej strefie wyświetlane są natomiast: rzeczywisty czas w godzinach, minutach i sekundach, data, a także bieżący program termostatu.

Ten ostatni działa w dwóch przedziałach czasowych, umownie nazwanych: „dzień” i „noc”. Do każdego z tych przedziałów przypisana została wartość temperatury. Z założenia w czasie „dzień” ustawiana jest wyższa temperatura, właściwa dla aktywności domowników (może to być na przykład +21°C). W czasie „noc” ustawiamy temperaturę niższą, na przykład +18°C. Przekłada się to niższe zużycie gazu, a dodatkowo w niższej temperaturze lepiej się śpi.

Przedział czasowy „dzień” zaczyna się o godzinie określonej przez Czas1 i kończy się o godzinie określonej przez Czas2. W tym przedziale wykonywany jest program o nazwie „Program #1” z przypisaną temperaturą regulacji Temp1.

Przedział czasowy „noc” zaczyna się o godzinie Czas2, a kończy o godzinie Czas1. W tym przedziale z kolei wykonywany jest czas regulacji „Program #2” z przypisaną Temp2. Wszystkie parametry programu: Czas1, Czas2, Temp1 i Temp2 są programowane. Jedyne ograniczenie bieżącej wersji oprogramowania stanowi warunek, że Czas1 musi być mniejszy od Czas2. Na przykład Czas1=07:00, Czas2=22:15, ale Czas2 nie powinien mieć na przykład wartości 0:30. Wtedy program regulacji będzie działał, ale po zaniku zasilania może błędnie określić, w którym przedziale czasowym się znajduje, aż do momentu osiągnięcia jednego z czasów: Czas1, lub Czas2. Na rysunku 5 pokazano zasadę czasowego podziału doby na dwa programy Program #1 i Program #2. W czasie wykonywania programu #1 termostat utrzymuje temperaturę Temp1, a w czasie trwania programu #2 – temperaturę Temp2.

Rysunek 5. Zasada działania programu termostatu

Temperatura jest regulowana przy zastosowaniu pętli histerezy. Załóżmy, że temperatura otoczenia okazuje się wyższa od temperatury Temp1. Termostat wyłącza wówczas grzanie pieca. Temperatura otoczenia spada, osiąga wartość Temp1. Termostat nadal nie włączy pieca – tak długo, aż temperatura otoczenia spadnie do wartości Temp1 – Hist, gdzie Hist jest wartością programowaną w zakresie od 0,1°C do 2°C z krokiem 0,1°C. Jeżeli temperatura otoczenia jest niższa od Temp1 – Hist, to termostat włącza grzanie. Temperatura w pomieszczeniu rośnie, aż osiągnie wartość wyższą od Temp1. Wtedy termostat wyłącza grzanie i cykl się powtarza. Takie rozwiązanie zapobiega częstym cyklom załącz-wyłącz, kiedy temperatura jest bliska wartości Temp1. Temperatura w pomieszczeniu będzie się w przybliżeniu wahać od wartości Temp1-Hist do Temp1. Wartość histerezy należy dobrać w zależności od warunków w ogrzewanych pomieszczeniach. Zbyt duża powoduje duże wahania temperatury, zbyt mała natomiast – częste cykle załącz-wyłącz. Prototyp termostatu pracował z histerezą 0,8°C. Histereza pozostaje wspólna dla obu programów.

Menu programowania jest dostępne po przyciśnięciu osi impulsatora. Można w nim ustawić czas, datę i termostat – fotografia 5.

Fotografia 5. Menu ustawień

Wybór jednej z funkcji w menu ustawień (czas, data, termostat) realizowany jest przez obrót gałki. Wybrana funkcja wyświetlana się na biało. Przyciśnięcie osi impulsatora sprawia, że rozpoczyna się wykonywanie wybranej funkcji.

Najbardziej rozbudowana jest funkcja ustawień termostatu. Można w niej zaprogramować:

  • histerezę w zakresie od 0,1°C do 2,0°C z krokiem 0,1°C,
  • temperaturę Temp1 w zakresie od 0°C do 31°C z krokiem 0,1°C,
  • temperaturę Temp2 w zakresie od 0°C do 31°C z krokiem 0,1°C,
  • czas 1 (godziny, minuty),
  • czas 2 (godziny, minuty).

Nastawy zmienia się przez obrót osi impulsatora, a zatwierdza jej przyciśnięciem. Ustawiana wartość wyświetlana się na biało, a po zatwierdzeniu zmienia kolor na niebieski – fotografia 6.

Fotografia 6. Przykładowy ekran ustawień termostatu

Po wejściu w menu ustawień termostatu użytkownik nie ma możliwości wybrania tylko jednej z nastaw. Musi „przeklikać” wszystkie pozycje. Sterownik pamięta każdą nastawę i jeżeli jakiejś nie chcemy modyfikować, powinniśmy sekwencyjnie przyciskać oś impulsatora, żeby przejść do kolejnej nastawy bez wprowadzania zmian. To uproszczenie nie wpływa znacząco na komfort użytkowania, ponieważ programowania termostatu nie wykonuje się często. Wszystkie nastawy są zachowywane w pamięci nieulotnej mikrokontrolera i odtwarzane po każdym zaniku napięcia zasilania. Wraz z podtrzymaniem bateryjnym zegara RTC zapewnia to w miarę niezakłócony cykl sterowania przy chwilowych zanikach napięcia sieciowego. Sterownik – po ponownym włączeniu zasilania – na podstawie ustawień Czas1 i Czas2 oraz bieżącego wskazania zegara oblicza czy aktywny jest Program #1, czy Program #2 i zaczyna regulować nastawione temperatury właściwe aktywnemu programowi.

Ustawienia czasu oraz daty nie wymagają szerszego komentarza. W trybie ustawiania czasu programujemy kolejno: godziny i minuty. Po ustawieniu minut oraz przyciśnięciu osi impulsatora, zerowany jest licznik sekund – i wartości godzin, minut i sekund są wpisywane do rejestrów układu DS3231, a zegar zaczyna odliczać nowy czas. W funkcji ustawienia daty programowane są: dzień miesiąca, miesiąc, a także rok.

Jak już wspomniałem, oprogramowanie zostało napisane w środowisku MPLAB firmy Microchip. Oprócz oczywistych elementów – takich jak środowisko IDE i kompilator C – istotnym wsparciem dla programisty jest wtyczka konfiguracyjna MCC. Oprócz konfiguracji urządzeń peryferyjnych, dostarcza kody źródłowe procedur do ich obsługi, co znacznie ułatwia i skraca pisanie programu. Trzeba przy tym pamiętać, że większość procedur komunikacji sprawdza warunek zakończenia transmisji w nieskończonych pętlach (procedury blokujące). Warto je nieco zmodyfikować, tak by – po określonym czasie oczekiwania w pętli na spełnienie warunku – tę pętlę przerwać. Jeżeli tego nie zrobimy ryzykujemy, że program prędzej czy później trwale się zawiesi. Można również pozostawić go tak jak jest – i skonfigurować moduł watchdoga.

Mikrokontroler jest taktowany wewnętrznym oscylatorem o częstotliwości 20 MHz. Przy zasilaniu +3,3 V nominalna częstotliwość taktowania powinna być ograniczona do 10 MHz, ale w praktyce – w temperaturach pokojowych – mikrokontroler pracuje poprawnie przy 20 MHz (okazuje się to istotne dla w miarę płynnej pracy wyświetlacza). Układ taktowania jest konfigurowany w oknie Clock Control wtyczki konfiguratora MCC – rysunek 6.


Rysunek 6. Konfiguracja układu taktowania

Mikrokontroler ma wbudowane 256 bajtów nieulotnej pamięci EEPROM przeznaczonej do przechowywania danych systemowych. Dostęp do pamięci nieulotnej – w tym EEPROM (ale też i Flash) – zapewnia specjalny moduł NVMCTRL (Nonvolatile Memory Controller). Po zaznaczeniu Place
Flash Functions in Separate w oknie NVMCTRL (rysunek 7), wtyczka MCC wygeneruje funkcje inicjalizujące moduł NVMCTRL oraz funkcje zapisu i odczytu bajtu z pamięci EEPROM (funkcje te używane są do zapisywania i odczytywania ustawień termostatu – listing 1).

Rysunek 7. Moduł NVMCTRL
/**************************************************
zapisanie bajtu do pamięci EEPROM
**************************************************/
uint8_t HMI_WriteEEPROM(uint8_t address,uint8_t data)
{
uint8_t status;
status = FLASH_WriteEepromByte(address, data);
return status;
}
/**************************************************
zapisanie bajtu do pamięci EEPROM
-procedura wygenerowana przez MMC
**************************************************/
/**
* \brief Write a byte to eeprom
*
* \param[in] eeprom_adr The byte-address in eeprom to write to
* \param[in] data The byte to write
*
* \return Status of write operation
*/
nvmctrl_status_t FLASH_WriteEepromByte(eeprom_adr_t eeprom_adr, uint8_t data)
{
/* Wait for completion of previous write */
while (NVMCTRL.STATUS & NVMCTRL_EEBUSY_bm)
;

/* Clear page buffer */
ccp_write_spm((void *)&NVMCTRL.CTRLA, NVMCTRL_CMD_PAGEBUFCLR_gc);

/* Write byte to page buffer */
*(uint8_t *)(EEPROM_START + eeprom_adr) = data;

/* Erase byte and program it with desired value */
ccp_write_spm((void *)&NVMCTRL.CTRLA, NVMCTRL_CMD_PAGEERASEWRITE_gc);

if (NVMCTRL.STATUS & NVMCTRL_WRERROR_bm)
{
return NVM_ERROR;
}
else
{
return NVM_OK;
}
}

Listing 1. Zapisanie danej do pamięci EEPROM

Zegar RTC DS3231 komunikuje się z mikrokontrolerem za pomocą magistrali I²C. Transmisję obsługuje sprzętowy moduł TWI konfigurowany w MCC – rysunek 8. Pracuje on jako master I²C z zegarem o częstotliwości 100 kHz.

Rysunek 8. Konfiguracja TWI (I²C master)

W przypadku interfejsu TWI, MCC dostarcza plik twi0_master_example.c z działającymi funkcjami transferu danych po magistrali I²C. Na listingu 2 pokazano funkcję przesyłania danych do zegara RTC DS3231, korzystającą z „przykładowej” funkcji I2C0_example_write1ByteRegister.

**************************************************
zapisz danej do rejestru o adresie reg
*************************************************/
void RTC_SendData(uint8_t reg, uint8_t data)
{
I2C0_example_write1ByteRegister(RTC_I2C_ADD, reg, data);
}
void I2C0_example_write1ByteRegister(twi0_address_t address, uint8_t reg, uint8_t data)
{
while(!I2C0_Open(address)); //sit here until we get the bus.
I2C0_SetDataCompleteCallback(wr1RegCompleteHandler_example,&data);
I2C0_SetBuffer(&reg,1);
I2C0_SetAddressNackCallback(I2C0_SetRestartWriteCallback,NULL); //NACK polling?
I2C0_MasterWrite();
while(I2C0_BUSY == I2C0_Close()); //sit here until finished.
}

Listing 2. Funkcja przesłania danej do zegara RTC

Mikrokontroler przesyła dane do sterownika wyświetlacza poprzez magistralę SPI. Wyświetlacz ma rozmiar 160×128 pikseli – żeby określić jasność i kolor każdego z pikseli, mikrokontroler musi przesłać do sterownika 2 bajty. Zapisanie całego wyświetlacza wymaga zatem transferu 128×160×2=40960 bajtów.

Ponadto trzeba często wysłać sekwencje komend sterujących, na przykład do ustalenia adresu piksela. Wszystko to sprawia, że transfer danych powinien być szybki, co z kolei wymaga wydajnego mikrokontrolera oraz – oczywiście – szybkiego interfejsu SPI. W naszym przypadku zegar taktujący przesyłaniem bitów ma częstotliwość 5 MHz przy taktowaniu mikrokontrolera częstotliwością 20 MHz. Konfiguracja interfejsu SPI została pokazana na rysunku 9.

Rysunek 9. Konfiguracja interfejsu SPI

Procedury przesłania danych i komend wymagają również ustawienia linii CD wyboru interfejsu SPI oraz linii wyboru rodzaju przesyłanych danych DC (data/command). Na listingu 3 pokazano procedurę przesyłającą 2 bajty dotyczące jednego piksela do pamięci obrazu wyświetlacza.

static void LCD_WriteData_NLen16Bit(uint16_t Data,uint32_t DataLen)
{
uint32_t i;
PORTC.OUT |= (1 << DC); //zapis danej
PORTC.OUT &= ~(1 << CS); //SPI aktywny
for(i = 0; i < DataLen; i++){
SPI0_ExchangeByte( (uint8_t)(Data >> 8) );
SPI0_ExchangeByte( (uint8_t)(Data & 0XFF) );
}
PORTC.OUT |= (1 << CS); //SPI nie aktywny
}

Listing 3. Przesłanie dwu bajtów do pamięci wyświetlacza

MMC wygenerowała procedurę wysyłania jednego bajtu przez interfejs SPI – listing 4.

uint8_t SPI0_ExchangeByte(uint8_t data)
{
SPI0.DATA = data;
while (!(SPI0.INTFLAGS & SPI_RXCIF_bm));
return SPI0.DATA;
}

Listing 4. Funkcja wysyłająca jeden bajt przez SPI

Przy dużej ilości przesyłanych danych zdarza się, że procedura oczekiwania na wysłanie bajtów ulega zawieszeniu, choć teoretycznie przy zastosowaniu SPI nie powinna. Drobna modyfikacja powoduje, że problem ten praktycznie znika. W pętli oczekiwania inkrementowany jest licznik. Jeżeli nie zostanie sprzętowo ustawiona flaga SPI_RXCIF oznaczająca, że bajt został wysłany (i odebrany), to wykonywana jest ponowna inicjalizacja modułu SPI SPI0_Initialize () i pętla kończy działanie – listing 5.

#define SPI_FRAME 0xD00
uint8_t SPI0_ExchangeByte(uint8_t data)
{
uint16_t frame = 0;
SPI0.DATA = data;
while (1)
{
if!(SPI0.INTFLAGS & SPI_RXCIF_bm)
return SPI0.DATA; //dana prawidłowo wysłana

++ frame;
if (frame >= SPI_FRAME)
{
SPI SPI0_Initialize ();
return(0);
}
}
return SPI0.DATA;
}

Listing 5. Zmodyfikowana procedura wysyłania bajtu

Ostatni moduł sprzętowy używany przez program to timer TCB (rysunek 10). Został on skonfigurowany tak, by zgłaszać cykliczne przerwania co jedną milisekundę. W procedurze obsługi tego przerwania jest realizowana obsługa impulsatora.

Rysunek 10. Konfiguracja Timera TCB

Główne procedury regulacji nie są zbyt skomplikowane. Po każdym pomiarze temperatury – wykonywanym co sekundę – wywołaniu ulega procedura Termostat, której argumentem jest temperatura w formacie zmiennoprzecinkowym – listing 6.

void Termostat(double temperature)
{
double hist, temp1, temp2;
HMI_GetTermostat(); //pobierz dane ustawień
//termostatu
hist = (double)termo.hist/100;
temp1 = (double)termo.temp1/10;
temp2 = (double)termo.temp2/10;


Termostat_Check_Time (); //sprawdź czy nie zmienił
//się program
Termostat_Check_Temperature (temperature);
}

Listing 6. Funkcja termostatu

Funkcja HMI_GetTermostat() odczytuje z pamięci EEPROM wszystkie ustawienia termostatu: histerezę, temperatury programów temp1 i temp2 oraz oba czasy. Następnie wywoływana jest funkcja Termostat_Check_Time () – listing 7. Ma ona za zadanie porównać bieżący czas (odczytany z rejestrów zegara RTC) z nastawami Czas1 i Czas2, a na podstawie wyniku tego porównania – określić, który program czasowy ma się wykonywać.

//odczytanie czasu i sprawdzenie który program mam być aktywny
//przy zmianie progów w czasowych

void Termostat_Check_Time (void)
{
uint8_t min, hour;
RTC_GetTime (); //pobierz czas z rejestrów DS3231
hour = HMI_ConvHexDec (time.hour);
min = HMI_ConvHexDec (time.min);
if (hour == termo.t1_hour && min == termo.t1_min)
{
termo.program = PR1;
return ;
}
else
if (hour >termo.t1_hour && hour < termo.t2_hour)
{
termo.program = PR1;
return ;
}
else
if (hour == termo.t2_hour && min < termo.t2_min)
{
termo.program = PR1;
return ;
termo.program = PR2
}

Listing 7. Identyfikacja aktywnego programu czasowego

Na podstawie wartości zmiennej termo.program funkcja Termostat_Check_Temperature (temperature) identyfikuje, która z temperatur ma być użyta w procesie regulacji. Procedura ta została pokazana na listingu 8. Opisana funkcja załącza lub wyłącza przekaźnik sterujący piecem, oraz wyświetla na ekranie głównym informację o aktywnym programie, a także wskazuje, czy grzanie jest włączone, czy wyłączone.

void Termostat_Check_Temperature (double temperature)
{
if(termo.program == PR1)
{
if(temperature < (temp1 – hist))
{
Heater = 1; //wlacz grzanie
if(termo.dpr1p)
{
LCD_DisplayString(20,70,"Prog#1",&Font20,COL6,WHITE);
LCD_DisplayString(108,70,"ON ",&Font20,COL6,BLACK);
termo.dpr1p = 0;
termo.dpr1np = 1;
}

}
if(temperature > temp1)
{
Heater = 0;
if(termo.dpr1np)
{
LCD_DisplayString(20,70,"Prog#1",&Font20,COL6,WHITE);
LCD_DisplayString(108,70,"OFF",&Font20,COL6,GREEN);
termo.dpr1np = 0;
termo.dpr1p = 1;
}
}
}
if (termo.program == PR2)
{
if(temperature < (temp2 – hist))
{
Heater = 1; //wlacz grzanie
if(termo.dpr2p)
{
LCD_DisplayString(20,70,"Prog#2",&Font20,COL6,WHITE);
LCD_DisplayString(108,70,"ON ",&Font20,COL6,BLACK);
termo.dpr2p = 0;
termo.dpr2np = 1;
}
}
if(temperature > temp2)
{
Heater = 0;
if(termo.dpr2np)
{
LCD_DisplayString(20,70,"Prog#2",&Font20,COL6,WHITE);
LCD_DisplayString(108,70,"OFF",&Font20,COL6,GREEN);
termo.dpr2np = 0;
termo.dpr2p = 1;
}
}

}

}

Listing 8. Funkcja termostatu

Program termostatu zajmuje 69% z 48 kB dostępnej pamięci Flash, zaś zdecydowana większość tej przestrzeni przypada na procedury związane z obsługą graficznego wyświetlacza, w tym także wzorce znaków alfanumerycznych. Również podczas pisania programu oprogramowanie interfejsu użytkownika HMI okazało się najbardziej pracochłonne. Można zadać sobie pytanie, czy warto poświęcać tyle czasu na bardziej lub mniej atrakcyjny interfejs użytkownika. Skoro jednak mamy dzisiaj możliwości używania tanich, dobrej jakości wyświetlaczy, wydajnych małych mikrokontrolerów, czy dobrych bezpłatnych narzędzi programistycznych, szkoda byłoby tego nie wykorzystać.

Tomasz Jabłoński, EP

Artykuł ukazał się w
Elektronika Praktyczna
sierpień 2024
DO POBRANIA
Materiały dodatkowe
Elektronika Praktyczna Plus lipiec - grudzień 2012

Elektronika Praktyczna Plus

Monograficzne wydania specjalne

Elektronik grudzień 2024

Elektronik

Magazyn elektroniki profesjonalnej

Raspberry Pi 2015

Raspberry Pi

Wykorzystaj wszystkie możliwości wyjątkowego minikomputera

Świat Radio listopad - grudzień 2024

Świat Radio

Magazyn krótkofalowców i amatorów CB

Automatyka, Podzespoły, Aplikacje listopad - grudzień 2024

Automatyka, Podzespoły, Aplikacje

Technika i rynek systemów automatyki

Elektronika Praktyczna grudzień 2024

Elektronika Praktyczna

Międzynarodowy magazyn elektroników konstruktorów

Elektronika dla Wszystkich grudzień 2024

Elektronika dla Wszystkich

Interesująca elektronika dla pasjonatów