Operácie

Kombinovaný snímač teploty a vlhkosti DHT22: Rozdiel medzi revíziami

Zo stránky SensorWiki

StudentMIPS (diskusia | príspevky)
Bez shrnutí editace
StudentMIPS (diskusia | príspevky)
Bez shrnutí editace
Riadok 121: Riadok 121:


Myslím si, že som svoj kód prehľadne okomentoval a preto nebudem v tejto časti vysvetľovať jeho funkčnosť.
Myslím si, že som svoj kód prehľadne okomentoval a preto nebudem v tejto časti vysvetľovať jeho funkčnosť.


Okrem týchto funkcií nepriamo využívam aj pár pomocných funkcií z knižníc. Tie používam dve:
Okrem týchto funkcií nepriamo využívam aj pár pomocných funkcií z knižníc. Tie používam dve:
Riadok 132: Riadok 133:
<tabs>
<tabs>
<tab name="Hlavný program"><syntaxhighlight  lang="c++" style="background: White;">
<tab name="Hlavný program"><syntaxhighlight  lang="c++" style="background: White;">
// Semestrálny projekt z predmetu Mikropočítačové systémy (MIPS)
// Téma: Kombinovaný snímač teploty a vlhkosti DHT22
// Vypracoval: Martin Hubocký
// Školský rok: 2024/2025
// ======================[ Knižnice (+ frekvencia) ]======================
#define F_CPU 16000000UL
#include <avr/io.h>
#include <avr/io.h>
#include <util/delay.h>
#include "uart.h"
#include "lcd_ch.h"


