Operácie

Inteligentný šatník: Rozdiel medzi revíziami

Zo stránky SensorWiki

StudentMIPS (diskusia | príspevky)
StudentMIPS (diskusia | príspevky)
 
(80 medziľahlých úprav od rovnakého používateľa nie je zobrazených.)
Riadok 29: Riadok 29:
Princíp fungovania je pomerne jednoduchý, keďže sa jedná len o prototyp, tak všetky funkcie sú len iba ako príklad, samotné riešenie v realite by bolo oveľa komplexnejšie. Funguje to tak, že z vnútornej strane dverí je nalepený senzor otvorenia dverí, ktorý sníma, či sú otvorené alebo zatvorené dvere. Snímanie je založené na magnete, ak je spojený, dvere sú zatvorené, ak je rozpojený, dvere sú otvorené. Následne ak otvoríme dvierka, tak sa rozpojí senzor a tým zapne LCD displej, na ktorom sa vypíše aktuálna teplota, predpoveď počasia a RGB LED dióda sa rozsvieti na farbu danú podľa teploty.
Princíp fungovania je pomerne jednoduchý, keďže sa jedná len o prototyp, tak všetky funkcie sú len iba ako príklad, samotné riešenie v realite by bolo oveľa komplexnejšie. Funguje to tak, že z vnútornej strane dverí je nalepený senzor otvorenia dverí, ktorý sníma, či sú otvorené alebo zatvorené dvere. Snímanie je založené na magnete, ak je spojený, dvere sú zatvorené, ak je rozpojený, dvere sú otvorené. Následne ak otvoríme dvierka, tak sa rozpojí senzor a tým zapne LCD displej, na ktorom sa vypíše aktuálna teplota, predpoveď počasia a RGB LED dióda sa rozsvieti na farbu danú podľa teploty.


[[Súbor:magnet_reismuller.jpg|400px|thumb|left|Senzor otvorenia dverí MC-38A.]]
[[Súbor:ledRGB.jpg|400px|thumb|center|RGB LED dióda.]]
[[Súbor:displej_reismuller.png|400px|thumb|right|LCD Displej HD44780.]]


=== Algoritmus a program ===
'''Čo sa týka reálneho fungovania takéhoto inteligentného šatníku, predstavoval by som si asi nasledovne:'''


Algoritmus programu je....
Princíp by nebol založený na generovaní náhodných čísel a podľa toho vypisovaní stavov na displeji, ale mohlo by to byť rozdelené na viacero častí, ako napríklad:


