Arduino

De Wikijoan
Dreceres ràpides: navegació, cerca

Contingut

Què és Arduino?

ArduinoMega.jpg

Arduino: the documetary: (castellà)

Informació sobre el Arduino Mega (aquest és un dels molts tipus d'Arduino que hi ha. No és el estàndar: és més potent):

The Arduino Mega is a microcontroller board based on the ATmega1280. It has 54 digital input/output pins (of which 14 can be used as PWM outputs), 16 analog inputs, 4 UARTs (hardware serial ports), a 16 MHz crystal oscillator, a USB connection, a power jack, an ICSP header, and a reset button. It contains everything needed to support the microcontroller; simply connect it to a computer with a USB cable or power it with a AC-to-DC adapter or battery to get started. The Mega is compatible with most shields designed for the Arduino Duemilanove or Diecimila.

L'Arduino Mega, que és el que jo finalment he comprat (set 2009) (jo he comprat un Roboduino de dfrobot.com), és, de fet, molt més potent que el Arduino estàndar (té més entrades, sortides, UART,...).

Mega - A larger, more powerful Arduino board, shield compatible with the Duemilanove and Diecmila.
This Roboduino Mega is a fully compatible Arduino Mega controller. There is no any difference between this board and official Arduino Mega.

Resum especificacions

Mirar l'enllaç per estudiar l'Arduino amb més detall.

Preus Arduino

Al final he comprat un Arduino Mega per 30€ a eBay, procedent del Regne Unit. Els distribuïdors d'Arduino a Espanya són:

arduino mega 49€ A larger, more powerful Arduino board, shield compatible with the Duemilanove and Diecmila. details

arduino nano 45€

Arduino Pro 328 - 5V/16MHz 17€

Ésta es la versión reducida de la placa Arduino ensamblada con componentes de superficie y quitando algunas partes para mejorar la robustez y la calidad del diseño final.

Arduino Mega 49€ Nuevo Arduino Mega con más memoria para el programa, más RAM y más pines. 100% compatible con la versión Duemilanove arduino nano 39,20€ arduino mini 29€

Arduino Mega 49€ (sense IVA) arduino mini 20€ (sense IVA) arduino nano 33€ (sense IVA)

Arduino Mega - 56.84 EUR IVA incl. Arduino Mini - 23.20 EUR IVA incl. Arduino Nano - 51.04 EUR IVA incl.

Compra Roboduino

jo al final he comprat en el eBay un roboduino per uns 30e, que és 100% compatible amb el Roboduino Mega (el layout és exactament el mateix). El fabrica www.dfrobot.com, i el venedor d'eBay és yerobot (Chen Ye).

Fòrum

Arduino Forum

Instal.lar Arduino a Ubuntu

mirar http://www.arduino.cc/playground/Linux/Ubuntu

prerrequisits:

i

$ sudo apt-get install gcc-avr
$ sudo apt-get install avr-libc

És important saber la versió:

$ avr-gcc -v
gcc version 4.3.2 (GCC)

aquesta versió o posteriors són les correctes

però compte!

You will also need a compatible kernel. For example, it needs USB serial support with the FTDI driver. If you have brltty installed (the default on recent versions of Ubuntu), you'll need to remove it.

Segueixo http://www.ladyada.net/learn/arduino/lesson0-lin.html

Sometimes the Linux distribution installs brltty (braille device) which will conflict with the Arduino. You must uninstall brltty! Do so by running

$ sudo apt-get remove brltty -> això ve del Braille

i mirar la resta de l'enllaç...

El driver FTDI el que fa és proporcionar un port COM virtual a través del USB (el software es comunica per aquest port COM).

Em descarrego arduino-0017.tgz També ens podem descarregar les fonts i compilar.

$ tar xvzf arduino-0017.tgz
$ cd arduino-0017
$ sudo ./arduino

i ja arrenca la interfície gràfica (basada en Java)

Nota important: arrencar ./arduino com a sudo per tal de què estigui disponible el port /dev/ttyUSB0

Ubuntu 10.04, Dell Studio 17, setembre 2010

Ho faig més fàcil, doncs existeix un paquet en un repositori privat (PPA)

$ sudo add-apt-repository ppa:arduino-ubuntu-team (és la manera manual d'afegir un repositori sense tocar el sources.list)
$ sudo apt-get update
$ sudo apt-get install arduino
$ arduino

ha quedat instal.lat a /usr/bin/arduino

Coses a mirar

Pachube is a web service available at http://www.pachube.com that enables you to store, share & discover realtime sensor, energy and environment data from objects, devices & buildings around the world. Pachube is a convenient, secure & scalable platform that helps you connect to & build the 'internet of things'.

Open Source Hardware

http://dam.mellis.org/ -> blog de'n David Mellis, un dels creadors d'Arduino

Primeres pràctiques

blink

Començo amb el primer exemple (blink), que tracta de fer pampalluguejar un led.

  1. Connecto l'Arduino al cable USB i s'encén el LED de power.
  2. Carrego el sketch (codi), i el grabo amb el nom de blink.
  3. El primer que s'ha de fer és dir quin és el port sèrie de comunicació amb l'ordinador. Marco Tools > Serial Port > /dev/ttyUSB0
  4. Faig un upload i falla, i és que he d'escollir el board correcte: Board > Arduino Mega
avrdude: Expected signature for ATMEGA328P is 1E 95 0F
         Double check chip, or use -F to override this check.

i ara ja tinc ben carregada l'aplicació.

Fico el LED (pota llarga en el pin 53 de la sortida digital i pota curta a GND), i el LED ja fa pampallugues.

 /*
   Blink
  
  Turns on an LED on for one second, then off for one second, repeatedly.
  
  The circuit:
  * LED connected from digital pin 13 to ground.
  
  * Note: On most Arduino boards, there is already an LED on the board
  connected to pin 13, so you don't need any extra components for this example.
  
  
  Created 1 June 2005
  By David Cuartielles
  
  http://arduino.cc/en/Tutorial/Blink
  
  based on an orginal by H. Barragan for the Wiring i/o board
  
  */

 int ledPin =  53;    // LED connected to digital pin 13

 // The setup() method runs once, when the sketch starts

 void setup()   {                
   // initialize the digital pin as an output:
   pinMode(ledPin, OUTPUT);     
 }

 // the loop() method runs over and over again,
 // as long as the Arduino has power

 void loop()                     
 {
   digitalWrite(ledPin, HIGH);   // set the LED on
   delay(1000);                  // wait for a second
   digitalWrite(ledPin, LOW);    // set the LED off
   delay(1000);                  // wait for a second
 }

blink sense delay

 /* Blink without Delay
  
  Turns on and off a light emitting diode(LED) connected to a digital  
  pin, without using the delay() function.  This means that other code
  can run at the same time without being interrupted by the LED code.
  
   The circuit:
  * LED attached from pin 13 to ground.
  * Note: on most Arduinos, there is already an LED on the board
  that's attached to pin 13, so no hardware is needed for this example.
  
  
  created 2005
  by David A. Mellis
  modified 17 Jun 2009
  by Tom Igoe
  
  http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay
  */

 // constants won't change. Used here to 
 // set pin numbers:
 const int ledPin =  13;      // the number of the LED pin

 // Variables will change:
 int ledState = LOW;             // ledState used to set the LED
 long previousMillis = 0;        // will store last time LED was updated

 // the follow variables is a long because the time, measured in miliseconds,
 // will quickly become a bigger number than can be stored in an int.
 long interval = 1000;           // interval at which to blink (milliseconds)

 void setup() {
   // set the digital pin as output:
   pinMode(ledPin, OUTPUT);      
 }

 void loop()
 {
   // here is where you'd put code that needs to be running all the time.

   // check to see if it's time to blink the LED; that is, is the difference
   // between the current time and last time we blinked the LED bigger than
   // the interval at which we want to blink the LED.
   if (millis() - previousMillis > interval) {
     // save the last time you blinked the LED 
     previousMillis = millis();   

     // if the LED is off turn it on and vice-versa:
     if (ledState == LOW)
       ledState = HIGH;
     else
       ledState = LOW;

     // set the LED with the ledState of the variable:
     digitalWrite(ledPin, ledState);
   }
 }

Utilització del terminal sèrie minicom

$ sudo apt-get install minicom

seria l'equivalent al hiperterminal en el món Linux.

Connecto el arduino:

$ dmesg | grep tty
[    0.004000] console [tty0] enabled
[ 2336.150704] usb 5-1: FTDI USB Serial Device converter now attached to ttyUSB0

veig que efectivament en connectar el Arduino al port USB es carrega el driver FTDI i reconeix el dispositiu com si fos un port sèrie: /dev/ttyUSB0

Ara anem a configurar minicom per tal que treballi per aquest port:

$ sudo minicom

per accedir a la configuració del port sèrie: Ctrl-A + F (surt el menú principal), i després la tecla O (configuració), i després configurem el port sèrie. La configuració correcta és els bauds amb què volem treballar (9600, 57600, 115200,...), 8N1, sense control de flux, i sobretot, configurar el port (/dev/ttyUSB0). Grabo la configuració amb el nom d'arduino:

       configuration
            The configuration argument is more interesting. Normally, minicom gets its defaults from a file called "minirc.dfl". If you however  give  an
            argument to minicom, it will try to get its defaults from a file called "minirc.configuration".  So it is possible to create multiple config‐
            uration files, for different ports, different users etc. Most sensible is to use device names, such as tty1, tty64, sio2 etc. If a user  cre‐
            ates his own configuration file, it will show up in his home directory as ’.minirc.dfl’.
You can use minicom to receive messages. Run minicom (you probably need to be root) and press Ctrl+A Z to display the available commands. Press 'o' for Options and choose 'Serial port setup' and make sure you've got the correct port selected (most likely /dev/ttyUSB0). Also make sure that the baud rate is set to 9600 (o el que sigui) 8N1 and that 'Hardware flow control' is set to 'no'. Once you are done with the settings use 'Save setup as dfl' and minicom will start up with the correct settings next time. Quit minicom and restart it to activate the new settings. You should now start receiving the 'Hello World!' messages. 

Arrenco amb aquesta nova configuració. Perquè no peti el arduino ha d'estar connectat, doncs el port es crea en el moment que el connectem:

$ sudo minicom arduino

I el més important: per tal que no em passi les pampallugues molestes de la pantalla que no em deixen veure els missatges, la finestra del terminal no ha d'estar maximitzada. De fet, això em passa perquè utilitzo una consola gràfica (xterm). (aquí m'hi he passat estona).

Ho he probat amb l'exemple blink2, i surten els missatges de com es va encenent i apagant el LED.

mirar també: http://todbot.com/blog/2006/12/06/arduino-serial-c-code-to-talk-to-arduino/

En comptes d'utilitzar el fitxer de configuració puc passar directament els paràmetres:

$ minicom -D /dev/ttyUSB0 -b 115200

Per no utilitzar sudo mirar el següent apartat.

/dev/ttyUSB0 sense root

$ ls -la /dev/ttyUSB0
crw-rw---- 1 root dialout 188,  0 des 27 13:55 /dev/ttyUSB0

És suficient en què l'usuari joan pertanyi al grup dialout. Ara, quan arrenco l'arduino (./arduino) j ho puc fer sense sudo i ja puc llegir en el port sèrie:

$ sudo adduser joan dialout

Ethernet Shield

Arduino web server.jpg

ja tinc el Ethernet Shield (9-11-2009), i em disposo a fer un petit web server seguint les instruccions de

Please note that the current design of the ethernet shield is not compatible with the Arduino Mega.

Però per sort hi ha un hack!:

Consisteix en una part de hack hardware i una altra part software. Es tracta de mapejar uns pins tal com s'explica en el link.

Canvis hardware:

Canvis software. A hardware/libraries/Ethernet/utility/spi.h:

#define SPI0_SS_BIT BIT2 -> BIT0
#define SPI0_SCLK_BIT BIT5 -> BIT1
#define SPI0_MOSI_BIT BIT3 -> BIT2
#define SPI0_MISO_BIT BIT4 -> BIT3
#define IINCHIP_CS_BIT BIT2 -> BIT0

Per no barrejar les llibreries, creo la llibreria Ethernet2, però això implica renombrar els fitxers a Ethernet2.h i Ethernet2.cpp, i les referències que hi ha a aquest fitxer dins de Serial.cpp i Client.cpp també.

joan@ubuntu-bbdd:~$ ping 192.168.0.9
PING 192.168.0.9 (192.168.0.9) 56(84) bytes of data.
64 bytes from 192.168.0.9: icmp_seq=1 ttl=128 time=2.07 ms
64 bytes from 192.168.0.9: icmp_seq=2 ttl=128 time=0.103 ms
64 bytes from 192.168.0.9: icmp_seq=3 ttl=128 time=0.106 ms
^C
--- 192.168.0.9 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms

Explicació:

The shield must be assigned a MAC address and a fixed IP address using the Ethernet.begin() function. A MAC address is a globally unique identifier for a particular device. Current Ethernet shields come with a sticker indicating the MAC address you should use with them. For older shields without a dedicated MAC address, inventing a random one should work, but don't use the same one for multiple boards. Valid IP addresses depend on the configuration of your network. (It is possible to use DHCP to dynamically assign an IP to the shield, but this is not yet implemented in the Ethernet library.) Optionally, you can also specify a network gateway and subnet.

Ethernet Shield + PHP + Mysql (Arduino és el client web)

Aquí va un exemple de com des del Arduino podem fer una inserció a una base de dades. Per exemple, si tinc un sensor de temperatura, en comptes de grabar els valors a EEPROM els puc inserir a una base de dades.

La idea és que l'arduino envia informació a un servidor web, i és aquest servidor web el que executa PHP i es connecta al mysql.

Re: arduino+ethernet shield+php Reply #5 - 01.04.2010 at 15:56:44 | It is also posted here: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1268504939 - post 7

But i assume that Danish isnt your 2. language so i have translated the comments:

The Arduino Code:

#include <Ethernet.h>
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192, 168, 1, 88 };
byte gw[] = {192,168,1,1};
byte server[] = { xxx, xxx, xxx, xxx  }; // Server IP
byte subnet[] = { 255, 255, 255, 0 };
int data = 0;
int tempPin = 2;  // In This case the temperature is taken from pin 2 and sent to a sql server