int main(void)
// ======================[ Definície a premenné ]======================
{
 
   unsigned int measuredValue;
#define Snimac_DHT22 PB0
uint8_t Pole_udajov[5];
 
#define RGB_teplota_cervena PC0
#define RGB_teplota_zelena PC1
#define RGB_teplota_modra PC2
#define RGB_vlhkost_cervena PC3
#define RGB_vlhkost_zelena PC4
#define RGB_vlhkost_modra PC5
 
#define Piezo PB5
 
int aktualny_stav_teplota = 0;
int posledny_stav_teplota = 0;
int aktualny_stav_vlhkost = 0;
int posledny_stav_vlhkost = 0;
 
// ======================[ Deklarácie pomocných funkcií ]======================
// (Bez tohto to malo problém s kompiláciou lebo mám funkcie definované až za main(), pretože mi to osobne prišlo prehľadnejšie)
 
void lcd_print_float(float hodnota);
void Vlastne_znaky(void);
void RGB_teplota(uint8_t cervena, uint8_t zelena, uint8_t modra);
void RGB_vlhkost(uint8_t cervena, uint8_t zelena, uint8_t modra);
void Farba_teplota(float teplota);
void Farba_vlhkost(float vlhkost);
void Pipnutie(uint8_t pocet_pipnuti);
void Pipnutie_dlhe(uint8_t pocet_pipnuti);
uint8_t Precitaj_senzor(void);
 
// ======================[ Hlavná funkcia main() ]======================
 
int main(void) {
    // Inicializácia výstupov RGB LED-iek a Pieza
    DDRC |= (1<<RGB_teplota_cervena) | (1<<RGB_teplota_zelena) | (1<<RGB_teplota_modra) | (1<<RGB_vlhkost_cervena) | (1<<RGB_vlhkost_zelena) | (1<<RGB_vlhkost_modra);
    DDRB |= (1 << Piezo);
 
    uart_init();                                                        // Inicializácia sériovej komunikácie (UART)
    lcd_init();                                                          // Inicializácia displeju
    lcd_command(0x0C);                                                  // Vypnutie kurzoru
 
    Vlastne_znaky();                                                    // Definovanie vlastných znakov (°C a ť)
 
    char buffer[32], pole_teplota[10], pole_vlhkost[10];                // Definície pomocných polí a ich dĺžok (budú využité neskôr v programe (UART))
 
    uart_puts("Spustenie\n");
    _delay_ms(1000);
    Precitaj_senzor();                                                  // Načítam dáta zo senzoru teploty a vlhkosti (DHT22)
    _delay_ms(2000);
 
    while (1) {
        _delay_ms(2000);
 
        if (Precitaj_senzor()) {                                        // Ak sa podarí načítať dáta zo senzoru...
            // Výpočet vlhkosti (resp. spracovanie do float premennej)
            uint16_t raw_vlhkost = ((uint16_t)Pole_udajov[0] << 8) | Pole_udajov[1];
            float vlhkost = raw_vlhkost / 10.0;
            // Výpočet teploty (resp. spracovanie do float premennej)
            uint16_t raw_teplota = ((uint16_t)Pole_udajov[2] << 8) | Pole_udajov[3];
            float teplota = raw_teplota / 10.0;
            if (Pole_udajov[2] & 0x80) {                                // Ak je teplota záporná uloží znamienko mínus
                teplota = -((raw_teplota & 0x7FFF) / 10.0);
            }
 
            // Výpis cez UART
dtostrf(teplota, 5, 1, pole_teplota);                        // Uloží hodnotu teploty do pole_teplota ktoré sa vypíše cez UART
            dtostrf(vlhkost, 5, 1, pole_vlhkost);                        // Uloží hodnotu vlhkosti do pole_vlhkost ktoré sa vypíše cez UART
            sprintf(buffer, "Teplota: %s C\n", pole_teplota);
            uart_puts(buffer);
            sprintf(buffer, "Vlhkost: %s %%\n", pole_vlhkost);
            uart_puts(buffer);
            // Výpis na displej
// (1. Riadok displeju)
            lcd_command(0x80);
            zob_text("Teplota:");
            Vypis_na_displej(teplota);
            lcd_data(1);                                                // znak °
            lcd_data('C');
            // (2. Riadok displeju)
            lcd_command(0xC0);
            zob_text("Vlhkos");
            lcd_data(2);                                                // znak ť
            lcd_data(':');
            Vypis_na_displej(vlhkost);
            lcd_data('%');
// Nastavenie farieb RGB LED-iek
            Farba_teplota(teplota);
            Farba_vlhkost(vlhkost);
}
else {                                                       // Ak by došlo k chybe pri načítaní dát zo senzoru... (Len sa vypíše na UART a displej)
            uart_puts("Chyba pri nacitani dat zo senzoru (DHT22)\n");
            lcd_command(0x80);
            zob_text("Chyba senzora   ");
            lcd_command(0xC0);
            zob_text("                ");
        }
    }
}
 
// ======================[ Funkcie pre farebnú signalizáciu a zvukovú signalizáciu ]======================
 
// Prevedie (Zasvieti) požadovanú farbu RGB diódy teploty na "kód"
void RGB_teplota(uint8_t cervena, uint8_t zelena, uint8_t modra) {      // Ak má príslušná farba RGB LED-ky zasvietiť musím zapísať log. 1, inak nesvieti
    if (cervena) PORTC |= (1<<RGB_teplota_cervena); else PORTC &= ~(1<<RGB_teplota_cervena);
    if (zelena) PORTC |= (1<<RGB_teplota_zelena); else PORTC &= ~(1<<RGB_teplota_zelena);
    if (modra) PORTC |= (1<<RGB_teplota_modra); else PORTC &= ~(1<<RGB_teplota_modra);
}
 
// Prevedie (Zasvieti) požadovanú farbu RGB diódy vlhkosti na "kód"
void RGB_vlhkost(uint8_t cervena, uint8_t zelena, uint8_t modra) {      // Ak má príslušná farba RGB LED-ky zasvietiť musím zapísať log. 1, inak nesvieti
    if (cervena) PORTC |= (1<<RGB_vlhkost_cervena); else PORTC &= ~(1<<RGB_vlhkost_cervena);
    if (zelena) PORTC |= (1<<RGB_vlhkost_zelena); else PORTC &= ~(1<<RGB_vlhkost_zelena);
    if (modra) PORTC |= (1<<RGB_vlhkost_modra); else PORTC &= ~(1<<RGB_vlhkost_modra);
}
 
// Na základe veľkosti hodnoty teploty vyhodnotí príslušnú farbu ktorou má RGB LED-ka svietiť, stav teploty (5 stavov (28°C; 40°C; interval 4°C)) a ak došlo k zmene stavu vyhodnotí smer zmeny t.j. či teplota stúpla alebo klesla (využije sa neskôr pri zvukovej signalizácii)
void Farba_teplota(float teplota) {
// Vyhodnotenie veľkosti hodnoty teploty a priradenie stavu
    if (teplota <= 28.0) {                                              // Ak je teplota menšia alebo rovná ako 28°C zaviesti biela farba a určí stav teploty ako stav 1
        RGB_teplota(1, 1, 1); aktualny_stav_teplota = 1;
    } else if (teplota <= 32.0) {                                        // Ak je teplota menšia alebo rovná ako 32°C zaviesti modrá farba a určí stav teploty ako stav 2
        RGB_teplota(0, 0, 1); aktualny_stav_teplota = 2;
    } else if (teplota <= 36.0) {                                        // Ak je teplota menšia alebo rovná ako 36°C zaviesti zelená farba a určí stav teploty ako stav 3
        RGB_teplota(0, 1, 0); aktualny_stav_teplota = 3;
    } else if (teplota <= 40.0) {                                        // Ak je teplota menšia alebo rovná ako 40°C zaviesti červená farba a určí stav teploty ako stav 4
        RGB_teplota(1, 0, 0); aktualny_stav_teplota = 4;
    } else {                                                            // Ak je teplota vaačšia ako 40°C zaviesti fialová farba a určí stav teploty ako stav 5
        RGB_teplota(1, 0, 1); aktualny_stav_teplota = 5;                // (Keďže tento stav sa považuje "akože" za nebezpečný, piezo bude pípať (Nebude pípať nonstop ale bude pípať za každým keď program main() spraví jeden cyklus))
        Pipnutie(5);
    }
 
    // Vyhodnotenie zmeny a smeru zmeny teploty
    if (aktualny_stav_teplota > posledny_stav_teplota) Pipnutie(2);      // Ak teplota stúpla piezo pípne dva krát (len ak došlo k zmene)
    else if (aktualny_stav_teplota < posledny_stav_teplota) Pipnutie(1); // Ak teplota klesla piezo pípne jeden krát (len ak došlo k zmene)
    posledny_stav_teplota = aktualny_stav_teplota;
}
 
// Na základe veľkosti hodnoty vlhkosti vyhodnotí príslušnú farbu ktorou má RGB LED-ka svietiť, stav vlhkosti (5 stavov (50%; 80%; interval 10%)) a ak došlo k zmene stavu vyhodnotí smer zmeny t.j. či vlhkosť stúpla alebo klesla (využije sa neskôr pri zvukovej signalizácii)
void Farba_vlhkost(float vlhkost) {
   
// Vyhodnotenie veľkosti hodnoty vlhkosti a priradenie stavu
if (vlhkost <= 50.0) {                                              // Ak je vlhkosť menšia alebo rovná ako 50% zaviesti biela farba a určí stav vlhkosti ako stav 1
        RGB_vlhkost(1, 1, 1); aktualny_stav_vlhkost = 1;
    } else if (vlhkost <= 60.0) {                                        // Ak je vlhkosť menšia alebo rovná ako 60% zaviesti modrá farba a určí stav vlhkosti ako stav 2
        RGB_vlhkost(0, 0, 1); aktualny_stav_vlhkost = 2;
    } else if (vlhkost <= 70.0) {                                        // Ak je vlhkosť menšia alebo rovná ako 70% zaviesti zelená farba a určí stav vlhkosti ako stav 3
        RGB_vlhkost(0, 1, 0); aktualny_stav_vlhkost = 3;
    } else if (vlhkost <= 80.0) {                                        // Ak je vlhkosť menšia alebo rovná ako 80% zaviesti červená farba a určí stav vlhkosti ako stav 4
        RGB_vlhkost(1, 0, 0); aktualny_stav_vlhkost = 4;
    } else {                                                            // Ak je vlhkosť väčšia ako 80% zaviesti fialová farba a určí stav vlhkosti ako stav 5
        RGB_vlhkost(1, 0, 1); aktualny_stav_vlhkost = 5;                // (Keďže tento stav sa považuje "akože" za nebezpečný, piezo bude pípať (pípnutie je dlhšie ako pri teplote) (Nebude pípať nonstop ale bude pípať za každým keď program main() spraví jeden cyklus))
        Pipnutie_dlhe(5);
    }
 
    // Vyhodnotenie zmeny a smeru zmeny vlhkosti
    if (aktualny_stav_vlhkost > posledny_stav_vlhkost) Pipnutie_dlhe(2); // Ak vlhkost stúpla piezo pípne dva krát (pípnutie je dlhšie ako pri teplote) (len ak došlo k zmene)
    else if (aktualny_stav_vlhkost < posledny_stav_vlhkost) Pipnutie_dlhe(1); // Ak vlhkost stúpla piezo pípne jeden krát (pípnutie je dlhšie ako pri teplote) (len ak došlo k zmene)
    posledny_stav_vlhkost = aktualny_stav_vlhkost;
}
 
// ======================[ Piezo reproduktor ]======================
 
// Pípanie pre teplotu
void Pipnutie(uint8_t pocet_pipnuti) {
    for (uint8_t i = 0; i < pocet_pipnuti; i++) {                        // Piezo pípa požadovaný "pocet_pipnuti" krát pre teplotu t. j. pípa krátko (100ms hučí a 100ms je ticho)
        PORTB |= (1 << Piezo);
        _delay_ms(100);
        PORTB &= ~(1 << Piezo);
        _delay_ms(100);
    }
}
 
// Pípanie pre vlhkosť
void Pipnutie_dlhe(uint8_t pocet_pipnuti) {                              // Piezo pípa požadovaný "pocet_pipnuti" krát pre vlhkosť t. j. pípa dlho (500ms hučí a 100ms je ticho)
    for (uint8_t i = 0; i < pocet_pipnuti; i++) {
        PORTB |= (1 << Piezo);
        _delay_ms(500);
        PORTB &= ~(1 << Piezo);
        _delay_ms(100);
    }
}
 
// ======================[ Čítanie zo senzora DHT22 ]======================
 
uint8_t Precitaj_senzor() {
    uint8_t bity[5] = {0};  // Pole pre 5 bajtov prijatých zo senzora (po 8 bitov) (2 bajty pre vlhkosť (celé číslo, desatinné číslo), 2 bajty pre teplotu (celé číslo, desatinné číslo), 1 bajt pre kontrolný súčet)
    uint8_t i, j;
 
    // Odoslanie "Štartovacieho" signálu
    DDRB |= (1 << Snimac_DHT22);
    PORTB &= ~(1 << Snimac_DHT22);
    _delay_ms(2);
    PORTB |= (1 << Snimac_DHT22);
    _delay_us(30);
    DDRB &= ~(1 << Snimac_DHT22);
 
    // Čakanie na odpoveď
    uint16_t timeout;
    timeout = 100;
    while ((PINB & (1 << Snimac_DHT22)) && timeout--) _delay_us(1);
    if (timeout == 0) return uart_puts("Timeout LOW\n"), 0;
    timeout = 100;
    while (!(PINB & (1 << Snimac_DHT22)) && timeout--) _delay_us(1);
    if (timeout == 0) return uart_puts("Timeout HIGH\n"), 0;
    timeout = 100;
    while ((PINB & (1 << Snimac_DHT22)) && timeout--) _delay_us(1);
    if (timeout == 0) return uart_puts("Timeout koniec HIGH\n"), 0;
 
    // Príjem dát (5*8 = 40 bitov)
    for (j = 0; j < 5; j++) {
        for (i = 0; i < 8; i++) {
            timeout = 100;
            while (!(PINB & (1 << Snimac_DHT22)) && timeout--) _delay_us(1);
            if (timeout == 0) return uart_puts("Timeout bit start\n"), 0;
 
            uint8_t count = 0;
            while ((PINB & (1 << Snimac_DHT22))) {
                _delay_us(1);
                if (++count > 100) break;
            }
 
            if (count > 40) bity[j] |= (1 << (7 - i));
        }
    }
 
    // Kontrola prijatých dát (Posledný bajt je súčtom 4 pred ním)
    if ((uint8_t)(bity[0] + bity[1] + bity[2] + bity[3]) != bity[4]) {
        uart_puts("Chyba: Kontrolny sucet\n");
        return 0;
    }
 
    // Uloženie hodnôt
    for (i = 0; i < 5; i++) Pole_udajov[i] = bity[i];
    return 1;
}
 
// ======================[ Výpis float hodnoty na LCD ]======================
 
void Vypis_na_displej(float hodnota) {
// Toto je všetko len formátovanie aby sa to vypísalo na displej "pekne"
// Rozdelenie na celé čísla a čísla za desatinnou čiarkou (DHT22 má rozlíšenie len na jedno desatinné miesto)
    int jednotky = (int)hodnota;
    int desatiny = (int)((hodnota - jednotky) * 10);
   
// V prípade že by teplota bola záporná (Nemal som ako vyskúšať takže neviem či je to úplne správne)
    if (hodnota < 0) {
        lcd_data('-');
        jednotky = -jednotky;
        desatiny = -desatiny;
    }
    // Vypísanie jednotiek
    if (jednotky >= 10)
        lcd_data('0' + (jednotky / 10));
    else
        lcd_data('0');
    // Vypísanie desatín
    lcd_data('0' + (jednotky % 10));
    lcd_data('.');
    lcd_data('0' + (desatiny % 10));
}


  while (1)
// ======================[ Vlastné znaky pre LCD ]======================
  {
    /*  relax  */
  }


  return(0);
void Vlastne_znaky(void) {
    unsigned char znak_stupen[8] = {0x06, 0x09, 0x09, 0x06, 0x00, 0x00, 0x00, 0x00};    // Vytvorenie vlastného znaku "°" pomocou jednotlivých pixelov (Samotný displej je síce 5*7 pixelov no mal som problém s kompiláciou a preto je všade 8 hodnôt (tvárim sa že je jeden znak je 5*8))
    unsigned char znak_t_makcen[8] = {0x0D, 0x0A, 0x1C, 0x08, 0x08, 0x09, 0x06, 0x00};  // Vytvorenie vlastného znaku "ť"
// Uložím znaky aby si ich pamätal displej
    def_znak(znak_stupen, 1);
    def_znak(znak_t_makcen, 2);
}
}


Riadok 150: Riadok 439:
<tab name="uart.c"><syntaxhighlight  lang="c++" style="background: LightBlue;">
<tab name="uart.c"><syntaxhighlight  lang="c++" style="background: LightBlue;">
#include <avr/io.h>
#include <avr/io.h>
//#include <util/setbaud.h>
#define BAUD 9600
#define F_CPU 16000000UL
void uart_init( void )
{
    UBRR0 =103;
/*
#if USE_2X
    UCSR0A |= _BV(U2X0);
#else
    UCSR0A &= ~(_BV(U2X0));
#endif*/
    UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); /* 8-bit data */
    UCSR0B = _BV(RXEN0) | _BV(TXEN0);  /* Enable RX and TX */
}


int main(void)
void uart_putc(char c)  
{
{
  unsigned int measuredValue;
  if (c == '\n')
    {
      uart_putc('\r');
    }
  loop_until_bit_is_set(UCSR0A, UDRE0); /* Wait until data register empty. */
  UDR0 = c;
}
 


   while (1)
void uart_puts(const char *s)
  {
{
    /* relax  */ 
 
   while(*s!='\0'){
  uart_putc(*s);
  s++;
   }
   }
 
}
  return(0);
char uart_getc(void) {
    loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */
    return UDR0;
}
}