a) Do zapojenia by bol implementovaný senzor teploty, vlhkosti a pri otvorení dverí by sa na displeji vypísala aktuálna hodnota teploty a vlhkosti.
b) Do zapojenia by sme zaimplementovali WiFi modul ESP8266, pomocou ktorého by sme sa pripojili na internet a buď cez nejaké open-source API alebo nami vytvorené vlastné API by sme získavali hodnoty teploty, vlhkosti, prípadne ďalšie dáta, ktoré by boli dostupné z API.
Moja predstava by bola asi zameraná skôr na bod b), pretože samotné zapojenie senzoru teploty a vlhkosti by bolo nie úplne prispôsobiteľné ku každej skrini. Ale zase bod b) bude o niečo náročnejší, ako bod a), pretože to programovanie a pripájanie sa na nejaké API a získavanie hodnoty, či zapisovanie na displej by bolo oveľa časovo náročnejšie, ako napríklad vyvŕtať dieru do steny, prípadne kúpiť nejaký senzor s pripojením na bluetooth, kde by sme sa na diaľku pripájali a tak získavali dáta.
<gallery widths=400px heights=400px perrow=3 style="margin-left: auto; margin-right: auto; text-align: center;">
Súbor:magnet_reismuller.jpg|thumb|Senzor otvorenia dverí MC-38A.
Súbor:ledRGB.jpg|thumb|RGB LED dióda.
Súbor:displej_reismuller.png|thumb|LCD Displej HD44780.
</gallery>
=== Zapojenie a schéma ===
LCD displej sme zapojili podľa návodu z [https://senzor.robotika.sk/sensorwiki/index.php/LCD_displej_s_radi%C4%8Dom_HD44780 cvičenia č.11]. Použili sme piny '''PD2,PD3,PD4''' a '''PB1,PB2,PB3,PB4'''. Senzor otvorenia dverí sme zapojili do pinu '''PB5''' a ako posledné RGB LED diódu sme zapojili do pinov '''PD5,PD6 a PD7'''. Pomohli sme si aj s Breadboardom, aby sme si uľahčili pripájanie '''ZEME''' a '''NAPÁJANIA 5V'''.
[[Obrázok:schema_zapojenia_reismuller.png|700px|thumb|center|Schéma zapojenia.]]
=== Program ===
Program sa skladá z hlavnej časti '''main.c''', kde sa riadi celý systém ovládanie '''RGB diódy''', '''LCD displeja''' a samotné fungovanie '''senzoru otvárania dverí'''. A 2 knižníc - '''lcd.c''' (Na fungovanie LCD dipleja) a '''uart.c''' (Na fungovanie sériovej komunikácie a ostatných funkcií použitých v '''main.c''').
Ako prvé sme si zadefinovali '''knižnice''', aby sme mohli ďalej pracovať s kódom v hlavnej časti programu. Ďalej sme už pokračovali len v '''hlavnej časti''' programu a to nasledovne:
Zadefinovali sme si porty na pripojenie do Arduina. Vytvorili sme funkciu '''generátora náhodných čísel''' a následne aj '''časovač''', ktorý umožní generátoru pomimo programu každú 1 sekundu vygenerovať 1 náhodné číslo v intervale od 1 po 6. Ako ďalšie sme si vytvorili funkciu '''stavy()''', kde sa nachádzajú funkcie na '''vypisovanie na displej''' a '''riadenie RGB LED diódy'''. Táto funkcia sa neskôr využije v programe. Potom sme si v hlavnej funkcii '''main()''' spustili inicializáciu '''UART komunikácie''' (UART komunikáciu využívame len čisto na DEBUG na nič iné), '''LCD dipleja''', '''RGB LED diódy''', '''časovača''' a '''senzoru otvorenia dverí'''. A ako posledné sme do '''while()''' funkcie, ktorá prebieha neustále dokola pridali samotné '''riadenie''' celého systému '''inteligentného šatníka''' ovládané '''senzorom otvorenia dverí''', kde sme využili aj funkciu '''stavy()'''.


<tabs>
<tabs>
<tab name="AVR C-code"><source lang="c++" style="background: LightYellow;">
<tab name="main.c"><source lang="c++" style="background: LightYellow;">
#define RED_PIN  PD5
#define GREEN_PIN PD6
#define BLUE_PIN  PD7
 
#define MAGNET_PIN PB5
 
#define LCD_CMD_DISPLAY_OFF_CURSOR_OFF 0x0C
#include <avr/io.h>
#include <avr/io.h>
#include <avr/interrupt.h> // Pre fungovanie random generátora
#include <stdlib.h> // Pre funkcie rand() a srand()
#include <stdio.h>
#include "uart.h"
#include "lcd.h"
FILE mystdout = FDEV_SETUP_STREAM(uart_putc, NULL, _FDEV_SETUP_WRITE);
   
static volatile int randomNumber = 0;
static volatile int priznak = 0;
static volatile int randomNum = 0;
void initRandomGenerator() {
    srand(TCNT0);
}
int generateRandomNumber(int min, int max) { // Zadefinovanie funkcie generátora náhodých čísel.
    randomNum = rand() % (max - min + 1);
    randomNum += min;
    return randomNum;
}
ISR(TIMER1_OVF_vect) {
    TCNT1 = 65536 - 45000; // Nastavenie timera na 5 sekúnd.
priznak = 1;
}
void stavy() {
if (randomNum == 1) {  
lcd_command(0x80); // Nastavenie pozície kurzora na 1. riadok, 1. políčko.
lcd_puts("Teplota: 30\x01\x02\nJasno, Bez vetra");
setRGBled(255, 0, 0);
}
 
if (randomNum == 2) {
lcd_command(0x80);
lcd_puts("Teplota: 25\x01\x02\nSlne\x04no, Veterno");
setRGBled(255, 165, 0);
}
 
if (randomNum == 3) {
lcd_command(0x80);
lcd_puts("Teplota: 16\x01\x02\nJasno, Slne\x04no  ");
setRGBled(255, 255, 0);
}
 
if (randomNum == 4) {
lcd_command(0x80);
lcd_puts("Teplota: 8\x01\x02 \nPoloobla\x04no,D\x03\x05\x06");
setRGBled(102, 204, 255);
}
 
if (randomNum == 5) {
lcd_command(0x80);
lcd_puts("Teplota: 2\x01\x02 \nZamra\x04\x07n\x08, D\x03\x05\x06 ");
setRGBled(153, 0, 204);
}
 
if (randomNum == 6) {
lcd_command(0x80);
lcd_puts("Teplota: -5\x01\x02\nZamra\x04\x07n\x08, Sneh ");
setRGBled(0, 0, 255);
}
}


int main(void)
int main(void) {
{
  uart_init(); // Inicializácia UARTu
   unsigned int measuredValue;
  initRandomGenerator(); // Inicializácia randomGenerator funkcie
  initRGBled(); // Inicilizácia RGB LED diódy
   stdout = &mystdout; // printf() funkcia je zapnutá


   while (1)
   printf("Spustam inicializaciu programu...\n");
   {
 
    /* relax */   
  DDRB &= ~(1 << MAGNET_PIN); // Nastavenie MAGNET pinu na INPUT
  PORTB |= (1 << MAGNET_PIN);
 
  TCCR1B |= (1 << CS12) | (1 << CS10); // Prescaler nastavený na 1024
  TIMSK1 |= (1 << TOIE1);
 
  TCCR0B |= (1 << CS00);
    
  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)
 
  lcd_init(); // Inicializácia LCD Displeja
  def_spec_znaky(); // Inicializácia špeciálnych znakov na displeji
  lcd_command(LCD_CMD_DISPLAY_OFF_CURSOR_OFF); // Vypnutie kurzora na displeji
 
  printf("Inicializacia bola uspesna!\n");
 
  sei();
 
  while(1) {
  if (PINB & (1 << MAGNET_PIN)) {
// Ak je magnet pripojený, do UARTu sa vypíše DEBUG, RGB LED dióda sa vypne a vynuluje sa LCD Displej
printf("Magnet je pripojeny!\r");
setRGBled(0, 0, 0);
lcd_command(0x01);
        } else {
// Ak je magnet odpojený, do UARTu sa vypíše DEBUG a spustí sa funkcia stavy().
printf("Magnet je odpojeny!\r");
if (priznak == 1) {
randomNum = generateRandomNumber(1, 6); // Nastavenie generátora náhodných čísel, aby generovalo len v intervale od 1 po 6.
stavy();
priznak = 0;
}
}
   }
   }
 
 
   return(0);
   return(0);
}
}


