Utilizarea limbajului de asamblare în Arduino IDE

Ce este ”Inline Assembler”?

Facilitatea de ”Inline Assembler” permite inserarea de cod în limbaj de asamblare în cadrul programelor de C/C++ compilate cu ajutorul GCC (compilatorul utilizat de mediul Arduino IDE). Utilizarea de cod în limbaj de asamblare permite optimizarea unor porțiuni de cod și obținerea unor programe mai mici ca dimensiune (în format binar). Pentru mai multe informații se recomandă consultarea materialului „Inline Assembler Cookbook”.

Inserarea de cod în limbaj de asamblare se face utilizând directiva asm (sau ___asm___) direct în program. De exemplu (instrucțiunea NOP în limbaj de asamblare nu are nici un efect):

asm ( “nop \n”);

Bineînțeles, în cadrul secțiunii de cod în limbaj de asamblare nu vom beneficia de aceleași avantaje și înlesniri ca într-un program obișnuit în limbaj de nivel înalt. Pentru a înțelege mai bine vom reface exemplul clasic din Arduino IDE – programul Blink:

void setup() {

  pinMode(13, OUTPUT);

}

void loop() {

  digitalWrite(13, HIGH);

  delay(1000);

  digitalWrite(13, LOW);  

  delay(1000);     

}

O variantă a acestui program utilizând directiva asm este:

void setup() {

 asm(“sbi  0x04, 0x5 \n”);

}

void loop() {

 asm(“cbi  0x05, 0x5 \n”);  

 delay(1000);                

 asm(“sbi  0x05, 0x5 \n”); 

 delay(1000);           

}

După cum se poate observa instrucțiunile pinMode și digitalWrite, specifice mediului Arduino IDE, au fost înlocuite cu instrucțiuni în limbaj de asamblare: sbi și cbi ce permit setarea sau ștergerea unui bit de la o anumită adresă din memorie. Mai mult decât atâta, nu am mai folosit referința la pinul plăcii Arduino așa cum suntem obișnuiți (pinul 13) ci adrese de memorie la care se află registrele interne de configurare ale pinului (registrul de sens DDRB – adresa 0x04 și registrul de ieșire PORTB – adresa 0x05, în ambele registre am manipulat bitul 5 corespondent pinului PB5 adică pinul 13 al plăcii Arduino). Comparați memoria program ocupată de exemplul original și cel care utilizează directiva asm.

2

Registre interne și echivalarea pinilor între mediul Arduino și arhitectura microcontrolerului ATmega328P

Pentru a ușura lucrul cu pinii I/O mediul Arduino IDE are propria modalitate de identificare a acestora (D0-D13, A0-A5) dar în realitate aceștia sunt organizați în trei porturi a câte 8 pini (PB0-PB7, PC0-PC7, PD0-PD7), echivalența între cele două organizări este reprezentată în diagrama următoare (nu toți pinii sunt prezenți la varianta THT a circuitului ATmega328P):

3

Pentru a putea manipula pinii microcontrolerului (la nivel de limbaj de asamblare) este nevoie să cunoaștem adresele registrelor DDRx (registrul de sens) și PORTx (registrul de ieșire) al portului din care face parte pinul. Pentru mai multe informații despre organizarea internă a registrelor interne este utilă consultarea manualului circuitului ATmega328P.

4 

Exemplu de program: joc de lumini

Presupunem următoarea schemă de interconectare a 8 leduri cu placa de dezvoltare Arduino Uno în mod individual – fiecare led este comandat în mod direct de câte un pin al plăcii de dezvoltare (led 1 – pin 2, led 2 – pin 3…. led 8 – pin 9):

5

Funcționalitatea sistemului va consta în realizarea a două jocuri de lumini. Secțiunea setup a programului va trebui să configureze toți cei opt pini utilizați ca fiind pini de ieșire. Varianta inițială ce utilizează instrucțiunea pinMode este:

void setup() {               

  pinMode(2, OUTPUT);

  pinMode(3, OUTPUT);  

  pinMode(4, OUTPUT); 

  pinMode(5, OUTPUT);   

  pinMode(6, OUTPUT); 

  pinMode(7, OUTPUT); 

  pinMode(8, OUTPUT); 

  pinMode(9, OUTPUT);

  Serial.begin(9600);

}

Prima variantă propusă utilizează instrucțiunea sbi ca și în exemplul precedent (adresa 0x0a este adresa registrului DDRD iar adresa 0x04 adresa registrului DDRB):

asm (

  “sbi 0x0a, 2 \n”

  “sbi 0x0a, 3 \n”

  “sbi 0x0a, 4 \n”

  “sbi 0x0a, 5 \n”

  “sbi 0x0a, 6 \n”

  “sbi 0x0a, 7 \n”

  “sbi 0x04, 0 \n”

  “sbi 0x04, 1 \n”

 );

O variantă mai scurtă este configurarea biților din cele două registre (DDRD și DDRB) simultan utilizând registrul de uz general R26 ca intermediar pentru transmiterea valorii către cele două registre:

asm (

    “ldi r26, 0b11111100 \n”

    “out 0x0a, r26 \n”

    “ldi r26, 0b00000011 \n”

    “out 0x04, r26 \n”

    : : : “r26”

    );

Utilizarea unui registru de uz general trebuie semnalizată compilatorului pentru a nu apărea suprapuneri în utilizarea registrelor – ultima linie din cod, a se vedea și materialul „Arduino Inline Assembly Tutorial #3 (Clobbers)”.

Prima variantă de joc de lumini va aprinde alternativ la un interval de 1 secundă ledurile de rang impar și ledurile de rang par (led 1, led 3, led 5, led 7 – led 2, led 4, led 6, led 8). Secțiunea loop (utilizând cod Arduino) este:

void loop() {

  for (int i=2; i<10; i++) {

      if ((i%2)==0) digitalWrite(i,HIGH);

      else digitalWrite(i,LOW);

   }

   delay(1000); 

   for (int i=2; i<10; i++) {

      if ((i%2)==0) digitalWrite(i,LOW);

      else digitalWrite(i,HIGH);

   }

   delay(1000);

}

Transpunerea în limbaj de asamblare este:

void loop() {

asm (

      “sbi 0x0b,2 \n”

      “cbi 0x0b,3 \n”

      “sbi 0x0b,4 \n”

      “cbi 0x0b,5 \n”     

      “sbi 0x0b,6 \n”

      “cbi 0x0b,7 \n”

      “sbi 0x05,0 \n”

      “cbi 0x05,1 \n”

      “ldi r25, 0x7F \n”

      “wait1: ldi r26, 0xFF \n”

      “wait2: ldi r27, 0xFF \n”

      “wait3: dec r27 \n”

      “nop \n”

      “brne wait3 \n”

      “dec r26 \n”

      “brne wait2 \n”

      “dec r25 \n”

      “brne wait1 \n”     

      “cbi 0x0b,2 \n”

      “sbi 0x0b,3 \n”

      “cbi 0x0b,4 \n”

      “sbi 0x0b,5 \n”     

      “cbi 0x0b,6 \n”

      “sbi 0x0b,7 \n”

      “cbi 0x05,0 \n”

      “sbi 0x05,1 \n”

      “ldi r25, 0x7F \n”

      “wait1b: ldi r26, 0xFF \n”

      “wait2b: ldi r27, 0xFF \n”

      “wait3b: dec r27 \n”

      “nop \n”

      “brne wait3b \n”

      “dec r26 \n”

      “brne wait2b \n”

      “dec r25 \n”

      “brne wait1b \n”

      : : : “r25” , “r26”, “r27”

  ); 

Cea de a doua variantă de joc de lumini va aprinde unul câte unul (pornind de la led-ul 1 până la led-ul 8) toate led-urile și apoi le va stinge în mod similar (în ordine inversă). Operația de aprindere sau stingere a unui led se va efectua la un interval de 500 milisecunde. Secțiunea loop (utilizând cod Arduino) este:

void loop() {

   for (int i=2;i<10;i++) {

     digitalWrite(i,HIGH);

     delay(500); }

   for (int i=9;i>1;i–) {

     digitalWrite(i,LOW);

     delay(500);

   }

  }

Transpunerea în limbaj de asamblare este:

void loop() {

asm (

      “start: sbi 0x0b,2 \n”

      “rcall wait \n”

      “sbi 0x0b,3 \n”

      “rcall wait \n”

      “sbi 0x0b,4 \n”

      “rcall wait \n”

      “sbi 0x0b,5 \n”

      “rcall wait \n”     

      “sbi 0x0b,6 \n”

      “rcall wait \n”

      “sbi 0x0b,7 \n”

      “rcall wait \n”

      “sbi 0x05,0 \n”

      “rcall wait \n”

      “sbi 0x05,1 \n”

      “rcall wait \n”     

      “cbi 0x0b,2 \n”

      “rcall wait \n”

      “cbi 0x0b,3 \n”

      “rcall wait \n”

      “cbi 0x0b,4 \n”

      “rcall wait \n”

      “cbi 0x0b,5 \n”

      “rcall wait \n”     

      “cbi 0x0b,6 \n”

      “rcall wait \n”

      “cbi 0x0b,7 \n”

      “rcall wait \n”

      “cbi 0x05,0 \n”

      “rcall wait \n”

      “cbi 0x05,1 \n”

      “rcall wait \n”     

      “rjmp start \n”

      “wait: ldi r25, 0x3F \n”

      “wait12: ldi r26, 0xFF \n”

      “wait22: ldi r27, 0xFF \n”

      “wait32: dec r27 \n”

      “nop \n”

      “brne wait32 \n”

      “dec r26 \n”

      “brne wait22 \n”

      “dec r25 \n”

      “brne wait12 \n”

      “ret \n”

      : : : “r25” , “r26”, “r27”

  );

}

Ambele jocuri de lumini utilizează instrucțiunile sbi și cbi pentru manipularea pinilor I/0 (pentru o listă completă a instrucțiunilor în limbaj de asamblare se recomandă parcurgerea materialului „AVR Instruction Set Manual”). Funcția de temporizare delay din mediul Arduino IDE este înlocuită cu o succesiune de bucle ce realizează o întârziere aproximativă (în a doua variantă această succesiune este implementată ca o subrutină).

Toilet Time

Ignorat sau râvnit, tihnit sau zbuciumat, relaxare sau chiar plăcut timp de lectură… putem descrie în multe moduri timpul petrecut la toaletă dar știm de fapt care este acest timp? În cadrul proiectului de față vom prezenta realizarea unui sistem ce permite măsurarea timpului petrecut la toaletă. Chiar dacă poate părea puțin bizară tematica propusă vă asigurăm că mulți pasionați de sisteme electronice programabile s-au gândit cel puțin o dată la un sistem care să accesorizeze toaleta proprie; câteva exemple de astfel de proiecte:

Sistemul propus de noi se bazează pe o placă de dezvoltare Adafruit Feather HUZZAH echipată cu microprocesorul WiFi ESP8266. Conectivitatea WiFi va permite consultarea timpului total petrecut la toaletă prin intermediul oricărui dispozitiv inteligent cu conectivitate de rețea (tabletă, telefon mobil). În plus, specific tuturor plăcilor din familia Feather, placa de dezvoltare se poate alimenta de la un acumulator LiPo de 3.7V permițând crearea simplă a unui sistem independent de alimentarea USB. Detectarea ocupării toaletei se va face cu ajutorul unui buton brick ce se va poziționa sub colacul toaletei. Greutatea colacului nu este suficientă pentru a apăsa butonul, butonul se va apăsa doar dacă toaleta este ocupată. Bineînțeles, se poate înlocui componenta buton brick cu un senzor de apăsare brick dacă se dorește perfecționarea dedectării ocupării toaletei sau dacă se dorește realizarea unui sistem cu mai mulți ”utilizatori”.

Schema de interconectare dintre placa de dezvoltare și brick-ul buton este următoarea:

2

Brick-ul se va alimenta la 3.3V iar ieșirea se va conecta la pinul GPIO12 al plăcii de dezvoltare.

Programul a fost dezvoltat și testat utilizând Arduino IDE 1.8.5 având instalată extensia ESP8266 Community 2.3.0. În cadrul programului trebuie personalizate datele de conectare WiFi (variabilele ssid și password).

#include <ESP8266WiFi.h>

#include <WiFiClient.h>

#include <ESP8266WebServer.h>

#include <EEPROM.h>

const char *ssid = “…”;

const char *password = “…”;

ESP8266WebServer server (80);

#define pinButton 12

Timpul total de utilizarea a toaletei este stocat în variabila globală toilettime ca număr de secunde. Consultarea timpului total se poate face accesând adresa IP a sistemului (oferită prin DHCP de către AP-ul WiFi) dintr-un client web (browser web). Procedura handleRoot() este responsabilă de construirea paginii HTML trimisă către clientul web. Timpul total se va afișa în format HH:MM:SS. Programul poate fi îmbunătățit în această privință pentru a afișa durate mai mari de timp (sub formă de zile, săptămâni, ani).

3

char temp[600];

unsigned long toilettime;

void handleRoot() {

int sec = toilettime % 60;

int min = (toilettime / 60) % 60;

int hr = toilettime / 3600;

snprintf ( temp, 600,”%02d:%02d:%02d”, hr, min, sec);

String page = “<html>\

<head>\

<meta http-equiv=’refresh’ content=’10’/>\

<title>Toillet Time</title>\

<style>\

body { background-color: #cccccc; font-family:

Arial, Helvetica, Sans-Serif; Color: #000088; }\

</style>\

</head>\

<body>\

<h1>Toilet Time</h1>\

<p><b>Your total time is:</b> ” + String(temp) + “

</p>\

</body>\

</html>”;

page.toCharArray(temp,page.length()+1);

server.send ( 200, “text/html”, temp );

}

Variabila ocupat are semnificația de toaletă ocupată. Când variabila ocupat are valoare true sistemul va contoriza timpul scurs și îl va adăuga la variabila toilettime. Conținutul variabilei toilettime se va salva în memoria flash a plăcii de dezvoltare la fiecare trecere din true în false a variabilei ocupat – acest lucru va asigura păstrarea timpului total și după un reset al plăcii de dezvoltare. Pentru operațiile cu memoria flash programul utilizează biblioteca Arduino IDE EEPROM. Placa de dezvoltare nu are memorie EEPROM, versiunea pentru ESP8266 a bibliotecii EEPROM utilizează aceleași funcții și metode ca la plăcile Arduino dar se folosește de memoria program flash. În cadrul secțiunii setup(), la fiecare nouă inițializare a programului, variabila toilettime se inițializează din memoria non-volatilă program.

boolean ocupat;

void setup() {

pinMode(pinButton, INPUT);

EEPROM.begin(512);

toilettime = 0;

toilettime += (long)EEPROM.read(0)<<24;

toilettime += (long)EEPROM.read(1)<<16;

toilettime += (long)EEPROM.read(2)<<8;

toilettime += (long)EEPROM.read(3);

WiFi.begin ( ssid, password );

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

delay ( 500 );

}

server.on ( “/”, handleRoot );

server.begin();

ocupat = false;

}

Variabilele start și stopp memorează momentele trecerii variabilei ocupat din false în true (așezarea pe toaletă) și din true în false (ridicarea de pe toaletă). În momentul adunării timpului scurs la variabila globală toilettime, conținutul acesteia este salvată și în memoria flash.

unsigned long start, stopp;

void loop() {

if ((!ocupat) && (digitalRead(pinButton)==1)) {

start = millis();

ocupat = true;

}

if (ocupat && (digitalRead(pinButton)==0)) {

stopp = millis();

ocupat = false;

toilettime += (stopp – start)/1000;

byte temp;

temp = (toilettime>>24) & 0xFF;

EEPROM.write(0, temp);

temp = (toilettime>>16) & 0xFF;

EEPROM.write(1, temp);

temp = (toilettime>>8) & 0xFF;

EEPROM.write(2, temp);

temp = toilettime & 0xFF;

EEPROM.write(3, temp);

EEPROM.commit();

}

server.handleClient();

}

În cazul în care vă plictisiți testând sistemul vă recomandăm aplicația mobilă Android Toilet Time – Mini-games for the bathroom.

Imprimanta Robofun 20-20-20 – HOW TO

Inainte de a incepe acest articol, te rog sa citesti cu mare atentie cele de mai jos.

Imprimanta 3D se alimenteaza in priza de 220 V. NICIODATA si sub nici un motiv nu desface carcasa imprimantei, nu introduce obiecte metalice in zona sursei de alimentare. Daca observi probleme in zona sursei sau a firelor de conexiune la priza, deconecteaza imediat imprimanta de sub tensiune si returneaz-o pentru reparatii. PERICOL DE ELECTROCUTARE !

De asemenea, nu lasa niciodata imprimanta 3D sub tensiune (conectata la priza) fara supraveghere. 

 

Pasii pentru a pune in functiune o imprimanta 3D Robofun  sunt cei de mai jos :

  1. descarca si instaleaza Cura (software-ul care proceseaza modelul 3D si il face usor de inteles pentru imprimanta)
  2. descarca si instaleaza Repetier (software-ul care gestioneaza procesul de printare)
  3. pune imprimanta sub tensiune si testeaza ca totul este OK din punct de vedere mecanic si software
  4. calibreaza distanta de start pe axa Z, daca este cazul
  5. calibreaza orizontalitatea bed-ul, daca este cazul
  6. primul print

 

Cand vei termina filamentul, va fi necesar sa il schimbi, conform instructiunilor de mai jos.

1. Instalare Cura

Cura este acel software care analizeaza obiectul 3D (pe care il ai in format STL) si genereaza un cod sursa pe care imprimanta il intelege (in format gcode).

Mergi la adresa web https://ultimaker.com/en/products/cura-software/list si descarca “Version: 2.3.1” (pe 32 de biti sau pe 64 de biti, in functie de ce arhitectura ai la PC; daca esti in dubiu, alege 32 de biti, va functiona oricum). Sigur ca poti alege si versiuni mai noi, insa tutorialul de mai jos este creat pentru Cura 2.3.1 Am ales aceasta versiune pentru ca este ultima care mai suporta versiune de 32 de biti.

Deschide fiecare grup de setari din partea dreapta si asigura-te ca totul este ca mai jos.

Optiunile “Retraction Distance” si “Retraction Speed” probabil ca nu sunt vizibile by default. Este necesar sa accesezi optiunea “Configure Settings Vizibility” din meniul “Settings” si sa le activezi (fa o cautare dupa “retract” – introdu acest text in campul “Filter” si va fi simplu).

 

 

2. Instalare Repetier

Repetier este acel software care se ocupa efectiv de procesul de printare. Rolul lui este de a trimite progresiv codul gcode la imprimanta si a monitoriza parametri de printare.

Descarca “Repetier Host Windows 2.0.5” de la adresa – https://www.repetier.com/download-now/ . Sigur, poti descarca si o versiune mai noua daca vrei, insa tutorialul de mai jos este pentru versiunea 2.0.5

 

3. Teste preliminare imprimanta

A. conectare cablu USB

Folosind cablul USB primit o data cu imprimanta, conecteaza imprimanta la PC, ca in poza de mai jos.

Nu toate cablurile USB sunt la fel de bune, asa ca pentru inceput, te rog sa folosesti cablul primit o data cu imprimanta. Mai tarziu, dupa ce printezi cateva zile, il poti schimba daca vrei, insa daca apar orice fel de probleme, intoarce-te la cablul USB original.Viteza de transfer este destul de mare, asa ca ai nevoie de un cablu care sa o poata suporta.

 

B. drivere si port USB

Ar trebui ca PC-ul sa vada automat imprimanta si sa creeze un nou port serial pentru comunicarea cu aceasta.

Deschide Control Panel, apoi Device Manager, si verifica sectiunea “Ports”. Ar trebui sa ai o inregistrare similara cu cea de mai jos. Probabil ca la tine numarul portului va fi mult mai mic (gen COM4, sau COM5).

Daca nu vezi o astfel de inregistrare in Device Manager, inseamna ca driver-ele nu sunt corect instalate. Ne poti contacta la adresa de email contact [at] robofun [dot] ro si te vom ajuta cu placere sa rezolvi problema.

C. conectare Repetier

Conecteaza imprimanta la 220 V, in priza. Inca o data, repet avertismentul de la inceput. NU deschide carcasa imprimantei si NU introduce obiecte metalice in zona sursei. Pericol de electrocutare !

Deschide programul “Repetier-Host”, instalat la pasul precedent.

Din meniul “Config”, alege optiunea “Printer Settings”. Selecteaza portul pe care l-ai vazut mai devreme in Device Manager, apoi selecteaza o viteza de transfer (Baud Rate) de 115200, si apasa OK.

Apasa butonul “Connect”, din stanga sus. Ar trebui ca eticheta butonului sa se schimbe in “Disconnect”, iar in partea de jos a ecranului sa vezi o serie de mesaje primite de la imprimanta, ca mai jos.

Daca nu vezi aceste mesaj, inseamna ca exista o problema si nu vei putea printa. Verifica inca o data in Device Manager numarul portului serial COM, si asigura-te ca este corect introdus in Printer Settings. Asigura-te ca viteza este de 115200. Daca nu reusesti, ne poti contacta la adresa de email contact [at] robofun [dot] ro si te vom ajuta cu placere sa rezolvi problema.

D. teste miscare din Repetier

Deschide tab-ul “Manual Control” (dreapta sus). Aceasta sectiune iti permite sa iti controlezi imprimanta manual, pentru teste.

Apasa “HOME X”. Ar trebui sa vezi ca axa X (hotend-ul) se misca. Apasa butonul “HOME Y”. Ar trebui sa vezi ca axa Y (bed-ul) se misca.

Daca nu se intampla asta, verifica daca imprimanta este in priza, si daca in priza chiar ai curent 🙂

 

 

E. teste incalzire din Repetier

In zona inferioara a tab-ul “Manual Control” vezi temperaturile curente ale bed-ului si ale extruderului. Ar trebui sa vezi temperatura ambianta in acest moment. Apasa pe icon-ul “INCALZIRE BED”, apoi apasa pe icon-ul “INCALZIRE HOTEND”, astfel incat sa nu mai fie taiate cu linie rosie. Vei observa ca si bed-ul si hotend-ul incep sa se incalzeasca.

 

F. test extrudare din Repetier

Dupa ce hotend-ul a atins 200 de grade (verifici temperatura afisata), apasa butonul “AVANS FILAMENT”. In functie de unde anume apesi, vei scoate 10 mm, 50 de mm sau 100 de mm de filament. Recomand sa apesi astfel incat sa scoti 50 de mm de filament. Motorul montat in partea de sus, cel care actioneaza extruder-ul va incepe sa se miste si vei observa cum filamentul iese prin hotend (este “extrudat”).

Miscarea filamentului trebuie sa fie continua, si la fel si curgerea filamentului topit prin hotend.

 

4. Calibrare pe axa Z

Este foarte important ca distanta dintre bed si hotend sa fie exact cat trebuie atunci cand incepe procesul de printare. Daca este prea mare, filamentul nu va adera la bed. Daca este prea mica, filamentul nu va avea loc sa iasa din cauza bed-ul. Acest lucru se regleaza din elementul din stanga.

Rolul lui este de a lovi in butonul mic, de culoare rosie, si de a semnaliza astfel pozitia de zero pe axa verticala. Este prins pe surub, astfel incat daca il rotesti spre dreapta, surubul se insurubeaza in prindere, iar elementul de reglaj se misca in sus. Daca il rotesti spre stanga, surubul se desurubeaza, iar elementul de reglaj de misca in jos. Atunci cand se misca in sus, el va lovi mai tarziu butonul, astfel incat distanta de start va fi mai mica. Cand se misca in jos, va lovi mai devreme butonul, deci distanta de start va fi mai mare.

Misca cu mana hotend-ul si bed-ul astfel incat hotend-ul sa se afle relativ in centrul bed-ul. Pune o coala de hartie obisnuita pe bed si apasa butonul “HOME Z”. Vei vedea ca hotend-ul incepe sa coboare. In momentul in care elementul de reglaj din poza de mai sus atinge butonul, hotend-ul se va opri. Foaia de hartie este prinsa intre hotend si bed in acest moment. Incearca sa o misti. Ar trebui sa o poti misca, dar cu un pic de rezistenta.

Daca este foarte bine fixata si nu o poti misca, inseamna ca distanta este prea mica. Apasa pe butonul “Z UP” ca sa misti axa Z in sus cu 10 mm, apoi roteste elementul de reglaj spre stanga, ca sa il deplasezi in jos (astfel incat sa loveasca mai devreme butonul) si apasa iar pe butonul “HOME Z”.

Daca foaia de hartie se misca liber, inseamna ca distanta este prea mare. Apasa pe butonul “Z UP” ca sa misti axa Z in sus cu 10 mm, apoi roteste elementul de reglaj spre dreapta, ca sa il deplasezi in sus (astfel incat sa loveasca mai tarziu butonul), si apasa iar pe butonul “HOME Z”.

Repeta pasii pana cand foaia de hartie se misca, dar cu un pic de rezistenta.

 

 

5. Calibrarea orizontalitatii bed-ului

Misca cu mana bed-ul si hotend-ul astfel incat sa duci hotend-ul in fiecare dintre cele patru colturi ale bed-ului, si repeta teste cu foaia de hartie de mai sus pentru fiecare colt. Ca diferenta, distanta o reglezi de data aceasta NU din elementul mobil folosit la pasul 4, ci direct din piulita de prindere a bed-ului din acel colt.

Bed-ul este prin pe arcuri, asa ca prin rasucirea piulitei de prindere poti ridica si cobori fiecare colt. Continua pana cand poti misca foaia de hartie relativ liber in fiecare colt.

 

6. Primul print

Descarca obiectul STL de aici – https://www.robofun.ro/docs/x-carriage.stl

Deschide Cura (instalat la unul dintre pasii anteriori)

Din meniul “File”, alege “Open File”. Selecteaza fisierul STL descarcat.

Apasa butonul “Save to File” (dreapta jos). Salveaza fisierul gcode unde vrei tu.

Deschide Repetier. Incarca fisierul gcode (butonul “Load”). Atentie mare la acest pas, incarca fisierul cu extensia .gcode si NU cel cu extensia .STL !

Apasa butonul “Start Print”.

Dupa ce hotend-ul se incalzeste la 210 grade, imprimanta va incepe sa printeze.

 

 

 

SCHIMBARE FILAMENT

Dupa primul print, urmeaza al doilea, apoi al treilea, si la un moment dat se termina filamentul. Operatiunea de schimbare este relativ simpla, cat timp urmezi exact pasii de mai jos.

  1. incalzesti hotendul la 210 grade (si astepti sa ajunga la temperatura asta).
  2. extrudezi circa 5-10 cm de filament (rotesti roata extruder-ului – manual sau din Repetier in sensul in care filamentul iese topit prin hotend). Acest pas este extrem de important. Dupa printul anterior, filamentul lichid s-a solidificat in hotend, in forma hotend-ului. Daca nu faci acest pas, atunci cand vei incerca sa il scoti, se va rupe. Scotandu-l prin hotend in forma lichida, te asiguri ca filamentul care a fost topit la pasul anterior si apoi solidificat este complet eliminat sub forma lichida.
  3. scoti complet filamentul din imprimanta (rotesti roata extruder-ului – manual sau din Repetier in sensul in care filamentul iese din imprimanta)
  4. indrepti noul filamentul la capat
  5. introduci noul filament si il cobori prin tubul de teflon pana la hotend, invartind roata extruderului.

Inainte sa apuci de treaba, urmareste neaparat si filmele de mai jos (cu sunet !)

 

 

 

 

 

 

Troubleshooting

1. PROBLEMA :

Obiectul nu se lipeste pe bed, sau se lipeste la inceput, dar in timpul printarii se dezlipeste

REZOLVARE:

Cel mai probabil distanta de start pe Z nu este cea corecta. Vezi mai sus sectiunea “4. Calibrare pe axa Z”. Daca este OK distanta, este posibil ca adezivul depus pe bed sa se fi uscat prea tare. Poti depune un nou strat de adeziv pe bed (vezi link ca sa intelegi despre ce adeziv vorbesc) . Poti deasemenea spala sticla (dupa ce o scoti din cele patru clame), o usuci, si abia apoi aplici adezivul.

2. PROBLEMA :

Avand hotend-ul incalzit la mai mult de 200 de grade, filamentul refuza sa curga.

REZOLVARE:

Cel mai probabil nu ai calibrat corect distanta de start pe axa Z, si curgerea filamentului a fost blocata de sticla de pe bed, datorita distantei extrem de mici intre hotend si bed (vezi filmele de la “4. Calibrare pe axa Z”).

Filamentul a fost fortat mai mult timp de catre surubul de transport, curgerea normala a fost blocata, si astfel filamentul a fost tocat de catre surub. Va trebui sa incerci sa il scoti si sa il pui din nou. Vezi filmul de mai jos.

 

 

 

New Year Countdown

Un element important al oricărui revelion este, bineînțeles, numărătoarea inversă până la trecerea în noul an – cronometrul care ne arată cât timp mai este până la deschiderea sticlei de șampanie și până la pornirea focurilor de artificii. În cadrul proiectului de față ne propunem să implementăm un sistem care să ne arate cu precizie cât timp mai este până la un anume moment de timp, poate să fie trecerea în noul an, o aniversare sau orice alt moment important.

Pentru a putea calcula cu exactitate timpul rămas trebuie să știm în primul rând data și ora la momentul actual. Pentru acest lucru vom utiliza o placă cu conectivitate WiFi ce ne va permite sincronizare de timp NTP și anume placa de dezvoltare Adafruit Feather M0 WiFi. Această placă este similară cu placa Arduino MKR1000, montajul propus poate fi realizat cu oricare dintre ele. Pe lângă conectivitatea WiFi, ambele plăci de dezvoltare permit alimentarea de la un acumulator LiPo de 3.7V permițând astfel realizarea simplă a unui montaj portabil. Pentru afișare vom utiliza un modul cu afișaj pe 7 segmente cu 4 caractere și circuit de comandă TM1637. Schema de interconectare dintre placa de dezvoltare și modulul de afișare este:

2

Modulul de afișare se va alimenta la 3.3V (pinul VCC se va conecta la pinul de 3V al plăcii de dezvoltare iar pinul GND la pinul de GND). Pinul CLK se va conecta la pinul 5 al plăcii de dezvoltare și pinul DIO la pinul 6. Comunicația între placa de dezvoltare și modulul de afișare se face serial.

Programul a fost dezvoltat și testat utilizând Arduino IDE 1.8.5 având instalate bibliotecile TM1637Display, Time 1.5.0, WiFi101 0.14.5 și extensia Adafruit SAMD Boards 1.0.21.

#include <TM1637Display.h>

#define CLK 5

#define DIO 6

TM1637Display display(CLK, DIO);

#include <SPI.h>

#include <WiFi101.h>

#include <WiFiUdp.h>

În cadrul programului trebuie personalizate informațiile de conectare WiFi (ssid[] și pass[]). Constanta timeZone conține decalajul de fus orar specific zonei grografice în care ne aflăm (2 pentru ora de iarnă în România).

int status = WL_IDLE_STATUS;

char ssid[] = “…”;       

char pass[] = “…”;   

unsigned int localPort = 2390;

IPAddress timeServer(129, 6, 15, 28);

const int NTP_PACKET_SIZE = 48;

byte packetBuffer[ NTP_PACKET_SIZE];

WiFiUDP Udp;

#include <TimeLib.h>

const int timeZone = 2;

tmElements_t TheDay;

Structurile SEG_DONE și dy conțin configurația de segmente pentru mesajul done și pentru literele d și Y. Mesajul done va fi afișat după ce numărătoare inversă se va încheia. Litele d și Y vor fi utilizate când se vor afișa anii și zilele rămase pâna la evenimentul programat.

const uint8_t SEG_DONE[] = {

  SEG_B | SEG_C | SEG_D | SEG_E | SEG_G,           // d

  SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F,   // O

  SEG_C | SEG_E | SEG_G,                           // n

  SEG_A | SEG_D | SEG_E | SEG_F | SEG_G            // E

  };

const uint8_t dy[] = {

  SEG_B | SEG_C | SEG_D | SEG_E | SEG_G,           // d

  SEG_B | SEG_E | SEG_F | SEG_G ,                  // Y

  };

În cadrul secțiunii setup se realizează conectarea la rețeaua WiFi și programarea evenimentului dorit (în exemplul nostru 1 ianuarie 2018 ora 0:00, anul este înregistrat ca diferență față de anul 1970). Instrucțiunea WiFi.setPins este necesară pentru placa Adafruit Feather M0, se va șterge în cazul plăcii Arduino MKR1000.

void setup() {

  WiFi.setPins(8,7,4,2);

  if (WiFi.status() == WL_NO_SHIELD) {

    while (true);

  }

  while ( status != WL_CONNECTED) {

    status = WiFi.begin(ssid, pass);

    delay(10000);

  }

  Udp.begin(localPort);

  setSyncProvider(getNtpTime);

  setSyncInterval(3600);

  TheDay.Second = 0;

  TheDay.Minute = 0;

  TheDay.Hour = 0;

  TheDay.Day = 1;

  TheDay.Month = 1;

  TheDay.Year = 48;

  }

Secțiunea loop implementează partea de verificare a diferenței de timp între momentul actual și data evenimentului (diferența se calculează în secunde și este stocată în variabila dif) și partea de afișare. Dacă diferența este negativă înseamnă că evenimentul a trecut și se afișează done. Dacă diferența este mai mare de 31556926 secunde (adică un an) pe ecran se va afișa diferența în ani întregi, pe trei caractere urmate de litera Y. Dacă diferența este mai mare de 86400 secunde (adică o zi) pe ecran se va afișa diferența în zile, pe trei caractere urmate de litera d. Dacă diferența este mai mică de o zi dar mai mare de o oră (3600 secunde) pe ecran se va afiș diferența în ore:min. În final, când avem un interval mai mic de o oră, pe ecran se va afișa diferența în format min:sec.

void loop() {

  time_t dif;

  dif = makeTime(TheDay) – now();

  display.setBrightness(0x0f);

  if (dif < 0) display.setSegments(SEG_DONE);

  else if (dif>31556926L) {

    display.showNumberDec(((1970+TheDay.Year) –

(year()+1)),true,3,0);

display.setSegments(dy+1, 1, 3); }

  else if (dif>86400L) {

display.showNumberDec((dif/86400L),true,3,0); display.setSegments(dy, 1, 3); }

  else if (dif>3600) {

display.showNumberDecEx((dif/3600L),0xFF,true,2,0); display.showNumberDec(((dif%3600L)/60),true,2,2); }

  else {

display.showNumberDecEx((dif/60),0xFF,true,2,0); display.showNumberDec((dif%60L),true,2,2); }

  delay(1000);

}

Funcții getNtpTime și sendNTPpacket sunt utilizate de biblioteca Time pentru sincronizarea de timp.

time_t getNtpTime() {

   sendNTPpacket(timeServer);

  delay(1000);

  if ( Udp.parsePacket() ) {

    Udp.read(packetBuffer, NTP_PACKET_SIZE);

    unsigned long highWord = word(packetBuffer[40],

packetBuffer[41]);

    unsigned long lowWord = word(packetBuffer[42],

packetBuffer[43]);

    unsigned long secsSince1900 = highWord << 16 | lowWord;

    const unsigned long seventyYears = 2208988800UL;

    unsigned long epoch = secsSince1900 – seventyYears;

    return (time_t) (secsSince1900 – 2208988800UL +

timeZone * SECS_PER_HOUR);

  }

  else return 0;

}

unsigned long 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();

}

Dacă se dorește implementarea unui afișaj pe 7 segmente utilizând o componentă proprie (un afișaj de mari dimensiuni de exemplu) se poate utiliza un circuit de tip shift register cu o schemă de interconectare de genul:

3

Pentru circuitul 74HC595 se poate avea în vedere utilizarea bibliotecii SparkFun 74HC595 Arduino Library pentru implementarea comenzii către caracterele pe 7 segmente.