void setup()
{

pinMode(tempPin, INPUT);
Serial.begin(9600);		   // Used for serial debugging

}
void loop()
{

Serial.println("Program running...");

 delay(5000);
 senddata();					   // Data is sent every 5 seconds

}
void senddata()
{

data = analogRead(tempPin);	     //Reading analog data


Ethernet.begin(mac, ip, gw, subnet);
Client client(server, 80);
Serial.println();
Serial.println("Forbinder…");
delay(1000);						//Keeps the connection from freezing

if (client.connect()) {
Serial.println("Connected");
client.print("GET http://server.com/script.php?vaerdi=");
client.print(data);
client.println(" HTTP/1.1");
client.println("Host: www.server.com");
client.println();
Serial.println();
				   }

else
{
Serial.println("Connection unsuccesfull");
}
//}
 //stop client
 client.stop();
 while(client.status() != 0)
{
  delay(5);
}
}

PHP Code:


<html>
	<?php

		$DATA = $_GET['vaerdi'];

			//Connect to database
			$opendb = mysql_connect("xxx.xxx.xxx.xxx", "database", "password") or mysql_error("Could not connect to database");
     		mysql_select_db("database");

     if ($opendb)
		{
     		mysql_query(" INSERT INTO tabel (Dato, DATA) VALUES ( NOW() , $DATA )");
		mysql_close($opendb);
		  }
	?>