</source></tab>
</source></tab>
<tab name="filename.h"><source lang="c++" style="background: LightYellow;">
 
<tab name="uart.c"><source lang="c++" style="background: LightYellow;">
#include <avr/io.h>
#include <avr/io.h>
#include <util/delay.h>
#include "uart.h"
#define RED_PIN  PD5
#define GREEN_PIN PD6
#define BLUE_PIN  PD7


void adc_init(void);                                   // A/D converter initialization
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


unsigned int adc_read(char a_pin);
 
    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)
{
  /* toto je vasa uloha */
}
 
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);
}
 
// Funkcia na inicializáciu pinov
void initRGBled() {
    // Nastavenie pinov ako OUTPUT
    DDRD |= (1 << RED_PIN) | (1 << GREEN_PIN) | (1 << BLUE_PIN);
}
 
// Funkcia na nastavenie farby
void setRGBled(uint8_t r, uint8_t g, uint8_t b) {
    // Nastavenie hodnôt pre červenú, zelenú a modrú LED diódu
    if (r > 0) {
        PORTD |= (1 << RED_PIN);
    } else {
        PORTD &= ~(1 << RED_PIN);
    }
 
    if (g > 0) {
        PORTD |= (1 << GREEN_PIN);
    } else {
        PORTD &= ~(1 << GREEN_PIN);
    }
 
    if (b > 0) {
        PORTD |= (1 << BLUE_PIN);
    } else {
        PORTD &= ~(1 << BLUE_PIN);
    }
}
</source></tab>
</source></tab>
</tabs>


