Buton Sonerie WiFi

Chiar dacă vechile sonerii (manuale sau cu fir) își au un farmec aparte, totuși, soneriile fără fir au devenit un lucru obișnuit la momentul actual datorită ușurinței de instalare. În cadrul lecției de față vă propunem realizarea unei sonerii formată doar din butonul de afară – avertizarea sonoră specifică va fi înlocuită, grație unei conexiuni WiFi, cu trimiterea unui email sau o avertizare pe telefonul mobil. Utilizând o astfel de sonerie puteți fi anunțat că este cineva la ușă chiar dacă nu sunteți acasă.

Pentru implementare vom utiliza un modul WiFi ESP8266-01S. Acest tip de modul bazat pe circuitul ESP8266 are un cost foarte mic dar este destul de dificil de utilizat spre deosebire de alte plăci de dezvoltare bazate pe același circuit. Modulul este gândit să fie utilizat ca modul WiFi serial pentru alte plăci de dezvoltare, vine preprogramat cu un firmware ce acceptă comenzi de tip AT. În plus, forma conectorului de pe acest modul nu dă posibilitatea de a fi folosit cu un breadboard. În cadrul lecției de față vom programa direct modulul fără a utiliza facilitatea de comunicație serială AT, vom utiliza modulul ca placă de dezvoltare. Pentru interconectarea modulului recomandăm utilizarea unor fire de interconectare de tip mamă-tată pentru a putea face legăturile cu un breadboard. Pentru mai multe informații legate de funcționarea modulului puteți consulta și materialul „ESP8266 WiFi Module for Dummies”.

3

Programarea modulului necesită un modul FTDI de 3.3V și instalarea extensiei ESP8266 Community sub Arduino IDE. Pentru mai multe detalii puteți consulta și materialul „How to Install the ESP8266 Board in Arduino IDE”. Conexiunile dintre modulul ESP8266-01S și programatorul FTDI necesare încărcării programului sunt următoarele:

  • Pinii GND și GPIO0 ai modulului ESP8266 se conectează la pinul GND al programatorului. Pinul GPIO0 este necesar să fie conectat la masă pentru programare.
  • Pinii VCC și CH_PD ai modulului ESP8266 se conectează la pinul VCC (adică 3.3V!!!) al programatorului. Pinul CH_PD se va menține conectat la VCC pe tot parcursul funcționării modulului – este pinul de activare al modulului.

4

  • Pinul RX al modulului ESP8266 se conectează la pinul TX al programatorului.
  • Pinul TX al modulului ESP8266 se conectează la pinul RX al programatorului.

Programul a fost dezvoltat și testat utilizând Arduino IDE 1.8.3 cu extensia ESP8266 Community 2.3.0 instalată. Pentru programare se selectează placa de dezvoltare ”Generic ESP8266 Module”. În cadrul programului trebuie personalizate datele de conectare WiFi (variabilele ssid și pass).

#include <ESP8266WiFi.h>

#include <ESP8266HTTPClient.h>

char ssid[] = “…”;

char pass[] = “…”;

WiFiClient client;

void setup() {

  WiFi.begin(ssid, pass);

  delay(5000);

  if (WiFi.status() != WL_CONNECTED) {

    delay(60000);

    ESP.restart();

  }

  IFTTTpublish();

  ESP.deepSleep(0);

}

void loop() {

}

Programul transmite prin Internet către serviciul IFTTT evenimentul de apăsare a butonului (procedura IFTTTpublish). Serviciul IFTTT permite redirectarea evenimentului către utilizator sub forma unui email, a unui avertizări pe telefonul mobil sau orice altă variantă dorită. În cadrul procedurii trebuie personalizate datele de identificare a evenimentului IFTTT Webhooks (variabilele KEY și EVENT) prin care se fac legătura între sistemul nostru și platforma IFTTT.