</html>

Arduino com a servidor web: obrir i tancar relés des de la web

Això és el que han de fer els alumnes del CS d'Arduino: una pàgina web hostatjada en el Arduino, que tingui botons per encendre i apagar les llums de la casa domòtica, i que sigui l'arduino el que commuti els relés.

Està ben explicat a: la solució està aquí:

La idea és que envio links del tipus:

i detecta el ? i el valor, i actua en conseqüència.

Està clar que de cara a enviar informació al servidor més val enviar números i no lletres.

#include <SPI.h>
#include <Client.h>
#include <Ethernet.h>
#include <Server.h>
#include <Udp.h>
/*
	Simple Ethernet Test
        Arduino server outputs simple text to browser
	The circuit:
	* Arduino Duemilanove
        * Arduino Ethernet shield
        * Basic FTDI breakout 5V
        *LED connected to GND and digital pin 4 via resistor
        http://www.sciencprog.com/
        Created: 2009.11.18
        By Minde
        Modified: 2011.04.06
          1. Changed obsolete Wstring.h functions to String.h
          2. Changed includes to match Ethernet library.
          3. Fixed LED control
        By Minde
*/

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address
byte ip[] = { 192, 168, 0, 110 };			// ip in lan
byte gateway[] = { 192, 168, 0, 1 };			// internet access via router
byte subnet[] = { 255, 255, 255, 0 };                   //subnet mask
Server server(80);                                      //server port
byte sampledata=50;            //some sample data - outputs 2 (ascii = 50 DEC)             
int ledPin1 = 4;  // LED pin
int ledPin2 = 5; 
int ledPin3 = 6; 
int ledPin4 = 7; 
char link[]="http://www.scienceprog.com/"; //link data
String readString = String(30); //string for fetching data from address
boolean LEDON1 = false; //LED status flag
boolean LEDON2 = false; //LED status flag
boolean LEDON3 = false; //LED status flag
boolean LEDON4 = false; //LED status flag

void setup(){
//start Ethernet
  Ethernet.begin(mac, ip, gateway, subnet);
//Set pin 4 to output
  pinMode(ledPin1, OUTPUT);  
  pinMode(ledPin2, OUTPUT); 
  pinMode(ledPin3, OUTPUT); 
  pinMode(ledPin4, OUTPUT); 
  
  //enable serial datada print  
  Serial.begin(9600);
}
void loop(){
// Create a client connection
Client client = server.available();
  if (client) {
    while (client.connected()) {
   if (client.available()) {
    char c = client.read();
     //read char by char HTTP request
    if (readString.length() < 100) 
      {
        //store characters to string 
        readString += c; //replaces readString.append(c);
      }  
        //output chars to serial port
        Serial.print(c);
        //if HTTP request has ended
        if (c == '\n') {
          //dirty skip of "GET /favicon.ico HTTP/1.1"
          if (readString.indexOf("?") <0)
          {
            //skip everything
          }
          else
          //lets check if LED should be lighted
        if(readString.indexOf("L=1") >0)//replaces if(readString.contains("L=1"))
           {
             if (LEDON1==false) {
               digitalWrite(ledPin1, HIGH);    // set the LED on
               LEDON1 = true;
             } else {
               digitalWrite(ledPin1, LOW);    // set the LED off
               LEDON1 = false;
             }  
         }else if (readString.indexOf("L=2") >0){
             if (LEDON2==false) {
               digitalWrite(ledPin2, HIGH);    // set the LED on
               LEDON2 = true;
             } else {
               digitalWrite(ledPin2, LOW);    // set the LED off
               LEDON2 = false;
             }  
           }else if (readString.indexOf("L=3") >0){
             if (LEDON3==false) {
               digitalWrite(ledPin3, HIGH);    // set the LED on
               LEDON3 = true;
             } else {
               digitalWrite(ledPin3, LOW);    // set the LED off
               LEDON3 = false;
             }    
           }else if (readString.indexOf("L=4") >0){
             if (LEDON4==false) {
               digitalWrite(ledPin4, HIGH);    // set the LED on
               LEDON4 = true;
             } else {
               digitalWrite(ledPin4, LOW);    // set the LED off
               LEDON4 = false;
             }  
           }
           
          // now output HTML data starting with standart header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();
          //set background to yellow
          client.print("<body style=background-color:yellow>");
          //send first heading
          client.println("<font color='red'><h1>HTTP test routines</font></h1>");
          client.println("<hr />");
          client.println("<hr />");
          //output some sample data to browser
          client.println("<font color='blue' size='5'>Sample data: ");
          client.print(sampledata);//lets output some data
          client.println("<br />");//some space between lines
          client.println("<hr />");
          //drawing simple table
          client.println("<font color='green'>Simple table: ");
          client.println("<br />");
          client.println("<table border=1><tr><td><a href='http://192.168.0.110/?L=1'>Encendre cuina</a></td><td><a href='http://192.168.0.110/?L=2'>Encendre habitacio</a></td></tr>");
          client.println("<tr><td><a href='http://192.168.0.110/?L=3'>Encendre lavabo</a></td><td><a href='http://192.168.0.110/?L=4'>Encendre traster</a></td></tr></table>");          
          client.println("<br />");
          client.println("<hr />");

          if (LEDON1==true) client.println("Cuina encesa<br />"); 
          else  client.println("Cuina apagada<br />");
          
          if (LEDON2==true) client.println("Habitacio encesa<br />"); 
          else  client.println("Habitacio apagada<br />");
          
          if (LEDON3==true) client.println("Lavabo ences<br />"); 
          else  client.println("Lavabo apagat<br />");

          if (LEDON4==true) client.println("Traster ences<br />"); 
          else  client.println("Traster apagat<br />");          

          client.println("<br />");

          client.println("</body></html>");
          //clearing string for next read
          readString="";
          //stopping client
          client.stop();
            }
          }
        }
      }
 }     

