Projekty na první pololetí

Kdo si nevybral téma na projekt sám, dostal téma náhodně přidělené. Pokud tady máte napsané jiné téma, než jste si domluvili, braňte se e-mailem u vyučujícího (stačí jedinou větou).

Kvinta A

Kvinta B

Lolin desky

Některé z desek, které používáme na hodině, mají na sobě nápis LoLin. Pro většinu účelů jsou dostačující, a shodou náhod jedině tyhle desky dokážou posílat e-mail (ukázka níže). Nepohodlné jsou tím, že popis nožiček neodpovídá číslům, jakými je ovládáme v programu.

Nápis na desce D0D1D2D3*D4*D5D6D7D8
Číslo portu 16540*2*14121315

*Už víme, že na port 0 (noha D3) je připojené tlačítko Flash a na port 2 (noha D4) modrá dioda. Přesto s nimi můžeme normálně pracovat v programu.

Například, když chceme zapnout napětí na nožičku s nápisem D0, použijeme příkaz digitalWrite(16, true);.

Ukázky kódu

Následující programy se určitě budou hodit pro řešení některých projektů. Můžete je bez váhání kopírovat a upravovat.

Číslicový displej

Tento program vypisuje postupně různé číslice na displeji. Nohy sedmisegmentového displeje jsou číslované od levého horního rohu proti směru hodinových ručiček. První nohou ho připojíme přes rezistor na VIN, následujícími čtyřmi nohami na piny D32, D33, D25, D26 (jsou vedle sebe) a posledními třemi nohami po řadě na D13, D14, D27 (pozor, D12 musíme přeskočit). Šestá noha se dá použít místo první, když nám to ušetří práci.

function show(num) {
  var segments = {
    0: [1, 2, 3, 4, 5, 6],
    1: [2, 3],
    2: [1, 2, 7, 5, 4],
    3: [1, 2, 3, 4, 7],
    4: [2, 3, 6, 7],
    5: [1, 3, 4, 6, 7],
    6: [1, 3, 4, 5, 6, 7],
    7: [1, 2, 3],
    8: [1, 2, 3, 4, 5, 6, 7],
    9: [1, 2, 3, 4, 6, 7],
    10: [1, 2, 3, 5, 6, 7],
    11: [3, 4, 5, 6, 7],
    12: [1, 4, 5, 6],
    13: [2, 3, 4, 5, 7],
    14: [1, 4, 5, 6, 7],
    15: [1, 5, 6, 7],
  };
  var conn = {6: D32, 7: D33, 5: D25, 4: D26, 1: D27, 2: D14, 3: D13};
  for (var i in conn) {
    conn[i].write(1);
  }
  for (var i of segments[num]) {
    conn[i].write(0);
  }
}

var i = 0;
function timedShow() {
  show(i);
  setTimeout(timedShow, 800);
  i = (i + 1) % 16;
}

timedShow();

Tlačítko

Pro ukázku připojíme rezistor kΩ mezi VIN a D14, a tlačítko mezi D14 a GND. Tlačítka bývají docela malá, takže asi budeme potřebovat použít propojovací dráty. Každým stiskem tlačítka se spustí funkce prepni a ta střídavě rozsvěcí a zhasíná diodu na desce.

var svetlo = 0;

function prepni(state, time, last) {
  svetlo = 1 - svetlo;
  digitalWrite(2, svetlo);
}

setWatch(prepni, D14, {repeat: true, edge: 'falling', debounce: 10});

Možné varianty funkce setWatch jsou 'rising', 'falling' a 'both'.

Pokud nám stačí jediné tlačítko, můžeme použít tlačítko Boot nebo Flash zabudované na desce. V tom případě místo D14 použijeme D0.

Reproduktor

Pro ukázku zapojíme reproduktor mezi D14 a GND. Program přepíná napětí tak rychle, jak umí, což vytváří nepříjemné ostré pískání o základní frekvenci asi 500 Hz.

napeti = 0;
while (1) {
  napeti = 1 - napeti;
  digitalWrite(14, napeti);
}

Procesor běží naplno a zvuk je každou chvíli přerušený, protože se deska musí občas věnovat i jiným věcem než našemu programu. Použijeme proto funkci analogWrite, abychom stejný tón zahráli jediným příkazem:

analogWrite(D14, 0.5, {freq : 500});

Frekvence obvykle používaných tónů si můžeme snadno najít na webu. Snadno můžeme frekvenci vyjádřit matematicky jako 440·2n12, kde n je počet půltónu od komorního A. Umocňování v programu jde zapsat jako Math.pow(2, n / 12).

Složitější zvuky jde přehrávat na portech D25 a D26 pomocí modulu Waveform. Budeme potřebovat připojit tranzistor pro zesílení. Tranzistor má tři nohy: emitor, kolektor a bázi. Reproduktor zapojíme mezi VIN a kolektor, emitor připojíme drátem na GND. Mezi D25 a bázi připojíme rezistor 10Ω.

var w = new Waveform(128);
for (var i=0;i<128;i++) {
	w.buffer[i] = 128+Math.sin(i*Math.PI/64)*127;
}
analogWrite(25, 0.5);
w.startOutput(D25, 4000, {repeat: true});

function zastav() {
	w.stop();
	analogWrite(25, 0);
}
setTimeout(zastav, 4000);

Analogové měření

Teplota i osvětlení se měří podobným způsobem. Zapojíme za sebou měřicí součástku (fotorezistor nebo termistor) a obyčejný rezistor zhruba stejné velikosti. Pomocí funkce analogRead pak měříme napětí.