Riadok 166: Riadok 484:


<tab name="uart.h"><syntaxhighlight  lang="c++" style="background: LightBlue;">
<tab name="uart.h"><syntaxhighlight  lang="c++" style="background: LightBlue;">
#include <avr/io.h>
#ifndef UART_H_
#define UART_H_
#define BAUD 9600
#define F_CPU 16000000UL


int main(void)
void uart_init( void );
{
void uart_putc( char c );
  unsigned int measuredValue;
void uart_puts( const char *s );


  while (1)
char uart_getc( void );
  {
    /*  relax  */ 
  }


  return(0);
#endif
}


</syntaxhighlight ></tab>
</syntaxhighlight ></tab>


<tab name="lcd_ch.c"><syntaxhighlight  lang="c++" style="background: LightGreen;">
<tab name="lcd_ch.c"><syntaxhighlight  lang="c++" style="background: LightGreen;">
#include <avr/io.h>
#include "lcd_ch.h"
 
unsigned char Znak_OO[8]= {0x00,0x00,0x00,0x00,0x00,0x00,0x15,0};// Prazdny znak dole su tri bodky
 
unsigned char Znak_SC[8]= {0x1A,0x1D,0x04,0x04,0x04,0x05,0x02,0};// st.C
unsigned char Znak_SM[8]= {0x0A,0x04,0x0E,0x10,0x0E,0x01,0x1E,0};//  s + mekcen
unsigned char Znak_CM[8]= {0x0A,0x04,0x0E,0x10,0x10,0x11,0x0C,0};//  c + mekcen
 
// Vynulovanie CGRAM
void def_Clear_spec_znaky(void){
// zapis specialneho znaku do CGRAM  na poziciu 0, a 7
for(char i = 0; i < 8; i++) def_znak( Znak_OO,i);
lcd_command(0x80);
}
 
 
void def_spec_znaky(void){
// zapis vlastnych znakkov do CGRAM  na poziciu 4, a 0 (8)
 
 
def_znak( Znak_SC,4);// stupen Celzia
def_znak( Znak_SM,0);// s + makcen
// obnovenie obsahu AC. AC nastvime na 1. riadok, 1. znak
lcd_command(0x80);
}
 
#ifndef _Shield_LCD
void def_spec_znaky_AC(void){
// zapis specialneho znaku do CGRAM  na poziciu 7
 
unsigned char obsah_AC = 0;
obsah_AC = lcd_read_AC(); //   
// kon_vyp = obsah_AC;
 
// sem dame nove vlastne znaky
def_znak( Znak_CM,7);// c + makcen
// obnovenie obsahu AC. AC
 
lcd_command(0x80|obsah_AC);
 
}
#endif
void ini_ports(void){
/* inicializacia portov - vstupy / vystupy
oba typy displaja */
// nasledovna # riadky su spolocne pre oba typy LCD
LCD_CTRL_DDR |= (1<<LCD_EN_pin); //  (Enable)    output 
LCD_CTRL_DDR |= (1<<LCD_RS_pin); //  (RS)        output 
LCD_DATA_DDR |= (1<<LCD_D4_pin)|(1<<LCD_D5_pin)|(1<<LCD_D6_pin)|(1<<LCD_D7_pin); // Datove piny ako Output (Data pre display)
#ifndef _Shield_LCD
// klasicky LCD vyuziva aj RW pin
LCD_CTRL_DDR |= (1<<LCD_RW_pin); // (RW)        output 
#endif
}
 
 
void En_imp(void) {
LCD_CTRL_PORT |= (1<<LCD_EN_pin); // -> "log.1"
LCD_DELAY; // cca 400 ns
LCD_CTRL_PORT &= ~(1<<LCD_EN_pin); // -> "log.0"  spolu cca 500 ns
}
 
void lcd_init(void)
{  // 4 bitove pripojenie display-a
ini_ports(); // inicializacia porov
_delay_ms(15);
// 1. -------------------
LCD_CTRL_PORT &= ~(1 << LCD_RS_pin); // set RS  = to "log. 0"  Instruction Register (IR)
#ifndef _Shield_LCD
LCD_CTRL_PORT &= ~(1 << LCD_RW_pin) ; // set R/W = to "log. 0" - Write
#endif
// RS R/W  DB7 DB6 DB5 DB4  DB3 DB2 DB1 DB0
// 0  0    0  0  1  1    x  x  x  x    = 0x30
PORT_DATA_WR_H(0x30); // 8-bitove pripojenie
En_imp();
// 2. -------------------
    // zopakujem  8-bitove pripojenie
_delay_ms(5); En_imp();
// 3. -------------------
// zopakujem  8-bitove pripojenie
    _delay_ms(1); En_imp(); // -  stacilo by delay 0.1ms, momentalne najkratsie nastavitelne je 1ms
// 4. -------------------
// zmenim na 4-bitove pripojenie
// RS R/W    DB7 DB6 DB5 DB4    DB3 DB2 DB1 DB0
// 0  0      0  0  1  0      x  x  x  x    = 0x20
PORT_DATA_WR_H(0x20); // 4-bitove pripojenie
_delay_ms(1); En_imp(); // -  stacilo by delay 0.04ms
// -------------------
// LCD function set      mod: DL = 0 - 4-bitove data, N = 1 - 2 riadky, F = 0 - 5x7 dots
// RS R/W    DB7 DB6 DB5 DB4    DB3 DB2 DB1 DB0
// 0  0      0  0  1  DL    N  F  x  x    = 0x28
// Mozeme nasledujuci prikaz pre LCD vynechat?
_delay_ms(2);
lcd_command(0x28);
// RS R/W    DB7 DB6 DB5 DB4    DB3 DB2 DB1 DB0
// 0  0      0  0  0  0     0  0  0  1    = 0x01 , Display clear
// Mozeme nasledujuci prikaz pre LCD vynechat?
_delay_ms(2);
lcd_command(0x01);
// RS R/W    DB7 DB6 DB5 DB4    DB3 DB2 DB1 DB0
// 0  0      0  0  0  0     0  1  I/D S      = 0x06, I/D = 1 - inkrement
// Mozeme nasledujuci prikaz pre LCD vynechat?
_delay_ms(2);
lcd_command(0x02);
// RS R/W    DB7 DB6 DB5 DB4    DB3 DB2 DB1 DB0
// 0  0      0  0  0  0     1  D  C  B      = 0x0E, D = C = 1 - Display a kurzor zapnute
// Mozeme nasledujuci prikaz pre LCD vynechat?
_delay_ms(2);
lcd_command(0x0E); // B = 0 - blikanie vypnute
}
 
 
//zapis data do Data Register
void lcd_data(unsigned char data){
while(busy_flag() & 0x80);
//while(rd_BF()); // test BF sa da realizovat pre klasicky LCD, nie Shield
LCD_CTRL_PORT |= (1<<LCD_RS_pin); //    (RS = High) 
#ifndef _Shield_LCD
LCD_CTRL_PORT &= ~(1<<LCD_RW_pin); //    (RW = Low, write)
#endif
wr_data (data);
}
 
// zapis commandu do Instruction Register
void lcd_command(unsigned char command){
while(busy_flag() & 0x80);
//while(rd_BF()); // test BF sa da realizovat pre klasicky LCD, nie Shield
LCD_CTRL_PORT &= ~(1<<LCD_RS_pin); //  (RS = Low) 
#ifndef _Shield_LCD
LCD_CTRL_PORT &= ~(1<<LCD_RW_pin); //  (RW = Low, write)
#endif
wr_data (command);
}
 
void wr_data(unsigned char data) {
PORT_DATA_WR_H(data); // data High nibble
En_imp();
PORT_DATA_WR_L(data); // data Low nibble
En_imp();
}
 
#ifdef _Shield_LCD
// namiesto testu BF "pockam".
// LCD typu Shield ma WR pripojene na GND
unsigned char busy_flag(void){
_delay_ms(2);
return(0);
}
#else
// namiesto testu BF "pockam". Vacsine prikazov tento cas vyhovuje
/*int busy_flag(void){
_delay_ms(2);
return(0);
}
*/
// klasicke pripojenie LCD umozni aj test BF
unsigned char busy_flag(void){ //  rd_BF 
unsigned char pom = 0;
LCD_CTRL_PORT &= ~(1<<LCD_RS_pin); //  (RS = Low) 
LCD_CTRL_PORT |= (1<<LCD_RW_pin); //    (RW = High, read)
    // port B, datove bity budu teraz input
LCD_DATA_DDR &= ~((1<<LCD_D4_pin)|(1<<LCD_D5_pin)|(1<<LCD_D6_pin)|(1<<LCD_D7_pin)); //  Datove piny nastavime  na input, (Data pre disp)
// Spravne by sa malo vycitavaj pred dobeznou hranou EN impulzu. Je tam urcity presah. Mozeme vycitat aj po dobeznej hrane.
En_imp();
pom = PORT_DATA_RD_H; // vycitam High nibble AC
En_imp();
pom |= PORT_DATA_RD_L; // vycitam Low nibble AC
// datove bity zase output
LCD_DATA_DDR |= (1<<LCD_D4_pin)|(1<<LCD_D5_pin)|(1<<LCD_D6_pin)|(1<<LCD_D7_pin); // Datove piny nastavime na output (Data pre disp)
//if(pom & 0x80) return 1; // display je busy
//else
return pom; // display je not busy
}
 
#endif
 
void zob_text(char *s){
register unsigned char c;
while((c = *s++)) lcd_data(c); // retazec konci "nulou"
}
 
void def_znak(unsigned char *ZnakArray,unsigned char kam) {
lcd_command(0x40|(kam << 3)); //nastavenie adresy znaku v CGRAM
for(unsigned char i = 0; i < 8; i++) lcd_data( *(ZnakArray + i));
}
 