Recordar que es pot executar una pàgina web en línia de comandes:

$ wget http://192.168.0.110/?L=1

i aquesta línia la puc integrar en una tasca cron per tal que s'executi cada minut:

$ sudo joe /etc/crotnab

*/1 * * * * root wget http://192.168.0.110/?L=1

$ sudo /etc/init.d/cron restart
<h1>HTTP test routines</font></h1>");
          client.println("<hr />");
          client.println("<hr />");
          //output some sample data to browser
          client.println("<font color='blue' size='5'>Sample data: ");
          client.print(sampledata);//lets output some data
          client.println("<br />");//some space between lines
          client.println("<hr />");
          //drawing simple table
          client.println("<font color='green'>Simple table: ");
          client.println("<br />");
          client.println("<table border=1><tr><td><a href='http://192.168.0.110/?L=1'>Encendre cuina</a></td><td><a href='http://192.168.0.110/?L=2'>Encendre habitacio</a></td></tr>");
          client.println("<tr><td><a href='http://192.168.0.110/?L=3'>Encendre lavabo</a></td><td><a href='http://192.168.0.110/?L=4'>Encendre traster</a></td></tr></table>");          
          client.println("<br />");
          client.println("<hr />");

          if (LEDON1==true) client.println("Cuina encesa<br />"); 
          else  client.println("Cuina apagada<br />");
          
          if (LEDON2==true) client.println("Habitacio encesa<br />"); 
          else  client.println("Habitacio apagada<br />");
          
          if (LEDON3==true) client.println("Lavabo ences<br />"); 
          else  client.println("Lavabo apagat<br />");

          if (LEDON4==true) client.println("Traster ences<br />"); 
          else  client.println("Traster apagat<br />");          

          client.println("<br />");

          client.println("</body></html>");
          //clearing string for next read
          readString="";
          //stopping client
          client.stop();
            }
          }
        }
      }
 }     

Recordar que es pot executar una pàgina web en línia de comandes:

$ wget http://192.168.0.110/?L=1

i aquesta línia la puc integrar en una tasca cron per tal que s'executi cada minut:

*/1 * * * * root wget -q -O /dev/null http://192.168.0.110/?L=1
<h1>HTTP test routines</font></h1>");
          client.println("<hr />");
          client.println("<hr />");
          //output some sample data to browser
          client.println("<font color='blue' size='5'>Sample data: ");
          client.print(sampledata);//lets output some data
          client.println("<br />");//some space between lines
          client.println("<hr />");
          //drawing simple table
          client.println("<font color='green'>Simple table: ");
          client.println("<br />");
          client.println("<table border=1><tr><td><a href='http://192.168.0.110/?L=1'>Encendre cuina</a></td><td><a href='http://192.168.0.110/?L=2'>Encendre habitacio</a></td></tr>");
          client.println("<tr><td><a href='http://192.168.0.110/?L=3'>Encendre lavabo</a></td><td><a href='http://192.168.0.110/?L=4'>Encendre traster</a></td></tr></table>");          
          client.println("<br />");
          client.println("<hr />");

          if (LEDON1==true) client.println("Cuina encesa<br />"); 
          else  client.println("Cuina apagada<br />");
          
          if (LEDON2==true) client.println("Habitacio encesa<br />"); 
          else  client.println("Habitacio apagada<br />");
          
          if (LEDON3==true) client.println("Lavabo ences<br />"); 
          else  client.println("Lavabo apagat<br />");

          if (LEDON4==true) client.println("Traster ences<br />"); 
          else  client.println("Traster apagat<br />");          

          client.println("<br />");

          client.println("</body></html>");
          //clearing string for next read
          readString="";
          //stopping client
          client.stop();
            }
          }
        }
      }
 }     

Recordar que es pot executar una pàgina web en línia de comandes:

$ wget http://192.168.0.110/?L=1

i aquesta línia la puc integrar en una tasca cron per tal que s'executi cada minut:

*/1 * * * * wget -q -O /dev/null http://192.168.0.110/?L=1
<h1>HTTP test routines</font></h1>");
          client.println("<hr />");
          client.println("<hr />");
          //output some sample data to browser
          client.println("<font color='blue' size='5'>Sample data: ");
          client.print(sampledata);//lets output some data
          client.println("<br />");//some space between lines
          client.println("<hr />");
          //drawing simple table
          client.println("<font color='green'>Simple table: ");
          client.println("<br />");
          client.println("<table border=1><tr><td><a href='http://192.168.0.110/?L=1'>Encendre cuina</a></td><td><a href='http://192.168.0.110/?L=2'>Encendre habitacio</a></td></tr>");
          client.println("<tr><td><a href='http://192.168.0.110/?L=3'>Encendre lavabo</a></td><td><a href='http://192.168.0.110/?L=4'>Encendre traster</a></td></tr></table>");          
          client.println("<br />");
          client.println("<hr />");

          if (LEDON1==true) client.println("Cuina encesa<br />"); 
          else  client.println("Cuina apagada<br />");
          
          if (LEDON2==true) client.println("Habitacio encesa<br />"); 
          else  client.println("Habitacio apagada<br />");
          
          if (LEDON3==true) client.println("Lavabo ences<br />"); 
          else  client.println("Lavabo apagat<br />");

          if (LEDON4==true) client.println("Traster ences<br />"); 
          else  client.println("Traster apagat<br />");          

          client.println("<br />");

          client.println("</body></html>");
          //clearing string for next read
          readString="";
          //stopping client
          client.stop();
            }
          }
        }
      }
 }     

