Arduino Budík Shield je rozšiřovací modul, který obsahuje spoustu zajímavých prvků. Tento Shield má stejný formát jako desky Arduino UNO, přičemž využívá velké množství propojovacích pinů. Obsahuje čtyřmístný 7-segmentový displej s řadičem TM1636, obvod reálného času DS1307, sirénku, fotorezistor, termistor, čtyři LED diody v různých barvách a tři tlačítka. Můžeme s ním tedy vytvořit spoustu různých zapojení včetně zmíněného budíku.

Arduino Budík Shield

Pro úspěšné propojení Budík Shieldu s Arduinem stačí tento Shield zapojit do Arduino desky.

Schéma zapojení Arduino Budík Shieldu

Pro úspěšné nahrání uvedeného ukázkového kódu je nutné stáhnout a naimportovat knihovnu TickTockShield, návod, jak na to je uveden zde. Ukázkový kód obsahuje na svém začátku připojení potřebných knihoven a nastavení čísel propojovacích pinů. Dále se zde nachází proměnná s velikostí odporu u termistoru a nastavení tempa hraného tónu. V podprogramu setup nejprve nastavíme komunikaci po sériové lince a následně směr všech vstupních a výstupních pinů. V dalším kroku vypneme všechny LED diody pomocí podprogramu a zahájíme inicializaci displeje z knihovny. Nekonečná smyčka loop v sobě obsahuje obsluhu pro většinu použitých součástek. V prvním kroku zde vytvoříme proměnnou pro uložení frekvence hraného tónu a načteme do další proměnné informaci o stisknutých tlačítkách. Následně provedeme postupně kontrolu všech tří tlačítek, kdy každé tlačítko obsahuje jinou funkci. Pro první tlačítko načteme úroveň intenzity světla v okolí do proměnné, tuto informaci vytiskneme na druhou číslici displeje a vyčkáme půl sekundy. Pro druhé tlačítko snížíme tón o hodnotu 100 (pokud už není menší než 100), vytiskneme výšku tónu na displej a zároveň po sériové lince. A pro třetí tlačítko provedeme naopak zvýšení tónu do hranice 2000 společně s vytištěním na displej a sériovou linku. Pokud ale nebylo v aktuálním běhu stisknuto žádné tlačítko, provedeme následující úsek kódu. Načteme si hodnotu okolní teploty do proměnné, kterou zobrazíme na displeji, a poté s nastavenou rychlostí postupně blikneme všemi LED diodami. Na konci smyčky si už jen počkáme po dobu 500 ms nebo případně o 200 ms více, pokud bylo stisknuto nějaké tlačítko.

Pod smyčkou loop se nachází použité podprogramy. Jako první je zde uveden podprogram pro zobrazení teploty, který ze vstupní teploty vytvoří čtyři znaky, které se následně vytisknou na displej. Další čtyři podprogramy jsou věnované práci s LED diodami, kdy první dva slouží pro zapínání a vypínání jednotlivých diod a následující dva obsahují vždy zapnutí či vypnutí všech diod najednou. Jako další se zde nachází podprogram pro bliknutí všemi LED diodami, který se zadanou rychlostí postupně pomocí masky projde všechny LED diody. Další dva podprogramy jsou věnované práci s fotorezistorem, kdy první z nich zpracovává vstupní data z analogového pinu a přepočte je na odpor. Druhý podprogram pak využije vypočítaný odpor a podle jeho velikosti vrací úroveň intenzity světla zjednodušenou na 8 úrovní. Následující podprogram slouží pro načtení stavu tlačítek, kdy při stisku kteréhokoliv z nich vždy vytiskneme informaci po sériové lince a zároveň nastavíme číslo tlačítka na výstup z podprogramu. A poslední podprogram je spojený s hraním tónu na sirénce, kdy podle vstupní výšky tónu a trvání zahrajeme nastavený tón.

// Arduino budík shield

// připojení potřebných knihoven
#include "Wire.h"
#include <TimerOne.h>
#include <MsTimer2.h>
#include <EEPROM.h>
#include "TM1636.h"
#include "TickTockShield.h"
// nastavení čísel propojovacích pinů
#define pinTermistor  A0
#define pinFotorezistor  A1
#define LED1  2
#define LED2  3
#define LED3  4
#define LED4  5
#define tlacitko1 11
#define tlacitko2 10
#define tlacitko3  9
#define pinSirenka 6
// nastavení velikosti odporu u termistoru
#define termistorOdpor 10000
// proměnná pro nastavení tempa hraného tónu
int tempo = 300;

void setup() {
  // komunikace po sériové lince rychlostí 9600 baud
  Serial.begin(9600);
  // nastavení směru vstupních a výstupních pinů
  pinMode(pinTermistor, INPUT);
  pinMode(pinFotorezistor, INPUT);
  pinMode(tlacitko1, INPUT);
  digitalWrite(tlacitko1, HIGH);
  pinMode(tlacitko2, INPUT);
  digitalWrite(tlacitko2, HIGH);
  pinMode(tlacitko3, INPUT);
  digitalWrite(tlacitko3, HIGH);
  pinMode(pinSirenka, OUTPUT);
  digitalWrite(pinSirenka, LOW);
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(LED3, OUTPUT);
  pinMode(LED4, OUTPUT);
  // vypnutí všech LED diod pomocí podprogramu
  vypniLED();
  // inicializace displeje z knihovny
  tm1636.init();
}
void loop() {
  // vytvoření proměnné pro uložení frekvence hraného tónu
  static int ton = 1000;
  // načtení informací o stisknutých tlačítkách do proměnné
  int16_t cisloTlacitka = nactiTlacitka();
  // kontrola stavu jednotlivých tlačítek
  if (tlacitko1 == cisloTlacitka) {
    // načtení intenzity světla v okolí do proměnné
    uint8_t urovenIntenzitySvetla = nactiIntenzituSvetla();
    // vyčištění celého displeje a vypsání intenzity světla
    // na druhou číslici displeje (číslování od nuly)
    tm1636.clearDisplay();
    tm1636.display(1, urovenIntenzitySvetla);
    // výpis informací o intenzitě po sériové lince
    Serial.print("Uroven intenzity svetla 0-7: ");
    Serial.println(urovenIntenzitySvetla);
    // pauza po dobu půl sekundy
    delay(500);
  }
  else if (tlacitko2 == cisloTlacitka) {
    // snížení hraného tónu o 100, pokud je jeho hodnota větší než 100
    if (ton > 100) {
      ton -= 100;
    }
    // vyčištění celého displeje a výpis tónu po jednotlivých číslicích
    tm1636.clearDisplay();
    tm1636.display(0, (ton / 1000));
    tm1636.display(1, ((ton % 1000) / 100));
    tm1636.display(2, 0);
    tm1636.display(3, 0);
    // zavolání podprogramu pro zahrání nastaveného tónu
    zahrajTon(ton, tempo);
    // vytištění frekvence hraného tónu po sériové lince
    Serial.print("Hrany ton: ");
    Serial.println(ton);
  }
  else if (tlacitko3 == cisloTlacitka) {
    // zvýšení hraného tónu o 100, pokud je jeho hodnota menší než 2000
    if (ton < 2000) {
      ton += 100;
    }
    // vyčištění celého displeje a výpis tónu po jednotlivých číslicích
    tm1636.clearDisplay();
    tm1636.display(0, (ton / 1000));
    tm1636.display(1, ((ton % 1000) / 100));
    tm1636.display(2, 0);
    tm1636.display(3, 0);
    // zavolání podprogramu pro zahrání nastaveného tónu
    zahrajTon(ton, tempo);
    // vytištění frekvence hraného tónu po sériové lince
    Serial.print("Hrany ton: ");
    Serial.println(ton);
  }
  // pokud není stisknuto tlačítko, vykonej následující
  else {
    // načtení okolní teploty do proměnné
    int8_t teplota = nactiTeplotu();
    // výpis teploty pomocí podprogramu
    zobrazTeplotu(teplota);
    // nastavení rychlosti blikání v rozsahu 1-10
    byte rychlost = 5;
    // zavolání podprogramu pro bliknutí všemi LED diodami
    blikniLED(rychlost);
  }
  // pokud bylo stisknuto nějaké tlačítko, počkej 200ms navíc
  if (cisloTlacitka > 0) {
    delay(200);
  }
  // pauza po dobu 500ms
  delay(500);
}
// podprogramu pro načtení teploty z termistoru,
// teplota může být v rozsahu -40 až +125°C
int8_t nactiTeplotu() {
  // vytvoření pomocných proměnných
  float teplota, odpor;
  int a;
  int B = 3975;
  // načtení hodnoty z termistoru
  a = analogRead(pinTermistor);
  // výpočet odporu termistoru
  odpor = (float)(1023 - a) * termistorOdpor / a;
  // výpočet teploty z odporu termistoru a jeho měřící konstanty B
  teplota = 1 / (log(odpor / termistorOdpor) / B + 1 / 298.15) - 273.15;
  // vrácení teploty ve formátu integer (celé číslo)
  return (int8_t)teplota;
}
// podprogram pro zobrazení teploty na displeji
void zobrazTeplotu(int8_t teplota) {
  // vytvoření pole pro uložení číslic
  int8_t teplotaPole[4];
  // pokud je teplota záporná, nastavíme na první znak záporné znaménko
  // a poté převedeme teplotu na kladnou pro správný výpis
  if (teplota < 0) {
    teplotaPole[0] = INDEX_NEGATIVE_SIGN;
    teplota = abs(teplota);
  }
  // pokud je teplota menší než 100°C, první znak bude prázdný
  else if (teplota < 100) {
    teplotaPole[0] = INDEX_BLANK;
  }
  // v ostatních případech zobrazuje nultý znak stovky
  else {
    teplotaPole[0] = teplota / 100;
  }
  // přepočet naměřené teploty pro správný výpis na zbývající znaky displeje,
  // na poslední znak se vypíše znak "C" (hexadecimálně 12)
  teplota %= 100;
  teplotaPole[1] = teplota / 10;
  teplotaPole[2] = teplota % 10;
  teplotaPole[3] = 12;
  // výpis teploty na displej
  tm1636.display(teplotaPole);
}
// zapnutí LED diody
inline void zapni(int pinLED) {
  digitalWrite(pinLED, HIGH);
}
// vypnutí LED diody
inline void vypni(int pinLED) {
  digitalWrite(pinLED, LOW);
}
// zapnutí všech LED diod
inline void zapniLED() {
  zapni(LED1);
  zapni(LED2);
  zapni(LED3);
  zapni(LED4);
}
// vypnutí všech LED diod
inline void vypniLED() {
  vypni(LED1);
  vypni(LED2);
  vypni(LED3);
  vypni(LED4);
}
// postupné rozsvícení všech čtyř LED diod, při volání se nastavuje rychlost
// v rozmezí 1 - 10
void blikniLED(byte rychlost) {
  // pokud je hodnota v platném rozsahu, zahaj blikání
  if ((rychlost > 0) && (rychlost < 11)) {
    // vytvoření masky pro blikání
    uint8_t maska = 0x01;
    // for smyčka pro bliknutí všemi LED diodami
    for (uint8_t i = 0; i < 4; i ++) {
      if (maska & 0x01)
        zapni(LED1);
      else
        vypni(LED1);
      if (maska & 0x02)
        zapni(LED2);
      else
        vypni(LED2);
      if (maska & 0x04)
        zapni(LED3);
      else
        vypni(LED3);
      if (maska & 0x08)
        zapni(LED4);
      else
        vypni(LED4);
      maska <<= 1;
      // pauza se počítá z nastavené rychlosti
      delay(500 / rychlost);
    }
    // vypnutí všech LED diod
    vypniLED();
  }
}
// získání dat z fotoodporu
float aktualniIntenzita() {
  // načtení dat z fotoodporu
  int fotoOdpor = analogRead(pinFotorezistor);
  // přepočtení odporu podle druhu senzoru
  float prepocetOdporu;
  prepocetOdporu = (float)(1023 - fotoOdpor) * 10 / fotoOdpor;
  // vrácení přepočtených dat z fotoodporu
  return prepocetOdporu;
}
// načtení intenzity světla v rozsahu 0-7 (0 je největší intenzita, 7 je tma)
uint8_t nactiIntenzituSvetla() {
  // vytvoření pomocných proměnných
  uint16_t odpor;
  uint8_t urovenIntenzitySvetla;
  // získání dat z fotoodporu
  odpor = (uint16_t)aktualniIntenzita();
  // vytištění dat po sériové lince
  Serial.print("Fotoodpor: ");
  Serial.println(odpor);
  // převod intenzity světla dle naměřeného odporu na menší rozsah
  if (odpor < 10)       urovenIntenzitySvetla = 0;
  else if (odpor < 50)  urovenIntenzitySvetla = 1;
  else if (odpor < 80)  urovenIntenzitySvetla = 2;
  else if (odpor < 110) urovenIntenzitySvetla = 3;
  else if (odpor < 140) urovenIntenzitySvetla = 4;
  else if (odpor < 170) urovenIntenzitySvetla = 5;
  else if (odpor < 200) urovenIntenzitySvetla = 6;
  else urovenIntenzitySvetla = 7;
  // vrácení úrovně intenzity světla
  return urovenIntenzitySvetla;
}
// načtení stavu všech tlačítek
int16_t nactiTlacitka() {
  // vytvoření proměnné, do které se uloží na začátku záporné číslo,
  // abychom poznali, že případně nebylo stisknuto žádné tlačítko
  int16_t cisloPinu = -1;
  // kontrola stisku všech tlačítek, pokud je některé stisknuto po dobu 20ms,
  // zaznamenáme jeho číslo do proměnné
  if (digitalRead(tlacitko1) == LOW) {
    delay(20);
    if (digitalRead(tlacitko1) == LOW) {
      cisloPinu = tlacitko1;
      Serial.println("Stisknuto tlacitko 1.");
    }
  }
  else if (digitalRead(tlacitko2) == LOW) {
    delay(20);
    if (digitalRead(tlacitko2) == LOW) {
      cisloPinu = tlacitko2;
      Serial.println("Stisknuto tlacitko 2");
    }
  }
  else if (digitalRead(tlacitko3) == LOW) {
    delay(20);
    if (digitalRead(tlacitko3) == LOW) {
      cisloPinu = tlacitko3;
      Serial.println("Stisknuto tlacitko 3");
    }
  }
  // vrácení čísla pinu tlačítka
  return cisloPinu;
}
// přehrání tónu na sirénce
void zahrajTon(int ton, int trvani) {
  // for smyčka, která ze zadaných údajů zahraje nastavený tón
  for (long i = 0; i < trvani * 1000L; i += ton * 2) {
    digitalWrite(pinSirenka, HIGH);
    delayMicroseconds(ton);
    digitalWrite(pinSirenka, LOW);
    delayMicroseconds(ton);
  }
}

Po nahrání ukázkového kódu do Arduino desky s připojeným budík Shieldem dostaneme například tento výsledek:

Stisknuto tlacitko 1.
Fotoodpor: 18
Uroven intenzity svetla 0-7: 1
Stisknuto tlacitko 2
Hrany ton: 900
Stisknuto tlacitko 3
Hrany ton: 1000

Arduino Budík Shield je vhodný jako jedno ze základních rozšíření pro začátečníky i pokročilé. Díky tomu, že obsahuje mnoho prvků, s kterými lze pracovat, se hodí na projekty jako například vstupní terminál, teploměr či právě náhrada digitálních hodin s budíkem. Jak bylo řečeno na začátku, na Shieldu se také nachází obvod pro práci s reálným časem DS1307, na který už byl publikován tento návod. Případně pro další ukázku mohu doporučit ukázkový kód přímo z knihovny, který lze najít v nabídce Soubor-Příklady-TickTockShield-RealTimeClock.

 

Seznam použitých komponent:

https://dratek.cz/arduino/974-arduino-uno-r3-atmega328p-1424115860.html

https://dratek.cz/arduino/938-arduino-budik-shield-1421354661.html

FB tw

Další podobné články