void IFTTTpublish() {

  String KEY = “…”;

  String EVENT = “ButonSonerie”;

  HTTPClient http;

  String data = String(“http” + “://maker.ifttt.com/trigger/” + EVENT + “/with/key/”) + KEY ;

  http.begin(data);

  int httpCode = http.GET();

  delay(500);

  http.end();

}

Sistemul nostru va funcționa în regim de consum redus în mod continuu (indus de instrucțiunea ESP.deepSleep(0) din secțiunea setup). Butonul va fi conectat pe pinul de RESET al modulului și va activa sistemul doar pentru a semnaliza evenimentul către platforma IFTTT după care va intra din nou în regim de consum redus. Acest lucru este extrem de util dacă dorim să alimentăm sistemul nostru de la o baterie sau un acumulator. Pentru buton vom utiliza un brick pentru o interconectare mai ușoară. Brick-ul este gândit să tragă linia OUT la VCC dar pinul de RESET al modulului ESP8266 necesită tragerea la masă din acest motiv vom inversa conectarea brick-ului (vom conecta VCC la GND și GND la VCC):

5

Atenție!!! Modulul ESP8266-01S nu are regulator de tensiune integrat. El trebuie alimentat fix la 3.3V. În plus necesită un curent destul de mare, nu poate fi alimentat din programatorul FTDI decât pe perioada programării. Pentru testare recomandăm o sursă de breadboard și pentru funcționarea autonomă un regulator Step-Down de 3.3V (de exemplu) pentru o alimentare de la un acumulator LiPo de 3.7V sau 7.2V.

Utilizarea serviciului IFTTT necesită înregistrare (gratuită). După înregistrare și conectarea la platforma IFTTT vom crea o nouă aplicație (New Applet) în care evenimentul this va fi de tipul Webhooks iar efectul that va fi de tipul Android Device / play a specific song.

6 7 8

Bineînțeles, așa cum am precizat anterior, efectual poate fi modificat după dorință în Email, SMS, postare web etc. sau ce vi se pare potrivit ca avertizare pentru butonul de sonerie. Este adevărat că sistemul propus în această lecție poate servi la fel de bine ca buton de panică, buton de recepție sau buton pentru servitori 😊. În cadrul efectului Play a specific song se va specifica denumirea unei piese aflată pe mobilul care trebuie să aibă aplicație IFTTT instalată. Dacă melodia nu este găsită se va deschide în mod automat pagina Youtube și va fi căutată. Vă recomandăm să încercați ”jinjer words of wisdom”.

Ceas IoT cu programare OTA

Realizarea unui ceas electronic este un proiect simplu dacă utilizăm o placă de dezvoltare programabilă dar asta nu înseamnă că nu există anumite provocări și în acest caz. Una din provocările majore ale implementării unui ceas electronic este acuratețea menținerii orei (asigurarea orei exacte). Acest lucru se realizează de obicei prin utilizarea unui modul RTC dar în cadrul proiectului de față vom utiliza o placă de dezvoltare NodeMCU care prin conectivitatea WiFi de care dispune ne va permite să realizăm o sincronizare de timp în rețea de tip NTP. Astfel nu vom avea nevoie de nici o componentă suplimentară pentru a asigura ora exactă.

Pentru afișare vom utiliza un ecran LCD grafic cu rezoluția de 84×48 pixeli de tip PCD8544 (LCD de Nokia 5110).

2

Funcționalitatea specială propusă în această lecție este adăugarea sistemului unei funcționalități de tip IoT adică raportarea prin Internet a unui parametru de mediu către o platformă IoT. Sistemul va măsura (și afișa) temperatura și o va trimite pentru înregistrare către platforma Robofun IoT. Astfel sistemul nostru nu va avea simpla funcționalitate de ceas/termometru electronic ci și de senzor IoT. Pentru măsurarea temperaturii vom utiliza un senzor digital brick DS18B20. Acest senzor are o acuratețe mare în măsurarea temperaturii, nu necesită decât 3 fire pentru conectarea la placa de dezvoltare și, cel mai interesant, permite de conectarea (pe aceleași trei fire) a mai multor senzori – sistemul poate fi extins foarte ușor prin adăugarea de noi senzori ce măsoară temperatura în zone diferite (interior / exterior, diverse camere etc.).

3

Ultima funcționalitate interesantă propusă pentru sistemul prezentat în această lecție este posibilitatea de programare la distanță – programare OTA (Over-The-Air). Pentru a reprograma / reîncărca programul nu este nevoie să desfacem carcasa sistemului și să conectăm placa de dezvoltare la calculator ci acest lucru poate fi făcut prin conexiunea WiFi a plăcii de dezvoltare. Singura limitare a acestei metode este că dimensiunea programului nu poate depăși jumătate din memoria program a plăcii de dezvoltare dar nu este cazul sistemului nostru.

4

Interconectarea componentelor (placă de dezvoltare, senzor de temperatură și ecran LCD) este prezentată în diagrama următoare:

5

Senzorul de temperatură va avea pinul D0 conectat la pinul D2 al plăcii de dezvoltare iar pinii 5V și GND la pinii 3.3V și GND ai plăcii de dezvoltare (senzorul funcționează la tensiuni între 3V și 5.5V). Chiar dacă programul prezentat în cele ce urmează este gândit pentru un sistem cu un singur senzor, sistemul acceptă adăugarea pe aceleași 3 fire a mai multor senzori de temperatură pe distanțe de până la 200 de metri.

Ecranul LCD comunică cu placa de dezvoltare prin protocoul SPI și implică următoarele conexiuni:

  • Pinul 1 (RST) al ecranului LCD se conectează la pinul D0 al plăcii de dezvoltare;
  • Pinul 2 (CE) al ecranului la pinul D1 al plăcii de dezvoltare;
  • Pinul 3 (DC) al ecranului la pinul D6 (HMISO) al plăcii de dezvoltare;
  • Pinul 4 (DIN) al ecranului la pinul D7 (HMOSI) al plăcii de dezvoltare;
  • Pinul 5 (CLK) al ecranului la pinul D5 (HSCLK) al plăcii de dezvoltare;
  • Pinul 6 (VCC) al ecranului la un pin de 3.3V al plăcii de dezvoltare;
  • Pinul 7 (LIGHT) al ecranului nu este conectat în schema noastră. Acest pin comandă aprinderea luminii de fundal a ecranului. Se poate conecta la un pin digital liber pentru comandă digitală sau PWM;
  • Pinul 8 (GND) al ecranului la un pin GND al ecranului.

Programul a fost dezvoltat și testat utilizând Arduino IDE 1.8.3 cu extensia ESP8266 Community 2.3.0 instalată. Prima încărcare a programului necesită conectarea plăcii la calculator prin intermediul cablului USB dar ulterior placa va putea fi reprogramată prin OTA (calculatorul de pe care se face programarea trebuie să fie în aceiași rețea ca placa NodeMCU):

6

#include <ESP8266WiFi.h>

#include <ESP8266HTTPClient.h>

#include <ESP8266mDNS.h>

#include <WiFiUdp.h>

#include <ArduinoOTA.h>

Programul utilizează și următoarele biblioteci: Time 1.5.0 – pentru a menține data și ora, sincronizarea NTP se face automat de către bibliotecă la intervale mai mari de timp; OneWire 2.3.3 și DallasTemperature 3.7.6 – pentru comunicația cu senzorul de temperatură; Adafruit GFX 1.2.2 și Adafruit PCD8544 versiune modificată pentru ESP8266 – pentru partea de afișare pe ecranul LCD. În cadrul programului trebuie personalizate datele de conectarea WiFi (variabilele ssid[] și pass[]). Constanta timeZone indică fusul orar (2 sau 3 pentru România, oră de iarnă sau vară).

#include <TimeLib.h>

const int timeZone = 3;

WiFiUDP Udp;

const int NTP_PACKET_SIZE = 48;

byte packetBuffer[NTP_PACKET_SIZE];

unsigned int localPort = 2390;   

char ssid[] = “…”;

char pass[] = “…”;

WiFiClient client;

#define HOSTNAME “ESP8266-OTA-“

#include <DallasTemperature.h>

#include <OneWire.h>

#define ONE_WIRE_BUS D2

OneWire oneWire(ONE_WIRE_BUS);

DallasTemperature sensors(&oneWire);

#include <SPI.h>

#include <Adafruit_GFX.h>

#include <Adafruit_PCD8544.h>

const int8_t RST_PIN = D0;

const int8_t CE_PIN = D1;

const int8_t DC_PIN = D6;

Adafruit_PCD8544 display =

Adafruit_PCD8544(DC_PIN, CE_PIN, RST_PIN);

Secțiunea setup() se va ocupa cu inițializarea conexiunii WiFi (în cazul unei erori pe ecranul LCD va apărea mesajul !WiFi și sistemul va intra într-o buclă de reinițializarea până la conectarea la rețea), inițializarea rețelei OneWire de senzori, inițializarea ecranului și a rutinei de programare OTA. În cazul unei inițializări normale pe ecranul LCD vor apărea informații legate de inițializarea sistemului (denumirea OTA, denumirea rețelei WiFi, adresa IP).

void setup() {

  sensors.begin();

  delay(100);

  display.begin();

  display.setContrast(60);

  display.setTextColor(BLACK);

  display.setCursor(0,0);

  display.setTextSize(1);

  display.clearDisplay();

  display.display();

  String hostname(HOSTNAME);

  hostname += String(ESP.getChipId(), HEX);

  WiFi.hostname(hostname);

  display.println(“Hostname:” + hostname);

  display.display();

  WiFi.begin(ssid, pass);

  delay(5000);

  if (WiFi.status() != WL_CONNECTED) {

    display.clearDisplay();

    display.setCursor(17,16);

    display.setTextSize(2);

    display.print(“!WiFi”);

    display.display();

    delay(10000);

    ESP.restart();

  }

  display.print(“Connected to “);

  display.println(ssid);

  display.print(“IP:”);

  display.println(WiFi.localIP());

  Udp.begin(localPort);

  setSyncProvider(getNtpTime);

  ArduinoOTA.setHostname((const char *)hostname.c_str());

  ArduinoOTA.begin();

  display.display();

  delay(1000);

  display.clearDisplay();

  display.display(); }

Secțiunea loop() se va ocupa cu achiziția parametrului temperatură și cu partea de afișare. Apelarea rutinei de postare IoT se va face la un interval de o oră (constanta postingInterval). Pe ecranul LCD vor apărea alternativ (câte 30 de secunde fiecare) ora/data și temperatura. Ecranul de afișare al temperaturii va conține și mesajul OK/Fail indicând dacă ultima postare IoT s-a efectuat cu succes sau nu (astfel sistemul are și o funcționalitate de supraveghere a bunei funcționări a serviciului IoT).

7

8

unsigned long lastConnectionTime = 0;

const unsigned long postingInterval = 60L * 60L * 1000L;

boolean myiot_ok;

void loop() {

    ArduinoOTA.handle();

    sensors.requestTemperatures();

    delay(100);

    float temperature = sensors.getTempCByIndex(0);

    display.clearDisplay();

    if (second()<30) {

      display.drawRoundRect(2,2,80,44,3,BLACK);

      display.setTextColor(BLACK);

      display.setCursor(13,10);

      display.setTextSize(2);

      printDigits(hour(),false);

      printDigits(minute(),true);

      display.println();

      display.setTextSize(1);

      display.setCursor(13,26);

      display.print(day());

      display.print(“/”);

      display.print(month());

      display.print(“/”);

      display.print(year());

      display.println();

      display.display(); 

    }

    else {

      display.fillScreen(BLACK);

      display.drawRoundRect(2,2,80,44,3,WHITE);

      display.setTextColor(WHITE);

      display.setTextSize(2);

      display.setCursor(22,10);

      display.print((int)temperature);

      display.print((char)247);

      display.println(“C”);

      display.setTextSize(2);

      if (myiot_ora!=-1) {

        if (myiot_ok) { 

          display.setCursor(30,26);

          display.println(“OK”);    }

        else {

          display.setCursor(20,26);

          display.println(“FAIL”); }

      }

      display.display();

    }

    if (millis() – lastConnectionTime > postingInterval) {

      if (IoTpublish(temperature)>0)

        { myiot_ok=true; }

      else

        { myiot_ok=false; }

    }

}

Funcția IoTpublish este responsabilă cu postarea IoT și returnează codul returnat de operația HTTP GET efectuată. În cadrul acesteia trebuie completată cheia de autentificare oferită de serviciul Robofun IoT (variabila SENSOR_TOKEN). Procedura printDigits este folosită pentru afișarea mai simplă a orei.

int IoTpublish(float temperature) {

  String SENSOR_TOKEN = “…”;

  HTTPClient http;

  String data = String(“http://iot.robofun.ro/api/v1/senzor/&#8221;) + SENSOR_TOKEN + “/input?value=” + String(temperature, DEC);

  http.begin(data);

  int httpCode = http.GET();

  delay(100);

  if(httpCode > 0) {

      if(httpCode == HTTP_CODE_OK) {

        String payload = http.getString();

      }

   }

  http.end();

  lastConnectionTime = millis();

  return httpCode;

}

void printDigits(int digits, boolean dots){

   if (dots) display.print(“:”);

  if(digits < 10)

    display.print(‘0’);

  display.print(digits);

}

Funcțiile getNtpTime și sendNTPpacket sunt apelate automat de către biblioteca Time și asigură partea de comunicație NTP. Constanta ntpServerName indică serverul NTP care este utilizat pentru sincronizarea de timp.

IPAddress timeServerIP;

const char* ntpServerName = “time.nist.gov”;

time_t lastsyncr;

time_t getNtpTime() {

  WiFi.hostByName(ntpServerName, timeServerIP);

  while (Udp.parsePacket() > 0) ;

  sendNTPpacket(timeServerIP);

  uint32_t beginWait = millis();

  while (millis() – beginWait < 2500) {

    int size = Udp.parsePacket();

    if (size >= NTP_PACKET_SIZE) {

      Udp.read(packetBuffer, NTP_PACKET_SIZE);

      unsigned long secsSince1900;

      secsSince1900 =  (unsigned long)packetBuffer[40]

<< 24;

      secsSince1900 |= (unsigned long)packetBuffer[41]

<< 16;

      secsSince1900 |= (unsigned long)packetBuffer[42]

<< 8;

      secsSince1900 |= (unsigned long)packetBuffer[43];

      lastsyncr = (time_t) (secsSince1900 – 2208988800UL +

timeZone * SECS_PER_HOUR);

      return lastsyncr;

    }

  }

  return 0;

}

void sendNTPpacket(IPAddress &address) {

  memset(packetBuffer, 0, NTP_PACKET_SIZE);

  packetBuffer[0] = 0b11100011;  

  packetBuffer[1] = 0; 

  packetBuffer[2] = 6; 

  packetBuffer[3] = 0xEC; 

  packetBuffer[12]  = 49;

  packetBuffer[13]  = 0x4E;

  packetBuffer[14]  = 49;

  packetBuffer[15]  = 52;

  Udp.beginPacket(address, 123);

  Udp.write(packetBuffer, NTP_PACKET_SIZE);

  Udp.endPacket(); }

După o oră după punerea în funcțiune a sistemului se pot consulta datele înregistrate în cadrul platformei Robofun IoT. Mai jos este o captură de ecran cu datele înregistrate de către sistemul de test în decursul unei zile.

9

Cum să realizăm un gateway LoRaWAN

Acoperirea rețelelor LoRaWAN la noi în țară este destul de scăzută (atât a rețelelor comerciale cât și a rețelei TTN). Din acest motiv, pentru a testa un sistem IoT LoRaWAN (ca cel descris în „Cum să realiză un sistem IoT LoRaWAN”) uneori este necesară realizarea unui sistem gateway LoRaWAN propriu. Sistemele profesionale de acest tip sunt destul de scumpe reprezentând o variantă de lux, a se vedea studiul comparativ a celor de la LorIoT.

O altă variantă este construirea unui sistem gateway propriu utilizând o placă de dezvoltare de genul Raspberry Pi. Problema în acest caz este generată de complexitatea modulației radio LoRa – sistemele gateway fiind sisteme care ascultă frecvențe radio multiple simultan (sunt denumite și concentratoare). Din acest motiv un modul radio LoRa obișnuit nu poate echipa un sistem gateway LoRaWAN fiind necesar un modul de tip concetrator, de exemplu: iC880A – LoRaWAN Concentrator 868MHz – modul cel mai adesea folosit în sisteme gateway LoRaWAN bazate pe Raspberry Pi.

2

Pentru mai multe detalii despre cum puteți construi un sistem gateway LoRaWAN bazat pe un modul de tip concentrator puteți consulta și materialele:

Chiar dacă prețul unui modul concentrator este mai mic decât a unui gateway profesional construirea unui astfel de sistem implică totuși un buget destul de mare.

Singura alternativă, accesibilă ca buget, este realizarea unui sistem gateway LoRaWAN de tipul One Channel (sau Single Channel). Adică vom un utiliza un modul radio LoRa obișnuit împreună cu o placă de tipul Raspberry Pi pentru realizarea unui sistem gateway. Dezavantajul unui astfel de gateway este faptul că ascultă pe o singură frecvență radio neputând comunica simultan cu mai multe sisteme IoT LoRaWAN. Acest tip de sisteme sunt considerate sisteme de tip ”forwarder” (Single Channel Forwarder) neavând o funcționalitate gateway LoRaWAN completă. Totuși, un astfel de sistem poate fi utilizat în locații izolate (fără acoperire LoRaWAN) pentru a testa comunicația LoRaWAN. Rețeaua TTN permite accesul acestor sisteme în rețea dar nu încurajează și nu asigură suport pentru ele fiind considerate compatibile dar neconforme cu specificațiile LoRaWAN.

Pentru implementare vom utiliza o placă de dezvoltare Raspberry Pi 3 și un hat LoRa/GPS. Testele au fost realizate sub Raspbian 9 (stretch) Lite, kernel 4.9.41-v7+.

Placa Raspberry Pi trebuie să aibă protocolul SPI activat (cu ajutorul utilitarului raspi-config) și pachetul wiringpi instalat.

$sudo raspi-config

4

$sudo apt-get update

$sudo apt-get install wiringpi

Pentru a implementa funcționalitatea de redirecționare a comunicației LoRa către platforma TTN vom utiliza software-ul single_chan_pkt_fwd.

$ wget https://github.com/tftelkamp/single_chan_pkt_fwd/archive/master.zip

$ unzip master.zip

$ cd single_chan_pkt_fwd-master

$ nano main.cpp

În fișierul main.cpp vom personaliza următoarele linii:

int ssPin = 6;

int dio0  = 7;

int RST   = 0;

sf_t sf = SF7;

uint32_t  freq = 868100000;

// opțional, dacă dorim să declarăm

// poziția și altitudinea sistemului

float lat=…;

float lon=…;

int   alt=…;

static char platform[24] = “Single Channel Gateway”;

static char email[40] = “…”;

static char description[64] = “…”;

#define SERVER1 “52.169.76.203”

#define PORT 1700

Salvăm (CTRL+O, CTRL+X), compilăm programul și îl lansăm în execuție:

$ make

$ sudo ./single_chan_pkt_fwd

5

Următorul pas necesită înregistrarea sistemului gateway în cadrul platformei TTN. În momentul înregistrării sistemului gateway este foarte important să bifăm opțiunea ”I’m using the legacy packet forwarder” (nu se poate modifica ulterior) și să copiem Gateway ID din consola ssh în consola de înregistrare.

6

După terminare înregistrării vom putea observa în consola TTN conexiunea dintre sistem și platforma TTN (Gateway Overview):

7

Pentru a face ca programul single_chan_pkt_fwd să ruleze automat la repornirea sistemului de operare adăugăm următoarea linie în fișierul /etc/rc.local (înainte de linia cu exit 0):

sudo /home/pi/single_chan_pkt_fwd-master/single_chan_pkt_fwd &

presupunând că am salvat și realizat compilarea în directorul utilizatorului pi.

Pentru mai multe informații legate de realizarea unui gateway LoRaWAN TTN Single Channel se pot consulta și următoarele materiale:

Cum să realizăm un sistem IoT LoRaWAN

În cadrul proiectului ”LoRa meets Robofun IoT” am văzut cum putem realiza un sistem IoT utilizând comunicația radio LoRa. Utilizând module radio LoRa putem transmite date la mare distanță dar pentru implementarea unui sistem IoT este necesară implementarea atât a modulului de achiziție (sau acționare) cât și a sistemului de tip gateway ce face legătura cu rețeaua Internet și cu serviciile cloud IoT. Specificațiile LoRaWAN permit implementare unor rețele radio LoRa standardizate astfel încât sistemele gateway să permită conectarea dispozitivelor IoT după un set de reguli larg acceptate. Realizarea unui sistem IoT LoRaWAN presupune realizare unui sistem de achiziție / acționare care respectă acest set de reguli și se conectează la o infrastructură de gateway-uri deja existentă (nu mai este nevoie să realizăm și să operăm sistemul gateway). Există mai multe rețele de gateway-uri LoRaWAN dar în cadrul acestui proiect vom arăta cum putem realiza un sistem ce folosește rețeaua TTN (The Things Network). Accesul în rețeaua TTN este gratuit deoarece se bazează pe gateway-uri particulare partajate între utilizatorii rețelei. Tot ce trebuie să faceți este să verificați dacă vă aflați în aria de acoperire a unui sistem gateway TTN.

Pentru sistemul IoT vom utiliza o placă de dezvoltare Arduino Uno și un shield Dragino LoRa echipat cu un modul radio LoRa în frecvență de 868MHz. Pentru partea de achiziție vom exemplifica măsurarea temperaturii utilizând un senzor brick conectat la pinul analogic A0 al plăcii de dezvoltare.

3

Pentru implementarea comunicației LoRaWAN vom utiliza biblioteca Arduino-LMIC. Testele au fost realizate utilizând Arduino IDE 1.8.3 și versiunea 1.5.0+arduino-1 a bibliotecii. Programul pleacă de la exemplul ttn-abp al bibliotecii în care vom efectua o serie de mici modificări. În primul rând trebuie să înregistrăm sistemul pe platforma TTN pentru a obține datele de autentificare în rețea:

static const PROGMEM u1_t NWKSKEY[16] = { … };

static const u1_t PROGMEM APPSKEY[16] = { … };

static const u4_t DEVADDR = … ;

Înregistrarea presupune crearea unui cont de utilizator, definirea unei aplicații (Applications) și, în cadrul aplicației, definirea unui dispozitiv (Device). În secțiunea se setări (Settings) a noului dispozitiv trebuie aleasă metoda ABP de activare și debifată opțiunea Frame Counter Checks. Tot în cadrul acestei secțiuni se regăsesc datele de autentificare în rețeua TTN. Pentru mai multe detalii legate de definirea aplicației și dispozitivului în rețeua TTN se poate consulta și materialul „LoRaWAN IoT with Arduino Uno, Dragino v1.3 & TheThingsNetwork”.

4

Tot în secțiunea de inițializare a exemplului se va șterge declarația mesajului mydata (se va defini din nou în program sub o altă formă) și se va modifica intervalul de postare a mesajelor (postarea la 1 minut este destul de agresivă pentru politica de utilizare a rețelei TTN).

const unsigned TX_INTERVAL = 3600;

Shield-ul Dragino LoRa necesită următoarea modificare în structura de definire a pinilor utilizați:

const lmic_pinmap lmic_pins = {

    .nss = 10,

    .rxtx = LMIC_UNUSED_PIN,

    .rst = 9,

    .dio = {2, 6, 7},

};

Ultima modificare adusă exemplului ttn-abp este rescrierea procedurii do_send pentru a trasmite valoare achiziționată de la brick-ul de temperatură în locul mesajului text predefinit. După cum se poate observa se va transmite valoarea returnată de funcția analogRead, prelucrarea numerică pentru a obține valoarea temperaturii se va face în sistemul cloud TTN.

void do_send(osjob_t* j){

    static uint8_t mydata[2];

    int reading = analogRead(A0);

    mydata[0] = highByte(reading);

    mydata[1] = lowByte(reading);

    if (LMIC.opmode & OP_TXRXPEND) {

        Serial.println(F(“OP_TXRXPEND, not sending”));

    } else {

        LMIC_setTxData2(1, mydata, sizeof(mydata), 0);

        Serial.println(F(“Packet queued”));

    }

}

După punerea în funcțiune a sistemului, și dacă vă aflați în aria de acoperire a unui gateway TTN, în consola TTN vor începe să apară valorile transmise de acesta (secțiunea Application Data). După cum se poate observa datele transmise sunt sub forma unui șir de valori în hexazecimal (2 octeți – 16 biți).

5

Pentru a transforma datele primite într-o formă mai ușor de înțeles se va scrie o funcție de decodare (în secțiunea Payload Formats / decoder). Această funcție va avea și rolul de a calcula temperatura echivalentă valorii achiziționate. După implementarea acestei funcții vom putea vedea în secțiunea de Application Data valoarea efectivă a temperaturii.

function Decoder(bytes, port) {

  var decoded = (((((bytes[0]<<8)|bytes[1])*5.0)/1024.0)-0.5)*100;

  return { value:decoded };

}

6

Atenție!!! Platforma TTN nu este o platformă IoT – nu stochează datele preluate de la sistemele LoRaWAN. Datele se pot observa în consolă doar dacă sunt transmise atunci când consola este deschisă. Platforma TTN permite în schimb transmiterea datelor primite prin rețeaua LoRaWAN către alte platforme online inclusiv platforme IoT. În secțiunea Integrations se pot defini diverse mecanisme automate de redirectare a datelor către sisteme precum Cayenne, OpenSensors sau IFTTT. Vom explica în cele ce urmează cum putem transmite datele către serviciul IFTTT care ne va trimite apoi valoarea temperaturii prin email. Bineînțeles, multitudinea de opțiuni oferite de platforma IFTTT permite redirectarea datelor către un serviciu IoT, postarea pe o rețea de socializare sau interacțiunea directă cu alte dispozitive IoT.

Definirea mecanismului automat de trimitere a datelor către serviciului IFTTT presupune adăugarea unui integrator de tipul IFTTT Maker (add integration / secțiunea Integrations). Conexiunea între cele două servicii (TTN și IFTTT) se realizează pe baza Event Name (trebuie să fie identic cu numele declanșatorului IFTTT) și Key (cheie de autentificare oferită de obiectul IFTTT Webhooks).

7

În cadrul platformei IFTTT se va realiza o regulă ce va avea declanșator serviciul Webhooks (Event Name trebuie să fie identic cu cel definit în platforma TTN) și ca efect transmiterea unui email.

8

La fiecare valoare a temperaturii transmisă de sistemul nostru vom primi un email de forma:

9

Pentru mai multe variante de realizare a unui sistem IoT LoRaWAN se pot consulta și următoarele materiale:

LoRa meets Robofun IoT

Modulele radio LoRa oferă posibilitatea de a transmite date la distanță mare (sute de metri sau chiar kilometri) utilizând module electronice de cost redus și cu un consum de energie scăzut. Acest lucru constituie o metodă eficientă pentru a extinde aria de acoperire pentru rețelele IoT fără fir. Chiar dacă semnalul WiFi are o acoperire limitată fiind influențat de puterea dispozitivelor de tip AP și de mediul în care operează (câmp deschis, locuințe sau birouri) există posibilitatea să extindem aria de acoperire radio a unei rețele IoT prin intermediul comunicațiilor ISM iar soluțiile LoRa oferă o variantă foarte bună cost / arie de acoperire.

Pentru a implementa o soluție LoRa în vederea extinderii ariei de acoperire IoT vom implementa un sistem gateway ce va realiza transferul datelor provenite de la modulele IoT către un sistem specific IoT și anume Robofun IoT. Modulul gateway propus se bazează pe placa de dezvoltare NodeMCU ce oferă conectivitate WiFi și un modul LoRa RFM96W în bandă de 433MHz. Conexiuniile între placa de dezvoltare și modulul radio sunt prezentate în diagrama următoare:

2.png

Modulul radio RFM96W se interconectează cu placa de dezvoltare prin intermediul magistralei SPI:

  • Pinul SCK al modulului se conectează la pinul D5 (GPIO14 – HSCLK);
  • Pinul MISO se conectează la pinul D6 (GPIO12 – HMISO);
  • Pinul MOSI se conectează la pinul D7 (GPIO13 – HMOSI);
  • Pinul CS se conectează la pinul D2;
  • Pinul RST se conectează la pinul D3;
  • Pinul G0 (INT) se conectează la pinul D1;
  • Vin și GND la pinii 3.3V și GND ai plăcii de dezvoltare.

Pentru ca placa să poată transmite prin Internet datele către serviciul Robofun IoT este necesară înregistrarea gratuită pe platformă:

3

După înregistrare și conectare este necesară definirea (Adauga senzor) a trei senzori: Temperatura, Umiditate și Nivel baterie, pentru a putea transmite datele primite de la sistemul IoT către platforma online. După definirea fiecărui senzor este necesar să copiem cheia de autentificare (Token) pentru a fi utilizată în program.

4

5

Programul a fost dezvoltat și testat utilizând Arduino IDE 1.8.3 (pentru instalarea plăcii NodeMCU sub Arduino IDE se poate vedea materialul „Quick Start to Nodemcu (ESP8266) on Arduino IDE”), extensia esp8266 versiunea 2.3.0 și biblioteca RadioHead 1.7.9. În cadrul programului trebuie personalizate datele de conectare la rețeaua WiFi (ssid și password) precum și cheile de autentificare pentru cele trei canale IoT (SENSOR_TOKEN1, SENSOR_TOKEN2 și SENSOR_TOKEN3).

#include <SPI.h>

#include <RH_RF95.h>

#include <ESP8266WiFi.h>

#include <ESP8266HTTPClient.h>

const char* ssid = “…”;

const char* password = “…”;

#define RFM95_CS D2

#define RFM95_RST D3

#define RFM95_INT D1

#define RF95_FREQ 434.0

RH_RF95 rf95(RFM95_CS, RFM95_INT);

#define LED D0

void setup() {

  pinMode(LED, OUTPUT);

  digitalWrite(LED,HIGH);    

  pinMode(RFM95_RST, OUTPUT);

  digitalWrite(RFM95_RST, HIGH);

  Serial.begin(9600);

  delay(100);

  Serial.println();

  Serial.println();

  Serial.println(“Gateway Module starting…”);

  Serial.print(“Connecting to “);

  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {

      delay(500);

      Serial.print(“.”);

    }

    Serial.println(“”);

    Serial.println(“WiFi connected”);

  digitalWrite(RFM95_RST, LOW);

  delay(10);

  digitalWrite(RFM95_RST, HIGH);

  delay(10);

  while (!rf95.init()) {

    Serial.println(“LoRa radio init failed”);

    while (1);

  }

  Serial.println(“LoRa radio init OK!”);

  if (!rf95.setFrequency(RF95_FREQ)) {

    Serial.println(“setFrequency failed”);

    while (1);

  }

  Serial.print(“Set Freq to: “);

  Serial.println(RF95_FREQ);

}

typedef struct {float temperature; float humidity;

float bat_voltage;} ParametriiRX;

ParametriiRX parametrii;

Ledul de pe placa de dezvoltare (conectat pe pinul D0) se va aprinde pe perioada recepției de mesaje LoRa. Toate datele primite prin intermediul LoRa vor fi postate pe platforma Robofun IoT. Sistemul va raporta și în consola serială toate mesajele recepționate.

6

void loop() {

  if (rf95.available())  {

    uint8_t buf[RH_RF95_MAX_MESSAGE_LEN];

    uint8_t len = sizeof(buf);

    if (rf95.recv(buf, &len)){

      digitalWrite(LED, LOW);

      RH_RF95::printBuffer(“Received: “, buf, len);

      parametrii = *(ParametriiRX*)buf;

      Serial.print(“Temperature: “);

      Serial.println(parametrii.temperature);

      Serial.print(“Humidity: “);

      Serial.println(parametrii.humidity);

      Serial.print(“Battery Voltage: “);

      Serial.println(parametrii.bat_voltage);

      Serial.print(“RSSI: “);

      Serial.println(rf95.lastRssi(), DEC);

      digitalWrite(LED, HIGH);

      String SENSOR_TOKEN1=”…”;

      String SENSOR_TOKEN2=”…”;

      String SENSOR_TOKEN3=”…”;

      HTTPClient http;

      String data = String(“http://iot.robofun.ro/api/v1/senzor/&#8221;) + SENSOR_TOKEN1 + “/input?value=” + String(parametrii.temperature, DEC);

      http.begin(data);

      int httpCode = http.GET();

      http.end();

      data = String(“http://iot.robofun.ro/api/v1/senzor/&#8221;) + SENSOR_TOKEN2 + “/input?value=” + String(parametrii.humidity, DEC);

      http.begin(data);

      httpCode = http.GET();

      http.end();

      data = String(“http://iot.robofun.ro/api/v1/senzor/&#8221;) + SENSOR_TOKEN3 +  “/input?value=” + String(parametrii.bat_voltage, DEC);

      http.begin(data);

      httpCode = http.GET();

      http.end();    }

    else    {

      Serial.println(“Receive failed”);    }

  }

}

Modulul LoRa ce va beneficia de extinderea ariei de comunicație (se poate afla la sute de metri, sau chiar kilometri în spațiu deschis, de aria de acoperire WiFi) se bazează pe placa de dezvoltare Feather M0 RFM95 433MHz LoRa – placă ce combină puterea unui microcontroler ARM Cortex-M0+ ATSAMD21 (la fel ca și plăcile Arduino M0/Zero) cu conectivitatea unui modul radio LoRa. Placa de dezvoltare va transmite către modulul gateway date preluate de la un senzor digital I2C de temperatură și umiditate Si7021 precum și nivelul bateriei proprii (unul dintre avantajele majore ale plăcilor Feather este posibilitatea de alimentare mobilă de la un acumulator LiPo de 3.7V).

Pentru mai multe informații legate de utilizarea plăcii Feather M0 RFM95 puteți consulta și materialul: „Adafruit Feather M0 Radio with LoRa Radio Module”.

Schema de interconectare între senzor și placa de dezvoltare este specifică unei magistrale I2C (pinii SDA și SCL conectați între senzor și placa de dezvoltare, alimentarea senzorului se va face la 3.3V):

7

Programul a fost dezvoltat și testat utilizând Arduino IDE 1.8.3, extensia Adafruit SAMD Boards 1.0.19 și bibliotecile RadioHead 1.7.9, Adafruit Si7021.

Decomentarea directivei debug va permite observarea funcționării modulului în consola serială.

//#define debug

7.5

#include <SPI.h>

#include <RH_RF95.h>

#define VBATPIN A7

#include <Adafruit_Si7021.h>

Adafruit_Si7021 sensor = Adafruit_Si7021();

#define RFM95_CS 8

#define RFM95_RST 4

#define RFM95_INT 3

#define RF95_FREQ 434.0

RH_RF95 rf95(RFM95_CS, RFM95_INT);

void setup() {

  pinMode(RFM95_RST, OUTPUT);

  digitalWrite(RFM95_RST, HIGH);

  sensor.begin();

  #ifdef debug

    while (!Serial);

    Serial.begin(9600);

    delay(100);

    Serial.println(“LoRa Sensor Module starting…”);

  #endif

  digitalWrite(RFM95_RST, LOW);

  delay(10);

  digitalWrite(RFM95_RST, HIGH);

  delay(10);

  while (!rf95.init()) {

    #ifdef debug

      Serial.println(“LoRa radio init failed”);

    #endif

    while (1);

  }

  #ifdef debug

    Serial.println(“LoRa radio init OK!”);

  #endif

  if (!rf95.setFrequency(RF95_FREQ)) {

    #ifdef debug

      Serial.println(“setFrequency failed”);

    #endif

    while (1);

  }

  #ifdef debug

    Serial.print(“Set Freq to: “);

    Serial.println(RF95_FREQ);

  #endif

  rf95.setTxPower(23, false);

}

typedef struct {float temperature; float humidity;

float bat_voltage;} ParametriiTX;

ParametriiTX parametrii;

void loop() {

  float voltage = analogRead(VBATPIN);

  voltage *= 2;   

  voltage *= 3.3;

  voltage /= 1024;

  parametrii.bat_voltage = voltage;

  parametrii.temperature = sensor.readTemperature();

  parametrii.humidity = sensor.readHumidity();

  #ifdef debug

    Serial.print(“Sample OK: “);

    Serial.print(parametrii.temperature);

   Serial.print(” *C, “);

    Serial.print(parametrii.humidity);

    Serial.println(” %”);

    Serial.print(“VBat: ” ); Serial.println(voltage);

    Serial.println(“Sending to Gateway Module”);

    Serial.println(“Sending…”); delay(10);

  #endif

  RH_RF95::printBuffer(“Sending: “, (uint8_t*)&parametrii, sizeof parametrii);

  #ifdef debug

    Serial.println(“Sending…”); delay(10);

  #endif

  rf95.send((uint8_t *)&parametrii, sizeof parametrii);

  #ifdef debug

    Serial.print(“Waiting for packet to complete…”);

delay(10);

  #endif

  rf95.waitPacketSent();

  #ifdef debug

    Serial.println(“done.”); delay(10);

  #endif

  delay(100);

  rf95.sleep();

  delay(60000);

}

După programarea și punerea în funcțiune a celor două sisteme se pot observa datele înregistrate în cadrul platformei Robofun IoT (capturile de ecran de mai jos reprezintă date înregistrate de sistemul de test pentru temperatură și umiditate).

8

9

Bineînțeles, sistemul LoRa poate deservi atât sisteme de achiziție (temperatură, umiditate, presiunea în diverse conducte, consumul de energie electrică, nivelul radiației solare etc.) dar și sisteme de acționare (chiar dacă nu a fost exemplificată această parte este posibil să comandăm de la distanță diverse mecanisme de închidere / deschidere, motoare etc).

Faceți cunoștință cu LoRa

Termenul de LoRa (sau tehnologie LoRa) se referă la o categorie de comunicații radio caracterizate de distanță mare de transmisie (Long Range) cu un consum mic de energie (Low Power). Spre deosebire de tehnologiile de transmisie radio digitale clasice, tehnologiile LoRa au capabilitatea de a comunica date la distanțe de câțiva kilometri sau chiar zeci de kilometri având aplicabilitate extraordinară în rețele de senzori wireless (fără fir), internetul obiectelor (IoT) și crearea de rețele de dispozitive inteligente. În spatele termenului de LoRa se află de fapt o multitudine de tehnologii proprietar sau deschise, similare ca funcționalitate dar total incompatibile ca implementare – domeniul de comunicații digitale radio la distanțe mari fiind la momentul actual într-o fază de pionierat în care stabilitatea oferită de standardizare și metode de interconectare tehnologică sunt un deziderat destul de îndepărtat. Alți termeni utilizați pentru a referi rețelele radio digitale cu raza mare de transmisie sunt: LoRaWAN (LoRa Wide Area Network), LPWAN (Low Power Wide Area Network), 6LowPAN (IPv6 Low-power Personal Area Network), LPN (Low Power Network) – unii dintre acești termeni sunt înregistrați ca mărci aparținând unor anumite companii sau consorții fiind folosiți pentru a identifica o anumită tehnologie LoRa (chiar și termenul de LoRa este marcă înregistrată a companiei Semtech).

Există foarte multe materiale care încearcă să clarifice asemănările / deosebirile și avantajele / dezavantajele oferite de fiecare tehnologie LoRa în parte, în acest sens vă recomandăm:

dar în cadrul materialului de față ne vom limita să prezentăm cele mai cunoscute tehnologii de transmisie radio la distanță mare la momentul actual precum și diverse dispozitive radio disponibile pe piață pentru implementarea acestor tehnologii (dispozitive aflate la un nivel decent de cost și complexitate pentru a le putea folosi în dezvoltarea unor sisteme proprii).

Tehnologii de transmisie radio la distanță mare  și dispozitive radio compatibile

LoRa –  Tehnologie radio ce utilizează benzi de frecvență radio ISM sub-Ghz pentru a transmite datele la distanțe mari cu un consum foarte mic de energie.

2

Este o tehnologie proprietar și este dezvoltată de compania Semtech. Specifică nivelul fizic de comunicație (modulația radio). Este implementată în circuitele integrate radio din seria SX1xxx produse de Semtech sau în circuitele RFM9x produse de HopeRF (care a cumpărat licența pentru nucleul radio LoRa). Cele două familii de circuite radio sunt compatibile deoarece implemetează același nucleu electronic de comunicație radio. Există mai multe plăci de dezvoltare și module de comunicație radio bazate pe circuitele din cele două familii:

  • Seeeduino LoRaWAN – placă de dezvoltare bazată pe un microcontroler ARM Cortex-M0+ ATSAMD21G18 (la fel ca și placa Arduino M0, placa este compatibilă cu mediul Arduino IDE) și un modul de comunicație radio RHF76-052 bazat pe circuitul SX1276 (compatibil LoRa).

3

  • Dragino LoRa Shield – shield Arduino bazat pe circuitul radio RFM98W (compatibil LoRa). Integrează un senzor de temperatură și indicator de baterie. Compatibil cu Arduino Uno, Leonardo, Mega.

4

  • Raspberry Pi LoRa/GPS HAT – shield (hat) pentru placa Raspberry Pi 2/3. Bazat pe un modul RFM92 (compatibil LoRa). Include un receptor GPS.

5

  • Adafruit Feather 32U4 / M0 RFM9x precum și shield-ul LoRa Radio Feather bazate pe module RFM9x și compatibile cu mediul Arduino IDE. Plăci de dezvoltare de mici dimensiuni, compacte și cu posibilitatea de alimentare de la un acumulator LiPo de 3.7V.

6

  • Modul radio Adafruit RFM96W ce permite utilizarea modului radio de la HopeRF împreună cu diverse plăci de dezvoltare inclusiv plăcile de dezvoltare Arduino.

7

LoRaWAN (LoRa Wide Area Network) – set de specificații deschise de tipul LPWAN (Low Power Wide Area Network) dezvoltate de consorțiul LoRa Alliance.

8

Completează tehnologia LoRA cu nivelul MAC. Chiar dacă este un set de specificații deschise la care contribuie o serie de companii importante (CISCO, IBM, ST, Renesas, ZTE, Microchip…) se bazează în totalitate pe nivelul fizic proprietar LoRa. Totuși, există o comunitate mare de utilizatori care și-au propus construirea unei rețelei globale LoRaWAN (The Thing Network) – în prezent puteți găsi acoperire TTN la noi în țară în București și Timișoara.

9

Sigfox – tehnologie LPWAN dezvoltată de compania franceză Sigfox. Utilizează modulație radio UNB (Ultra Narrow Band) și frecvențe radio ISM sub-GHz. Acoperire aproapre totală în circa 30 de țări.

10

Multiplii producători pentru circuite radio compatibile: Microchip, Texas Instruments, NXP sau ON Semiconductors și numeroase plăci de dezvoltare din care trebuie să menționăm placa de dezvoltare:

  • Arduino MKR FOX 1200 echipată cu un microcontroler ARM Cortex-M0+ SAMD21 (la fel ca și placa Arduino M0) și un circuit radio ATAB8520E (compatibil Sigfox).

11

6LowPAN (IPv6 Low-power Personal Area Network) este un set de specificații realizate de o comisie, cu același nume, a IETF (Internet Engineering Task Force). Specificațiile își propun extinderea seturilor de protocoale Internet pentru diferite metode de comunicație IoT (implementarea protocoalelor Internet în dispozitive specializate simple cu un consum redus de energie) și au influențat diverse tehnologii proprietar din domeniul LPWAN precum Thread dând naștere la diverse derivații funcționale pentru protocoalele radio existente precum IPv6 over BLE.

12

Controlere USB

Controlerele USB sunt circuite integrate ce permit interfațarea unui sistem electronic cu un port USB. Controlerele USB se pot configura dar nu pot executa un program (nu sunt programabile) putând efectua doar sarcini simple de conversie între diverse protocoale seriale sau paralele și comunicația USB. Aceste circuite pot înlocui un microcontroler într-un sistem simplu de achiziție, comandă sau comunicație scăzând prețul și complexitatea sistemului. Exemple de astfel de circuite:

  • Familia de circuite FTDI FT-X ce include convertoare USB-to-UART, USB-to-SPI sau USB-to-I2C. Circuitul FT232RL a echipat plăcile de dezvoltare Arduino Duemilanove (plăci Arduino de generație mai veche) pentru conversia USB-to-UART fiind înlocuite ulterior cu microcontrolerele ATmega16U2/8U2 pentru plăcile Arduino Uno și Arduino Mega. Modulele necesare programării plăcilor de dezvoltare Arduino Ethernet și Arduino Pro Mini se bazează pe același circuit FT232RL. Adafruit FT232H Breakout (imagine de mai jos) este un exemplu de modul capabil să ofere simultan conectivitate UART, I2C și SPI prin intermediul unei conexiuni USB.

1

  • Seria de circuite Smart I/O a companiei Prolific conține diverse circuite (PL-2303xx) pentru conversia USB-to-UART, acestea fiind regăsite pe majoritatea clonelor de plăci Arduino sau pe diverse module ieftine de conversie USB-to-RS232 sau USB-to-UART.

2

  • Controlerul USB Microchip MCP2221 este un circuit cu facilități de configurare extrem de flexibile putând fi utilizat simultan pentru conversia USB-UART, USB-I2C, USB-parallel și chiar și pentru achiziția analogică prin intermediul conexiunii USB. Datorită prețului scăzut și al facilităților oferite vom utiliza acest controler pentru cele două exemple din cadrul lecției.

3

Controlerul USB MCP2221

Unul dintre avantajele controlerului MCP2221 este disponibilitatea în format THT (PDIP14) permițând astfel realizarea de montaje pe breadboard fără a fi nevoie de un modul de tip breakout, în plus circuitul nu necesită sursă de oscilație (cuarț) extern sau alte componente suplimentare (cu alte cuvinte este utilizabil la un cost minimal). Pinii circuitului au următoarele semnificații și funcționalități:

  • VDD, VSS (5V, GND) sunt pinii de alimentare a circuitului și trebuie conectați la pinii de alimentare a conexiunii USB;
  • D+, D- sunt pinii de comunicație USB, se conectează la pinii corespondenți ai conexiunii USB;
  • SCL, SDA sunt cele două linii de comunicație ale magistralei I2C;
  • /RST pin de resetare a circuitului;
  • Vusb pin de alimentare la 3.3V în cazul în care nu se dorește alimentarea oferită de conexiunea USB (nu se utilizează pinii VDD și VSS);
  • URx, UTx sunt pinii de comunicație UART;
  • GP0, GP1 – pini I/O de uz general; pot fi folosiți și ca pini de comandă pentru LED-urile de activitate RX, TX pentru comunicația serială; pinul GP1 poate fi folosit ca și pin de achiziție analogică sau ca linie de întrerupere externă.
  • GP2 – pin I/O de uz general; poate fi folosit ca pin de intrare analogică, pin de ieșire analogică sau pin de stare a conexiunii USB (USBCFG);
  • GP3 – pin I/O de uz general; poate fi folosit ca pin de intrare analogică, pin de ieșire analogică sau comandă pentru LED-ul de activitate magistrală I2C.

4

După cum se poate observa funcționalitatea oferită de controlerul USB MCP2221 este una diversă: convertor USB-to-UART, convertor USB-to-I2C, achiziție analogică prin USB, comandă digitală prin USB, comandă analogică prin USB. Pentru configurarea controlerului se utilizează programul MCP2221 Utility (captură de ecran de mai jos).

5

Prin intermediul acestui program se poate modifica:

  • Descriptorul USB al controlerului:
    • VID / PID ce identifică în mod unic dispozitivul USB și pe baza cărora sistemul de operare instalează driverele corecte – modificarea acestora conduce la probleme de instalare a driverelor implicite Microchip;
    • Curentul necesar funcționării dispozitivului (între 100mA și 500mA);
    • Dacă se alimentează din conexiunea USB sau se alimentează în mod autonom;
    • Informații descriptive (pot fi modificate fără probleme pentru personalizarea descrierii perifericului USB): descriere, producător, număr serial.
  • Funcționalitatea și configurația celor patru pini GPIO (GP0-GP3):
    • GP0: pin I/O (direcție, stare inițială), SSPND (USB state) sau LED_URx;
    • GP1: pin I/O (direcție, stare inițială), generator semnal de ceas (CLK_OUT), pin achiziție analogică (tensiune referință), linie de întrerupere externă (tip declanșare) sau LED_UTx;
    • GP2: pin I/O (direcție, stare inițială), USBCFG, pin de achiziție analogică (tensiune referință) sau pin de comandă analogică (tensiune referință);
    • GP3: pin I/O (direcție, stare inițială), LED_I2C, pin de achiziție analogică (tensiune referință) sau pin de comandă analogică (tensiune referință);

Datorită facilităților diverse oferite de controlerul MCP2221 se pot realiza proiecte embedded variate în care microcontrolerul să fie înlocuit de circuitul MCP2221. În cadrul acestei lecții vom exemplifica utilizarea circuitului MCP2221 prin două sisteme simple: un ceas USB și un termometru USB.

Sistem de tip Ceas USB

Controlerul MCP2221 este văzut de sistemul de operare ca două dispozitive USB distincte: un dispozitiv CDC prin care se realizează conversia USB-to-UART (un port serial) și un dispozitiv HID prin care se realizează comunicația cu restul de componente (pini I/O, magistrală I2C, pini analogici). Pentru proiectul Ceas USB ne vom folosi de facilitatea de convertor USB-to-UART a circuitului MCP2221 pentru a comanda afișarea orei pe un LCD grafic serial de rezoluție 128×64 pixeli. Schema de interconectare este foarte simplă:

6Pinii D+ și D- ai conexiunii USB vor fi conectați direct la controlerul USB. Pinii de alimentare ai conexiunii USB vor asigura funcționarea a controlerului și a ecranului LCD. Comunicația serială între controler și afișaj va fi unidirecțională și va folosi o singură linie: pinul 6 (UTx) al controlerului va fi conectat la pinul RX al afișajului.

7

Pentru ca sistemul să funcționeze, pe PC va rula un program ce va prelua ora de pe sistemul PC și va transmite comenzile de afișare pe portul serial către afișaj (controlerul USB va fi o componentă transparentă pentru program). Programul va necesita o parte de inițializare:

  • Dacă dispozitivul USB cu ID-ul xxxxxxx este conectat:
    • Identifică portul serial asociat cu dispozitivul USB cu ID-ul xxxxxxx;
    • Transmite pe portul serial comandă de ștergere a ecranului: 0x7C,0x00

și o buclă infinită în care:

  • Transmite pe portul serial comandă de poziționare pe X: 0x7C, 0x18, … și pe Y: 0x7C, 0x19, …;
  • Preia ora de pe sistemul PC și transmite ora pe portul serial.

Sistem de tip Termometru USB

Sistemul Termometru USB își propune citirea unui senzor de temperatură I2C conectat la controlerul MCP2221. Temperatura citită poate fi ulterior afișată pe ecranul PC-ului. Senzorul utilizat va fi TMP102 dar se poate utiliza orice alt senzor I2C sau analogic. Schema de interconectare a celor două componente este:

8

Deoarece senzorul TMP102 funcționează la 3.3V va fi alimentat prin intermediul pinului Vusb al controlerului MCP2221 (controlerul are inclus un regulator de tensiune 5V->3.3V – imagine de mai jos).

9

Liniile magistralei I2C (SCL și SDA) se vor conecta la pinii 10 și 9 ai controlerului. Din punct de vedere al programului ce va rula pe PC, comunicația cu magistrala I2C se va realiza prin intermediul unei biblioteci software puse la dispoziție de Microchip: MCP2221 DLL. Pentru a realiza achiziția de temperatură de la senzor este necesar să utilizăm următoarele funcții ale bibliotecii (directorul bibliotecii include exemple de utilizare pentru mai multe limbaje de programare):

  • DllInit() – pentru inițializarea comunicației;
  • GetConnectionStatus() – pentru a verifica dacă dispozitivul este conectat;
  • SelectDev(ID) – pentru a selecta dispozitivul;

ReadI2C() – ce va avea ca parametrii adresa senzorului I2C și numărul de octeți citiți.