Comunicar-se amb arduino: C, Java i altres

En el playground del Arduino està tota la informació:

De fet, qualsevol llenguatge de programació que implementi la comunicació pel port sèrie ho podrà fer.

Per exemple, mirar arduino-serial.c. Fer també un exemple amb Java.

EEPROM externa: Data logging

1650 línies * 20 bytes = 33000 samples = 33000 bytes = 33 KB no havíem quedat que la EEPROM del Arduino Mega eren 4KB? Doncs he de mirar el programa, però és possible que tota la informació es guarda en la Flash Memory. He de mirar si quan connecto el Arduino són el fitxer wav o no (mirar si per tal de què soni he de fer un upload de l'aplicació cada vegada).


Arduino Mega:

jo tinc la EEPROM 24LC16, que vol dir 16Kb = 2KB (compte!). També existeixen memòries més grans com la 24LC256 (256Kb = 32KB). L'avantatge dels EEPROMs és que es poden concatenar i així aconseguir més memòria.

El que ve a continuació ho he provat de fer amb la 24LC16 de Microchip (un xip que tenia de fa anys, potser està malament) i no me n'he ensortit; així que he comprat un Atmel 24C512, i per fi sí que m'ha sortit. Compte!: m'ha sortit un dels codis que he trobat. Els dos primers codis no funcionaven del tot.

El 24C512 té 512Kb de memòria, que són 64KB, i amb 64KB ja es pot grabar uns quants segons d'audio (tot això ve perquè vull ficar audio a dins d'una EEPROM, veure projecte Audio PCM amb Arduino). Quants segons? Doncs una mostra és un byte, i per tenir una qualitat acceptable he de mostrejar a 8000 Hz. El meu límit són 64KB, 64000 mostres. Per tant, 64000/8000 = 8 segons, més que acceptable per fer una joguina musical (una nina que plori, per exemple). A més, recordem que les EEPROM es poden encadenar.

Segueixo:

connectant el 24LC16:

Pin#	Descripció		Connect to
1		Address 0	High for 1, Low for 0
2		Address 1	High for 1, Low for 0
3		Address 2	High for 1, Low for 0
4		GND		Ground
5		SDA		Arduino Pin 4, pull up to 5V via 1K resistor
6		SDL (SCK?)	Arduino Pin 5, pull up to 5V via 1K resistor
7		Write Protect	Low to enable write, Hight to disable write
8		Supply Voltage	5V

Pins 1, 2 i 3 determinen l'adreça del xip. El protocol I2C utilitza 7 bits de direcció i un bit de control.

Llegeixo que utilitzant la llibreria wire.h no cal fer el pull-up dels pins 4 i 5 amb les dues resistències. D'altre banda, els pins 4 i 5 (analògics) són per a l'Arduino normal. Recordo que jo tinc l'arduino Mega.

Amb els pins A0, A1 i A2 aconseguim redireccionar 8 adreces diferents:

                      A2  A1  A0
| 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | = 0x50
| 0 | 1 | 0 | 1 | 0 | 0 | 0 | 1 | = 0x51
| 0 | 1 | 0 | 1 | 0 | 0 | 1 | 0 | = 0x52
| 0 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | = 0x53
| 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | = 0x54
| 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | = 0x55
| 0 | 1 | 0 | 1 | 0 | 1 | 1 | 0 | = 0x56
| 0 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | = 0x57

D'aquesta manera el meu dispositiu tindrà una direcció física, i quan el fiqui en un bus I2C on hi poden haver varis dispositius, el meu dispositiu només farà cas dels missatges que li vagin dirigits. Recordem que el protocol I2C és un protocol de coumunicació sèrie bifilar, on per un fil van les dades (SDA, Serial Data) i per un altre fil va el rellotge (Serial Clock, SCL) i el senyal de control (veure wikipedia i datasheets, per ex: http://ww1.microchip.com/downloads/en/devicedoc/21203N.pdf).

Xip 24LC16 de MicroChip:

         |_|
A0  pin1     pin8 Vcc
A1  pin2     pin7 WP
A2  pin3     pin6 SCL
VSS pin4     pin5 SDA

Llegeixo en el datasheet que la memòria són 8 blocs de 256 bytes (8*256*8=16384 bits = 16 Kb = 2KB)

Per entendre el funcionament, la clau està en el protocol I2C que he d'estudiar. El protocol I2C és un protocol de comunicació sèrie de 2 fils, que són els pins SCL (clock) i SDA (dades).

The device is organized as eight blocks of 256 x 8 bit memory with a 2-wire serial interface.

per escriure el byte 0xAB al primer bloc de l'adreça 0x50 farem:

i2c_eeprom_write_byte( 0x50, 1, 0xAB );

The bus must be controlled by a master device which generates the Serial Clock (SCL), controls the bus access, and generates the Start and Stop conditions while the 24XX256 works as a slave -> És a dir, el Arduino i el programa que hi ha a dins fan de màster, i la memòria EEPROM fa de slave, que és on escric i llegeixo la informació.

The Chip Select bits A2, A1 and A0 can be used to expand the contiguous address space. És a dir, pud ficar en el mateix bus diferents EEPROM (amb adreces diferents, és clar, i d'aquesta manera aconseguir fer un espai de memòria contigu més gran.

Anem doncs a fer un data logger basant-nos en el codi que trobem a

La llibreria Wire.h és de les que s'instal.len amb el SDK, o sigui que no cal fer res especial.

Canvis:

El codi que finalment ha funcionat és:

/* Ejemplo EEPROM
 * Autor: kans
 * Fecha: 05/03/2008
 */

#include <Wire.h> //libreria I2C

//Las siguientes funciones para lectura y escritura en una EEPROM se encuentran en el wiki de Arduino: http://www.arduino.cc/playground/Code/I2CEEPROM

void i2c_eeprom_write_byte( int deviceaddress, unsigned int eeaddress, byte data ) {
  int rdata = data;
  Wire.beginTransmission(deviceaddress);
  Wire.send((int)(eeaddress >> 8)); // MSB
  Wire.send((int)(eeaddress & 0xFF)); // LSB
  Wire.send(rdata);
  Wire.endTransmission();
}

// WARNING: address is a page address, 6-bit end will wrap around
// also, data can be maximum of about 30 bytes, because the Wire library has a buffer of 32 bytes
void i2c_eeprom_write_page( int deviceaddress, unsigned int eeaddresspage, byte* data, byte length ) {
  Wire.beginTransmission(deviceaddress);
  Wire.send((int)(eeaddresspage >> 8)); // MSB
  Wire.send((int)(eeaddresspage & 0xFF)); // LSB
  byte c;
  for ( c = 0; c < length; c++)
    Wire.send(data[c]);
  Wire.endTransmission();
}

byte i2c_eeprom_read_byte( int deviceaddress, unsigned int eeaddress ) {
  byte rdata = 0xFF;
  Wire.beginTransmission(deviceaddress);
  Wire.send((int)(eeaddress >> 8)); // MSB
  Wire.send((int)(eeaddress & 0xFF)); // LSB
  Wire.endTransmission();
  Wire.requestFrom(deviceaddress,1);
  if (Wire.available()) rdata = Wire.receive();
  return rdata;
}

// maybe let's not read more than 30 or 32 bytes at a time!
void i2c_eeprom_read_buffer( int deviceaddress, unsigned int eeaddress, byte *buffer, int length ) {
  Wire.beginTransmission(deviceaddress);
  Wire.send((int)(eeaddress >> 8)); // MSB
  Wire.send((int)(eeaddress & 0xFF)); // LSB
  Wire.endTransmission();
  Wire.requestFrom(deviceaddress,length);
  int c = 0;
  for ( c = 0; c < length; c++ )
    if (Wire.available()) buffer[c] = Wire.receive();
}


void setup() {
  //char cadena[] = "hola mundo desde una eeprom"; //cadena a escribir
  char cadena[] = "Joan,Rita,Maria,Pere!"; //cadena a escribir
  Wire.begin(); //es obligatorio inicializar la conexion
  Serial.begin(9600);
  i2c_eeprom_write_page(0x50, 0, (byte *)cadena, sizeof(cadena)); //escribir la cadena al principio de la EEPROM; comentar esta linea para probar que la memoria es no volatil
  delay(10); //pequeña pausa despues de escribir en la memoria
}

void loop() {
  int addr=0; //direccion a leer
  byte b = i2c_eeprom_read_byte(0x50, 0); //acceso a la primera posicion de memoria
  
  while (b!=0) {
    Serial.print((char)b); //enviar al ordenador
    addr++; //siguiente direccion
    b = i2c_eeprom_read_byte(0x50, addr); //acceso a posicion de memoria
  } 
  Serial.println();
  delay(2000);
}

LiquidCrystal Library

PC1602F.jpg

Ja tinc un display de 16x2 posicions: el PC1602F. Mirant el datasheet s'identifiquen ràpidament els pins:

15 16  1   2   3   4   5  6  7   8   9  10  11  12  13  14
*   *  *   *   *   *   *  *  *   *   *   *   *   *   *   *
A   K  GND Vdd Vo  RS  RW E DB0 DB1 DB2 DB3 DB4 DB5 DB6 DB7

Vdd=5V
Vo=contrast adjust (màxim contrast=GND; mínim contrast=Vcc, no es veu res)
RS=register select signal
RW=data read/write (read=1; write=0)
E=Enable signal
DBX=Data bus line

A register select (RS) pin that controls where in the LCD's memory you're writing data to. You can select either the data register, which holds what goes on the screen, or an instruction register, which is where the LCD's controller looks for instructions on what to do next.

És a dir, que no només es tracta d'escriure informació en el display, sinó que també es poden ficar instruccions per dir com s'ha de comportar i què ha de fer el display.

An Enable pin that enables writing to the registers

8 data pins (D0 -D7). The states of these pins (high or low) are the bits that you're writing to a register when you write, or the values you're reading when you read.

The process of controlling the display involves putting the data that form the image of what you want to display into the data registers, then putting instructions in the instruction register. The LiquidCrystal library simplifies this for you so you don't need to know the low-level instructions.

The Hitachi-compatible LCDs can be controlled in two modes: 4-bit or 8-bit. The 4-bit mode requires seven I/O pins from the Arduino, while the 8-bit mode requires 11 pins. For displaying text on the screen, you can do most everything in 4-bit mode

Exemple HelloWorld

Com es veu en el diagrama de l'exemple (http://arduino.cc/en/uploads/Tutorial/lcd_bb.png) s'utilitzen els pins de dades D4,D5,D6 i D7 (pins 11, 12, 13, 14) connectats a PWM 5,4,3,2; hi ha un potenciòmetre per al contrast que jo no utilitzaré (Vo=GND per tal que veiem alguna cosa); El RS (pin4) està connectat a PWM12; el Enable (E, pin 6) està connectat a PWM11; i el R/W (pin 5) està connectat a GND i així es pot escriure en el LCD. Jo tinc un Arduino Mega en comptes d'un arduino normal: suposo que els pins són els mateixos.

hello_world_lcd.pde

 /*
   LiquidCrystal Library - setCursor
  
  Demonstrates the use a 16x2 LCD display.  The LiquidCrystal
  library works with all LCD displays that are compatible with the 
  Hitachi HD44780 driver. There are many of them out there, and you
  can usually tell them by the 16-pin interface.
  
  This sketch prints to all the positions of the LCD using the
  setCursor(0 method:
  
  The circuit:
  * LCD RS pin to digital pin 12
  * LCD Enable pin to digital pin 11
  * LCD D4 pin to digital pin 5
  * LCD D5 pin to digital pin 4
  * LCD D6 pin to digital pin 3
  * LCD D7 pin to digital pin 2
  * 10K resistor:
  * ends to +5V and ground
  * wiper to LCD VO pin (pin 3)
  
  Library originally added 18 Apr 2008
  by David A. Mellis
  library modified 5 Jul 2009
  by Limor Fried (http://www.ladyada.net)
  example added 9 Jul 2009
  by Tom Igoe 
  modified 22 August 2009
  by Tom Igoe
  
  http://www.arduino.cc/en/Tutorial/LiquidCrystal
  */

 // include the library code:
 #include <LiquidCrystal.h>

 // these constants won't change.  But you can change the size of
 // your LCD using them:
 const int numRows = 2;
 const int numCols = 16;

 // initialize the library with the numbers of the interface pins
 LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

 void setup() {
   // set up the LCD's number of rows and columns: 
   lcd.begin(numRows, numCols);
 }sketch_nov19b

 void loop() {
   // loop from ASCII 'a' to ASCII 'z':
   for (int thisLetter = 'a'; thisLetter <= 'z'; thisLetter++) {
     // loop over the rows:
     for (int thisRow= 0; thisRow < numRows; thisRow++) {
       // loop over the columns:
       for (int thisCol = 0; thisCol < numCols; thisCol++) {
         // set the cursor position:
         lcd.setCursor(thisCol,thisRow);
         // print the letter:
         lcd.print(thisLetter, BYTE);
         delay(200);
       }
     }
   }
 }

Altres exemples

Faig els altres exemples que hi ha a www.arduino.cc, que són fàcils d'entendre.

Playground: login

Arduino PlayGround: joanillo/jq****

He penjat la referència del Arduinotes i aniré penjant més coses.

Llibreria TVOut

Es tracta de fer una interfície de l'ordino amb la tele analògica. La tele pot ser una bona sortida per presentar informació i fer projectes divertits.

Emular un teclat PS/2. LLibreria ps2dev.h

La idea és fer un joystick: en comptes de jugar amb el teclat, tenir una consola amb Joystick i botons. El joistick i botons són micro-switches que entren en les entrades digitals de l'Arduino, i el connector PS/2 es connecta al PC. Per tant, l'arduino està emulant un teclat o un mouse PS/2. Aquest seria el primer pas per a fer una màquina Arcade. L'arduino de fet substitueix els controladors I-PAC que s'utilitzen en aquestes màquines per fer aquesta funció.

Típicament, un joc amb un sol jugador ha de tenir un joystick, 4 botons i un altre botó per la moneda. Això són 9 micro-switches que s'han de correspondre a 9 entrades digitals de l'Arduino. L'ATMega168 té 14 Digital I/O Pins.

i això s'ha de poder fer amb l'Arduino sense problemes. A diferència del projecte Arduinotes, en què el teclat PS-2 era per entrar informació a l'Arduino, ara l'Arduino ha de posar informació en el connector PS-2 que s'ha d'enviar al PC. Ara bé, de fet, la idea és molt diferent, tant que no serveix la llibreria PS2Keyboard.h. Aquesta llibreria era per llegir el teclat (fer una interfície del teclat amb l'arduino), i jo el que vull és emular el teclat (connectat l'Arduino al PC com si fos un teclat)

The PS2 protocol is a simple synchronous serial connection and we already have the library code in the playground. La llibreria que busco es diu ps2dev.h
My example of using ps2dev as a keyboard:

edit 'ps2dev.h'
Code:

comment out #include "WConstants.h"
and add a line #include <WProgram.h>
...
//#include "WConstants.h"
#include <WProgram.h>
... 

here is code: I used royboy's code siliconrepublic.blogspot.com

codi 1. funciona amb el connector PS/2 a USB

nota: i no funciona amb el connector PS/2 de forma nativa. I és que la clau està en el delay(20) de la funció ack().

#include "ps2dev.h" // to emulate a PS/2 device

PS2dev keyboard(3,2); // PS2dev object (2:data, 3:clock)
int enabled = 0; // pseudo variable for state of "keyboard"

void ack() {
  //acknowledge commands
  while(keyboard.write(0xFA));
}

int keyboardcommand(int command) {
  unsigned char val;
  switch (command) {
  case 0xFF: //reset
    ack();
    //the while loop lets us wait for the host to be ready
    while(keyboard.write(0xAA)!=0);
    break;
  case 0xFE: //resend
    ack();
    break;
  case 0xF6: //set defaults
    //enter stream mode
    ack();
    break;
  case 0xF5: //disable data reporting
    //FM
    enabled = 0;
    ack();
    break;
  case 0xF4: //enable data reporting
    //FM
    enabled = 1;
    ack();
    break;
  case 0xF3: //set typematic rate
    ack();
    keyboard.read(&val); //do nothing with the rate
    ack();
    break;
  case 0xF2: //get device id
    ack();
    keyboard.write(0xAB);
    keyboard.write(0x83);
    break;
  case 0xF0: //set scan code set
    ack();
    keyboard.read(&val); //do nothing with the rate
    ack();
    break;
  case 0xEE: //echo
    //ack();
    keyboard.write(0xEE);
    break;
  case 0xED: //set/reset LEDs
    ack();
    keyboard.read(&val); //do nothing with the rate
    ack();
    break;
  }
}

void setup() {
  // send the keyboard start up
  while(keyboard.write(0xAA)!=0);
  delay(10);
}

void loop() {
  unsigned char c;
  //if host device wants to send a command:
  if( (digitalRead(3)==LOW) || (digitalRead(2) == LOW)) {
    while(keyboard.read(&c)) ;
    keyboardcommand(c);
  }
  else{ //send keypresses accordingly using scancodes
  // secancodes: http://www.computer-engineering.org/ps2keyboard/scancodes2.html
  keyboard.write(0x1C); // \
  keyboard.write(0xF0); //  |- send 'a'
  keyboard.write(0x1C); // /
  delay (1000); // wait 1 second
  }
}
 

I finalment, l'enllaç a la llibreria ps2dev.h està a:

al final de tot, on posa Emulating a PS2 device

Els arxius WConstants.h i WProgram.h que són necessaris estan a /home/joan/arduino-0022/hardware/arduino/cores/arduino

Compilo l'exemple ps2_mouse.pde que està a la carpeta exemples/ de la llibreria ps2dev. Obtinc l'error:

In file included from /home/joan/arduino-0022/hardware/arduino/cores/arduino/WProgram.h:6,
                 from ps2_mouse.cpp:4:
/usr/lib/gcc/avr/4.3.4/../../../avr/include/math.h:475: error: expected unqualified-id before ‘double’
/usr/lib/gcc/avr/4.3.4/../../../avr/include/math.h:475: error: expected `)' before ‘double’
/usr/lib/gcc/avr/4.3.4/../../../avr/include/math.h:475: error: expected `)' before ‘double’

i la solució està explicada a:

In ps2dev.h, comment out the line that includes WConstants.h.  Put in a lline that includes WProgram.h:

//#include "WConstants.h"  // The original line---for really old arduino stuff
#include "WProgram.h"      // This is what you should have for arduino-0021

Ara obtinc un error d'un altre tipus:

/usr/local/lib/gcc/avr/4.5.2/../../../../avr/bin/ld: cannot find crtm1280.o: No such file or directory

i dóna un error similar escollint l'arduino mega o un altre:

/usr/local/lib/gcc/avr/4.5.2/../../../../avr/bin/ld: cannot find crtm168.o: No such file or directory
etc

però aquest és un problema general de la meva instal.lació que fa que l'exemple més senzill no funcioni.

Cerco aquests fitxers per veure si els tinc:

$ sudo find -name crtm1280.o
./usr/lib/avr/lib/avr51/crtm1280.o
./usr/lib/avr/lib/avr5/crtm1280

(això no és un problema de la llibreria, és un problema de la meva instal.lació que hi ha un cacao amb la instal.lació del avr)

A l'Institut compila sense problemes.

L'exemple que ve en el codi és per emular un ratolí (el punter es mou en diagonal per la pantalla). La manera de conectar un teclat PS2 (adaptació de l'anterior) el podem treure d'aquí:

(El codi està més amunt)

La connexió del connector femella del teclat PS2 es pot veure en el Arduinotes.

   II         (connector femella)
6      5
4      3
  2  1

4: Vcc
3: GND
1: Data
5: CLK

Les primeres proves que he fet amb la llibreria no han funcionat.

Amb el portàtil no puc treballar perquè no tinc port PS2... però això no és cert: (http://siliconrepublic.blogspot.com/) He comprat un adaptador de connector PS2 a USB, per treballar amb el portàtil amb un teclat PS2 (i amb el Arduino com a emulador de teclat) i ha funcionat correctament l'exemple. (Recordem que el connector del teclat és el blau).

The PS2dev library (http://www.arduino.cc/playground/ComponentLib/Ps2mouse) lets the Arduino emulate a PS/2 device 
and I used a PS/2 to USB converter off the shelf for 3 bucks since my laptop does not have a PS/2 port. 
Also note that the pins 3 and 4 of the PS/2 connector can power the Arduino very well :)

Això és interessant, el host PS2 (l'ordinador) alimenta el Arduino a través dels pins del conector PS2. No necessito cap connexió externa. Ha funcionat sense problemes amb el portàtil. Ara falta fer-ho funcionar amb un ordinador amb connector PS2, que és la configuració senzilla, i de moment no m'ha funcionat.

Hi ha un altre projecte que utilitza la llibreria ps2dev.h, i del qual es pot adaptar també el codi (em sembla que el codi és més complet):

codi 2. Funciona el connector PS/2 de forma nativa

nota: i no funciona amb l'adaptador PS/2 a USB. I és que la clau està en el delay(20) de la funció ack().

#include "ps2dev.h" 

PS2dev keyboard(3,2); // PS2dev object (2:data, 3:clock)
int enabled =0; // pseudo variable for state of "keyboard"

void ack() {
//acknowledge commands
while(keyboard.write(0xFA));
//Serial.println("ACK");
delay(20);
}


int keyboardcommand(int command) {
unsigned char val;
switch (command) {
case 0xFF: //reset
ack();
//the while loop lets us wait for the host to be ready
while(keyboard.write(0xAA)!=0);
break;
case 0xFE: //resend
ack();
break;
case 0xF6: //set defaults
//enter stream mode
ack();
break;
case 0xF5: //disable data reporting
//FM
enabled = 0;
ack();
break;
case 0xF4: //enable data reporting
//FM
enabled = 1;
ack();
break;
case 0xF3: //set typematic rate
ack();
keyboard.read(&val); //do nothing with the rate
ack();
break;
case 0xF2: //get device id
ack();
keyboard.write(0xAB);
keyboard.write(0x83);
break;
case 0xF0: //set scan code set
ack();
keyboard.read(&val); //do nothing with the rate
ack();
break;
case 0xEE: //echo
//ack();
keyboard.write(0xEE);
break;
case 0xED: //set/reset LEDs
ack();
keyboard.read(&val); //do nothing with the rate
ack();
break;
}
}

void setup() {
//Serial.begin(57600);
delay(2000); //initialization time just in case
// send the keyboard start up
while(keyboard.write(0xAA)!=0);
delay(10); //necessari ficar aquest valor per tal que funcioni el connector PS/2 (amb el conversor PS/2 a USB no cal!). En canvi, si fico delay(1000) no funciona
//while (keyboard.write(0xAA) != 0); //en el codi extret del keyglobe el 0xAA s'envia dues vegades.
}

void loop() {

unsigned char c;
//if host device wants to send a command:
if( (digitalRead(3)==LOW) || (digitalRead(2) == LOW)) {
while(keyboard.read(&c)) ;
keyboardcommand(c);
}
else{ 
  keyboard.write(0x1C);
  delay(50); //sembla ser que es necessari, depn tamb del scancode.
  keyboard.write(0xF0);
  keyboard.write(0x1C);
  delay (1000); // wait 1 second

}

}

La diferència entre el codi 1 i el codi 2, que fa funcionar el connector PS/2 directament de forma nativa, és:

void ack() {
//acknowledge commands
while(keyboard.write(0xFA));
//Serial.println("ACK");
delay(20);
}

La clau està en el delay(20). Me n'he adonat perquè tenia el Serial.println("ACK"); (que fica un retard), que si el trec deixava de funcionar.

Amb el codi 1 carrego el codi en el micro, i aparentment funciona. Ara bé, quan faig un reset deixa de funcionar.

Altres coses que són importants per al bon funcionament són:

Protocol PS/2 mouse/keyboard

Expandir les entrades digitals

El problema del Arduino 168 (a diferència del Arduino Mega) és que hi ha només 13 entrades digitals. que van justes per a un joystick (4 pins) + 6 botons (6 pins) + data +clock. És a dir, un jugador. Per a dos jugadors necessito més entrades digitals. Una possible solució és utilitzar el Parallel to Serial Shifting-In with a CD4021BE.

Emular un teclat USB

Així com el teclat PS2 és la solució senzilla, el teclat USB és més complicat degut al protocol. Tanmateix, hi ha una solució software que donaria peu a implementar fàcilment una solució:

i l'exemple del teclat USB és el HIDKeys (HIDKeys demonstrates how V-USB can be used to implement the USB Human Interface Device (HID) class specification). Es pot descarregar el software genèric i el software del HIDKeys per a Linux.

POE, Power Over Ethernet, en un arduino (maig 2012)

Els alumnes han comprat un arduino que té incorporat el Ethernet Shield i POE.

La casa que fabrica els mòduls POE és Silver Telecom

i el mòdul que porta el Arduino és similar al Ag9000 Series:

La idea és que el switch proporciona 48V que s'envien per 4 línies del RJ-45, i que hi ha una conversió DC-DC per aplicar un output de 3.5 o 5V. Veure diagrama de blocs en el datasheet.



creat per Joan Quintana Compte, octubre 2009

Eines de l'usuari
Espais de noms
Variants
Accions
Navegació
IES Jaume Balmes
Gestió Empresarial
Informàtica musical
Media Art
joanillo.org Planet
Eines