Operácie

Senzor teploty a vlhkosti SHT31: Rozdiel medzi revíziami

Z SensorWiki

 
(14 medziľahlých úprav od rovnakého používateľa nie je zobrazených.)
Riadok 4: Riadok 4:
 
== Zadanie ==
 
== Zadanie ==
  
Sem príde text zadania, ak bolo len voľne formulované, rozpíšte ho podrobnejšie
+
Mojou úlohou v tomto zadaní bolo zapojiť, naprogramovať a overiť funkčnosť senzoru SHT31 a získané informácie vypísať na LCD displej a aj na obrazovku.
  
Mojou úlohou v tomto zadaní bolo zapojiť, naprogramovať a overiť funkčnosť senzoru teploty a vlhkosti SHT31. Výpis informácii v o teplote a vlhkosti som pri mojom riešení realizoval pomocou LCD displeja a aj pomocou výpisu na obrazovku.
+
[[Obrázok:Arduino_NANO_Pinout.jpg|400px|thumb|center|Arduino NANO.]]
 +
 
 +
=== SHT31 ===
 +
 
 +
SHT31 je digitálny snímač teploty a vlhkosti vyrobený spoločnosťou Sensirion. Používa kombináciu senzorov teploty a vlhkosti, ktoré sú umiestnené na jednom čipe. Tieto senzory merajú teplotu a vlhkosť vzduchu a generujú digitálny výstup, ktorý je následne spracovaný mikrokontrlerom alebo iným zariadením. SHT31 komunikuje cez I2C (Inter-Integrated Circuit) zbernicu, pomocou ktorej môže mikrokontroler komunikovať so snímačom a taktiež si vyžiadať údaje o teplote a vlhkosti. Snímače SHT31 sú známe svojou vysokou presnosťou merania teploty a vlhkosti. Jeho presnosť teploty je typicky +-0,2 stupňa Celzia a presnosť relatívnej vlhkosti sa pohybuje v rozmedzí len +-2%.  
  
[[Obrázok:Arduino_NANO_Pinout.jpg|400px|thumb|center|Arduino NANO.]]
 
 
[[Obrázok:SENZOR_SHT31_T_H.jpg|400px|thumb|center|Senzor teploty a vlhkosti SHT31.]]
 
[[Obrázok:SENZOR_SHT31_T_H.jpg|400px|thumb|center|Senzor teploty a vlhkosti SHT31.]]
  
Riadok 21: Riadok 24:
 
== Analýza  a opis riešenia ==
 
== Analýza  a opis riešenia ==
  
Na začiatok si môžeme podľa priložených schém pripojiť senzor SHT31 k mikroprocesoru. Na jeho správne používanie musíme použiť pri SCL (časovom kanále) a SDA (dátovom kanále) pull up rezistory.   
+
Na začiatok si môžeme podľa priloženej schémy pripojiť senzor SHT31 k mikrokontroleru. Na jeho správne používanie musíme použiť pri SCL (časovom kanále) a SDA (dátovom kanále) pull up rezistory.   
  
[[Súbor:OBVOD_SHT31.png|400px|thumb|center|Schéma zapojenia sensoru SHT31.]]
+
[[Súbor:Schema_SHT31.png|400px|thumb|center|Schéma zapojenia sensoru SHT31.]]
  
Po pripojení senzoru si môžeme pripojiť k mikroprocesoru aj LCD displej, ktorý zapojíme podľa priloženej schémy zapojenia.
+
Po pripojení senzoru si môžeme pripojiť k adruinu aj LCD displej, ktorý taktiež zapojíme podľa priloženej schémy zapojenia.
  
 
[[Súbor:LCD_schema_zapojenia.png|400px|thumb|center|Schéma zapojenia LCD displeja.]]
 
[[Súbor:LCD_schema_zapojenia.png|400px|thumb|center|Schéma zapojenia LCD displeja.]]
  
 
Ak sa nám už správne podarilo pripojiť senzor aj displej, hardvérová časť nášho zadania je hotová.
 
Ak sa nám už správne podarilo pripojiť senzor aj displej, hardvérová časť nášho zadania je hotová.
Ďalej nasleduje programová časť. Pri tejto časti budeme používať datasheety, priložené vyššie. Ak chceme aby náš senzor vypisoval informácie na displej, budeme potrebovať knižnicu pre LCD displej. Pre výpis cez sériový kanál na obrazovku budeme potrebovať knižnicu UART. A pre použitie samotného senzora budeme ešte potrebovať používať knižnicu pre I2C zbernicu, ktorá slúži na prenos dát zo senzoru a na ich čítanie.
+
Ďalej nasleduje programová časť. Pri tejto časti budeme používať datasheety, priložené vyššie. Ak chceme aby náš senzor vypisoval informácie na displej, budeme potrebovať knižnicu pre LCD displej. Pre výpis cez sériový kanál na obrazovku budeme potrebovať knižnicu UART, a pre použitie samotného senzora budeme ešte potrebovať používať knižnicu pre I2C zbernicu, ktorá slúži na komunikáciu mikroprocesora so senzorom, pomocou ktorej budeme vedieť zo senzoru vyčítať získané dáta.
Samotný program budeme písať podľa datasheetu, kde si naštudujeme ako náš senzor komunikuje s mikroprocesorom a ako z neho čítať dáta. Na to nám slúži tento obrázok nižšie z datasheetu, ktorý opisuje ako správne komunikovať a vyčítavať zo senzoru informácie.  
+
Samotný program budeme písať podľa datasheetu, kde si naštudujeme ako náš senzor komunikuje s mikroprocesorom a ako z neho čítať dáta. Na to nám slúži obrázok priloženy nižšie, ktorý opisuje ako správne komunikovať a vyčítavať informácie zo senzoru.  
  
 
[[Súbor:CITANIE_DAT_SHT31.png|400px|thumb|center|Algoritmus čítania dát zo senzoru.]]
 
[[Súbor:CITANIE_DAT_SHT31.png|400px|thumb|center|Algoritmus čítania dát zo senzoru.]]
  
Na začiatku začneme posielať I2C adresu a hodnotu, ktorou nastavíme, že chceme zapisovať. Po prijatí ACK (acknowledge), nastavíme MSB (most significant bit) a s ním si pre jednoduchosť vypneme Clock stretching. Ďalej nastavíme LSB (least significant bit), ktorým si volíme repeatebility. Ďalej pošleme informáciu o adrese a hodnote a počkáme na ACK, inak posielanie opakujeme v cykle až kým nedostaneme odpoveď. Keď odpoveď dostaneme, môžeme si do bufferu vyčítať dáta ktoré nám prišli zo senzoru. Tieto dáta nám prídu v dvoch častiach. Jedna nám hovorí o teplote a druhá o vlhkosti. Pomocou vzorčekov, ktoré si nájdeme v datasheete si údaje zo senzoru prepočítame a za pomoci nami vytvorenej funkcie na výpočet a výpis ich môžeme vypísať na displej ale aj cez sériovú linku na obrazovku.
+
Na začiatku začneme posielať I2C adresu a hodnotu, ktorou nastavíme, že chceme zapisovať dáta. Po prijatí ACK (acknowledge), nastavíme MSB (most significant bit) a s ním si pre jednoduchosť vypneme Clock stretching. Ďalej nastavíme LSB (least significant bit), ktorým si volíme repeatebility. Ďalej pošleme informáciu o adrese a hodnote, a počkáme na ACK, inak posielanie opakujeme v cykle až kým nedostaneme odpoveď. Keď odpoveď dostaneme, môžeme si do bufferu vyčítať dáta ktoré nám prišli zo senzoru. Tieto dáta nám prídu v dvoch častiach. Prvá nám hovorí o teplote a druhá o vlhkosti. Pomocou vzorčekov, ktoré si nájdeme v datasheete si údaje zo senzoru prepočítame a za pomoci nami vytvorenej funkcie na výpočet a výpis ich môžeme vypísať na displej ale aj cez sériovú linku na obrazovku.
  
 
=== Algoritmus a program ===
 
=== Algoritmus a program ===
  
 
Algoritmus programu spočíva v prijímaní informácii zo senzoru, ktoré prekonvertujeme na požadované veličiny (Pre nás stupne Celzia pre teplotu a % pre vlhkosť), a následne ich vypíšeme aby sme si mohli pozrieť, čo sa nám podarilo odmerať a či nám všetko správne funguje.
 
Algoritmus programu spočíva v prijímaní informácii zo senzoru, ktoré prekonvertujeme na požadované veličiny (Pre nás stupne Celzia pre teplotu a % pre vlhkosť), a následne ich vypíšeme aby sme si mohli pozrieť, čo sa nám podarilo odmerať a či nám všetko správne funguje.
 
  
 
<tabs>
 
<tabs>
Riadok 48: Riadok 50:
 
Autor: Marián Sušina
 
Autor: Marián Sušina
 
*/
 
*/
 +
  
 
/* hlavickove subory pre komunikaciu s UART, LCD displejom a I2C zbernicou */
 
/* hlavickove subory pre komunikaciu s UART, LCD displejom a I2C zbernicou */
Riadok 53: Riadok 56:
 
#include <stdio.h>
 
#include <stdio.h>
 
#include <util/delay.h>
 
#include <util/delay.h>
 +
#include <stdbool.h>
 
#include "uart.h"
 
#include "uart.h"
 
#include "lcd_ch.h"
 
#include "lcd_ch.h"
Riadok 69: Riadok 73:
  
 
int temp_int = (int)(temperature * 10);   // Prevod na cele cislo s jednym desatinnym miestom
 
int temp_int = (int)(temperature * 10);   // Prevod na cele cislo s jednym desatinnym miestom
sprintf(str, "\fTeplota:%d.%d C\r", temp_int / 10, temp_int % 10); // Formatovanie teploty s jednym desatinnym miestom
+
sprintf(str, "\fTeplota:%d.%d \x04\r", temp_int / 10, temp_int % 10); // Formatovanie teploty s jednym desatinnym miestom
 
lcd_puts(str);   // Vypis teploty na displej
 
lcd_puts(str);   // Vypis teploty na displej
printf("Teplota: %d.%d\r\n", temp_int / 10, temp_int % 10);
+
printf("Teplota: %d.%d \x04\r\n", temp_int / 10, temp_int % 10);   // Vypis teploty cez seriovu linku
  
 
int humi_int = (int)(humidity * 10); // Prevod na cele cislo s jednym desatinnym miestom
 