int main(void)
/* ******************************************************** */
/* vypis retazca na poziciu, resp. podla nasledovnych */
/* formatovacich prikazov                                      */
/*  : \r - prechod na novy riadok                              */
/*  : \f - prechod na zaciatok displeja                        */
/* ********************************************************    */
void lcd_puts( const char *s)   /* definicia funkcie */
{
{
   unsigned int measuredValue;
    
 
}
  while (1)
  {
    /*  relax  */ 
  }


   return(0);
#ifndef _Shield_LCD
int8_t lcd_read_AC(void){ //  rd_BF    
char pom_AC ;
while((pom_AC = busy_flag( )) & 0x80);
// kedze po BF = 0 este cca 4us sa nezmenil obsah AC
// treba vycitat este raz 
pom_AC = busy_flag( );
return pom_AC; // display not busy
}
}
#endif


</syntaxhighlight ></tab>
</syntaxhighlight ></tab>


<tab name="lcd_ch.h"><syntaxhighlight  lang="c++" style="background: LightGreen;">
<tab name="lcd_ch.h"><syntaxhighlight  lang="c++" style="background: LightGreen;">
#ifndef F_CPU
#define F_CPU 16000000UL /* Define CPU frequency here 16MHz */
#endif
#ifndef LCD_CH_H_
#define LCD_CH_H_
#include <avr/io.h>
#include <avr/io.h>
#include <util/delay.h>
/* Nasledovne define rozhodne ktora cast programu sa prelozi:
  LCD Shiled (WR ma pripojene na GND) a
  priradenie pinov je dane napr.:
  "zamrzne"
  -    https://www.14core.com/wiring-the-lcd-16x2-keypad-shield-on-arduino/
  - https://wiki.dfrobot.com/LCD_KeyPad_Shield_For_Arduino_SKU__DFR0009
  resp.
  LCD, zapojenie vid. stranka MIPS
  "zamrzne"
  - http://senzor.robotika.sk/sensorwiki/index.php/LCD_displej_s_radi%C4%8Dom_HD44780
  , ktore ma pripojene aj pin WR
  t.j. moze sa testovat aj pin BF
*/
/* !!!!!!!
    #define _Shield_LCD
    !!!!!!! */
extern unsigned char kon_vyp;
#ifdef _Shield_LCD
#define LCD_CTRL_DDR DDRB
#define LCD_CTRL_PORT PORTB
#define LCD_DATA_DDR DDRD
#define LCD_DATA_PORT PORTD
// Riadiaca zbernica display-a
#define LCD_RS_pin 0
#define LCD_RW_pin = 0
#define LCD_EN_pin 1
// Datova zbernica
#define LCD_D4_pin 4
#define LCD_D5_pin 5
#define LCD_D6_pin 6
#define LCD_D7_pin 7
#else
// LCD  klasik yapojenie vid. MIPS
#define LCD_CTRL_DDR DDRD
#define LCD_CTRL_PORT PORTD
#define LCD_DATA_DDR DDRB
#define LCD_DATA_PORT PORTB
#define LCD_DATA_PIN PINB
#define LCD_RS_pin 2
#define LCD_RW_pin 3
#define LCD_EN_pin 4
#define LCD_D4_pin 1
#define LCD_D5_pin 2
#define LCD_D6_pin 3
#define LCD_D7_pin 4
#endif
// Oneskorenie 6 SC
#define NOP() asm("nop")
#define LCD_DELAY NOP();NOP();NOP();NOP();NOP();NOP();
#ifdef _Shield_LCD
// formatovanie dat
#define PORT_DATA_WR_H(x) LCD_DATA_PORT &=0b00001111; LCD_DATA_PORT |= (x & 0xF0 )
#define PORT_DATA_WR_L(x) LCD_DATA_PORT &=0b00001111; LCD_DATA_PORT |= (x & 0x0F )<<4
#else
#define PORT_DATA_WR_H(x) LCD_DATA_PORT &=0b11100001; LCD_DATA_PORT |= (x & 0xF0 )>>3
#define PORT_DATA_WR_L(x) LCD_DATA_PORT &=0b11100001; LCD_DATA_PORT |= (x & 0x0F )<<1
#define PORT_DATA_RD_H ((LCD_DATA_PIN & ((1<<LCD_D4_pin)|(1<<LCD_D5_pin)|(1<<LCD_D6_pin)|(1<<LCD_D7_pin)))<<3)
#define PORT_DATA_RD_L ((LCD_DATA_PIN & ((1<<LCD_D4_pin)|(1<<LCD_D5_pin)|(1<<LCD_D6_pin)|(1<<LCD_D7_pin)))>>1)
#endif
/* Public functions for your use */
#ifndef _Shield_LCD
int8_t lcd_read_AC(void); 
void def_spec_znaky_AC(void);
#endif
void lcd_init(void);
void lcd_data(unsigned char );
void lcd_command(unsigned char );
// void lcd_puts(const char *s);  /* deklaracia funkcie  */
void ini_ports(void);
void En_imp(void);
void wr_data (unsigned char );
unsigned char busy_flag(void);
void zob_text(char *);
void def_Clear_spec_znaky(void);


int main(void)
{
  unsigned int measuredValue;


  while (1)
void def_znak(unsigned char *,unsigned char );
  {
void def_spec_znaky(void);
    /*  relax  */ 
  }


  return(0);
#endif /* LCD_CH_H_ */
}


</syntaxhighlight ></tab>
</syntaxhighlight ></tab>

Verzia z 21:29, 2. máj 2025

Záverečný projekt predmetu MIPS / LS2025 - Martin Hubocký

Zadanie

Mojím zadaním bolo vytvoriť program, ktorý bude zo senzoru DHT22 (Snímač teploty a vlhkosti) čítať a spracovávať dáta a cez UART sériovú komunikáciu ich vypísať na obrazovku monitoru. V prípade že sa mi to podarí spravím rozšírenie programu aby sa dáta zobrazovali na displeji typu LCD (Liquid Crystal Display).

Obrázok 1: Mikrokontrolér Arduino UNO R3 a jeho vsupno-výstupné periférie


Analýza a opis riešenia

Postup vypracovávania projektu a opis činnosti zariadenia

Najskôr som vo vývojovom prostredí Arduino IDE overil funkčnosť snímača. V tomto prostredí sa nachádza množstvo knižníc, takže mi "spojazdnenie" snímaču trvalo pár minút. Keď som si bol istý že snímač funguje, prešiel som do prostredia AVR, kde to bez knižníc bolo trochu tažšie (trochu dosť :) ). Najskôr sa mi dlhú dobu nedarilo, potom sa mi podarilo cez UART vypísať celočíselné hodnoty, a napokon aj desatinné miesta. Na komunikáciu cez UART som samozrejme použil knižnicu, ktorú sme si vytvárali na cvičení z predmetu.


Ďalej som postupoval s pripojením displeja k mikrokontroléru podľa návodu na stránke (Tu), kde bol takisto aj link na stiahnutie knižnice lcd_ch.h (a lcd_ch.c), ktorú takisto vo svojom programe používam. Vytvoril (zadefinoval) som si dva vlastné znaky. 1. bol znak "°" (Stupeň Celzia), a 2. bol znak "ť" ktorý sa mi nepodaril práve najkrajšie (Pretože displej ktorý vo svojom projekte používam vykresľuje jeden znak pomocou políčka o rozmeroch 5x7 pixelov a nie 5x8 pixelov ako niektoré iné modely). Takisto som vypol kurzor displeju pretože mi osobne vadil. Zo začiatku som si myslel že displej nefunguje, no neskôr som si uvedomil svoju amatérsku chybu keď som zistil že som pomocou potenciometra nemal nastavený správny jas. Okrem toho som s displejom žiadny iný problém nemal.


Týmto som mal hlavnú úlohu svojho projektu splnenú, no rozhodol som sa ho ešte obohatiť o svetelnú a zvukovú signalizáciu. Do zapojenia som pridal dve RGB LED diódy (aj s rezistormi k nim) a jedno Piezo. Jedna dióda mala signalizovať stav teploty a druhá stav vlhkosti. Každá má 5 stavov:

1. Veľmi nízka hodnota - Biela farba - (1. Teplota je nižšia ako 28 °C), (2. Vlhkosť je nižšia ako 50 %)

2. Nízka hodnota - Modrá farba - (1. Teplota je v rozmedzí 28 - 32 °C), (2. Vlhkosť je v rozmedzí 50 - 60 %)

3. Stredná hodnota - Zelená farba - (1. Teplota je v rozmedzí 32 - 36 °C), (2. Vlhkosť je v rozmedzí 60 - 70 %)

4. Vysoká hodnota - Červená farba - (1. Teplota je v rozmedzí 36 - 40 °C), (2. Vlhkosť je v rozmedzí 70 - 80 %)

5. Veľmi vysoká hodnota - Fialová farba - (1. Teplota je vyššia ako 40 °C), (2. Vlhkosť je vyššia ako 80 %)

Úlohou pieza je signalizovať zmenu týchto 5 stavov (pípaním). Keďže piezo je len jedno, signalizuje zmenu stavu aj pre teplotu aj pre vlhkosť, no rozdiel je v tom že pri zmene stavu teploty spraví "krátke pípnutie" a pri zmene vlhkosti "dlhé pípnutie". Piezo rozlišuje aj to, či sa stav zmenil smerom nahor alebo nadol (teda napríklad či sa teplota zvýšila alebo znížila), a to tak, že pri zmene stavu nahor (inkrementácii), pípne dva krát a pri zmene stavu nadol (dekrementácii), pípne len raz. Teda ak sa napríklad zvýši stav vlhkosti, piezo spraví dve dlhé pípnutia, ak sa napríklad zníži stav teploty piezo spraví jedno krátke pípnutie a pod. Ak sa stane že teplota alebo vlhkosť dosiahne posledný 5. stav (najvyšší), piezo bude pípať "stále" (v skutočnosti bude pípať 5x v každej main() slučke programu). V tomto prípade som nepredpokladal že by som pri mojom "amatérskom testovaní" mohol vytvoriť také podmienky, že by mohlo dôjsť k 5. stavu teploty aj vlhkosti súčasne keďže zo zvyšujúcou sa teplotou vlhkosť klesá a zas naopak.


Poslednou vecou ktorú som spravil bolo, že som si zo starej stavebnice poskladal držiak na ktorý som umiestnil snímač aby som si uľahčil testovaciu (overovaciu) časť tohto projektu.


Obrázok 2: Finálny vzhľad zariadenia

Schéma zapojenia a jej popis

Mikrokontrolér Arduino UNO R3

- MASTER (riadiaci orgán celého zariadenia)

- sú k nemu pripojené všetky ostatné zariadenia a súčiastky použité v projekte

- je napájaný priamo z notebooku pomocou USB kábla (a zároveň je ním aj programovaný)

Snímač teploty a vlhkosti DHT22

- má 3 piny:

    VCC   - pripojený k 5V pinu mikrokontroléra
    GND   - pripojený ku GND (Zem) pinu mikrokontroléra
    DATA  - pripojený k D8 pinu mikrokontroléra
            --> Cez tento pin prichádzajú do mikrokontroléra dáta v tvare: 
               [Vlhkosť celé číslo, Vlhkosť desatinné číslo, Teplota celé číslo, Teplota desatinné číslo, Kontrolný súčet]
               [8 bitov, 8 bitov, 8 bitov, 8 bitov, 8 bitov; 8 + 8 + 8 + 8 + 8 = 40 bitový prenos]

Liquid Crystal Display typu DEM16216

- má 16 pinov:

    VSS   - pripojený ku GND (Zem) pinu mikrokontroléra
    VDD   - pripojený k 5V pinu mikrokontroléra
            --> Piny VSS a VDD slúžia na napájanie displeja
    VO    - je naň prostredníctvom potenciometra privedené napätie
            --> Týmto pinom sa v závislosti od privedeného napätia nastavuje jas (kontrast)
    RS    - je pripojený k D2 pinu mikrokontroléra
            --> Slúži na výber registra (Command RS=0; DATA RS=1)
    R/W   - je pripojený k D3 pinu mikrokontroléra
            --> Slúži na výber medzi čítaním alebo zápisom (READ R/W=1; WRITE R/W=0)
    E     - je pripojený k D4 pinu mikrokontroléra
            --> Slúži na spustenie časového signálu (Hovorí displeju kedy má čítať) (Reaguje pri dobežnej hrane)
    D0-D3 - sú nezapojené (pretože nepoužívam 8 bitový mód ale len 4 bitový)
    D4-D7 - sú zapojené k pinom D9-D12 mikrokontroléru
            --> Slúžia na 4 bitový prenos dát
    A     - pripojený ku GND (Zem) pinu mikrokontroléra
    K     - pripojený k 5V pinu mikrokontroléra
            --> Piny A a K slúžia na zapnutie podsvietenia displeja

RGB LED Diódy

- každá má 4 piny:

    R     - sú cez odpory R6 a R3 (220 Ω) pripojené k A0 (LED1) a A3 (LED2) pinom mikrokontroléra
            --> Slúžia na zapínanie červenej LED diódy (privedením log. 1)
    G     - sú cez odpory R5 a R2 (220 Ω) pripojené k A1 (LED1) a A4 (LED2) pinom mikrokontroléra
            --> Slúžia na zapínanie zelenej LED diódy (privedením log. 1)
    B     - sú cez odpory R4 a R1 (220 Ω) pripojené k A2 (LED1) a A5 (LED2) pinom mikrokontroléra
            --> Slúžia na zapínanie modrej LED diódy (privedením log. 1)
    GND     - obidva piny (LED1 aj LED2) sú pripojené ku GND (Zem) pinu mikrokontroléra

Piezo

- má 2 piny:

    VCC     - pripojený k D13 pinu mikrokontroléra
              --> V závislosti od signálu vydá piezo zvuk (V mojom prípade je to vždy log. 1 a teda frekvencia zvuku je vždy rovnaká)
    GND     - pripojený ku GND (Zem) pinu mikrokontroléra
Obrázok 3: Schéma zapojenia vytvorená v programe EAGLE


Algoritmus a program

Vo svojom hlavnom programe som si vytvoril nasledovné funkcie:

  • void lcd_print_float(float hodnota);
  • void Vlastne_znaky(void);
  • void RGB_teplota(uint8_t cervena, uint8_t zelena, uint8_t modra);
  • void RGB_vlhkost(uint8_t cervena, uint8_t zelena, uint8_t modra);
  • void Farba_teplota(float teplota);
  • void Farba_vlhkost(float vlhkost);
  • void Pipnutie(uint8_t pocet_pipnuti);
  • void Pipnutie_dlhe(uint8_t pocet_pipnuti);
  • uint8_t Precitaj_senzor(void);

Myslím si, že som svoj kód prehľadne okomentoval a preto nebudem v tejto časti vysvetľovať jeho funkčnosť.


Okrem týchto funkcií nepriamo využívam aj pár pomocných funkcií z knižníc. Tie používam dve:

  • uart.h (a uart.c) - Túto knižnicu sme si robili na cvičení z predmetu počas semestru
  • lcd_ch.h (a lcd_ch.c) - Túto knižnicu som podľa dohody s vyučujúcim použil z web-stránky ktorej odkaz je uvedený na spodku pod názvom "Práca s displejom"


Tu je výpis celého kódu aj spolu s knižnicami:


// Semestrálny projekt z predmetu Mikropočítačové systémy (MIPS)
// Téma: Kombinovaný snímač teploty a vlhkosti DHT22
// Vypracoval: Martin Hubocký
// Školský rok: 2024/2025

// ======================[ Knižnice (+ frekvencia) ]======================

#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include "uart.h"
#include "lcd_ch.h"

// ======================[ Definície a premenné ]======================

#define Snimac_DHT22 PB0
uint8_t Pole_udajov[5];

#define RGB_teplota_cervena PC0
#define RGB_teplota_zelena PC1
#define RGB_teplota_modra PC2
#define RGB_vlhkost_cervena PC3
#define RGB_vlhkost_zelena PC4
#define RGB_vlhkost_modra PC5

#define Piezo PB5

int aktualny_stav_teplota = 0;
int posledny_stav_teplota = 0;
int aktualny_stav_vlhkost = 0;
int posledny_stav_vlhkost = 0;

// ======================[ Deklarácie pomocných funkcií ]====================== 
// (Bez tohto to malo problém s kompiláciou lebo mám funkcie definované až za main(), pretože mi to osobne prišlo prehľadnejšie)

void lcd_print_float(float hodnota);
void Vlastne_znaky(void);
void RGB_teplota(uint8_t cervena, uint8_t zelena, uint8_t modra);
void RGB_vlhkost(uint8_t cervena, uint8_t zelena, uint8_t modra);
void Farba_teplota(float teplota);
void Farba_vlhkost(float vlhkost);
void Pipnutie(uint8_t pocet_pipnuti);
void Pipnutie_dlhe(uint8_t pocet_pipnuti);
uint8_t Precitaj_senzor(void);

// ======================[ Hlavná funkcia main() ]======================

int main(void) {
	
    // Inicializácia výstupov RGB LED-iek a Pieza
	
    DDRC |= (1<<RGB_teplota_cervena) | (1<<RGB_teplota_zelena) | (1<<RGB_teplota_modra) | (1<<RGB_vlhkost_cervena) | (1<<RGB_vlhkost_zelena) | (1<<RGB_vlhkost_modra);
    DDRB |= (1 << Piezo);

    uart_init();                                                         // Inicializácia sériovej komunikácie (UART)
    lcd_init();                                                          // Inicializácia displeju
    lcd_command(0x0C);                                                   // Vypnutie kurzoru

    Vlastne_znaky();                                                     // Definovanie vlastných znakov (°C a ť)

    char buffer[32], pole_teplota[10], pole_vlhkost[10];                 // Definície pomocných polí a ich dĺžok (budú využité neskôr v programe (UART))

    uart_puts("Spustenie\n");
    _delay_ms(1000);
    Precitaj_senzor();                                                   // Načítam dáta zo senzoru teploty a vlhkosti (DHT22)
    _delay_ms(2000);

    while (1) {
        _delay_ms(2000);

        if (Precitaj_senzor()) {                                         // Ak sa podarí načítať dáta zo senzoru...
			
            // Výpočet vlhkosti (resp. spracovanie do float premennej)
            uint16_t raw_vlhkost = ((uint16_t)Pole_udajov[0] << 8) | Pole_udajov[1];
            float vlhkost = raw_vlhkost / 10.0;
			
            // Výpočet teploty (resp. spracovanie do float premennej)
            uint16_t raw_teplota = ((uint16_t)Pole_udajov[2] << 8) | Pole_udajov[3];
            float teplota = raw_teplota / 10.0;
			
			
            if (Pole_udajov[2] & 0x80) {                                 // Ak je teplota záporná uloží znamienko mínus
                teplota = -((raw_teplota & 0x7FFF) / 10.0);
            }

            // Výpis cez UART
			dtostrf(teplota, 5, 1, pole_teplota);                        // Uloží hodnotu teploty do pole_teplota ktoré sa vypíše cez UART
            dtostrf(vlhkost, 5, 1, pole_vlhkost);                        // Uloží hodnotu vlhkosti do pole_vlhkost ktoré sa vypíše cez UART
			
            sprintf(buffer, "Teplota: %s C\n", pole_teplota);
            uart_puts(buffer);
            sprintf(buffer, "Vlhkost: %s %%\n", pole_vlhkost);
            uart_puts(buffer);
			
            // Výpis na displej
			// (1. Riadok displeju)
            lcd_command(0x80);
            zob_text("Teplota:");
            Vypis_na_displej(teplota);
            lcd_data(1);                                                 // znak °
            lcd_data('C');
            // (2. Riadok displeju)
            lcd_command(0xC0);
            zob_text("Vlhkos");
            lcd_data(2);                                                 // znak ť
            lcd_data(':');
            Vypis_na_displej(vlhkost);
            lcd_data('%');
			
			// Nastavenie farieb RGB LED-iek
            Farba_teplota(teplota);
            Farba_vlhkost(vlhkost);
			}
			
			else {                                                       // Ak by došlo k chybe pri načítaní dát zo senzoru... (Len sa vypíše na UART a displej)
            uart_puts("Chyba pri nacitani dat zo senzoru (DHT22)\n");
            lcd_command(0x80);
            zob_text("Chyba senzora   ");
            lcd_command(0xC0);
            zob_text("                ");
        }
    }
}