Pridajte sem aj zbalený kompletný projekt, napríklad takto (použite jednoznačné pomenovanie, nemôžeme mať na serveri 10x ''zdrojaky.zip'':  
<tab name="uart.h"><source lang="c++" style="background: LightYellow;">
#define set_bit(ADDRESS,BIT) (ADDRESS |= (1<<BIT))
#define clear_bit(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))
 
#ifndef F_CPU
#define F_CPU 16000000UL /* Define CPU frequency here 16MHz */
#endif
 
#ifndef UART_H_
#define UART_H_
 
#include <stdio.h>
#include <avr/io.h>
#include <util/delay.h>
 
#define BAUD_PRESCALE  (((F_CPU / (BAUDRATE * 16UL))) - 1)
 
void hw_init( void );
void uart_init( void );
int uart_putc( char c, FILE *stream );
void uart_puts( const char *s );
 
char uart_getc( void );
 
void initRGBled();
 
void setRGBled(uint8_t r, uint8_t g, uint8_t b);
 
int generateRandomNumber(int min, int max);
 
void initRandomGenerator();
 
void delay(int delay);
 
#endif /* UART_H_ */
</source></tab>
 
<tab name="lcd.c"><source lang="c++" style="background: LightYellow;">
#include <avr/io.h>
#include "lcd.h"
 
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));
}
 
/* Primitivne funkcie, nepredpoklada sa ich vyuzitie uzivatelom */
unsigned char Znak_S[8]= {0xE,0xE,0xE,0x0,0x0,0x0,0x0,0};// stupen
unsigned char Znak_SM[8]= {0x0A,0x04,0x0E,0x10,0x0E,0x01,0x1E,0};//  s + mekcen
unsigned char Znak_C[8]= {0xe,0x11,0x10,0x10,0x10,0x11,0xe,0};//  C
unsigned char Znak_CM[8]= {0xa,0x4,0xe,0x11,0x10,0x11,0xe,0};//  c + mekcen
unsigned char Znak_DA[8]= {0x2,0x4,0xe,0x01,0x0f,0x11,0x0f,0};//  Dlhe a
unsigned char Znak_Z[8]= {0xa,0x4,0x1f,0x2,0x4,0x8,0x1f,0};//  z + mekcen
unsigned char Znak_D[8]= {0x5,0x5,0xc,0x14,0x14,0x14,0xc,0};//  d + mekcen
unsigned char Znak_E[8]= {0x0,0x0,0xe,0x11,0x1f,0x10,0xe,0};//  e
unsigned char Znak_DE[8]= {0x1,0x2,0xe,0x11,0x1f,0x10,0xe,0};//  dlhe e
/* Funkcia zapise jeden bajt po SPI zbernici do zariadenia */
void def_spec_znaky(void){
// zapis vlastnych znakkov do CGRAM  na poziciu 4, a 0 (8)
 
def_znak( Znak_S,1);// stupen
def_znak( Znak_C,2);// C
def_znak( Znak_CM,4);// c + mekcen
def_znak( Znak_DA,3);// dlhe a
def_znak( Znak_Z,5);// z + mekcen
def_znak( Znak_D,6);// d + mekcen
def_znak( Znak_E,7);// e
def_znak( Znak_DE,8);// dlhe e
// obnovenie obsahu AC. AC nastvime na 1. riadok, 1. znak
lcd_command(0x80);
}
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"
}
 
/* ******************************************************** */
/* vypis retazca na poziciu, resp. podla nasledovnych */
/* formatovacich prikazov                                      */
/*  : \n - prechod na novy riadok                              */
/*  : \f - prechod na zaciatok displeja                        */
/* ********************************************************    */
void lcd_puts(char *str) {
    while (*str) {
        if (*str == '\n') {
            lcd_command(0xC0); // Presun na začiatok 2. riadka (0x80 + 0x40)
        } else if (*str == '\f') {
            lcd_command(0x80); // Presun na začiatok 1. riadka (displeja)
        } else {
            lcd_data(*str); // Vypíš znak na displej
        }
        str++; // Presun na ďalší znak vstupného reťazca
    }
}
 
#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
 
</source></tab>
 
<tab name="lcd.h"><source lang="c++" style="background: LightYellow;">
#ifndef LCD_H_
#define LCD_H_
 
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
 