int humi_int = (int)(humidity * 10); // Prevod na cele cislo s jednym desatinnym miestom
sprintf(str, "Vlhkost:%d.%d %%", humi_int / 10, humi_int % 10); // Formatovanie vlhkosti s jednym desatinnym miestom
+
sprintf(str, "Vlhkos\x03:%d.%d %%", humi_int / 10, humi_int % 10); // Formatovanie vlhkosti s jednym desatinnym miestom
 
lcd_puts(str); // Vypis vlhkosti na displej
 
lcd_puts(str); // Vypis vlhkosti na displej
printf("Vlhkost: %d.%d\r\n", humi_int / 10, humi_int % 10);
+
printf("Vlhkos\x03: %d.%d %%\r\n", humi_int / 10, humi_int % 10); // Vypis vlhkosti cez seriovu linku
 
}
 
}
  
Riadok 124: Riadok 128:
 
uart_init();
 
uart_init();
 
lcd_init();
 
lcd_init();
 
+
 +
lcd_cursor(false); //vypnutie kurzora
 +
 +
/* inicializacia specialnych znakov */
 +
def_spec_znaky();
 +
 
stdout = &mystdout; // funkcia printf();
 
stdout = &mystdout; // funkcia printf();
  
Riadok 138: Riadok 147:
 
return (0);
 
return (0);
 
}
 
}
 
</source></tab>
 
<tab name="lcd_ch.c"><source lang="c++" style="background: LightYellow;">
 
#include "lcd_ch.h"
 
 
void lcd_data(unsigned char);
 
void lcd_command(unsigned char);
 
 
void ini_ports(void);
 
void En_imp(void);
 
 
void wr_data(unsigned char);
 
unsigned char busy_flag(void);
 
int8_t lcd_read_AC(void);
 
 
void zob_text(char *);
 
void def_Clear_spec_znaky(void);
 
 
void def_znak(unsigned char *, unsigned char);
 
void def_spec_znaky(void);
 
 
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);
 
}
 
 
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);
 
}
 
 
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)
 
// klasicky LCD vyuziva aj RW pin
 
LCD_CTRL_DDR |= (1 << LCD_RW_pin); // (RW)        output
 
}
 
 
void EnOn(void)
 
{
 
LCD_CTRL_PORT |= (1 << LCD_EN_pin); // -> "log.1"
 
LCD_DELAY; // cca 400 ns
 
}
 
 
void EnOff(void)
 
{
 
LCD_CTRL_PORT &= ~(1 << LCD_EN_pin); // -> "log.0"
 
LCD_DELAY;
 
}
 
 
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)
 
LCD_CTRL_PORT &= ~(1 << LCD_RW_pin); // set R/W = to "log. 0" - Write
 
// 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)
 
;
 
LCD_CTRL_PORT |= (1 << LCD_RS_pin); //    (RS = High)
 
LCD_CTRL_PORT &= ~(1 << LCD_RW_pin); //    (RW = Low, write)
 
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)
 
LCD_CTRL_PORT &= ~(1 << LCD_RW_pin); //  (RW = Low, write)
 
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();
 
}
 
 
// 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.
 
// Spravne vycitavanie pocas EN impulzu.
 
EnOn();
 
pom = PORT_DATA_RD_H; // vycitam High nibble AC
 
EnOff();
 
 
EnOn();
 
pom |= PORT_DATA_RD_L; // vycitam Low nibble AC
 
EnOff();
 
// 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
 
}
 
 
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));
 
}
 
 
void lcd_putc(char ch)
 
{
 
switch (ch)
 
{
 
case '\r':
 
lcd_command(0xC0); // Presun na za?iatok 2. riadka (0x80 + 0x40)
 
break;
 
 
case '\f':
 
lcd_command(0X80); // Presun na zaciatok 1. riadku
 
break;
 
 
default:
 
lcd_data(ch);
 
}
 
}
 
 
/* ******************************************************** */
 
/* vypis retazca na poziciu, resp. podla nasledovnych */
 
/* formatovacich prikazov                                      */
 
/*  : \r - prechod na novy riadok                              */
 
/*  : \f - prechod na zaciatok displeja                        */
 
/* ********************************************************    */
 
 
void lcd_puts(char *str)
 
{ /* definicia funkcie */
 
 
while (*str)
 
{
 
lcd_putc(*str++);
 
}
 
}
 
 
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
 
}
 
 
 
</source></tab>
 
<tab name="lcd_ch.h"><source lang="c++" style="background: LightYellow;">
 
/*
 
* lcd_ch.h
 
*
 
* Created: 3/10/2021 7:05:39 PM
 
*  Author: Admin
 
*/
 
#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>
 
 
// LCD  klasik zapojenie vid. MIPS
 
//  - http://senzor.robotika.sk/sensorwiki/index.php/LCD_displej_s_radi%C4%8Dom_HD44780
 
 
#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
 
 
// Oneskorenie 6 SC
 
#define NOP() asm("nop")
 
#define LCD_DELAY \
 
    NOP();        \
 
    NOP();        \
 
    NOP();        \
 
    NOP();        \
 
    NOP();        \
 
    NOP();
 
 
#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)
 
 
void lcd_init(void);
 
void lcd_putc(char ch);
 
void lcd_puts(char *str);
 
 
#endif /* LCD_CH_H_ */
 
 
</source></tab>
 
<tab name="uart.c"><source lang="c++" style="background: LightYellow;">
 
/* ************************************************************************* */
 
/* FileName:            uart.c                                              */
 
/* ************************************************************************* */
 
 
#include <avr/io.h>
 
#include <util/delay.h>
 
#include "uart.h"
 
 
void hw_init( void )
 
{
 
  DDRB |= (1<<LED);    // PORTB.5 kde je LED ma byt OUTPUT
 
  /* sem si mozete dopisat svoje vlastne inicializacne prikazy */
 
}
 
 
void uart_init( void )
 
{
 
//  for different BAUD rate change the project settings, or uncomment
 
//  following two lines:
 
// #undef  BAUD          // avoid compiler warning
 
//  #define BAUD 115200
 
 
  #include <util/setbaud.h>  // requires defined BAUD
 
 
 
  UBRR0H = UBRRH_VALUE;
 
  UBRR0L = UBRRL_VALUE;
 
  #if USE_2X                // defined in setbaud.h
 
    UCSR0A |= (1 << U2X0);
 
  #else
 
    UCSR0A &= ~(1 << U2X0);
 
  #endif
 
 
 
    UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); /* 8-bit data */
 
    UCSR0B = _BV(RXEN0) | _BV(TXEN0);  /* Enable RX and TX */
 
}
 
 
 
int uart_putc( char c, FILE *stream )
 
{
 
  if (c == '\n')
 
      uart_putc('\r',stream);
 
 
 
  loop_until_bit_is_set(UCSR0A, UDRE0); /* Wait until data register empty. */
 
  UDR0 = c;
 
  return 0;
 
}
 
 
 
void uart_puts(const char *s, FILE *stream)
 
{
 
while(*s)
 
{
 
uart_putc(*s++, stream);
 
}
 
}
 
 
char uart_getc(void)
 
{
 
    loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */
 
    return UDR0;
 
}
 
 
void delay(int delay)      // vlastna funkcia pre dlhsie casy
 
{
 
  for (int i=1; i<=delay; i++)
 
  _delay_ms(1);
 
}
 
 
</source></tab>
 
<tab name="uart.h"><source lang="c++" style="background: LightYellow;">
 
/* ************************************************************************* */
 
/* FileName:            uart.h                                              */
 
/* ************************************************************************* */
 
 
#define LED PB5  // internal on-board LED
 
 
/* na testovanie su uz zadefinovane */
 
// bit_is_set(PINB, SW1)
 
// bit_is_clear(PINB, SW1)
 
 
/* na cakanie su preddefinovane slucky */
 
// loop_until_bit_is_set(PINB, SW1);    // cakanie na uvolnenie tlacitka
 
// loop_until_bit_is_clear(PINB, SW1);  // cakanie na stlacenie tlacitka
 
 
 
#define set_bit(ADDRESS,BIT) (ADDRESS |= (1<<BIT))
 
#define clear_bit(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))
 
 
#ifndef UART_H_
 
#define UART_H_
 
 
#include <stdio.h>
 
 
#define BAUD_PRESCALE  (((F_CPU / (BAUDRATE * 16UL))) - 1)  // vzor?ek z datasheetu
 
 
void hw_init( void );
 
void uart_init( void );
 
   
 
/* Following definition is compatible with STDIO.H, for more
 
* information see https://www.appelsiini.net/2011/simple-usart-with-avr-libc/
 
*/
 
 
int uart_putc( char c, FILE *stream );
 
void uart_puts( const char *s, FILE *stream);
 
 
char uart_getc( void );
 
 
void delay(int delay);
 
 
#endif /* UART_H_ */
 
 
</source></tab>
 
<tab name="i2cmaster.c"><source lang="c++" style="background: LightYellow;">
 
/*************************************************************************
 
* Title:    I2C master library using hardware TWI interface
 
* Author:  Peter Fleury <pfleury@gmx.ch>  http://jump.to/fleury
 
* File:    $Id: twimaster.c,v 1.4 2015/01/17 12:16:05 peter Exp $
 
* Software: AVR-GCC 3.4.3 / avr-libc 1.2.3
 
* Target:  any AVR device with hardware TWI
 
* Usage:    API compatible with I2C Software Library i2cmaster.h
 
**************************************************************************/
 
#include <inttypes.h>
 
#include <compat/twi.h>
 
 
#include "i2cmaster.h"
 
 
 
/* define CPU frequency in hz here if not defined in Makefile */
 
#ifndef F_CPU
 
#define F_CPU 16000000UL
 
#endif
 
 
/* I2C clock in Hz */
 
#define SCL_CLOCK  100000L
 
 
 
/*************************************************************************
 
Initialization of the I2C bus interface. Need to be called only once
 
*************************************************************************/
 
void i2c_init(void)
 
{
 
/* initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1 */
 
 
TWSR = 0;                        /* no prescaler */
 
TWBR = ((F_CPU / SCL_CLOCK) - 16) / 2;  /* must be > 10 for stable operation */
 
 
}/* i2c_init */
 
 
 
/*************************************************************************
 
  Issues a start condition and sends address and transfer direction.
 
  return 0 = device accessible, 1= failed to access device
 
*************************************************************************/
 
unsigned char i2c_start(unsigned char address)
 
{
 
uint8_t  twst;
 
 
// send START condition
 
TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);
 
 
// wait until transmission completed
 
while (!(TWCR & (1 << TWINT)));
 
 
// check value of TWI Status Register. Mask prescaler bits.
 
twst = TW_STATUS & 0xF8;
 
if ((twst != TW_START) && (twst != TW_REP_START)) return 1;
 
 
// send device address
 
TWDR = address;
 
TWCR = (1 << TWINT) | (1 << TWEN);
 
 
// wail until transmission completed and ACK/NACK has been received
 
while (!(TWCR & (1 << TWINT)));
 
 
// check value of TWI Status Register. Mask prescaler bits.
 
twst = TW_STATUS & 0xF8;
 
if ((twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK)) return 1;
 
 
return 0;
 
 
}/* i2c_start */
 
 
 
/*************************************************************************
 
Issues a start condition and sends address and transfer direction.
 
If device is busy, use ack polling to wait until device is ready
 
 
Input:  address and transfer direction of I2C device
 
*************************************************************************/
 
void i2c_start_wait(unsigned char address)
 
{
 
uint8_t  twst;
 
 
 
while (1)
 
{
 
// send START condition
 
TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);
 
 
// wait until transmission completed
 
while (!(TWCR & (1 << TWINT)));
 
 
// check value of TWI Status Register. Mask prescaler bits.
 
twst = TW_STATUS & 0xF8;
 
if ((twst != TW_START) && (twst != TW_REP_START)) continue;
 
 
// send device address
 
TWDR = address;
 
TWCR = (1 << TWINT) | (1 << TWEN);
 
 
// wail until transmission completed
 
while (!(TWCR & (1 << TWINT)));
 
 
// check value of TWI Status Register. Mask prescaler bits.
 
twst = TW_STATUS & 0xF8;
 
if ((twst == TW_MT_SLA_NACK) || (twst == TW_MR_DATA_NACK))
 
{
 
/* device busy, send stop condition to terminate write operation */
 
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);
 
 
// wait until stop condition is executed and bus released
 
while (TWCR & (1 << TWSTO));
 
 
continue;
 
}
 
//if( twst != TW_MT_SLA_ACK) return 1;
 
break;
 
}
 
 
}/* i2c_start_wait */
 
 
 
/*************************************************************************
 
Issues a repeated start condition and sends address and transfer direction
 
 
Input:  address and transfer direction of I2C device
 
 
Return:  0 device accessible
 
  1 failed to access device
 
*************************************************************************/
 
unsigned char i2c_rep_start(unsigned char address)
 
{
 
return i2c_start(address);
 
 
}/* i2c_rep_start */
 
 
 
/*************************************************************************
 
Terminates the data transfer and releases the I2C bus
 
*************************************************************************/
 
void i2c_stop(void)
 
{
 
/* send stop condition */
 
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);
 
 
// wait until stop condition is executed and bus released
 
while (TWCR & (1 << TWSTO));
 
 
}/* i2c_stop */
 
 
 
/*************************************************************************
 
  Send one byte to I2C device
 
 
  Input:    byte to be transfered
 
  Return:  0 write successful
 
1 write failed
 
*************************************************************************/
 
unsigned char i2c_write(unsigned char data)
 
{
 
uint8_t  twst;
 
 
// send data to the previously addressed device
 
TWDR = data;
 
TWCR = (1 << TWINT) | (1 << TWEN);
 
 
// wait until transmission completed
 
while (!(TWCR & (1 << TWINT)));
 
 
// check value of TWI Status Register. Mask prescaler bits
 
twst = TW_STATUS & 0xF8;
 
if (twst != TW_MT_DATA_ACK) return 1;
 
return 0;
 
 
}/* i2c_write */
 
 
 
/*************************************************************************
 
Read one byte from the I2C device, request more data from device
 
 
Return:  byte read from I2C device
 
*************************************************************************/
 
unsigned char i2c_readAck(void)
 
{
 
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA);
 
while (!(TWCR & (1 << TWINT)));
 
 
return TWDR;
 
 
}/* i2c_readAck */
 
 
 
/*************************************************************************
 
Read one byte from the I2C device, read is followed by a stop condition
 
 
Return:  byte read from I2C device
 
*************************************************************************/
 
unsigned char i2c_readNak(void)
 
{
 
TWCR = (1 << TWINT) | (1 << TWEN);
 
while (!(TWCR & (1 << TWINT)));
 
 
return TWDR;
 
 
}/* i2c_readNak */
 
 
</source></tab>
 
<tab name="i2cmaster.h"><source lang="c++" style="background: LightYellow;">
 
#ifndef _I2CMASTER_H
 
#define _I2CMASTER_H
 
/*************************************************************************
 
* Title:    C include file for the I2C master interface
 
*          (i2cmaster.S or twimaster.c)
 
* Author:  Peter Fleury <pfleury@gmx.ch>
 
* File:    $Id: i2cmaster.h,v 1.12 2015/09/16 09:27:58 peter Exp $
 
* Software: AVR-GCC 4.x
 
* Target:  any AVR device
 
* Usage:    see Doxygen manual
 
**************************************************************************/
 
 
/**
 
@file
 
@defgroup pfleury_ic2master I2C Master library
 
@code #include <i2cmaster.h> @endcode
 
 
@brief I2C (TWI) Master Software Library
 
 
Basic routines for communicating with I2C slave devices. This single master
 
implementation is limited to one bus master on the I2C bus.
 
 
This I2c library is implemented as a compact assembler software implementation of the I2C protocol
 
which runs on any AVR (i2cmaster.S) and as a TWI hardware interface for all AVR with built-in TWI hardware (twimaster.c).
 
Since the API for these two implementations is exactly the same, an application can be linked either against the
 
software I2C implementation or the hardware I2C implementation.
 
 
Use 4.7k pull-up resistor on the SDA and SCL pin.
 
 
Adapt the SCL and SDA port and pin definitions and eventually the delay routine in the module
 
i2cmaster.S to your target when using the software I2C implementation !
 
 
Adjust the  CPU clock frequence F_CPU in twimaster.c or in the Makfile when using the TWI hardware implementaion.
 
 
@note
 
    The module i2cmaster.S is based on the Atmel Application Note AVR300, corrected and adapted
 
    to GNU assembler and AVR-GCC C call interface.
 
    Replaced the incorrect quarter period delays found in AVR300 with
 
    half period delays.
 
 
@author Peter Fleury pfleury@gmx.ch  http://tinyurl.com/peterfleury
 
@copyright (C) 2015 Peter Fleury, GNU General Public License Version 3
 
 
@par API Usage Example
 
  The following code shows typical usage of this library, see example test_i2cmaster.c
 
 
@code
 
 
#include <i2cmaster.h>
 
 
 
#define Dev24C02  0xA2      // device address of EEPROM 24C02, see datasheet
 
 
int main(void)
 
{
 
    unsigned char ret;
 
 
    i2c_init();                            // initialize I2C library
 
 
    // write 0x75 to EEPROM address 5 (Byte Write)
 
    i2c_start_wait(Dev24C02+I2C_WRITE);    // set device address and write mode
 
    i2c_write(0x05);                        // write address = 5
 
    i2c_write(0x75);                        // write value 0x75 to EEPROM
 
    i2c_stop();                            // set stop conditon = release bus
 
 
 
    // read previously written value back from EEPROM address 5
 
    i2c_start_wait(Dev24C02+I2C_WRITE);    // set device address and write mode
 
 
    i2c_write(0x05);                        // write address = 5
 
    i2c_rep_start(Dev24C02+I2C_READ);      // set device address and read mode
 
 
    ret = i2c_readNak();                    // read one byte from EEPROM
 
    i2c_stop();
 
 
    for(;;);
 
}
 
@endcode
 
 
*/
 
 
 
/**@{*/
 
 
#if (__GNUC__ * 100 + __GNUC_MINOR__) < 304
 
#error "This library requires AVR-GCC 3.4 or later, update to newer AVR-GCC compiler !"
 
#endif
 
 
#include <avr/io.h>
 
 
/** defines the data direction (reading from I2C device) in i2c_start(),i2c_rep_start() */
 
#define I2C_READ    1
 
 
/** defines the data direction (writing to I2C device) in i2c_start(),i2c_rep_start() */
 
#define I2C_WRITE  0
 
 
 
/**
 
@brief initialize the I2C master interace. Need to be called only once
 
@return none
 
*/
 
extern void i2c_init(void);
 
 
 
/**
 
@brief Terminates the data transfer and releases the I2C bus
 
@return none
 
*/
 
extern void i2c_stop(void);
 
 
 
/**
 
@brief Issues a start condition and sends address and transfer direction
 
 
@param    addr address and transfer direction of I2C device
 
@retval  0  device accessible
 
@retval  1  failed to access device
 
*/
 
extern unsigned char i2c_start(unsigned char addr);
 
 
 
/**
 
@brief Issues a repeated start condition and sends address and transfer direction
 
 
@param  addr address and transfer direction of I2C device
 
@retval  0 device accessible
 
@retval  1 failed to access device
 
*/
 
extern unsigned char i2c_rep_start(unsigned char addr);
 
 
 
/**
 
@brief Issues a start condition and sends address and transfer direction
 
 
If device is busy, use ack polling to wait until device ready
 
@param    addr address and transfer direction of I2C device
 
@return  none
 
*/
 
extern void i2c_start_wait(unsigned char addr);
 
 
 
/**
 
@brief Send one byte to I2C device
 
@param    data  byte to be transfered
 
@retval  0 write successful
 
@retval  1 write failed
 
*/
 
extern unsigned char i2c_write(unsigned char data);
 
 
 
/**
 
@brief    read one byte from the I2C device, request more data from device
 
@return  byte read from I2C device
 
*/
 
extern unsigned char i2c_readAck(void);
 
 
/**
 
@brief    read one byte from the I2C device, read is followed by a stop condition
 
@return  byte read from I2C device
 
*/
 
extern unsigned char i2c_readNak(void);
 
 
/**
 
@brief    read one byte from the I2C device
 
 
Implemented as a macro, which calls either @ref i2c_readAck or @ref i2c_readNak
 
 
@param    ack 1 send ack, request more data from device<br>
 
              0 send nak, read is followed by a stop condition
 
@return  byte read from I2C device
 
*/
 
extern unsigned char i2c_read(unsigned char ack);
 
#define i2c_read(ack)  (ack) ? i2c_readAck() : i2c_readNak();
 
 
 
 
/**@}*/
 
#endif
 
 
 
</source></tab>
 
</source></tab>
 
</tabs>
 
</tabs>
  
Pridajte sem aj zbalený kompletný projekt, napríklad takto (použite jednoznačné pomenovanie, nemôžeme mať na serveri 10x ''zdrojaky.zip'':
 
  
Zdrojový kód: [[Médiá:projektSHT31MarianSusina.zip|zdrojaky.zip]]
+
Zdrojový kód obsahujúci všetky použité knižnice: [[Médiá:projektSHT31MarianSusina.zip|SHT31D.zip]]
  
  
 
=== Overenie ===
 
=== Overenie ===
  
Po pripojení senzora SHT31 a LCD displeja si vieme overiť funkčnosť programu. Po jeho spustení sa nám začne na LCD displeji ale aj na obrazovke zobrazovať teplota a vlhkosť v intervaloch jendej sekundy.
+
Po pripojení senzora SHT31 a LCD displeja si vieme overiť funkčnosť programu. Po jeho spustení sa nám začne na LCD displeji ale aj na obrazovke zobrazovať teplota a vlhkosť v intervaloch jednej sekundy.
  
[[Súbor:REALNE_PRIPOJENE_ZARIADENIE.jpg|400px|thumb|center|Zapojenie v realite.]]
+
[[Súbor:REALNE_PRIPOJENE_ZARIADENIE_SHT31.jpg|400px|thumb|center|Zapojenie v realite.]]
  
 
'''Video: overenie funkčnosti'''
 
'''Video: overenie funkčnosti'''
<center><youtube>_l02MBu41n0</youtube></center>
+
<center><youtube>https://youtu.be/UQCB-i0sPlg?si=hrC4AC80-KYkaX24</youtube></center>
  
Kľúčové slová 'Category', ktoré sú na konci stránky nemeňte.
 
  
 
[[Category:AVR]] [[Category:MIPS]]
 
[[Category:AVR]] [[Category:MIPS]]

Aktuálna revízia z 17:37, 28. apríl 2024

Záverečný projekt predmetu MIPS / LS2024 - Marián Sušina


Zadanie

Mojou úlohou v tomto zadaní bolo zapojiť, naprogramovať a overiť funkčnosť senzoru SHT31 a získané informácie vypísať na LCD displej a aj na obrazovku.

Arduino NANO.

SHT31

SHT31 je digitálny snímač teploty a vlhkosti vyrobený spoločnosťou Sensirion. Používa kombináciu senzorov teploty a vlhkosti, ktoré sú umiestnené na jednom čipe. Tieto senzory merajú teplotu a vlhkosť vzduchu a generujú digitálny výstup, ktorý je následne spracovaný mikrokontrlerom alebo iným zariadením. SHT31 komunikuje cez I2C (Inter-Integrated Circuit) zbernicu, pomocou ktorej môže mikrokontroler komunikovať so snímačom a taktiež si vyžiadať údaje o teplote a vlhkosti. Snímače SHT31 sú známe svojou vysokou presnosťou merania teploty a vlhkosti. Jeho presnosť teploty je typicky +-0,2 stupňa Celzia a presnosť relatívnej vlhkosti sa pohybuje v rozmedzí len +-2%.

Senzor teploty a vlhkosti SHT31.

Literatúra:

Analýza a opis riešenia

Na začiatok si môžeme podľa priloženej schémy pripojiť senzor SHT31 k mikrokontroleru. Na jeho správne používanie musíme použiť pri SCL (časovom kanále) a SDA (dátovom kanále) pull up rezistory.

Schéma zapojenia sensoru SHT31.

Po pripojení senzoru si môžeme pripojiť k adruinu aj LCD displej, ktorý taktiež zapojíme podľa priloženej schémy zapojenia.

Schéma zapojenia LCD displeja.

Ak sa nám už správne podarilo pripojiť senzor aj displej, hardvérová časť nášho zadania je hotová. Ďalej nasleduje programová časť. Pri tejto časti budeme používať datasheety, priložené vyššie. Ak chceme aby náš senzor vypisoval informácie na displej, budeme potrebovať knižnicu pre LCD displej. Pre výpis cez sériový kanál na obrazovku budeme potrebovať knižnicu UART, a pre použitie samotného senzora budeme ešte potrebovať používať knižnicu pre I2C zbernicu, ktorá slúži na komunikáciu mikroprocesora so senzorom, pomocou ktorej budeme vedieť zo senzoru vyčítať získané dáta. Samotný program budeme písať podľa datasheetu, kde si naštudujeme ako náš senzor komunikuje s mikroprocesorom a ako z neho čítať dáta. Na to nám slúži obrázok priloženy nižšie, ktorý opisuje ako správne komunikovať a vyčítavať informácie zo senzoru.

Algoritmus čítania dát zo senzoru.

Na začiatku začneme posielať I2C adresu a hodnotu, ktorou nastavíme, že chceme zapisovať dáta. Po prijatí ACK (acknowledge), nastavíme MSB (most significant bit) a s ním si pre jednoduchosť vypneme Clock stretching. Ďalej nastavíme LSB (least significant bit), ktorým si volíme repeatebility. Ďalej pošleme informáciu o adrese a hodnote, a počkáme na ACK, inak posielanie opakujeme v cykle až kým nedostaneme odpoveď. Keď odpoveď dostaneme, môžeme si do bufferu vyčítať dáta ktoré nám prišli zo senzoru. Tieto dáta nám prídu v dvoch častiach. Prvá nám hovorí o teplote a druhá o vlhkosti. Pomocou vzorčekov, ktoré si nájdeme v datasheete si údaje zo senzoru prepočítame a za pomoci nami vytvorenej funkcie na výpočet a výpis ich môžeme vypísať na displej ale aj cez sériovú linku na obrazovku.

Algoritmus a program

Algoritmus programu spočíva v prijímaní informácii zo senzoru, ktoré prekonvertujeme na požadované veličiny (Pre nás stupne Celzia pre teplotu a % pre vlhkosť), a následne ich vypíšeme aby sme si mohli pozrieť, čo sa nám podarilo odmerať a či nám všetko správne funguje.

/*
	SHT31D_projekt.c
	Autor: Marián Sušina
*/


/* hlavickove subory pre komunikaciu s UART, LCD displejom a I2C zbernicou */
#include <avr/io.h>
#include <stdio.h>
#include <util/delay.h>
#include <stdbool.h>
#include "uart.h"
#include "lcd_ch.h"
#include "i2cmaster.h"

/* Inicializacia funkcie printf() cez UART */
FILE mystdout = FDEV_SETUP_STREAM(uart_putc, NULL, _FDEV_SETUP_WRITE);

/* Adresa senzora v I2C zbernici */
#define SHT31 0x44

/* Funkcia na zobrazenie teploty a vlhkosti na LCD displeji a do Terminalu. Teplota a vlhkost sa formatuje s jednym desatinnym miestom */
void display_temperature_humidity(float temperature, float humidity)
{
	char str[20];

	int temp_int = (int)(temperature * 10);							   // Prevod na cele cislo s jednym desatinnym miestom
	sprintf(str, "\fTeplota:%d.%d \x04\r", temp_int / 10, temp_int % 10); // Formatovanie teploty s jednym desatinnym miestom
	lcd_puts(str);													   // Vypis teploty na displej
	printf("Teplota: %d.%d \x04\r\n", temp_int / 10, temp_int % 10);	   // Vypis teploty cez seriovu linku

	int humi_int = (int)(humidity * 10);							// Prevod na cele cislo s jednym desatinnym miestom
	sprintf(str, "Vlhkos\x03:%d.%d %%", humi_int / 10, humi_int % 10); // Formatovanie vlhkosti s jednym desatinnym miestom
	lcd_puts(str);													// Vypis vlhkosti na displej
	printf("Vlhkos\x03: %d.%d %%\r\n", humi_int / 10, humi_int % 10);	// Vypis vlhkosti cez seriovu linku
}

/* Funkcia na meranie teploty a vlhkosti */
void measure()
{
	uint8_t buf[6];
	i2c_start_wait(SHT31 << 1 | I2C_WRITE); // posiela I2C adresu a hodnotu na zapis a caka na potvrdenie ACK
	i2c_write(0x24);						// nastavenie MSB -> vypneme s nim Clock stretching
	i2c_write(0x0B);						// nastavenie LSB -> nastavyme si repeatebility na medium
	i2c_stop();

	_delay_ms(1); // pauza 1ms po prikaze (podla datasheetu)

	while (i2c_start(SHT31 << 1 | I2C_READ)) // posleme adresu a hodnotu na citanie a pockame na ACK
	{
		i2c_stop(); // ak prisiel NAK posleme STOP
	}

	for (uint8_t i = 0; i < 6; i++) // precitame 6 bajtov zo snimaca
	{
		buf[i] = i2c_read(i != 5); // zapiseme hodnoty zo snimaca do bufferu
	}
	i2c_stop();

	uint16_t T_RAW = buf[0] << 8 | buf[1];	// hodnota teploty
	uint16_t RH_RAW = buf[3] << 8 | buf[4]; // hodnota vlhkosti
	float T = 175.0 * T_RAW / 0xFFFF - 45;	// prepocet na stupne C
	float RH = RH_RAW * 100.0 / 0xFFFF;		// prepocet na %

	display_temperature_humidity(T, RH); // spustenie funkcie na vypis teploty a vlhkosti na displeji a v terminale
}

int main(void)
{

	/* inicializacia portov - vstupy / vystupy */

	DDRD |= (1 << LCD_EN_pin); // Pin D4 (Enable)  PORTD  output
	DDRD |= (1 << LCD_RW_pin); // Pin D3 (RW)      PORTD  output
	DDRD |= (1 << LCD_RS_pin); // Pin D2 (RS)      PORTD  output

	LCD_DATA_PORT |= (1 << LCD_D4_pin) | (1 << LCD_D5_pin) | (1 << LCD_D6_pin) | (1 << LCD_D7_pin); // Piny 1,2,3,4, PORTB ako output (Data pre display)

	/* inicializacia I2C, UARTu a LCD displeja */
	i2c_init();
	uart_init();
	lcd_init();
	
	lcd_cursor(false); //vypnutie kurzora
	
	/* inicializacia specialnych znakov */
	def_spec_znaky();
	
	stdout = &mystdout; // funkcia printf();

	lcd_puts("Start");
	_delay_ms(500);
	
	while (1)
	{
		measure();
		_delay_ms(1000);
	}

	return (0);
}


Zdrojový kód obsahujúci všetky použité knižnice: SHT31D.zip


Overenie

Po pripojení senzora SHT31 a LCD displeja si vieme overiť funkčnosť programu. Po jeho spustení sa nám začne na LCD displeji ale aj na obrazovke zobrazovať teplota a vlhkosť v intervaloch jednej sekundy.

Zapojenie v realite.

Video: overenie funkčnosti