// ======================[ Funkcie pre farebnú signalizáciu a zvukovú signalizáciu ]======================

// Prevedie (Zasvieti) požadovanú farbu RGB diódy teploty na "kód"
void RGB_teplota(uint8_t cervena, uint8_t zelena, uint8_t modra) {       // Ak má príslušná farba RGB LED-ky zasvietiť musím zapísať log. 1, inak nesvieti
    if (cervena) PORTC |= (1<<RGB_teplota_cervena); else PORTC &= ~(1<<RGB_teplota_cervena);
    if (zelena) PORTC |= (1<<RGB_teplota_zelena); else PORTC &= ~(1<<RGB_teplota_zelena);
    if (modra) PORTC |= (1<<RGB_teplota_modra); else PORTC &= ~(1<<RGB_teplota_modra);
}

// Prevedie (Zasvieti) požadovanú farbu RGB diódy vlhkosti na "kód"
void RGB_vlhkost(uint8_t cervena, uint8_t zelena, uint8_t modra) {       // Ak má príslušná farba RGB LED-ky zasvietiť musím zapísať log. 1, inak nesvieti
    if (cervena) PORTC |= (1<<RGB_vlhkost_cervena); else PORTC &= ~(1<<RGB_vlhkost_cervena);
    if (zelena) PORTC |= (1<<RGB_vlhkost_zelena); else PORTC &= ~(1<<RGB_vlhkost_zelena);
    if (modra) PORTC |= (1<<RGB_vlhkost_modra); else PORTC &= ~(1<<RGB_vlhkost_modra);
}

// Na základe veľkosti hodnoty teploty vyhodnotí príslušnú farbu ktorou má RGB LED-ka svietiť, stav teploty (5 stavov (28°C; 40°C; interval 4°C)) a ak došlo k zmene stavu vyhodnotí smer zmeny t.j. či teplota stúpla alebo klesla (využije sa neskôr pri zvukovej signalizácii) 
void Farba_teplota(float teplota) {
	
	// Vyhodnotenie veľkosti hodnoty teploty a priradenie stavu
    if (teplota <= 28.0) {                                               // Ak je teplota menšia alebo rovná ako 28°C zaviesti biela farba a určí stav teploty ako stav 1
        RGB_teplota(1, 1, 1); aktualny_stav_teplota = 1;
    } else if (teplota <= 32.0) {                                        // Ak je teplota menšia alebo rovná ako 32°C zaviesti modrá farba a určí stav teploty ako stav 2
        RGB_teplota(0, 0, 1); aktualny_stav_teplota = 2;
    } else if (teplota <= 36.0) {                                        // Ak je teplota menšia alebo rovná ako 36°C zaviesti zelená farba a určí stav teploty ako stav 3
        RGB_teplota(0, 1, 0); aktualny_stav_teplota = 3;
    } else if (teplota <= 40.0) {                                        // Ak je teplota menšia alebo rovná ako 40°C zaviesti červená farba a určí stav teploty ako stav 4
        RGB_teplota(1, 0, 0); aktualny_stav_teplota = 4;
    } else {                                                             // Ak je teplota vaačšia ako 40°C zaviesti fialová farba a určí stav teploty ako stav 5
        RGB_teplota(1, 0, 1); aktualny_stav_teplota = 5;                 // (Keďže tento stav sa považuje "akože" za nebezpečný, piezo bude pípať (Nebude pípať nonstop ale bude pípať za každým keď program main() spraví jeden cyklus))
        Pipnutie(5);
    }

    // Vyhodnotenie zmeny a smeru zmeny teploty 
    if (aktualny_stav_teplota > posledny_stav_teplota) Pipnutie(2);      // Ak teplota stúpla piezo pípne dva krát (len ak došlo k zmene)
    else if (aktualny_stav_teplota < posledny_stav_teplota) Pipnutie(1); // Ak teplota klesla piezo pípne jeden krát (len ak došlo k zmene)
    posledny_stav_teplota = aktualny_stav_teplota;
}

// Na základe veľkosti hodnoty vlhkosti vyhodnotí príslušnú farbu ktorou má RGB LED-ka svietiť, stav vlhkosti (5 stavov (50%; 80%; interval 10%)) a ak došlo k zmene stavu vyhodnotí smer zmeny t.j. či vlhkosť stúpla alebo klesla (využije sa neskôr pri zvukovej signalizácii) 
void Farba_vlhkost(float vlhkost) {
    
	// Vyhodnotenie veľkosti hodnoty vlhkosti a priradenie stavu
	if (vlhkost <= 50.0) {                                               // Ak je vlhkosť menšia alebo rovná ako 50% zaviesti biela farba a určí stav vlhkosti ako stav 1
        RGB_vlhkost(1, 1, 1); aktualny_stav_vlhkost = 1;
    } else if (vlhkost <= 60.0) {                                        // Ak je vlhkosť menšia alebo rovná ako 60% zaviesti modrá farba a určí stav vlhkosti ako stav 2
        RGB_vlhkost(0, 0, 1); aktualny_stav_vlhkost = 2;
    } else if (vlhkost <= 70.0) {                                        // Ak je vlhkosť menšia alebo rovná ako 70% zaviesti zelená farba a určí stav vlhkosti ako stav 3
        RGB_vlhkost(0, 1, 0); aktualny_stav_vlhkost = 3;
    } else if (vlhkost <= 80.0) {                                        // Ak je vlhkosť menšia alebo rovná ako 80% zaviesti červená farba a určí stav vlhkosti ako stav 4
        RGB_vlhkost(1, 0, 0); aktualny_stav_vlhkost = 4;
    } else {                                                             // Ak je vlhkosť väčšia ako 80% zaviesti fialová farba a určí stav vlhkosti ako stav 5
        RGB_vlhkost(1, 0, 1); aktualny_stav_vlhkost = 5;                 // (Keďže tento stav sa považuje "akože" za nebezpečný, piezo bude pípať (pípnutie je dlhšie ako pri teplote) (Nebude pípať nonstop ale bude pípať za každým keď program main() spraví jeden cyklus))
        Pipnutie_dlhe(5);
    }

    // Vyhodnotenie zmeny a smeru zmeny vlhkosti
    if (aktualny_stav_vlhkost > posledny_stav_vlhkost) Pipnutie_dlhe(2); // Ak vlhkost stúpla piezo pípne dva krát (pípnutie je dlhšie ako pri teplote) (len ak došlo k zmene)
    else if (aktualny_stav_vlhkost < posledny_stav_vlhkost) Pipnutie_dlhe(1); // Ak vlhkost stúpla piezo pípne jeden krát (pípnutie je dlhšie ako pri teplote) (len ak došlo k zmene)
    posledny_stav_vlhkost = aktualny_stav_vlhkost;
}

// ======================[ Piezo reproduktor ]======================

// Pípanie pre teplotu
void Pipnutie(uint8_t pocet_pipnuti) {
    for (uint8_t i = 0; i < pocet_pipnuti; i++) {                        // Piezo pípa požadovaný "pocet_pipnuti" krát pre teplotu t. j. pípa krátko (100ms hučí a 100ms je ticho)
        PORTB |= (1 << Piezo);
        _delay_ms(100);
        PORTB &= ~(1 << Piezo);
        _delay_ms(100);
    }
}

// Pípanie pre vlhkosť
void Pipnutie_dlhe(uint8_t pocet_pipnuti) {                              // Piezo pípa požadovaný "pocet_pipnuti" krát pre vlhkosť t. j. pípa dlho (500ms hučí a 100ms je ticho)
    for (uint8_t i = 0; i < pocet_pipnuti; i++) {
        PORTB |= (1 << Piezo);
        _delay_ms(500);
        PORTB &= ~(1 << Piezo);
        _delay_ms(100);
    }
}

// ======================[ Čítanie zo senzora DHT22 ]======================

uint8_t Precitaj_senzor() {
	
    uint8_t bity[5] = {0};  // Pole pre 5 bajtov prijatých zo senzora (po 8 bitov) (2 bajty pre vlhkosť (celé číslo, desatinné číslo), 2 bajty pre teplotu (celé číslo, desatinné číslo), 1 bajt pre kontrolný súčet)
    uint8_t i, j;

    // Odoslanie "Štartovacieho" signálu
    DDRB |= (1 << Snimac_DHT22);
    PORTB &= ~(1 << Snimac_DHT22);
    _delay_ms(2);
    PORTB |= (1 << Snimac_DHT22);
    _delay_us(30);
    DDRB &= ~(1 << Snimac_DHT22);

    // Čakanie na odpoveď
    uint16_t timeout;
    timeout = 100;
    while ((PINB & (1 << Snimac_DHT22)) && timeout--) _delay_us(1);
    if (timeout == 0) return uart_puts("Timeout LOW\n"), 0;
    timeout = 100;
    while (!(PINB & (1 << Snimac_DHT22)) && timeout--) _delay_us(1);
    if (timeout == 0) return uart_puts("Timeout HIGH\n"), 0;
    timeout = 100;
    while ((PINB & (1 << Snimac_DHT22)) && timeout--) _delay_us(1);
    if (timeout == 0) return uart_puts("Timeout koniec HIGH\n"), 0;

    // Príjem dát (5*8 = 40 bitov)
    for (j = 0; j < 5; j++) {
        for (i = 0; i < 8; i++) {
            timeout = 100;
            while (!(PINB & (1 << Snimac_DHT22)) && timeout--) _delay_us(1);
            if (timeout == 0) return uart_puts("Timeout bit start\n"), 0;

            uint8_t count = 0;
            while ((PINB & (1 << Snimac_DHT22))) {
                _delay_us(1);
                if (++count > 100) break;
            }

            if (count > 40) bity[j] |= (1 << (7 - i));
        }
    }

    // Kontrola prijatých dát (Posledný bajt je súčtom 4 pred ním)
    if ((uint8_t)(bity[0] + bity[1] + bity[2] + bity[3]) != bity[4]) {
        uart_puts("Chyba: Kontrolny sucet\n");
        return 0;
    }

    // Uloženie hodnôt
    for (i = 0; i < 5; i++) Pole_udajov[i] = bity[i];
    return 1;
}