#define LCD_RS_pin 0
#define LCD_EN_pin 1
#define LCD_D4_pin 4
#define LCD_D5_pin 5
#define LCD_D6_pin 6
#define LCD_D7_pin 7
 
#else
#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
 
#define NOP() asm("nop")
#define LCD_DELAY NOP();NOP();NOP();NOP();NOP();NOP();
 
#ifdef _Shield_LCD
#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
 
#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 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);


Zdrojový kód: [[Médiá:projektMenoPriezvisko.zip|zdrojaky.zip]]


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


=== Overenie ===
#endif /* LCD_H_ */
</source></tab>
</tabs>


Na používanie našej aplikácie stačia dve tlačítka a postup používania je opísaný v sekcii popis riešenia.  
Zdrojový kód: [[Médiá:reismuller_semestralna_praca.zip|reismuller_semestralna_praca.zip]]
Na konci uvádzame fotku záverečnej obrazovky pred resetom. Vypísaný je tu priemerný čas a najlepší čas.  


[[Súbor:fotka.jpg|400px|thumb|center|Aplikácia.]]
=== Overenie funkčnosti ===
 
Overenenie funkčnosti môžeme vidieť na videu, ktoré sa nachádza nižšie.
Taktiež môžeme vidieť aj 2 fotky so zapojením.
 
<gallery widths=400px heights=400px perrow=2 style="margin-left: auto; margin-right: auto; text-align: center;">
Súbor:zapojenie1_reismuller.jpg|400px|Zapojenie.
Súbor:zapojenie2_reismuller.jpg|400px|Zapojenie.
</gallery>


'''Video:'''
'''Video:'''
<center><youtube>_l02MBu41n0</youtube></center>
<center><youtube>qaBlvGWYyzM</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 19:28, 28. apríl 2024

Záverečný projekt predmetu MIPS / LS2024
Vypracoval: Tomáš Reismüller
Projekt: Inteligentný šatník
Študijný odbor: Automobilová mechatronika
Ročník: 2. Bc.

Zadanie

Cieľom tohto projektu bolo vytvoriť prototyp inteligentného šatníka, ktorý nám po otvorení dvierok vypíše na LCD displeji vonkajšiu teplotu aj s aktuálnou predpoveďou počasia a následne rozsvieti RGB LED diódu na farbu danú podľa teploty, napríklad: Červená = 30 °C,Modrá = -2 °C, a pod.

Vývojová doska ARDUINO-UNO-R3.

Literatúra:


Analýza a opis riešenia

Model inteligentného šatníku je zostrojený z troch rôznych súčiastok a to: LCD displej s radičom HD44780,Senzor otvorenia dverí MC-38A,RGB LED dióda. Tieto súčiastky sú zapojené pomocou Breadboardu do Arduina UNO R3.

Princíp fungovania je pomerne jednoduchý, keďže sa jedná len o prototyp, tak všetky funkcie sú len iba ako príklad, samotné riešenie v realite by bolo oveľa komplexnejšie. Funguje to tak, že z vnútornej strane dverí je nalepený senzor otvorenia dverí, ktorý sníma, či sú otvorené alebo zatvorené dvere. Snímanie je založené na magnete, ak je spojený, dvere sú zatvorené, ak je rozpojený, dvere sú otvorené. Následne ak otvoríme dvierka, tak sa rozpojí senzor a tým zapne LCD displej, na ktorom sa vypíše aktuálna teplota, predpoveď počasia a RGB LED dióda sa rozsvieti na farbu danú podľa teploty.


Čo sa týka reálneho fungovania takéhoto inteligentného šatníku, predstavoval by som si asi nasledovne:

Princíp by nebol založený na generovaní náhodných čísel a podľa toho vypisovaní stavov na displeji, ale mohlo by to byť rozdelené na viacero častí, ako napríklad:

a) Do zapojenia by bol implementovaný senzor teploty, vlhkosti a pri otvorení dverí by sa na displeji vypísala aktuálna hodnota teploty a vlhkosti.

b) Do zapojenia by sme zaimplementovali WiFi modul ESP8266, pomocou ktorého by sme sa pripojili na internet a buď cez nejaké open-source API alebo nami vytvorené vlastné API by sme získavali hodnoty teploty, vlhkosti, prípadne ďalšie dáta, ktoré by boli dostupné z API.

Moja predstava by bola asi zameraná skôr na bod b), pretože samotné zapojenie senzoru teploty a vlhkosti by bolo nie úplne prispôsobiteľné ku každej skrini. Ale zase bod b) bude o niečo náročnejší, ako bod a), pretože to programovanie a pripájanie sa na nejaké API a získavanie hodnoty, či zapisovanie na displej by bolo oveľa časovo náročnejšie, ako napríklad vyvŕtať dieru do steny, prípadne kúpiť nejaký senzor s pripojením na bluetooth, kde by sme sa na diaľku pripájali a tak získavali dáta.


Zapojenie a schéma

LCD displej sme zapojili podľa návodu z cvičenia č.11. Použili sme piny PD2,PD3,PD4 a PB1,PB2,PB3,PB4. Senzor otvorenia dverí sme zapojili do pinu PB5 a ako posledné RGB LED diódu sme zapojili do pinov PD5,PD6 a PD7. Pomohli sme si aj s Breadboardom, aby sme si uľahčili pripájanie ZEME a NAPÁJANIA 5V.

Schéma zapojenia.

Program

Program sa skladá z hlavnej časti main.c, kde sa riadi celý systém ovládanie RGB diódy, LCD displeja a samotné fungovanie senzoru otvárania dverí. A 2 knižníc - lcd.c (Na fungovanie LCD dipleja) a uart.c (Na fungovanie sériovej komunikácie a ostatných funkcií použitých v main.c).

Ako prvé sme si zadefinovali knižnice, aby sme mohli ďalej pracovať s kódom v hlavnej časti programu. Ďalej sme už pokračovali len v hlavnej časti programu a to nasledovne: Zadefinovali sme si porty na pripojenie do Arduina. Vytvorili sme funkciu generátora náhodných čísel a následne aj časovač, ktorý umožní generátoru pomimo programu každú 1 sekundu vygenerovať 1 náhodné číslo v intervale od 1 po 6. Ako ďalšie sme si vytvorili funkciu stavy(), kde sa nachádzajú funkcie na vypisovanie na displej a riadenie RGB LED diódy. Táto funkcia sa neskôr využije v programe. Potom sme si v hlavnej funkcii main() spustili inicializáciu UART komunikácie (UART komunikáciu využívame len čisto na DEBUG na nič iné), LCD dipleja, RGB LED diódy, časovača a senzoru otvorenia dverí. A ako posledné sme do while() funkcie, ktorá prebieha neustále dokola pridali samotné riadenie celého systému inteligentného šatníka ovládané senzorom otvorenia dverí, kde sme využili aj funkciu stavy().

#define RED_PIN   PD5
#define GREEN_PIN PD6
#define BLUE_PIN  PD7

#define MAGNET_PIN PB5

#define LCD_CMD_DISPLAY_OFF_CURSOR_OFF 0x0C
 
#include <avr/io.h>
#include <avr/interrupt.h> // Pre fungovanie random generátora
#include <stdlib.h> // Pre funkcie rand() a srand()
#include <stdio.h>
#include "uart.h"
#include "lcd.h"

FILE mystdout = FDEV_SETUP_STREAM(uart_putc, NULL, _FDEV_SETUP_WRITE);
    
static volatile int randomNumber = 0;
static volatile int priznak = 0;
static volatile int randomNum = 0;

void initRandomGenerator() {
    srand(TCNT0);
}

int generateRandomNumber(int min, int max) { // Zadefinovanie funkcie generátora náhodých čísel.
    randomNum = rand() % (max - min + 1);
    randomNum += min;
    return randomNum;
}

ISR(TIMER1_OVF_vect) {
    TCNT1 = 65536 - 45000; // Nastavenie timera na 5 sekúnd.
	priznak = 1;
}

void stavy() {
	if (randomNum == 1) {	  
		lcd_command(0x80); // Nastavenie pozície kurzora na 1. riadok, 1. políčko.
		lcd_puts("Teplota: 30\x01\x02\nJasno, Bez vetra");
		setRGBled(255, 0, 0);
	}
	  
	if (randomNum == 2) { 
		lcd_command(0x80);
		lcd_puts("Teplota: 25\x01\x02\nSlne\x04no, Veterno");
		setRGBled(255, 165, 0);
	}
	  
	if (randomNum == 3) {
		lcd_command(0x80);
		lcd_puts("Teplota: 16\x01\x02\nJasno, Slne\x04no  ");
		setRGBled(255, 255, 0);
	}
	  
	if (randomNum == 4) {
		lcd_command(0x80);
		lcd_puts("Teplota: 8\x01\x02 \nPoloobla\x04no,D\x03\x05\x06");
		setRGBled(102, 204, 255);
	}
	  
	if (randomNum == 5) {
		lcd_command(0x80);
		lcd_puts("Teplota: 2\x01\x02 \nZamra\x04\x07n\x08, D\x03\x05\x06 ");
		setRGBled(153, 0, 204);
	}
	  
	if (randomNum == 6) {
		lcd_command(0x80);
		lcd_puts("Teplota: -5\x01\x02\nZamra\x04\x07n\x08, Sneh ");
		setRGBled(0, 0, 255);
	}
}

int main(void) {
  uart_init(); // Inicializácia UARTu
  initRandomGenerator(); // Inicializácia randomGenerator funkcie
  initRGBled(); // Inicilizácia RGB LED diódy
  stdout = &mystdout; // printf() funkcia je zapnutá

  printf("Spustam inicializaciu programu...\n");
  
  DDRB &= ~(1 << MAGNET_PIN); // Nastavenie MAGNET pinu na INPUT
  PORTB |= (1 << MAGNET_PIN);
  
  TCCR1B |= (1 << CS12) | (1 << CS10); // Prescaler nastavený na 1024
  TIMSK1 |= (1 << TOIE1);
  
  TCCR0B |= (1 << CS00);
  
  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)
  
  lcd_init(); // Inicializácia LCD Displeja
  def_spec_znaky(); // Inicializácia špeciálnych znakov na displeji
  lcd_command(LCD_CMD_DISPLAY_OFF_CURSOR_OFF); // Vypnutie kurzora na displeji
  
  printf("Inicializacia bola uspesna!\n");
  
  sei();
  
  while(1) { 
	  if (PINB & (1 << MAGNET_PIN)) {
			// Ak je magnet pripojený, do UARTu sa vypíše DEBUG, RGB LED dióda sa vypne a vynuluje sa LCD Displej
			printf("Magnet je pripojeny!\r");
			setRGBled(0, 0, 0);
 			lcd_command(0x01);
        } else {
			// Ak je magnet odpojený, do UARTu sa vypíše DEBUG a spustí sa funkcia stavy().
			printf("Magnet je odpojeny!\r");
			
			if (priznak == 1) {
				randomNum = generateRandomNumber(1, 6); // Nastavenie generátora náhodných čísel, aby generovalo len v intervale od 1 po 6.
				stavy();
				priznak = 0;
			}
		}
  }
  
  return(0);
}
#include <avr/io.h>
#include <util/delay.h>
#include "uart.h"

#define RED_PIN   PD5
#define GREEN_PIN PD6
#define BLUE_PIN  PD7

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)
{
  /* toto je vasa uloha */
}

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);
}

// Funkcia na inicializáciu pinov
void initRGBled() {
    // Nastavenie pinov ako OUTPUT
    DDRD |= (1 << RED_PIN) | (1 << GREEN_PIN) | (1 << BLUE_PIN);
}

// Funkcia na nastavenie farby
void setRGBled(uint8_t r, uint8_t g, uint8_t b) {
    // Nastavenie hodnôt pre červenú, zelenú a modrú LED diódu
    if (r > 0) {
        PORTD |= (1 << RED_PIN);
    } else {
        PORTD &= ~(1 << RED_PIN);
    }

    if (g > 0) {
        PORTD |= (1 << GREEN_PIN);
    } else {
        PORTD &= ~(1 << GREEN_PIN);
    }

    if (b > 0) {
        PORTD |= (1 << BLUE_PIN);
    } else {
        PORTD &= ~(1 << BLUE_PIN);
    }
}
#define set_bit(ADDRESS,BIT) (ADDRESS |= (1<<BIT))
#define clear_bit(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))

#ifndef F_CPU
 #define F_CPU 16000000UL	/* Define CPU frequency here 16MHz */
#endif

#ifndef UART_H_
#define UART_H_

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

#define BAUD_PRESCALE  (((F_CPU / (BAUDRATE * 16UL))) - 1)

void hw_init( void );
void uart_init( void );
	 
int uart_putc( char c, FILE *stream );
void uart_puts( const char *s );

char uart_getc( void );

void initRGBled();

void setRGBled(uint8_t r, uint8_t g, uint8_t b);

int generateRandomNumber(int min, int max);

void initRandomGenerator();

void delay(int delay); 

#endif /* UART_H_ */
#include <avr/io.h>
#include "lcd.h"

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));		
}

/* Primitivne funkcie, nepredpoklada sa ich vyuzitie uzivatelom */	
unsigned char Znak_S[8]= {0xE,0xE,0xE,0x0,0x0,0x0,0x0,0};// stupen	
unsigned char Znak_SM[8]= {0x0A,0x04,0x0E,0x10,0x0E,0x01,0x1E,0};//  s + mekcen	
unsigned char Znak_C[8]= {0xe,0x11,0x10,0x10,0x10,0x11,0xe,0};//  C	
unsigned char Znak_CM[8]= {0xa,0x4,0xe,0x11,0x10,0x11,0xe,0};//  c + mekcen
unsigned char Znak_DA[8]= {0x2,0x4,0xe,0x01,0x0f,0x11,0x0f,0};//  Dlhe a
unsigned char Znak_Z[8]= {0xa,0x4,0x1f,0x2,0x4,0x8,0x1f,0};//  z + mekcen
unsigned char Znak_D[8]= {0x5,0x5,0xc,0x14,0x14,0x14,0xc,0};//  d + mekcen
unsigned char Znak_E[8]= {0x0,0x0,0xe,0x11,0x1f,0x10,0xe,0};//  e
unsigned char Znak_DE[8]= {0x1,0x2,0xe,0x11,0x1f,0x10,0xe,0};//  dlhe e
	
/* Funkcia zapise jeden bajt po SPI zbernici do zariadenia */
void def_spec_znaky(void){
// zapis vlastnych znakkov do CGRAM  na poziciu 4, a 0 (8) 

 def_znak( Znak_S,1);// stupen
 def_znak( Znak_C,2);// C
 def_znak( Znak_CM,4);// c + mekcen
 def_znak( Znak_DA,3);// dlhe a
 def_znak( Znak_Z,5);// z + mekcen
 def_znak( Znak_D,6);// d + mekcen
 def_znak( Znak_E,7);// e
 def_znak( Znak_DE,8);// dlhe e
 
 // obnovenie obsahu AC. AC nastvime na 1. riadok, 1. znak
 lcd_command(0x80);
}
	 
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"
}

/* ********************************************************	*/
/* vypis retazca na poziciu, resp. podla nasledovnych 		*/
/* formatovacich prikazov                                       */
/*   : \n - prechod na novy riadok                              */
/*   : \f - prechod na zaciatok displeja                        */
/* ********************************************************     */
void lcd_puts(char *str) {
    while (*str) {
        if (*str == '\n') {
            lcd_command(0xC0); // Presun na začiatok 2. riadka (0x80 + 0x40)
        } else if (*str == '\f') {
            lcd_command(0x80); // Presun na začiatok 1. riadka (displeja)
        } else {
            lcd_data(*str); // Vypíš znak na displej
        }
        str++; // Presun na ďalší znak vstupného reťazca
    }
}

#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 LCD_H_
#define LCD_H_

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

	#define LCD_RS_pin 0
	#define LCD_EN_pin 1
	#define LCD_D4_pin 4
	#define LCD_D5_pin 5
	#define LCD_D6_pin 6
	#define LCD_D7_pin 7

#else
	#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

#define NOP() asm("nop")	
#define LCD_DELAY	NOP();NOP();NOP();NOP();NOP();NOP();

#ifdef _Shield_LCD
#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

#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 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_H_ */

Zdrojový kód: reismuller_semestralna_praca.zip

Overenie funkčnosti

Overenenie funkčnosti môžeme vidieť na videu, ktoré sa nachádza nižšie. Taktiež môžeme vidieť aj 2 fotky so zapojením.

Video: