Arduino

De Jose Castillo Aliaga
Ir a la navegación Ir a la búsqueda

Arduino és una placa de circuit imprès simple basada en microcontrolador de codi obert provinent de la plataforma de codi obert Wiring amb l'objectiu de fer més simple i accessible el disseny de circuits electrònics amb microcontroladors.

El maquinari consisteix en dissenys simples de maquinari lliure amb processadors Atmel AVR en una placa amb pins E/S. L'entorn de desenvolupament implementa el llenguatge Processing de Wiring, molt semblant a C++. Arduino es pot utilitzar per desenvolupar objectes interactius autònoms o pot ser connectat a programari de l'ordinador (p. ex. Macromedia Flash, Processing, Max/MSP, Pure Data). Les plaques es poden muntar a mà o adquirir-se i els IDE de font oberta es poden descarregar de franc.

Arquitectura

Els microcontroladors com els que impulsen els Arduinos estan dissenyats per a aplicacions embegudes. A diferència de les computadores de propòsit general, un processador encastat normalment té una tasca ben definida que ha de realitzar de manera fiable i eficaç (i a un cost mínim). El disseny de microcontroladors tendeix a ser bastant espartà. Es renuncia als luxes d'emmagatzematge en memòria cau de diverses capes i dels sistemes de memòria virtual basats en disc, per exemple.

El model de Harvard resulta ser una bona elecció per a aplicacions embegudes i el Atmega 328 empleats en l' Arduino UNO utilitza una arquitectura Harvard relativament pura. Els programes s'emmagatzemen a la memòria Flash i les dades s'emmagatzemen a la memòria SRAM.

La major diferència entre aquests microcontroladors i el seu ordinador de propòsit general és la gran quantitat de memòria disponible . L'Arduino UNO té només 32K bytes de memòria Flash i 2K bytes de SRAM. Això és més de 100 mil vegades menys memòria física que un PC de gamma baixa. I això sense comptar el disc!

El treball en aquest ambient minimalista, ha d'utilitzar els seus recursos de manera intel ligent.

Memòria

Free Memory.png

Dins d'Arduino trobem 3 tipus de memòria:

  • Flash
  • SRAM
  • EEPROM

La memòria flash s'utilitza per emmagatzemar la imatge del programa i les dades inicialitzats. Podeu executar el codi del programa de flash, però no pot modificar les dades en la memòria flash del seu codi d'execució. Per modificar les dades, primer s'han de copiar en la SRAM

La memòria flash és la mateixa tecnologia utilitzada per al pendrives i targetes SD. És no volàtil, pel que el seu programa encara hi serà quan el sistema estiga apagat.

La memòria flash té una vida finita de prop de 100.000 cicles d'escriptura. Així que si carregues 10 programes per dia, tots els dies durant els propers 27 anys, és possible trencar-la. No obstant, si es puguera escriure durant l'execució, pot ser aquests cicles serien insuficients.

SRAM o memòria estàtica d'accés aleatori, es pot llegir i escriure des del programa en execució. La memòria SRAM s'utilitza per a diversos fins per un programa en execució:

  • Dades estàtics - Es tracta d'un bloc d'espai reservat en SRAM per a totes les variables globals i estàtiques del seu programa. Per a les variables amb els valors inicials, el sistema d'execució copia el valor inicial del flash quan s'inicia el programa.
  • Heap - El Heap és per als elements de dades assignats dinàmicament. La pila creix a partir de la part superior de l'àrea de dades estàtica.
  • Stack - La pila és per a les variables locals i ha de mantenir un registre de les interrupcions i trucades a funcions. La pila creix des de la part superior de la memòria cap avall, cap al heap. Cada interrupció, crida a la funció i/o assignació de variable local, fa que la pila creixi.

Quant l'Stack i el Heap col·lisionen pot sorgir un problema greu.

EEPROM és una altra forma de memòria no volàtil que pot ser llegit o escrit del seu programa d'execució. Només es pot llegir byte a byte, pel que pot ser una mica difícil d'usar. També és més lenta que la SRAM i té una vida finita de prop de 100.000 cicles d'escriptura (es pot llegir tantes vegades com vulgui).

Si bé no pot prendre el lloc de SRAM, hi ha moments en que pot ser molt útil.

L'arduino UNO, per exemple, té 32K de SRAM, 2K de SRAM i 1KB de EEPROM.

Mesurar la memòria lliure

La memòria lliure flash és fàcil, el propi compilador ens diu la que ocupa el programa.

Per un altra banda, saber la EEPROM que tenim lliure és tasca i responsabilitat del programador, ja que pot tenir control total sobre ella. Miren les funcions per a escriure o llegir de la memòria EEPROM:

// ************************************************
// Write floating point values to EEPROM
// ************************************************
void EEPROM_writeDouble(int address, double value)
{
   byte* p = (byte*)(void*)&value;
   for (int i = 0; i < sizeof(value); i++)
   {
      EEPROM.write(address++, *p++);
   }
}

// ************************************************
// Read floating point values from EEPROM
// ************************************************
double EEPROM_readDouble(int address)
{
   double value = 0.0;
   byte* p = (byte*)(void*)&value;
   for (int i = 0; i < sizeof(value); i++)
   {
      *p++ = EEPROM.read(address++);
   }
   return value;
}


Saber la memòria SRAM utilitzada és més complicat perquè és dinàmica. Es pot calcular la distància del Stack i el Heap amb aquesta funció:

int freeRam () 
{
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

No obstant, el Heap pot estar fragmentat i aquesta mesura no és fiable.

Coses que consumeixen Molta SRAM:

Targetes SD Encara que les targetes són memòria, els seus buffers ocupen sobre 512Bytes
Pixels de colors Si volem emmagatzemar el color, necessitem 3bytes per pixel (Un arduino UNO pot suportar sobre 500pixels si el programa és curt)
Displays RBG La mateixa raó que els píxels. Per exemple: la resolució 32x32 necessita 1600bytes.
Displays Monocroms Sols necessita 1bit. Per tant, pot tindre molta més resolució. El de 128x64 ocupa 512 bytes.

Optimitzar l'ús de Memòria

Per optimitzar la memòria Flash, es pot:

  • Esborrar codi no útil com: Biblioteques que no s'utilitzen, Funcions que no serveixen per a res, variables o codi que mai es pot executar.
  • Consolidar codi repetit en funcions.

Per optimitzar la memòria SRAM:

  • Esborrar variables no utilitzades.
  • Evitar les Strings o fer-les més curtes. Cada lletra ocupa 1Byte, i sols tenim 1024!. Existeix una funció F() que manté les strings en memòria Flash.
 Serial.println("Sram sram sram sram. Lovely sram! Wonderful sram! Sram sra-a-a-a-a-am sram sra-a-a-a-a-am sram. 
 Lovely sram! Lovely sram! Lovely sram! Lovely sram! Lovely sram! Sram sram sram sram!");
 Serial.println(F("Sram sram sram sram. Lovely sram! Wonderful sram! Sram sra-a-a-a-a-am sram sra-a-a-a-a-am sram. 
 Lovely sram! Lovely sram! Lovely sram! Lovely sram! Lovely sram! Sram sram sram sram!"));

La segona opció ocupa 180 bytes menys.

  • Guardar les dades estàtiques en PROGMEM
  • Reduir la mida de les variables. De veritat necessites un int per a guardar un valor de 0 a 255? Pots utilitzar un byte.

PWM

Modulació de Ample de Pols (PWM) és una tècnica per controlar la potència. També l'utilitzem per controlar la brillantor de cadascun dels LEDs.

Aproximadament cada 1/500 d'un segon, la sortida PWM produirà un pols. La longitud d'aquest pols és controlada per la funció de 'analogWrite'. Així 'analogWrite(0)' no produirà cap pols en absolut i 'analogWrite (255)' va a produir un pols que dura tot el cicle fins al següent impuls, de manera que la sortida és en realitat tot el temps.

Si s'especifica un valor en el analogWrite que està entre 0 i 255 i després anem a produir un pols. Si el pols de sortida és només d'alta el 5% del temps, llavors només rebrà el 5% de la potència màxima.No podem veure el LED encès i apagat a aquesta velocitat, per a nosaltres només es veu com la brillantor està canviant .

Projectes

Aquest són el projectes més "acadèmics". Podeu vorer altres projectes en l'article: Trastejant amb arduino

Kit de 10 segments LED

Anem a jugar i fer algunes combinacions en una tira de 10 LEDS. En realitat es pot fer en 10 leds normals, però queda més vistós.

Aquest és l'esquema:

Leds10 bb.png

Podem carregar aquest programa:

// LED bargraph demo code
// ...in which we provide a few functions to drive a 10-segment LED bargraph
// Mike Grusin, SparkFun Electronics
// This code is completely free to use for your purposes

// Hardware setup
// connect Arduino digital pins 0-9 to LED bargraph pins 1-10
// connect LED pins 11-20 via 330-Ohm resistors to ground

void setup() 
{
  int pin;
  
  // set pins 0 to 9 as outputs
  for (pin = 0; pin <= 9; pin++)
  {
    pinMode(pin,OUTPUT);
  }
}

void loop()
{
  int number;
  
// exercise lightOne() up and down

  for (number = 1; number <= 10; number++)
  {
    lightOne(number);
    delay(250);
  }
  
  for (number = 10; number >= 1; number--)
  {
    lightOne(number);
    delay(250);
  }

// exercise barGraph() up and down

  for (number = 1; number <= 10; number++)
  {
    barGraph(number);
    delay(250);
  }
  
  for (number = 10; number >= 1; number--)
  {
    barGraph(number);
    delay(250);
  }

// exercise binary() up and down

  for (number = 0; number <= 1023; number++)
  {
    binary(number);
    delay(10);
  }
  
  for (number = 1023; number >= 0; number--)
  {
    binary(number);
    delay(10);
  }
}

void lightOne(int number)
// input is a number from 0 to 10
// lights only that LED on the bargraph
// (0 lights no LEDs)
{
  int pin;

  for (pin = 0; pin <= 9; pin++)
  {
    if (number-1 == pin)
    {
      digitalWrite(pin,HIGH);
    }
    else
    {
      digitalWrite(pin,LOW);
    }
  }
}

void barGraph(int number)
// input is a number from 0 to 10
// lights that LED and below on the bargraph
// (0 lights no LEDs)
{
  int pin;

  for (pin = 0; pin <= 9; pin++)
  {
    if (number-1 >= pin)
    {
      digitalWrite(pin,HIGH);
    }
    else
    {
      digitalWrite(pin,LOW);
    }
  }
}

void binary(int number)
// input is a number from 0 to 1023 (10 bits)
// if a bit is '1' in that number, the corresponding LED is lit, otherwise it is off
{
  int pin;

  for (pin = 0; pin <= 9; pin++)
  {
    if (number & (1 << pin)) // check if bit position 'pin' in 'number' is a 1 or not
    {
      digitalWrite(pin,HIGH); // it's a 1!
    }
    else
    {
      digitalWrite(pin,LOW); // it's a 0!
    }
  }
}

Font: https://www.sparkfun.com/tutorials/284

Fotos: [1] [2]

Comptador

Per a fer aquest comptador utlitzem un Display BCD i un xip cd4511be

Si tenim en compte que el xip decodificador té aquestes entrades:

Cd4511 pin.jpg

i el display aquestes:

Displaybcd.png

Les connexions quedaran:

Arduino cd4511be
2 A
3 B
4 C
5 D
5v Vdd, LT, BL
GND VSS, LE

Les connexions del xip 4511 aniràn a les lletres segons l'esquema.

Contador.png

Primera versió del programa:

void setup()
{
 
  for (int i=2;i<6;i++){ 
  pinMode(i,OUTPUT);
  }
  
}
void loop()
{
  digitalWrite(2,0);
  digitalWrite(3,0);
  digitalWrite(4,0);
  digitalWrite(5,0);
  delay(1000);
  
  digitalWrite(2,1);
  digitalWrite(3,0);
  digitalWrite(4,0);
  digitalWrite(5,0);
  delay(1000);
  
  digitalWrite(2,0);
  digitalWrite(3,1);
  digitalWrite(4,0);
  digitalWrite(5,0);
  delay(1000);
  
  digitalWrite(2,1);
  digitalWrite(3,1);
  digitalWrite(4,0);
  digitalWrite(5,0);
  delay(1000);
  
  digitalWrite(2,0);
  digitalWrite(3,0);
  digitalWrite(4,1);
  digitalWrite(5,0);
  delay(1000);
  
  digitalWrite(2,1);
  digitalWrite(3,0);
  digitalWrite(4,1);
  digitalWrite(5,0);
  delay(1000);
 
  digitalWrite(2,0);
  digitalWrite(3,1);
  digitalWrite(4,1);
  digitalWrite(5,0);
  delay(1000);
  
  digitalWrite(2,1);
  digitalWrite(3,1);
  digitalWrite(4,1);
  digitalWrite(5,0);
  delay(1000);
  
  
  digitalWrite(2,0);
  digitalWrite(3,0);
  digitalWrite(4,0);
  digitalWrite(5,1);
  delay(1000);
  
  
  digitalWrite(2,1);
  digitalWrite(3,0);
  digitalWrite(4,0);
  digitalWrite(5,1);
  delay(1000);
}

Solució amb un for:

int n=0;

byte BCD[16][4]={{0,0,0,0},{1,0,0,0},{0,1,0,0},{1,1,0,0},
{0,0,1,0},{1,0,1,0},{0,1,1,0},{1,1,1,0},{0,0,0,1},{1,0,0,1},
{0,1,0,1},{1,1,0,1},{0,0,1,1},{1,0,1,1},{0,1,1,1},{1,1,1,1}};

void setup()
{
  for (int i=2;i<6;i++){ 
  pinMode(i,OUTPUT); 
  }
}

void loop()
{
  for (int i=0;i<4;i++){
  digitalWrite(i+2,BCD[n][i]);
  }
  delay(100);
 
 if (n!=9) n++; else n=0;
 
}

Fotos: [3] [4] [5]

LCD Nokia 5110

Per a fer aquest projecte he utilitzat la biblioteca que han fet per a aquest post: http://electronicavm.wordpress.com/2012/02/13/nokia-lcd-3310-arduino/

No obstant, en el meu LCD hi ha alguns canvis. La placa que el suporta pareix no ser la mateixa que la de l'article. La localització del pins no és la mateixa. No obstant, una vegada averiguat el canvi, el funcionament és perfecte.

Per a fer aquest projecte, necessitem un LCD per a nokia 3110/5110. (Datasheet: https://www.sparkfun.com/datasheets/LCD/Monochrome/Nokia5110.pdf )

Aquest és el meu esquema (Recorda que pot no ser igual en la teua placa)

Nokia1.png

Observa que la meua llum, (7) Té entrada de GND, no de 3V.

Aquest és el codi de l'exemple:

#include <NokiaLCD.h>
 
NokiaLCD NokiaLCD(3,4,5,6,7); // (SCK, MOSI, DC, RST, CS)
 
void setup() {
NokiaLCD.init(); // Init screen.
 NokiaLCD.clear(); // Clear screen.
}
 
void loop() {
 NokiaLCD.setCursor(1,1);
 NokiaLCD.print("Hello World!");
}

El controlador del LCD conté:

  • Una DDRAM de 48x84 bits (com que és blanc i negre, sols necessita un bit per pixel)
  • Un oscilador, per tant no necessita un rellotge extern.
  • Un pin de Reset extern. (RES)
  • Una interficie en serie de màxim 4Mbits/s (SDIN)
  • Una entrada de rellotge de sincronització serial (SCLK)
  • D/C, entrada de comandament de dades. Permet enviar comandaments o dades.
  • SCE, Chip Enable, permet activar l'entrada de dades.
  • El SCE i el RES tenen una senyal active-LOW, vol dir que la senyal es dona quant canvia d'estat HIGH a LOW

Les dades es carreguen en bytes en els 48 per 84 bits de la RAM de visualització de dades. Les columnes són abordades per la direcció de punter. Els rangs d'adreces són: X 0-83 (1010011), i 0 a 5 (101). Les adreces fora aquests rangs no estan permeses. Pot tindre un adreçament vertical o horitzontal.

Adresamentvertical.png Adreçament vertical V=1

Adresamenthoritzontal.png Adreçament horitzontal V=0

Les instruccions que accepta tenen dos modes: Si D/C está en LOW s'entén que és un byte de comandament. Si D/C està en HIGH, els bytes es guarden en memòria RAM.

La biblioteca està basada en aquest article: www.arduino.cc/playground/Code/PCD8544 Anem a analitzar el codi:

// Definició dels pins d'arduino que es corresponen amb les entrades del LCD
#define PIN_SCE   7 // Entrada SCE, activa l'entrada de dades
#define PIN_RESET 6 // RESET
#define PIN_DC    5 // Perment canviar de comandes a dades.
#define PIN_SDIN  4 // Eixida serial
#define PIN_SCLK  3 // Eixida del rellotge del serial.

#define LCD_C     LOW // Aquestes constants permeten fer que el PIN_DC estiga en High i Low.
#define LCD_D     HIGH  // C per a comandaments i D per a dades.

#define LCD_X     84 // Columnes
#define LCD_Y     48 // Files


static const byte ASCII[][5] =
{
 {0x00, 0x00, 0x00, 0x00, 0x00} // 20  
,{0x00, 0x00, 0x5f, 0x00, 0x00} // 21 !
,{0x00, 0x07, 0x00, 0x07, 0x00} // 22 "
,{0x14, 0x7f, 0x14, 0x7f, 0x14} // 23 #
,{0x24, 0x2a, 0x7f, 0x2a, 0x12} // 24 $
,{0x23, 0x13, 0x08, 0x64, 0x62} // 25 %
,{0x36, 0x49, 0x55, 0x22, 0x50} // 26 &
...

Acó simplement és una matriu de les lletres ASCII en la que es guarda separat per Bytes la representació gràfica de la lletra. Per exemple:

,{0x7e, 0x11, 0x11, 0x11, 0x7e} // 41 A 

La lletra A és 01111110, 00010001, 00010001, 00010001, 00010001, 01111110. Si coloquem aquest bytes en vertical, un al costat d'altre:

0 1 1 1 0
1 0 0 0 1
1 0 0 0 1
1 0 0 0 1
1 1 1 1 1
1 0 0 0 1
1 0 0 0 1
0 0 0 0 0

Anem a analitzar les funcions en un ordre distint al que estan escrites per entendre millor el funcionament. La primera és:

void LcdWrite(byte dc, byte data)
{
  digitalWrite(PIN_DC, dc);
  digitalWrite(PIN_SCE, LOW);
  shiftOut(PIN_SDIN, PIN_SCLK, MSBFIRST, data);
  digitalWrite(PIN_SCE, HIGH);
}

Aquesta funció escriu en el LCD el que necessitem. El primer que rep és el bit dc per saber si són dades o comandaments. Escriu en el PIN_DC i fica el SCE a 0, indicant que ara comença a enviar dades.

shiftOut és una funció de arduino per a enviar dades en serie. Accepta el pin SDIN per a enviar, el rellotge i MSBFIRST (bit més significatiu primer)

Finalment, envia el sce a HIGH per a indicar que ha acabat d'enviar dades.

Analitzem la següent funció:

void LcdCharacter(char character)
{
  LcdWrite(LCD_D, 0x00);
  for (int index = 0; index < 5; index++)
  {
    LcdWrite(LCD_D, ASCII[character - 0x20][index]);
  }
  LcdWrite(LCD_D, 0x00);
}

El que fa es escriure un caracter al LCD. La primera ordre és escriure en el el LCD 0x00, després els 5 bytes de la lletra i, finalment 0x00

La funció clear:

void LcdClear(void)
{
  for (int index = 0; index < LCD_X * LCD_Y / 8; index++)
  {
    LcdWrite(LCD_D, 0x00);
  }
}

Escriu en tots els bytes de la memòria de vídeo del LCD 0x00

La funció per inicialitzar:

void LcdInitialise(void)
{
  pinMode(PIN_SCE, OUTPUT); 
  pinMode(PIN_RESET, OUTPUT);
  pinMode(PIN_DC, OUTPUT);
  pinMode(PIN_SDIN, OUTPUT);
  pinMode(PIN_SCLK, OUTPUT);
  digitalWrite(PIN_RESET, LOW);
  digitalWrite(PIN_RESET, HIGH);
  LcdWrite(LCD_C, 0x21 );  // LCD Extended Commands.
  LcdWrite(LCD_C, 0xB1 );  // Set LCD Vop (Contrast). 
  LcdWrite(LCD_C, 0x04 );  // Set Temp coefficent. //0x04
  LcdWrite(LCD_C, 0x14 );  // LCD bias mode 1:48. //0x13
  LcdWrite(LCD_C, 0x0C );  // LCD in normal mode.
  LcdWrite(LCD_C, 0x20 );  //LCD basic commands
  LcdWrite(LCD_C, 0x0C );
}

Primer de tot, estableix per a qué serveix cada pin. Després força a que el pin de RESET tinga un pas de LOW a HIGH per a que el LCD es reinicie. Gràcies a la funció d'escriptura, escriu ordres per a configurar el LCD

Fotos: [6] [7]

Sensor de temperatura

Per a aquest projecte tinc un sensor DS18B20 protegit per a l'aigua.

Aquest sensor té 3 cables.

  • El Verd és per als 5V, que necessita una resistència de 4k7 ohm en mig. També es connecta dirèctament al pin 2 de la placa arduino.
  • El roig i el groc els connectem junts i els dos al GND.

Temperatura1 bb.png

Per a fer fucionar aquest sensor necessitem la blblioteca Dallas temperature control i OneWire

Una vegada descarregada e instal·lada la biblioteca, fem aquest codi:

#include <OneWire.h>
#include <DallasTemperature.h>

// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 2

// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature. 
DallasTemperature sensors(&oneWire);

void setup(void)
{
  // start serial port
  Serial.begin(9600);
  Serial.println("Dallas Temperature IC Control Library Demo");

  // Start up the library
  sensors.begin();
}

void loop(void)
{ 
  // call sensors.requestTemperatures() to issue a global temperature 
  // request to all devices on the bus
  Serial.print("Requesting temperatures...");
  sensors.requestTemperatures(); // Send the command to get temperatures
  Serial.println("DONE");
  
  Serial.print("Temperature for the device 1 (index 0) is: ");
  Serial.println(sensors.getTempCByIndex(0));  
  delay(1000);
}

Enllaços



Construcció Robots: https://www.futurice.com/blog/prototyping-with-pela-blocks/ https://pelablocks.org/