Abychom z naměřeného napětí mohli určit množství světla anebo teplotu, musíme obvod ručně nakalibrovat. To znamená, že si zajistíme nějaké přesné podmínky, například teplotu 0° tajícího ledu, 100° vařící se vody anebo 37° v podpaží, a zapíšeme si, jaké napětí přístroj dává. Ze dvou takhle naměřených hodnot už jde odhadmo vymyslet lineární rovnice a dopočítat tak jakoukoliv jinou teplotu.

Měření teploty

Pro ukázku zapojíme rezistor 1 kΩ mezi VIN a D35, a termistor mezi D35 a GND. Místo nohy D35 by šlo použít i kteroukoliv z D32 až D34 anebo na desce Lolin nohu A0. Následující program rozsvítí diodu na desce, když termistor držíme v teplé ruce:

while (1) {
  var svetlo = analogRead(35);
  if (svetlo > 0.64) {
    digitalWrite(2, true);
  } else {
    digitalWrite(2, false);
  }
}

Měření světla

Pro ukázku zapojíme fotorezistor mezi VIN a D35, a rezistor 1 kΩ mezi D35 a GND. Místo nohy D35 by šlo použít i kteroukoliv z D32 až D34 anebo na desce Lolin nohu A0. Následující program rozsvítí diodu na desce, pokud je obvod ve tmě:

while (1) {
  var svetlo = analogRead(35);
  if (svetlo < 0.4) {
    digitalWrite(2, true);
  } else {
    digitalWrite(2, false);
  }
}

Webový server

Tohle je velice jednoduchá ukázka použití wifi. Založíme vlastní wifi (access point) a na ní spustíme webový server, který jen vypisuje, že běží. Několik složitějších ukázek najdete v zápiskách, jako například vypínač světla a přesměrování na jinou stránku. S porovnáváním rozdílů mezi podobnými programy vám může pomoct vhodný nástroj.

var wifi = require("Wifi");
var http = require("http");

function poPripojeni() {
    http.createServer(priPozadavku).listen(80);
    console.log("Server bezi na adrese http://" + wifi.getAPIP().ip);
}

function priPozadavku(req, res) {
  res.writeHead(200, {"Content-Type": "text/html"});
  res.end("Server funguje.");
}

wifi.startAP("mojeSit", {authMode: "wpa", password: "hesloheslo"}, poPripojeni);
console.log("Zakladam sit...");

Náhodné číslo

Funkce Math.random() vrací náhodné číslo mezi 0 a 1 (ten interval je zleva uzavřený, zprava otevřený). Když chceme náhodné číslo v jiném rozsahu, můžeme ho něčím vynásobit. Když chceme celé číslo, můžeme ho zaokrouhlit funkcí Math.floor(x). Následující ukázka vypíše do konzole náhodné číslo od 0 do 1000 (možná vyjde 0, ale nikdy nevyjde 1000):

console.log(Math.floor(Math.random() * 1000));

Posílání e-mailu

Pro e-mailovou komunikaci nemáme zabudovanou podporu, takže je všechno trochu složité. Pro ukázku se přihlásíme nezabezpečeným protokolem SMTP k účtu kvintagjs@centrum.cz, který je vytvořený jen pro ten účel. Heslo toho účtu je GJSZAK01, ať ho nezapomeneme. Stejným heslem se tato ukázka přihlašuje i na školní wifi.

Z hloupých technických důvodů následující ukázka funguje jen na Lolin desce.

var wifi = require("Wifi");
var net = require("net");
var message;

function poPripojeni() {
  console.log("Connected. My IP:", wifi.getIP().ip);
  sendMail("a.dominec@gymjs.cz", "Funguje to", "Odesilani z ESP funguje! To je super.");
}

function sendMail(recipient, subject, text) {
  message = ["EHLO centrum.cz\r\n",
  "AUTH LOGIN\r\n",
  btoa("kvintagjs@centrum.cz") + "\r\n",
  btoa("GJSZAK01") + "\r\n",
  "MAIL FROM: <kvintagjs@centrum.cz>\r\n",
  "RCPT TO: <" + recipient + ">\r\n",
  "DATA\r\nTo: <" + recipient + ">\r\nSubject:" + subject + "\r\n" + text + "\r\n.\r\n",
  "QUIT\r\n"];

  wifi.getHostByName("smtp.centrum.cz", sendMailToIp);
}

function sendMailToIp(ipAddress) {
  console.log("centrum.cz IP:", ipAddress);
  net.connect({host: ipAddress, port: 25}, sendMailOverSocket);
}

function sendMailOverSocket(socket) {
  var i = 0;
  socket.write(message[0]);
  socket.on("data", function(data) {
    console.log(data);
    socket.write(message[++i]);
  });
  socket.on("close", function() {
    console.log("Connection closed, done.");
  });
}

wifi.connect("GJS-STUDENT", {password: "GJSZAK01"}, poPripojeni);

Nastavení hodin

Použijeme protokol NTP, abychom se nějakého serveru na Internetu zeptali, kolik je hodin. Získaný čas bude přesný na milisekundu, což nás ale nejspíš ani nezajímá. Co se týká připojení na Internet, spolehneme se na školní wifi.

var wifi = require("Wifi");
var sntp = require('sntp');

function poPripojeni() {
  sntp.time({host: 'ntp.nic.cz'}, casZiskan);
}

function casZiskan(err, time) {
  if (!err){
    setTime((Date() + time.t) / 1000);
    E.setTimeZone(1);
    console.log('Aktualni cas:', Date());
  }
}
wifi.connect("GJS-STUDENT", {password: "GJSZAK01"}, poPripojeni);
console.log("Pripojuju se na sit...");