// ======================[ Výpis float hodnoty na LCD ]======================

void Vypis_na_displej(float hodnota) {
	// Toto je všetko len formátovanie aby sa to vypísalo na displej "pekne"
	
	// Rozdelenie na celé čísla a čísla za desatinnou čiarkou (DHT22 má rozlíšenie len na jedno desatinné miesto)
    int jednotky = (int)hodnota;
    int desatiny = (int)((hodnota - jednotky) * 10);
    
	// V prípade že by teplota bola záporná (Nemal som ako vyskúšať takže neviem či je to úplne správne)
    if (hodnota < 0) {
        lcd_data('-');
        jednotky = -jednotky;
        desatiny = -desatiny;
    }
	
    // Vypísanie jednotiek
    if (jednotky >= 10)
        lcd_data('0' + (jednotky / 10));
    else
        lcd_data('0');
		
    // Vypísanie desatín
    lcd_data('0' + (jednotky % 10));
    lcd_data('.');
    lcd_data('0' + (desatiny % 10));
}

// ======================[ Vlastné znaky pre LCD ]======================

void Vlastne_znaky(void) {
    unsigned char znak_stupen[8] = {0x06, 0x09, 0x09, 0x06, 0x00, 0x00, 0x00, 0x00};    // Vytvorenie vlastného znaku "°" pomocou jednotlivých pixelov (Samotný displej je síce 5*7 pixelov no mal som problém s kompiláciou a preto je všade 8 hodnôt (tvárim sa že je jeden znak je 5*8))
    unsigned char znak_t_makcen[8] = {0x0D, 0x0A, 0x1C, 0x08, 0x08, 0x09, 0x06, 0x00};  // Vytvorenie vlastného znaku "ť"
	
	// Uložím znaky aby si ich pamätal displej
    def_znak(znak_stupen, 1); 
    def_znak(znak_t_makcen, 2);
}
#include <avr/io.h>
//#include <util/setbaud.h>
#define BAUD 9600
#define F_CPU 16000000UL
void uart_init( void ) 
{
     UBRR0 =103;
/*
#if USE_2X
    UCSR0A |= _BV(U2X0);
#else
    UCSR0A &= ~(_BV(U2X0));
#endif*/

    UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); /* 8-bit data */
    UCSR0B = _BV(RXEN0) | _BV(TXEN0);   /* Enable RX and TX */
}


void uart_putc(char c) 
{
   if (c == '\n') 
    {
       uart_putc('\r');
    }
   loop_until_bit_is_set(UCSR0A, UDRE0); /* Wait until data register empty. */
   UDR0 = c;
}


void uart_puts(const char *s)
{
  
  while(*s!='\0'){
	  uart_putc(*s);
	  s++;
  }
}
char uart_getc(void) {
    loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */
    return UDR0;
}
#ifndef UART_H_
#define UART_H_
#define BAUD 9600
#define F_CPU 16000000UL

void uart_init( void );
void uart_putc( char c );
void uart_puts( const char *s );

char uart_getc( void );

#endif
#include "lcd_ch.h"

unsigned char Znak_OO[8]= {0x00,0x00,0x00,0x00,0x00,0x00,0x15,0};// Prazdny znak	dole su tri bodky

unsigned char Znak_SC[8]= {0x1A,0x1D,0x04,0x04,0x04,0x05,0x02,0};// st.C	
unsigned char Znak_SM[8]= {0x0A,0x04,0x0E,0x10,0x0E,0x01,0x1E,0};//  s + mekcen	
unsigned char Znak_CM[8]= {0x0A,0x04,0x0E,0x10,0x10,0x11,0x0C,0};//  c + mekcen

// Vynulovanie CGRAM
void def_Clear_spec_znaky(void){
	// zapis specialneho znaku do CGRAM  na poziciu 0, a 7
	for(char i = 0; i < 8; i++) def_znak( Znak_OO,i);
	lcd_command(0x80);
} 


 
void def_spec_znaky(void){
// zapis vlastnych znakkov do CGRAM  na poziciu 4, a 0 (8) 


 def_znak( Znak_SC,4);// stupen Celzia
 def_znak( Znak_SM,0);// s + makcen
 // obnovenie obsahu AC. AC nastvime na 1. riadok, 1. znak
 lcd_command(0x80);
}		

#ifndef _Shield_LCD
void def_spec_znaky_AC(void){
// zapis specialneho znaku do CGRAM  na poziciu 7

unsigned char obsah_AC = 0;
 obsah_AC = lcd_read_AC(); //     
 // kon_vyp = obsah_AC;

 // sem dame nove vlastne znaky
 def_znak( Znak_CM,7);// c + makcen
 // obnovenie obsahu AC. AC 

lcd_command(0x80|obsah_AC);

}		
#endif
	 
void ini_ports(void){	 	
	
/* inicializacia portov - vstupy / vystupy 
oba typy displaja */
// nasledovna # riadky su spolocne pre oba typy LCD
LCD_CTRL_DDR |= (1<<LCD_EN_pin);	//  (Enable)    output  
LCD_CTRL_DDR |= (1<<LCD_RS_pin);	//  (RS)        output  	
LCD_DATA_DDR |= (1<<LCD_D4_pin)|(1<<LCD_D5_pin)|(1<<LCD_D6_pin)|(1<<LCD_D7_pin);	// Datove piny ako Output (Data pre display)
#ifndef _Shield_LCD
// klasicky LCD vyuziva aj RW pin
LCD_CTRL_DDR |= (1<<LCD_RW_pin);	//	(RW)        output  
	
#endif
}	


void En_imp(void) {
	LCD_CTRL_PORT |= (1<<LCD_EN_pin);	// -> "log.1"
	LCD_DELAY;							// cca 400 ns
	LCD_CTRL_PORT &= ~(1<<LCD_EN_pin);	// -> "log.0"  spolu cca 500 ns
}

void lcd_init(void)
{   // 4 bitove pripojenie display-a
	ini_ports(); // inicializacia porov
	 _delay_ms(15);
	// 1. -------------------
	LCD_CTRL_PORT &= ~(1 << LCD_RS_pin);		// set RS  = to "log. 0"  Instruction Register (IR)
#ifndef _Shield_LCD
	LCD_CTRL_PORT &= ~(1 << LCD_RW_pin)	;		// set R/W = to "log. 0" - Write
#endif
	// RS R/W   DB7 DB6 DB5 DB4   DB3 DB2 DB1 DB0
	// 0  0     0   0   1   1     x   x   x   x     = 0x30
	PORT_DATA_WR_H(0x30);	// 8-bitove pripojenie
	En_imp();
	// 2. -------------------
    // zopakujem  8-bitove pripojenie
	_delay_ms(5); En_imp();
	// 3. -------------------
	// zopakujem  8-bitove pripojenie
    _delay_ms(1); En_imp(); // -  stacilo by delay 0.1ms, momentalne najkratsie nastavitelne je 1ms
	// 4. -------------------
	// zmenim na 4-bitove pripojenie
	// RS R/W    DB7 DB6 DB5 DB4    DB3 DB2 DB1 DB0
	// 0  0      0   0   1   0      x   x   x   x    = 0x20
	PORT_DATA_WR_H(0x20);	// 4-bitove pripojenie
	_delay_ms(1); En_imp(); // -  stacilo by delay 0.04ms
	// -------------------		
	// LCD function set      mod: DL = 0 - 4-bitove data, N = 1 - 2 riadky, F = 0 - 5x7 dots 
	// RS R/W    DB7 DB6 DB5 DB4    DB3 DB2 DB1 DB0
	// 0  0      0   0   1   DL     N   F   x   x     = 0x28
	// Mozeme nasledujuci prikaz pre LCD vynechat?
	_delay_ms(2);
	lcd_command(0x28);
	// RS R/W    DB7 DB6 DB5 DB4    DB3 DB2 DB1 DB0
	// 0  0      0   0   0   0	    0   0   0   1     = 0x01 , Display clear
	// Mozeme nasledujuci prikaz pre LCD vynechat?
	_delay_ms(2);
	lcd_command(0x01);
	// RS R/W    DB7 DB6 DB5 DB4    DB3 DB2 DB1 DB0
	// 0  0      0   0   0   0	    0   1   I/D S      = 0x06, I/D = 1 - inkrement
	// Mozeme nasledujuci prikaz pre LCD vynechat?
	_delay_ms(2);
	lcd_command(0x02);
	// RS R/W    DB7 DB6 DB5 DB4    DB3 DB2 DB1 DB0
	// 0  0      0   0   0   0	    1   D   C   B      = 0x0E, D = C = 1 - Display a kurzor zapnute
	// Mozeme nasledujuci prikaz pre LCD vynechat?
	_delay_ms(2);
	lcd_command(0x0E);								// B = 0 - blikanie vypnute
}


//zapis data do Data Register
void lcd_data(unsigned char data){	
	while(busy_flag() & 0x80);
	//while(rd_BF()); // test BF sa da realizovat pre klasicky LCD, nie Shield
	LCD_CTRL_PORT |= (1<<LCD_RS_pin);		//    (RS = High)  
#ifndef _Shield_LCD
	LCD_CTRL_PORT &= ~(1<<LCD_RW_pin);		//    (RW = Low, write) 
#endif
	wr_data (data);	
}

// zapis commandu do Instruction Register
void lcd_command(unsigned char command){ 
	while(busy_flag() & 0x80);
	//while(rd_BF()); // test BF sa da realizovat pre klasicky LCD, nie Shield
	LCD_CTRL_PORT &= ~(1<<LCD_RS_pin);		//   (RS = Low)  
#ifndef _Shield_LCD
	LCD_CTRL_PORT &= ~(1<<LCD_RW_pin);		//   (RW = Low, write) 
#endif
	wr_data (command);	
}

void wr_data(unsigned char data) { 
	PORT_DATA_WR_H(data);		// data High nibble
	En_imp();
			
	PORT_DATA_WR_L(data);		// data Low nibble
	En_imp();
}

#ifdef _Shield_LCD
// namiesto testu BF "pockam". 
// LCD typu Shield ma WR pripojene na GND		
unsigned char busy_flag(void){
	_delay_ms(2);	
	return(0);
}	
#else
// namiesto testu BF "pockam". Vacsine prikazov tento cas vyhovuje		
/*int busy_flag(void){
	_delay_ms(2);	
	return(0);
}
*/
// klasicke pripojenie LCD umozni aj test BF
unsigned char busy_flag(void){ //  rd_BF   
	unsigned char pom = 0;
	LCD_CTRL_PORT &= ~(1<<LCD_RS_pin);	//   (RS = Low)  
	LCD_CTRL_PORT |= (1<<LCD_RW_pin);	//    (RW = High, read) 
    // port B, datove bity budu teraz input
	LCD_DATA_DDR &= ~((1<<LCD_D4_pin)|(1<<LCD_D5_pin)|(1<<LCD_D6_pin)|(1<<LCD_D7_pin));	//  Datove piny nastavime  na input, (Data pre disp)
	
	// Spravne by sa malo vycitavaj pred dobeznou hranou EN impulzu. Je tam urcity presah. Mozeme vycitat aj po dobeznej hrane.
	En_imp();
	pom = PORT_DATA_RD_H; // vycitam High nibble AC
	En_imp();
	pom |= PORT_DATA_RD_L; // vycitam Low nibble AC
	// datove bity zase output
	LCD_DATA_DDR |= (1<<LCD_D4_pin)|(1<<LCD_D5_pin)|(1<<LCD_D6_pin)|(1<<LCD_D7_pin);	// Datove piny nastavime na output (Data pre disp) 
	//if(pom & 0x80) return 1;	// display je busy
	//else 
	return pom;					// display je not busy
}

#endif
	

void zob_text(char *s){
	register unsigned char c;
	while((c = *s++))	lcd_data(c); // retazec konci "nulou"
}

void def_znak(unsigned char *ZnakArray,unsigned char kam) {	
	lcd_command(0x40|(kam << 3)); //nastavenie adresy znaku v CGRAM
	for(unsigned char i = 0; i < 8; i++) lcd_data( *(ZnakArray + i));		
}


/* ********************************************************	*/
/* vypis retazca na poziciu, resp. podla nasledovnych 		*/
/* formatovacich prikazov                                       */
/*   : \r - prechod na novy riadok                              */
/*   : \f - prechod na zaciatok displeja                        */
/* ********************************************************     */
 void lcd_puts(  const char *s)   /* definicia funkcie		*/
{
  
}

#ifndef _Shield_LCD
int8_t lcd_read_AC(void){ //  rd_BF   
	char pom_AC ;
	
	while((pom_AC = busy_flag( )) & 0x80);
	// kedze po BF = 0 este cca 4us sa nezmenil obsah AC
	// treba vycitat este raz  
	pom_AC = busy_flag( );
	return pom_AC;					// display not busy
	
}
#endif
#ifndef F_CPU
 #define F_CPU 16000000UL	/* Define CPU frequency here 16MHz */
#endif

#ifndef LCD_CH_H_
 #define LCD_CH_H_

#include <avr/io.h>
#include <util/delay.h>

/* Nasledovne define rozhodne ktora cast programu sa prelozi: 
   LCD Shiled (WR ma pripojene na GND) a
   priradenie pinov je dane napr.:
   "zamrzne"
   -    https://www.14core.com/wiring-the-lcd-16x2-keypad-shield-on-arduino/
   -	https://wiki.dfrobot.com/LCD_KeyPad_Shield_For_Arduino_SKU__DFR0009
   resp. 
   LCD, zapojenie vid. stranka MIPS
   "zamrzne"
   - http://senzor.robotika.sk/sensorwiki/index.php/LCD_displej_s_radi%C4%8Dom_HD44780
   , ktore ma pripojene aj pin WR
   t.j. moze sa testovat aj pin BF
*/

 /* !!!!!!! 
    #define _Shield_LCD
    !!!!!!! */
extern unsigned char kon_vyp;

#ifdef _Shield_LCD
	#define LCD_CTRL_DDR DDRB
	#define LCD_CTRL_PORT PORTB

	#define LCD_DATA_DDR DDRD
	#define LCD_DATA_PORT PORTD

	// Riadiaca zbernica display-a
	#define LCD_RS_pin 0
	#define LCD_RW_pin = 0
	#define LCD_EN_pin 1
	// Datova zbernica
	#define LCD_D4_pin 4
	#define LCD_D5_pin 5
	#define LCD_D6_pin 6
	#define LCD_D7_pin 7

#else
	// LCD  klasik yapojenie vid. MIPS
	#define LCD_CTRL_DDR DDRD
	#define LCD_CTRL_PORT PORTD

	#define LCD_DATA_DDR DDRB
	#define LCD_DATA_PORT PORTB
	#define LCD_DATA_PIN PINB

	#define LCD_RS_pin 2
	#define LCD_RW_pin 3
	#define LCD_EN_pin 4

	#define LCD_D4_pin 1
	#define LCD_D5_pin 2
	#define LCD_D6_pin 3
	#define LCD_D7_pin 4

#endif
 



// Oneskorenie 6 SC
#define NOP() asm("nop")	
#define LCD_DELAY	NOP();NOP();NOP();NOP();NOP();NOP();

#ifdef _Shield_LCD
// formatovanie dat
#define PORT_DATA_WR_H(x) LCD_DATA_PORT &=0b00001111; LCD_DATA_PORT |= (x & 0xF0 )
#define PORT_DATA_WR_L(x) LCD_DATA_PORT &=0b00001111; LCD_DATA_PORT |= (x & 0x0F )<<4
#else

#define PORT_DATA_WR_H(x) LCD_DATA_PORT &=0b11100001; LCD_DATA_PORT |= (x & 0xF0 )>>3
#define PORT_DATA_WR_L(x) LCD_DATA_PORT &=0b11100001; LCD_DATA_PORT |= (x & 0x0F )<<1

#define PORT_DATA_RD_H ((LCD_DATA_PIN & ((1<<LCD_D4_pin)|(1<<LCD_D5_pin)|(1<<LCD_D6_pin)|(1<<LCD_D7_pin)))<<3)
#define PORT_DATA_RD_L ((LCD_DATA_PIN & ((1<<LCD_D4_pin)|(1<<LCD_D5_pin)|(1<<LCD_D6_pin)|(1<<LCD_D7_pin)))>>1)


#endif

/* Public functions for your use */
#ifndef _Shield_LCD
int8_t lcd_read_AC(void);   
void def_spec_znaky_AC(void);
#endif
	
void lcd_init(void);
void lcd_data(unsigned char );
void lcd_command(unsigned char );
// void lcd_puts(const char *s);  /* deklaracia funkcie  */



void ini_ports(void);
void En_imp(void);

void wr_data (unsigned char );
unsigned char busy_flag(void);

void zob_text(char *);
void def_Clear_spec_znaky(void);


void def_znak(unsigned char *,unsigned char );
void def_spec_znaky(void);

#endif /* LCD_CH_H_ */

Kompletný projekt nájdete tu:

Zdrojový kód: ProjektMartinHubocky.zip

Overenie funkčnosti zariadenia

Funkčnosť zariadenia som overil veľmi jednoducho a to tak že som menil teplotu a vlhkosť v okolí snímača a sledoval či sa zariadenie správa tak ako som chcel. Vlhkosť som menil tak že som na snímač dýchal ústami čím sa mi podarilo zvýšiť vlhkosť niekedy až na 90%. Účinok je takmer instantný a rovnako tak je aj pokles naspäť veľmi rýchly. No a ako som menil teplotu? (.....) Bohužiaľ ma nenapadlo nič "inteligentnejšie" ako ohrievať snímač zospodu zapaľovačom. Bolo to pomerne rýchle, no ale samozrejme som svoju "šikovnosť" nezaprel a raz sa mi podarilo snímač "opáliť". Našťastie stále funguje...

Na obrázku číslo 5 môžete vidieť funkčnosť UART-u a nižšie je video kde môžete vidieť priebeh testovania zariadenia. Rád by som podotkol že na videu sú farby RGB LED diód veľmi skreslené a ťažko ich od seba odlíšiť (niekedy sa zdá že sa farby ani nezmenili), za čo sa ospravedlňujem.

Obrázok 4: Overovanie funkčnosti zariadenia


Obrázok 5: Výpis hodnôt pomocou UART-u



Video:

Literatúra a použité zdroje

Dokumentácia k mikrokontroléru:

Dokumentácia k snímaču DHT22:

Dokumentácia k LCD displeju: