Vous êtes sur la page 1sur 55

Cerradura electronica

10-12-2012
http://www.youtube.com/watch?v=xSuP_aj86Bk
He modificado la cerradura electronica, que se puede ver en el video, para que funione con Arduino.
He usado:
Un Arduino Nano. 12
Un teclado keypad de ebay. 3
Un lcd 1602 que vale unos 5
Un modulo de dos rels de ebay. 3
Un sensor magnetico de puerta abierta. 4
Un zumbador. 3
El Motor con mando a distancia de ABUs Hometec. 70 (En Alemania cuesta unos 40, en ferreteria Espaola unos 150...
sin comentarios)
Estoy esperando de china:
-RCT por I2C. Mi arduino atrasa 10 minutos al da Se puede paliar por soft, pero el RTC es lo suyo y vale menos de 3
-Un LCD con I2C para liberar pines y as poder poner sensor temperatura 18B20, grabador de tarjetas SD, sensor llamadas
al timbre (poniendole un rel de 220 en paralelo) y cuarta columna keypad.
He conectado los dos rels a los botones del motor que abren y cierran la puerta manualmente. He tenido que usar el motor
alrevs (que cierre cuando abre y viceversa).
El codigo fuente es el siguiente (compilado con Arduino 1.0.2):

/*******************************************************************************
* CERRADURA ELECTRONICA de Antonio EB4CAK
* Pongo este programa bajo licencia GNU GPL.
*
* 22-5-2011 INICIO
* 20-6-11 Version 1.0
* 12-7-11 V 1.1 Puerta se cierra ante clave erronea - corregir bug que no cierra la puerta * 10-9-11 V 1.2 Avisa de la ultima clave erronea
* 08-10-12 v 1.3 Modificacion para Mari Carmen y aadida clave 7 generica
* 1-12-2012 v1.4 Adaptacion de STM8s a Arduino. Quitada clave7. Espera incremental si error.
* 7-12-2012 Lo instalo
******************************************************************************
Cosas Pendientes:
-RTC (pines A4 y A5)
-SD para grabar entradas y salidas
-Pin de entrada para avisar si han llamado al timbre
PINES:
2 Teclado Col 1
3 Teclado Col 2
4 ABRIRCERRADURA Rele cerradura ON
5 CERRARCERRADURA Rele cerradura OFF
6 Teclado Col 3
7 Zumbador
Teclado Col 4 (Opcional)
8 Teclado Fila 1
9 Teclado Fila 2

10Teclado Fila 3
11Teclado Fila 4
12 LCD RS
13* LCD E
A0 LCD D4
A1 LCD D5
A2 LCD D6
A3 LCD D7
A4* RTC
A5* RTC
A6 Sensor timbre? 18b20?
A7 Sensor puerta abierta (Poner una R de 5v al pin y luego el pin a Masa pasando por el interruptor)

*/
#include <LiquidCrystal.h>
#include <Keypad.h>
#include <Time.h> // Para la hora
#include <Wire.h>
#include <DS1307RTC.h> // a basic DS1307 library that returns time as a time_t
#include <EEPROM.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 13, 17, 16, 15, 14);
//////////// Config teclado
const byte ROWS = 4; //Filas
const byte COLS = 3; //Columnas
char keys[ROWS][COLS] = {
{'1','2','3'},
{'4','5','6'},
{'7','8','9'},
{'*','0','#'}
};
byte rowPins[ROWS] = {8,9,10,11}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {2,3,6}; //connect to the column pinouts of the keypad
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
//////////// Fin Config Teclado
////// Claves
char Clave1[15]={"1234"}; // Pueden ser 15 caracteres o menos.
char Clave2[15]={"00000000"};
char Clave3[15]={"1111111111111"}; // Para Mari Carmen
char Clave4[15]={"32165498732165"}; // Clave de un solo uso
char Clave5[15]={"32112346549878"}; // Clave de un solo uso
char Clave6[15]={"55555556546546"}; // Clave de un solo uso
// Nota: Hay que cambiar estas claves. Solo son de prueba para la difusion del codigo.
////// Fin Claves
#define LUNES 2
#define MARTES 3
#define MIERCOLES 4
#define JUEVES 5
#define VIERNES 6
#define SABADO 7
#define DOMINGO 1
#define SI 0xFF
#define NO 0
#define COMPROBAR 1 // Usado en exceso_de_tiempo
#define INICIAR 2 // Usado en exceso_de_tiempo
#define ANULAR 0
// Usado en exceso_de_tiempo

#define SensorPuerta A7
#define BUZZ 7 //Definimos el pin del zumbador
#define ABRIRCERRADURA 4
#define CERRARCERRADURA 5
#define INACTIVO HIGH // Para no liarse con ABRIRCERRADURA
#define ACTIVO LOW

/********* PARA TEMPORIZACIONES Y RELES ***********/


unsigned int error_acumulativo=1; // Para que a cada codigo erroneo la espera sea mayor
/********* FIN PARA TEMPORIZACIONES Y RELES *************/

time_t pctime = 1354786049; // Tiempo inicial de prueba hasta poner el RTC.


time_t TiempoError = 0; // Para pintar hora de ultima entrada erronea
void setup() {
delay(50); // Por si acaso, para estabilizar.
Serial.begin(9600); // Para depuracion solo.
lcd.begin(16, 2); // 16 Columnas y 2 filas
lcd.clear(); //Para evitar que queden cosas mal.
pinMode(BUZZ, OUTPUT); // Esto se puede quitar.
pinMode(ABRIRCERRADURA, OUTPUT);
pinMode(CERRARCERRADURA, OUTPUT);
digitalWrite(ABRIRCERRADURA, INACTIVO); // Reles inactivos
digitalWrite(CERRARCERRADURA, INACTIVO); // Reles inactivos
/* Aqui PONEMOS RTC Revisarlo para varios intentos
setSyncProvider(RTC.get); // the function to get the time from the RTC
if(timeStatus()!= timeSet)
Serial.println("Unable to sync with the RTC");
else
Serial.println("RTC has set the system time");
*/
setTime(pctime);
melodia(2); // Musiquilla que indica reinico
}// Del setup
void loop() {
pinta_reloj();
delay(5);
char key = keypad.getKey(); // Capturamos tecla
clave_tecla(key);
// Comprobamos si es la clave OK
// Pintamos errores
if(TiempoError)pinta_reloj_eventos();
// Si PUERTA ABIERTA pasamos a modo configuracion
if(analogRead(SensorPuerta) > 500){ //
if(analogRead(SensorPuerta) > 500){
luz_puerta(SI);
// Encendemos la luz de la entrada
modo_configuracion();
luz_puerta(SI);
// Volvemos para iniciar contador otra vez
}else luz_puerta(NO); // Con la puerta cerrada pensamos en apagar la luz de la entrada y en cerrar la cerradura a los x
seg.

}// Del loop

/************************************************************************/
/************
Pintamos la Hora
***********************/
/************************************************************************/
void pinta_reloj(){
int dia;
dia=weekday();
lcd.setCursor(0,0); // Situamos el cursor
if(hour() < 10) lcd.print('0');
lcd.print(hour());
printDigits(minute());
// printDigits_segundos(second());
lcd.print(" ");
/* lcd.print(day(),DEC);
lcd.print("/");
lcd.print(month(),DEC);
lcd.print("/");
lcd.print(year(),DEC); */
switch(dia){
case LUNES:
lcd.print("L");
break;
case MARTES:
lcd.print("M");
break;
case MIERCOLES:
lcd.print("X");
break;
case JUEVES:
lcd.print("J");
break;
case VIERNES:
lcd.print("V");
break;
case SABADO:
lcd.print("S");
break;
case DOMINGO:
lcd.print("D");
break;
}
}//Fin pinta_reloj()
void printDigits(int digits){
// utility function for digital clock display: prints preceding colon and leading 0

lcd.print(":");
if(digits < 10)
lcd.print('0');
lcd.print(digits);
}
void printDigits_segundos(int digits){
// utility function for digital clock display: prints preceding colon and leading 0
lcd.print(".");
if(digits < 10)
lcd.print('0');
lcd.print(digits);
}

/************************************************************************/
/************ Centralizacion de Musiquillas
***********************/
/* Tuve problemas hasta que descubr que sin el delay() no funciona */
/************************************************************************/
void melodia(int tipo){ // Musiquillas 1->Error 2->Inicio 3->Correcto 4->Pulsar tecla 5->puerta abierta 6->Puerta
cerrada
switch(tipo){
case 1:
cerrar_puerta(); // En caso de clave mal, echamos cerrojo
tone(BUZZ,2000);
TiempoError=now(); // Memorizamos hora para recordar el ultimo error
delay(2000*error_acumulativo++); // Mas retraso y acumulativo (puede llegar a un pitido de 35 horas por cada
error)
noTone(BUZZ);
break;
case 2:
tone(BUZZ,1000); delay(50);
tone(BUZZ,4000); delay(50);
tone(BUZZ,1000); delay(50);
noTone(BUZZ);
break;
case 3:
tone(BUZZ,1000); delay(20);
tone(BUZZ,4000); delay(40);
tone(BUZZ,2000); delay(20);
tone(BUZZ,1000); delay(40);
tone(BUZZ,4000); delay(40);
tone(BUZZ,2000); delay(20);
tone(BUZZ,1000); delay(40);
tone(BUZZ,4000); delay(60);
tone(BUZZ,2000); delay(40);
tone(BUZZ,1000); delay(40);
tone(BUZZ,4000); delay(40);
tone(BUZZ,1000); delay(60);
noTone(BUZZ);
error_acumulativo=1; // Reiniciamos la espera si claves errorneas.
break;
case 4:
tone(BUZZ,1000); delay(80);
noTone(BUZZ);
break;
case 5:
tone(BUZZ,2000);
tone(BUZZ,4000);
tone(BUZZ,1000);
tone(BUZZ,4000);

delay(80);
delay(50);
delay(80);
delay(30);

noTone(BUZZ);
break;
case 6:
tone(BUZZ,4000); delay(40);
tone(BUZZ,2000); delay(30);
tone(BUZZ,4000); delay(30);
tone(BUZZ,1000); delay(100);
noTone(BUZZ);
break;
}//Del switch
noTone(BUZZ); // Por si acaso.
}//del melodia()

/************************************************************************/
/* Entramos en modo configuracion al abrir la puerta */
/* Solo saldremos al cerrar la puerta */
/* Mantenemos la luz de la entrada encendida */
/************************************************************************/
void modo_configuracion(void){
char key=0; char estado=0;
melodia(5); // Avisamos de puerta abierta
lcd.setCursor(0,1); // Situamos el cursor
lcd.print(" CONFIG PULSE 0 ");
pctime=now(); // Igualamos pctime al tiempo del sistema.
// Encender luz entrada (y mantenerla despues, quizas usando exceso_de_tiempo())
while(analogRead(SensorPuerta) > 500){ // Mientras la puerta este abierta:
pinta_reloj();
key = keypad.getKey(); //Capturamos tecla
if (key) //new key has been pressed
{
melodia(4); // Pitidito de pulsacion
if(key=='0')
estado++; // Cambiamos de menu con el CERO
if(estado>4)estado=1; // Lo hacemos ciclico
switch(estado)
{
case 1: // BORRAR ENTRADAS ERRONEAS
lcd.setCursor(0,1);
lcd.print(" BORRAR ENTRADA");
if(key=='*'){TiempoError=0;error_acumulativo=1;}
if(key=='#'){TiempoError=0;error_acumulativo=1;}
break;
case 2: // AJUSTAR HORA
lcd.setCursor(0,1);
lcd.print(" AJUSTE HORA ");
if(key=='*'){pctime-=3600;}
if(key=='#'){pctime+=3600;}
setTime(pctime);

// igualamos el tiempo de sistema al de pctime


break;

case 3: // AJUSTAR MINUTOS


lcd.setCursor(0,1);
lcd.print(" AJUSTE MINUTOS");
if(key=='*'){pctime-=60;}
if(key=='#'){pctime+=60;}

setTime(pctime);
break;
case 4: // AJUSTAR DIA
lcd.setCursor(0,1);
lcd.print(" AJUSTE DIA ");
if(key=='*'){pctime-=86400;}
if(key=='#'){pctime+=86400;}
setTime(pctime);
break;
}

} // Del si key
} // Del while
lcd.clear();
// Al salir hay que limpiar el display
melodia(6); // Cantamos q la puerta se cierra
}

/************************************************************************/
/* COMPROBAMOS LAS TECLA PULSADAS en busca de claves */
/************************************************************************/
void clave_tecla(char Tecla){
static char oldkey, posicion_clave=0;
static char Clave[15];
if(exceso_de_tiempo(10, COMPROBAR)){posicion_clave=0; melodia(1); return;} // Damos seal de error
if (Tecla != oldkey) //new key has been pressed
{
if (Tecla)
{
melodia(4); // Pitidito de pulsacion
exceso_de_tiempo(10, INICIAR);

Clave[posicion_clave]=Tecla;
Clave[posicion_clave+1]=0; // Finalizamos la cadena para evitar errores
if(posicion_clave < 14){ posicion_clave++; }
else{ // Si metemos 15 num y no hay clave hay que esperar
posicion_clave=0;
melodia(1);
exceso_de_tiempo(10, ANULAR);
// Implantar esperas si se mete codigo erroneo X veces
}
if(!strcmp(Clave, Clave1)){
clave_correcta();

// CLAVE CORRECTA
// abrir puerta

posicion_clave=0; // Reiniciamos contador


}
if(!strcmp(Clave, Clave2)){ // CLAVE CORRECTA
clave_correcta();
// abrir puerta
posicion_clave=0; // Reiniciamos contador
}
/* La clave3 funcionar los dias de curro de 2 a 9 (OJO Hasta el RTC pongo todos los dias de
9 a 23) */
if(hour()>9 && hour()<23 /* && day()!=DOMINGO && day()!=SABADO*/)
if(!strcmp(Clave, Clave3)){ // CLAVE CORRECTA
clave_correcta();
// abrir puerta
posicion_clave=0; // Reiniciamos contador
}
/* CLAVES DE UN SOLO USO */
if(!EEPROM.read(100))
if(!strcmp(Clave, Clave4)){ // CLAVE CORRECTA
clave_correcta();
// abrir puerta
posicion_clave=0; // Reiniciamos contador
EEPROM.write(100, NO); // La clave queda invalidada // OJO poner temporizacion
para que se pueda usar durante ~10 min.
}
if(!EEPROM.read(101))
if(!strcmp(Clave, Clave5)){ // CLAVE CORRECTA
clave_correcta();
// abrir puerta
posicion_clave=0; // Reiniciamos contador
EEPROM.write(101, NO); // La clave queda invalidada
}
if(!EEPROM.read(102))
if(!strcmp(Clave, Clave6)){ // CLAVE CORRECTA
clave_correcta();
// abrir puerta
posicion_clave=0; // Reiniciamos contador
EEPROM.write(102, NO); // La clave queda invalidada
}
oldkey = Tecla; // Antirebotes
}
else // Si no hay tecla pulsada o tecla no correcta
{
oldkey = 255;
}
} // Del si tecla != oldkey
}
/*****************************************************/
/* Abrir puerta, cerrarla luego, memorizar evento y */
/*****************************************************/
void clave_correcta(){
digitalWrite(ABRIRCERRADURA, ACTIVO); // abrimos puerta
melodia(3); // Usamos melodia de timer
digitalWrite(ABRIRCERRADURA, INACTIVO); // Dejamos de abrir puerta
exceso_de_tiempo(10, ANULAR);
}
/*****************************************************/
/* Cerrar Puerta solo si esta cerrada, memorizar evento y */
/*****************************************************/
void cerrar_puerta(){

if(analogRead(SensorPuerta) < 500){ //Si la puerta est cerrada


digitalWrite(CERRARCERRADURA, ACTIVO); // Echamos el cerrojo
melodia(6); // Avisamos del cierre y lo usamos de timer
digitalWrite(CERRARCERRADURA, INACTIVO); // Dejamos de cerrar
}
}
/************************************************************************/
/* Para comprobar si ha pasado mucho tiempo (en segundos) sin respuesta */
/************************************************************************/
char exceso_de_tiempo(int tiempo_espera, char tipo_operacion)
{
static time_t hora2=0;
pctime=now();
if(tipo_operacion == INICIAR) hora2=pctime;
if(tipo_operacion == ANULAR) hora2=0;
if(tipo_operacion == COMPROBAR){
if(hora2){

// Para que no salte sin iniciar


if((hora2+tiempo_espera) < pctime){
hora2=0;
// Para no comprobar de nuevo sin iniciar
return SI; // TIEMPO DE ESPERA EXCEDIDO
}

}
}
return NO; // Tiempo de espera no excedido
}

/************************************************************************/
/* Pintamos horas de eventos especificos */
/************************************************************************/
void pinta_reloj_eventos(){
int dia;
dia=weekday(TiempoError);
lcd.setCursor(0,1); // Situamos el cursor
if(hour() < 10) lcd.print('0');
lcd.print(hour(TiempoError));
printDigits(minute(TiempoError));
lcd.print(" ");
/* lcd.print(day(),DEC);
lcd.print("/");
lcd.print(month(),DEC);
lcd.print("/");
lcd.print(year(),DEC); */
switch(dia){
case LUNES:
lcd.print("L");
break;
case MARTES:
lcd.print("M");
break;
case MIERCOLES:

lcd.print("X");
break;
case JUEVES:
lcd.print("J");
break;
case VIERNES:
lcd.print("V");
break;
case SABADO:
lcd.print("S");
break;
case DOMINGO:
lcd.print("D");
break;
}
} // Fin del void pinta_reloj_eventos()

/******************************************************************/
/**
Encendemos y apagamos la luz de la entrada
**/
/**
La luz se apaga con 20seg de reatraso
**/
/** Tambin cerramos la cerradura a los 20 seg de cerrar puerta **/
/******************************************************************/
void luz_puerta(char estado)
{
static time_t horaX=0;
if(estado){
//GPIO_WriteHigh(GPIOA, GPIO_PIN_3); // Encendemos luz
horaX=now(); // Empezamos a contar (cada vez que pasemos por aqui, empezamos a contar)
}else{
// Si el estado es NO, nos preparamos para apagar y cerrar
if((horaX) && (now() > (horaX+20))){
//GPIO_WriteLow(GPIOA, GPIO_PIN_3); //Apagar luz
cerrar_puerta();
horaX=0; // Reiniciamos el contador
}
} // Del else
}

Example
1.
#include <Password.h>
2.
3.
Password password = Password( "1234" );
4.
5.
void setup(){
6.
Serial.begin(9600);
7.
8.
password.append('1');//add 1 to the guessed password
9.
password.append('2');//add 2 to the guessed password
10.
password.append('3');//add 3 to the guessed password
11.
password.append('4');//add 4 to the guessed password
12.
//should print true, since 1234 == 1234
13.
Serial.println( password.evaluate()?"true":"false" );
14.
15.
password.reset(); //reset the guessed password to NULL
16.
//should print false, since 1234 != NULL
17.
Serial.println( password.evaluate()?"true":"false" );
18.
19.
password.set("qwerty"); //set target password to qwerty
20.
//should print true, since qwerty == qwerty
21.
Serial.println( password.is("qwerty")?"true":"false" );
22.
//should print false, since qwerty != qwirty
23.
Serial.println( password.is("qwirty")?"true":"false" );
24.
}
25.
26.
void loop(){/*nothing to loop*/}

Teclado numrico 34 con


LCD
10 enero, 2012Arduino, Micros, Teclado numrico con LCD.Arduino, Cristal
Liquido,HD44780, Keypad, LCD, LiquidCrystal, Switch, Teclado

Prologo.
En otro artculo ya hice un esbozo superficial sobre las pantallas de cristal lquido LCD,
distinguiendo dos grandes grupos, las pantallas alfanumricas y las pantallas grficas.
Por el momento, nos referiremos las pantallas LCD alfanumricas, en concreto las de
cuatro lneas y 40 columnas. En la actualidad la mayora de los LCD estn controlados
con el conocido HD44780 de Hitachi. El cual puede ser configurado para manejar un
display de matriz de puntos de cristal lquido bajo el control de un microprocesador de 4
u 8 bits.
En este artculo, pretendo hacer una aplicacin que tenga utilidad para quien disponga
de un LCD y quiera realizar una aplicacin que le sirva de ayuda en su trabajo o para
una aplicar en un proyecto. Hay muchas aplicaciones descritas en gran cantidad de
artculos y webs de distintos autores y en todas ellas subyace un toque personal que
hace la diferencia, espero que en este, tambin encuentren la novedad o el punto que
buscaban.
El propsito de este artculo es reunir una serie de unidades sencillas, como base de
los ejemplos, con pantalla de cristal lquido LCD, que se encuentran disponibles para
trabajar con Arduino. Se describen algunos ejercicios para comprender los principios de
uso y sin perder el carcter didctico de lo descrito.

Display LCD.
El uso de este dispositivo se ha extendido en los ltimos aos debido a la proliferacin
de los microcontroladores con sus cada ves mayores prestaciones y los sistemas de
desarrollo que los sustentan. Hay esencialmente dos tipos de pantalla para elegir, serie
y paralelo, en referencia a cmo se conectan y se comunican con el mismo PC.

En cuanto a los LCD, en el mercado


pueden encontrarse distintos modelos que se adaptan a las necesidades de los
proyectos que se planteen. As, podemos encontrar LCD de una lnea y 8 a 40
caracteres, 4 lneas por 40 caracteres y tantas lneas y caracteres que se necesiten.
Los LCD grficos estn avanzando tanto que sus precios son cada da ms asequibles
a cualquier necesidad.

La mayora de los LCD paralelos son muy similares, usan chips de interfaz estndar en
la industria (como el HD44780 o HD44100) para la asignacin de pines, a menudo son
idnticos.

En este artculo, slo tratar de los LCD de cuatro


lneas y 20 caracteres o columnas. Naturalmente por que es el que tengo a mi
disposicin. Para controlar pantallas Cristal Liquido (LCD) basada en el Hitachi
HD44780 (o compatible) se necesita la Nueva librera LiquidCrystal que nos
proporciona FM, como se le conoce en el foro. Adems, tambin utilizaremos un
teclado 34 similar al de la imagen de abajo, dos resistencias, dos LEDs, dos
pulsadores y algunos hilos de colores para conectar todo.No voy a entrar sobre los pros
y los contras de cada uno, ya que este no es el objetivo del presente artculo, sin
embargo, lo que voy a decir es que que, fundamentalmente, la decisin se reduce a su
costo en comparacin con la facilidad de uso, es la cuestin.

Si bien los displays serie son ms fciles de poner en marcha y


tienen un poco mejor ayuda con el software, adems de tener algunas caractersticas
adicionales. Por otro lado, los LCD paralelos, necesita cablearlas usted mismo, pero
son mucho ms baratos y en su mayor parte se puede mostrar la misma informacin.

Lo que pretendo realizar es un teclado, con el


que introducir una clave de un nmero de entre 4, 6 o ms dgitos y el programa
compare los dgitos que se pulsan por el usuario, con la clave guardada y si hay
coincidencia que, haga una cosa, en caso de no coincidir que, haga otra cosa. En
principio, se ve sencillo.

Para abordar el proyecto, necesitamos unos pocos


materiales a parte de la placa Arduino y el LCD, como estos mostrados.
El ms importante, el teclado, este tipo de teclados, a pesar de que es de los aos 80
(foto de Futurlec), es bastante corriente y fcil de encontrar en el mercado. El resto de
componentes, es de uso comn. El circuito electrnico que voy a utilizar se muestra en
la imagen que sigue.

Mediante la ayuda de un teclado de 12


pulsadores, podemos entrar una serie de dgitos que, formen el cdigo secreto para
activar un sistema, si existe coincidencia o por el contrario, pondr en accin otro
sistema que indique que, se est forzando el acceso no autorizado a la instalacin, por
un desconocido.
Para esto, en primer lugar debemos configurar la librera Keypad.zip y declararemos los
7 pines de Arduino que conformaran el teclado, por un lados las 4 lneas (rows) y las 3
columnas (cols) y la conformacin que tomarn los contactos, como se puede ver a
continuacin:
El primer paso es incluir la librera y las constantes que vamos a utilizar:
?

Ver cdigo PHP

1
2
3
4
5
6
7
8
9
10

#include "Keypad.h"
const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] = {
{'1','2','3'},
{'4','5','6'},
{'7','8','9'},
{'*','0','#'}
};

El paso que sigue es, reservar memoria en bytes, para los valores de los pulsadores y
la asignacin del pin que se corresponde con los de Arduino. Sin embargo, hay que
observar que, vamos a necesitar un nmero alto de pines en este y los siguientes
ejemplos. Por este motivo, la asignacin de pines, se hace con vistas a no tener que
cambiar con frecuencia dicha disposicin. Adems, se asignaran otras variables, en
funcin de las necesidades que surjan.
?

Ver cdigo PHP

1
2

byte rowPins[ROWS] = {5, 4, 3, 2}; //conecta los pinouts row del keypad
byte colPins[COLS] = {8, 7, 6}; //conecta los pinouts column del keypad

Este es el momento de crear el teclado propiamente dicho, es decir, con esta


sentencia, el programa generar una matriz que ver como un teclado, al que se
remitir, cuando tenga que representar un dgito. Esto se consigue con la siguiente
lnea:
?

Ver cdigo PHP

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

Tenemos que guardar una clave, luego, necesitamos hacer una reserva de memoria y
adems, el cdigo que introduzca el usuario, tambin requiere un espacio de memoria.
Posteriormente, con slo comparar ambas matrices, obtendremos fcilmente si hay
coincidencia entre ambas. Veamos como se hace:
?

Ver cdigo PHP

1
2

char PIN[6]={'1','2','3','4','5','6'}; // o numero secreto (!)


char attempt[6]={0,0,0,0,0,0}; // usado para comparar

En la asignacin de las dos matrices de 6 dgitos, utilizamos la funcin char para


almacenar los bytes de cada matriz. Una, para los dgitos de entrada llamada attempt,
se compararn con la otra matriz, contenida en PIN. Slo, si hay coincidencia, la clave
es correcta y actuar la salida correspondiente. Se han dispuesto dos salidas
complementarias, las cuales se pueden conectar a los dispositivos adecuados que,
deriven la potencia necesaria para sus actuadores.
En el setup, configuramos los distintos pines, segn convenga a cada uno, se declara
el puerto serie y su velocidad:

Ver cdigo PHP

1
2
3
4
5
6

pinMode(sal1, OUTPUT);
pinMode(sal2, OUTPUT);
Serial.begin(9600); //Configura la velocidad del puerto serie
keypad.setHoldTime(500); // Default is 1000mS
keypad.setDebounceTime(250); // Default is 50mS

Destacar las funciones que afectan al rebote de los pulsadores que, estn integrados
en
la
librera keypad representados
por keypad.setHoldTime y keypad.setDebounceTime. Aqu. se ha reducido su
tiempo de mantenimiento como se puede apreciar en el propio cdigo.
Adems, se ha incluido el mensaje que presentar al inicio del programa. En este
mensaje, se puede hacer una descripcin corta de lo que hay que hacer para entrar el
cdigo PIN. Esto se ha hecho con el siguiente cdigo:
?

Ver cdigo PHP

1
2
3
4
5

Serial.println(" Debe introducir la secuencia: ");


Serial.print(" * X X X X X X # ");
Serial.println(" &gt;&gt; X = del 0 al 9");
incorrectPIN();Serial.print(" ");
Serial.println(" Intentelo: ");

En este punto, para una mayor claridad, se deben declarar las rutinas que intervengan
en el programa, acurdese de hacer comentarios, para poder comprender qu hace
cada rutina. As pues, se declara la rutina void correctPIN() que, se ejecutar en el caso
de haber coincidencia, es decir:
?

Ver cdigo PHP

1
2

digitalWrite(10, LOW); // desactiva un contacto pin 1


digitalWrite(11, HIGH); // activa un contacto pin 2

Y le seguir la rutina void incorrectPIN() que se ejecutar en el caso contrario. Que


hace exactamente lo mismo pero invertidos
?

Ver cdigo PHP

1
2

digitalWrite(11, LOW); // desactiva un contacto pin 2


digitalWrite(10, HIGH); // activa un contacto pin 1

Se ha incluido una rutina para activar un sistema (en este caso, visual) para activar un
LED en su caso. Con void readKeypad(), se lee cualquier entrada de teclado, o sea,
hace un chequeo del teclado, de modo que cuando se presione un pulsador o llave.
Esto lo consigue mediante este cdigo, asignando a char key, todo lo que llegue por el
teclado con: char key = keypad.getKey(); si no se produce una entrada, permanecer
en espera. Gracias a esta sentencia de if (key != NO_KEY), en la cual permanecer la
ejecucin del programa, esperando a que se produzca una entrada. As que, este es el
listado:
?

Ver cdigo PHP

1
2

char key = keypad.getKey();


if (key != NO_KEY)

Le sigue la funcin switch (key) que es capaz de detectar la tecla que se ha pulsado.
Cuando se produce una entrada del teclado, se guarda en la variable attempt, lo
reconoce y evala con PIN[] si es exactamente igual, sale de esta subrutina y salta a la
subrutinacorrectPIN() y sigue hasta el final de la misma.
En caso de que la evaluacin no sea exacta, salta a la subrutina incorrectPIN(); y
cuando termina, vuelve hasta la lnea: for (int zz=0; zz<6; zz++) // borrar tentativa, para
borrar la tentativa actual.
En ltimo lugar est el lazo o loop() que, en este caso, contiene la llamada
a readKeypad();que ejecutar continuamente.
Veamos un primer ejemplo, este es el cdigo para el programa de reconocimiento de
clave:

Nmero PIN
?

Ver cdigo PHP


1
2
3
4
5
6
7
8

//
// pin_clave.pde - keypad switch con seis-digitos para el PIN
// basado en un programa de: http://tronixstuff.wordpress.com/
/* Usando el actual ejemplo de hardware se pueden activa algo o
desactivar mediante el teclado - emulando lo que se puede
encontrar en algunos sistemas de alarma y as sucesivamente.
Nuestro objetivo con este ejemplo es muy simple. El sistema

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71

espera para obtener un PIN que se guarda previamente.


Si el PIN es correcto, hacer algo. Si el PIN es incorrecto,
hacer otra cosa. Este ejemplo es para darle un concepto y un
marco para construir ideas propias.
19.10.2011 funciona bien.
*/
#include "Keypad.h"
const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns char
keys[ROWS][COLS] = {
{'1','2','3'},
{'4','5','6'},
{'7','8','9'},
{'*','0','#'}};
byte rowPins[ROWS] = {
5, 4, 3, 2}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {
8, 7, 6}; //connect to the column pinouts of the keypad
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
char PIN[6]={'1','2','3','4','5','6'}; // su numero secreto (!)
char attempt[6]={0,0,0,0,0,0}; // usado para comparar int z=0;
int led13= 13; int sal1 = 10; // salida1, pin A4
int sal2 = 11; // salida2, pin A5
void setup()
{
pinMode(sal1, OUTPUT);
pinMode(sal2, OUTPUT);
Serial.begin(9600); //Configura la velocidad del puerto serie
keypad.setHoldTime(500); // Default is 1000mS
keypad.setDebounceTime(250); // Default is 50mS
Serial.println(" Debe introducir la secuencia: ");
Serial.print(" * X X X X X X # ");
Serial.println(" &gt;&gt; X = del 0 al 9");
incorrectPIN();
Serial.print(" ");
Serial.println(" Intentelo: ");
}
void correctPIN() // hacer esto. Si el PIN escrito es correcto
{
digitalWrite(10, LOW); // desactiva un contacto pin 1
digitalWrite(11, HIGH); // activa un contacto pin 2
Serial.print(" Correcto ");
Serial.print(attempt);
}
void incorrectPIN()
// hacer esto. Si el PIN escrito es incorrecto
{
digitalWrite(11, LOW); // desactiva un contacto
digitalWrite(10, HIGH); // activa un contacto
Serial.print("Incorrecto ");
//Serial.print(" ");
}
void led()
{
if (led13 == LOW)
led13= HIGH;
else
{
led13 = LOW;
}

72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114

}
void checkPIN()
{
int correct=0;
for (int q=0; q&lt;=5; q++)
{
if (attempt[q]==PIN[q])
{ correct++;
}
}
if (correct==6)
{ correctPIN();
} else
{ incorrectPIN();
}
for (int zz=0; zz&lt;6; zz++) // borrar tentativa
{ attempt[zz]=0;
}
}
void readKeypad()
{
char key = keypad.getKey();
if (key != NO_KEY)
{
switch(key)
{
case '*': z=0;
Serial.println(" ");
break;
case '#': delay(50);
Serial.println(" ");
checkPIN();
break;
default: attempt[z]=key; z++;
}
Serial.print("*");
led();
}
}
void loop()
{
readKeypad();
}

Este cdigo, es susceptible de ser modificado y mejorado, sin duda. Por ese motivo,
vamos a seguir en nuestro empeo en descubrir nuevos modos de lograr ese resultado
e incluso mejorarlo. A continuacin, veremos otra forma de enfocar el proyecto para
lograr el mismo resultado.

Ejemplo PIN con LCD.


Esto esta listo, sin embargo, si le aadimos un LCD, tendremos un proyecto mucho ms
profesional que, podremos incluir en un proyecto que requiera de un sistema de

seguridad que, incluya una clave de 6 o ms dgitos. Veamos los pasos a seguir, para
comprender cmo lograrlo.

EL CIRCUITO.
En primer lugar, presento el esquema electrnico es muy sencillo, a pesar de los cables
que necesita utilizar para el conexionado de los distintos componentes. Se adjunta el
archivo Fritzing, aunque lleva pequeas modificaciones (el teclado y el PCF8574 son de
mi creacin).

Como
previsiblemente se van a necesitar muchos puertos del Arduino, he pensado en aplicar
un expansor de puertos, para actualizar y refrescar conocimientos, se puede leer

el expansor de puerto. Aqu, lo utilizamos para interconectar el teclado, porque necesita


7 entradas/salidas, de igual modo, se podra haber utilizado para el LCD. En este
ejemplo, se ha dotado de un display LCD de 204 como se aprecia en el circuito
anterior.

El cdigo.
El siguiente es el cdigo del segundo ejemplo, en este listado, he introducido unos
cambios que permitirn una mayor flexibilidad, en el especto de margen de clave a
utilizar, gracias a usar la librera Password que, nos facilita esta labor a la hora de crear
y comparar una matriz de n dgitos.
La idea es la misma descrita en el ejemplo anterior. La inclusin de un LCD, para su
control, hace necesario el uso de la librera LiquidCrystal, por supuesto, tambin hace
falta usar las libreras incluidas en el ejemplo anterior que, no es necesario repetir.
Un punto a resaltar es que debido a que necesitamos ms puertos del Arduino, en este
caso, vamos a utilizar las entradas analgicas como entradas digitales, esto es posible
si los declaramos con el numeral que le corresponde, es decir, en Arduino, los pines
digitales normalmente, van del pin0 al pin13. Segn el playground de Arduino:
?

Ver cdigo PHP

1
2
3
4
5
6
7
8
9
10

Mapeo de Pins.
Los pines de Arduino correspondientes a los pines analgicos son desde el 14
al 19.
Observa que esto son pines de Arduino y no corresponden con los nmeros
de los pines fsicos del chip Atmega. Los pines analgicos, pueden usarse
de manera idntica que los digitales, as que por ejemplo, podras ver un
cdigo como este para configurar un pin analgico, y establecerlo a HIGH:
pinMode(14, OUTPUT);
digitalWrite(14, HIGH);

Aqu, usaremos los siguientes, del pinA0 por pin14 a pinA3 por pin17, procurando no
utilizar los pines analgicos pinA4 y pinA5, por si se emplean en algn momento como
E/S I2C.
?

Ver cdigo PHP

byte rowPins[ROWS] = {5, 4, 3, 2}; // pines a conectar los row del teclado.

2 byte colPins[COLS] = {16, 15, 14}; // AN0, AN1 y AN2. Por falta de pines
3 const int buttonPin = 6; // para los rels mediante una R de 10k y un
4 transistor NPN
5 int sal1 = 17; // pin A4 salida a rele
int sal2 = 18; // pin A5 salida a rele

En la subrutina: void keypadEvent(KeypadEvent eKey) se hace atiende al teclado y


compara con la clave guardada. La subrutina: void guessPassword() es la que,
mediante la ayuda de un transistor universal NPN, permite activar o desactivar un rel
con el que, podemos manejar la potencia necesaria para abrir o cerrar el sistema de
acceso, si es el caso.

Nmero PIN largo.


?

Ver cdigo PHP


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

/* password_lcd.pde
Basado en artculos de la red.
Modificado y adaptado el 07.11.2011 por V. Garcia.
Para hispavila.com Utilizamos las libreras:
[Password.h LiquidCrystal.h Keypad.h] que puede
encontrar en:
http://www.hispavila.com/3ds/atmega/clavenum.html
Usando el actual ejemplo de hardware se pueden activa
algo o desactivar mediante el teclado - emulando lo
que se puede encontrar en algunos sistemas de alarma y
as sucesivamente. Nuestro objetivo con este ejemplo
es muy simple. Un sistema de espera para obtener un PIN
que se especifique previamente. Si el PIN es correcto,
hacer algo. Si el PIN es incorrecto, hacer otra cosa.
Lo que las acciones pueden llegar a hacer. Con el proyecto
vamos a activar o desactivar una salida digital.
Este ejemplo es para darle un concepto y un marco para
adaptar o construir ideas propias.
Usa 4654 bytes con el IDE v. 00013
*/
#include &lt;Password.h&gt;
#include &lt;LiquidCrystal.h&gt;
#include &lt;Keypad.h&gt;
LiquidCrystal lcd(7, 8, 9, 10, 11, 12); Password
password = Password( "1234456" ); // aqu puede poner su pasword
const byte ROWS = 4; // Cuatro rows
const byte COLS = 3; // Tres columns
// Define el Keymap
char keys[ROWS][COLS] = {
{'1','2','3',},
{'4','5','6',},
{'7','8','9',},
{'*','0',' ',} };
// Conectar keypad ROW0, ROW1, ROW2 y ROW3 a los pines de Arduino.
byte rowPins[ROWS] = {5, 4, 3, 2}; // pines a conectar los row del teclado.
byte colPins[COLS] = {16, 15, 14}; // AN0, AN1 y AN2. Por falta de pines
const int buttonPin = 6; //
int buttonState = 0;

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101

int i;
int sal1 = 17; // pin A4 salida a rele
int sal2 = 18; // pin A5 salida a rele
// Crear el Keypad
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
#define ledPin 13
void setup()
{
pinMode(buttonPin, INPUT);
pinMode(sal1, OUTPUT);
pinMode(sal2, OUTPUT);
pinMode(ledPin, OUTPUT);
lcd.begin(20, 4);
digitalWrite(ledPin, LOW);

// pone el LED off

Serial.begin(9600);
keypad.addEventListener(keypadEvent); //aad. un evento listener para el
keypad
keypad.setDebounceTime(250);
lcd.clear();
//Borra el LCD
lcd.setCursor(0,0);
lcd.print("Entre secuencia PIN:");
lcd.setCursor(2,2);
lcd.print("* Para terminar");
lcd.setCursor(0,3);
lcd.print(" Intentelo: ");
}
void loop()
{
keypad.getKey();
buttonState = digitalRead(buttonPin);
if (buttonState == HIGH)
{
lcd.clear();
}
}
// atender algunos eventos especiales
void keypadEvent(KeypadEvent eKey)
{
switch (keypad.getState())
{ case
PRESSED: lcd.print(eKey);
switch (eKey)
{
case ' ': guessPassword();
break;
default: password.append(eKey);
}
}
}
void guessPassword()
{
if (password.evaluate())
{
digitalWrite(ledPin,HIGH); // activa el LED de la puerta .5 seg.
delay(500);
digitalWrite(ledPin,LOW); // desactiva LED de la puerta
digitalWrite(sal1, HIGH); // activa rel1 de la puerta
digitalWrite(sal2, LOW); // desactiva rel2 de la puerta
lcd.clear();
lcd.setCursor(0,0);

102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140

lcd.print("PASSWORD VALIDO "); //


password.reset(); //resetea password despues de entrada correcta
delay(1000);
lcd.setCursor(0,0);
lcd.print("Bienvenido, Sr.");
delay(1000);
for (int positionCounter = 0; positionCounter &lt; 22; positionCounter++)
{
// scroll one position right:
lcd.scrollDisplayRight(); // espera un poco
delay(150);
}
delay(35000); // espera 35 segundos antes de volver a inicio
setup(); // al inicio
} else
{
i = i++;
digitalWrite(ledPin,LOW);
digitalWrite(sal1, LOW);
digitalWrite(sal2, HIGH);
lcd.clear();
lcd.print("PASSWORD INVALIDO ");
password.reset(); //resets password after INCORRECT entry
delay(2000); // tiempo de retardo
lcd.clear();
lcd.setCursor(0,2);
lcd.print(" Intentelo: ");
}
if (i==3)
{
lcd.setCursor(0,1);
lcd.print("Lo siento... ");
lcd.setCursor(0,2);
lcd.print("Intentelo mas tarde");
delay(30000);
lcd.clear();
lcd.setCursor(0,2);
lcd.print(" Intentelo: ");
i=0;
}
}

A estas subrutinas, se les ha incluido unos mensajes que, estn acordes en cada caso,
para hacer comprender al usuario, la situacin que impera en cada momento. De modo
que al iniciar el proceso, rige un mensaje que invita a introducir un nmero PIN y la
forma de hacer su entrada mediante la pulsacin de la tecla * (asterisco), como
confirmacin del PIN introducido.
Mediante la librera Pasword, se evala el PIN introducido y se produce un destello de
un LED por un corto perodo de tiempo 1/2 segundo cuando hay coincidencia con la
clave correcta. En ese momento, el mensaje que muestra la pantalla LCD, cambia a un
nuevo mensaje que, le indica al usuario que ha obtenido el acceso y termina el
proceso.

Un tiempo despus (este intervalo de tiempo se puede ajustar a su gusto, antes de


compilar), se vuelve a inicia todo el proceso, a la espera de un nuevo intento por un
nuevo usuario.
Este ejemplo es un proyecto completo, ya que como elementos externos, slo
necesita de dos resistencias de 10k, dos transistores universales NPN y dos diodos
1N4007 y dos rels de 12V con doble contacto o similar, para poder activar cargas de
mayor consumo. Para terminar el presente tutorial, se muestra un archivo AVI que
ilustra el proyecto.
Por supuesto que pude utilizar un dispositivo expansor de puertos como el conocido
PCF8574. No lo he incluido en este diseo, por que los pines del Arduino Diecimila,
estn clavados, es decir, el proyecto no necesita ms de los que ya tiene. Sin
embargo se muestra una distribucin del mismo proyecto utilizando el PCF8574, por si
alguien lo quisiera incluir.

En este
diseo, para mayor claridad, no se han incluido los rels y los componentes asociados
para su control.
Nota.- En estos ejemplos, se utilizado un LCD de 204, sin duda que el usuario, puede
adaptar otro tipo de LCD, modificando los pines que se dedican al control de cada tipo
de LCD.

string

Descripcin
Los strings se representan como arrays de caracteres (tipo char)
que terminan con el caracter NULL.

Ejemplos
Todas las siguientes son declaraciones vlidas de strings.
char
char
char
char
char
char

Str1[15];
Str2[8] = {'a', 'r', 'd', 'u', 'i', 'n', 'o'};
Str3[8] = {'a', 'r', 'd', 'u', 'i', 'n', 'o', '\0'};
Str4[ ] = "arduino";
Str5[8] = "arduino";
Str6[15] = "arduino";

Posibilidades de declaracind e strings

Declarar un array de caracteres sin incializarlo como en Str1


Declarar un array de caracteres (con un caracter extra) y el
compilador aadir el caracter NULL requerido, como en STR2
Explicitar el caracter NULL, Str3

Inicializar con un string constante entre comillas dobles; el


compilador medir el tamao del array para ajustar el string
constante y caracter NULL para finalizar, Str4

Inicializar el array con un tamao explcito y un string


constante, Str5

Inicializar el array, dejando un espacio extra para un string


ms largo, Str6
Terminacin NULL
Generalmente, los strings se finalizan con un caracter NULL (cdigo
ASCII 0). Esto permite a funciones (como Serial.print()) establecer
dnde est el final del string. De otra forma, seguira leyendo los
siguientes bytes de la memoria que no forman parte del string.

Esto significa que tu string necesita tener espacio para un caracter


ms del texto que quieres que contenga. Esto es por lo que Str2 y
Str5 necesitan 8 caracteres, incluso aunque "arduino" tenga slo 7 la ltima posicin es automticamante completada con un caracter
NULL. Str4 ser automticamente dimensionada a 8 caracteres, uno
para el NULL extra. En Str3, hemos incluido nosotros mismos el
caracter NULL (escrito como '\0').
Ten en cuenta que es posible tener un string sin un caracter NULL al
final (p.e. si t has especificado la longitud de Str2 como 7 en lugar
de 8). Esto romper la mayora de funciones que usen strings, por
lo que no deberas hacerlo intencionadamente. Por lo tanto, si
detectas algn comportamiento extrao (operando con los
caracteres, no con el string), este podra se el problema
Comillas simples o dobles
Los string siempre se definen entre comillas dobles ("Abc") y los
caracteres siempre se definen dentro de comillas simples ('A').
Envolviendo string largos
Puedes envolver strings largos de sta manera:
char miString[] = "Esta es la primera linea"
" esta es la segunda linea"
" etcetera";

Arrays de strings

Amenudo es conveniente, al trabajar con grandes cantidades de


texto, como proyectos con displays LCD, configurar un array de
strings. Como los strings son en s mismo arrays, esto es un
ejemplo real de un array bidimensional.
En el cdigo de abajo, el asterisco despus del tipo de dato char
"char*" indica que es un array de "punteros". Todos los nombres de
arrays son punteros, por lo que esto es necesario para crear un
array de aarys. Los punteros son una de las partes ms exotricas
de C como para que los principieantes puedan llegar a entenderlas,
pero no es necesario entender punteros en detalle para usarlos con
efectividad.
Ejemplo
char* miStrings[]={"Este es el string 1", "Este es el string 2", "Este es el string 3",
"Este es el string 4", "Este es el string 5","Este es el string 6"};
void setup(){
Serial.begin(9600);
}
void loop(){
for (int i = 0; i < 6; i++){
Serial.println(miStrings[i]);
delay(500);
}
}
#include <EEPROM.h>
int a = 0;
int valor;
void setup()
{
Serial.begin(9600);
}
void loop()
{

valor = EEPROM.read(a);
Serial.print(a);
Serial.print("\t");
Serial.print(value);
Serial.println();
a = a + 1;
if (a == 512)
a = 0;
delay(500);
}
#include <EEPROM.h>
void setup()
{
for (int i = 0; i < 512; i++)
EEPROM.write(i, i);
}
void loop()
{
}

Cadena (Formalmente Cadena de caracteres) Librera

Desde la versin 0.8, esta librera ha sido actualizado usando la API


de la Librera de unin de cadenas, esta fue basada en la versin
0.1 y fue extendida por Hernando Barragan. La descarga de arriba
contiene ejemplos adicionales y una versin compatible con
Arduino.
La version 0.8 es la correccin de la versin anterior. Exista una
problema con la memoria, solucionado por Mikal Hart. Esta es una
publicacin provisional.
Mucho del trabajo en programacin se basa en enviar y recibir
cadenas de texto de datos en ASCII. Aunque Arduino no es una

plataforma diseada para manipulaciones complejas de cadenas de


caracteres, hay veces que se necesita leer una cadena o hacer otras
operaciones con las mismas. Puede que ests intentando leer datos
proveniente de un receptor GPS, o enviando comandos a un
transmisor Bluetooth o Zigbee que usa comandos estilo AT. Si eso
es lo que intentas hacer, esta librera es para ti.
Descarga: String.zip
Para usar, descomprime el archivo y copia los archivos
descomprimidos a la carpeta lib/targets/libraries dentro del
directorio de la aplicacin Arduino. Despus reinicia la aplicacin.
Cuando reinicies la aplicacin, vers algunos mensajes de
advertencia en el panel de depuracin que est en la parte inferior
del programa los cuales puedes ignorar.
Existe una diferencia entre la esa versin y esta: La librera String
de Arduino contiene la funcin
funcin

toCharArray().

getChars()

en vez de la

El funcionamiento de ambas funciones es el

mismo. El nombre se cambi para que existiera coherencia en los


nombres.
Esta versin ha sido probada con la versin de la aplicacin Arduino
0015.
Funciones:
char charAt(int posicin) - Devuelve el carcter en posicin
(argumento de la funcin)

void append(String estaCadena) - Aade la representacin(cadena)


estaCadena a otra. estaCadena puede se un entero, long, carcter o
array de caracteres
int capacity() - Devuelve la capacidad interna de la cadena. Esto es
diferente del nmero de caracteres de la cadena
boolean contains(String thisString) - Devuelve verdadero si la
cadena contiene estaCadena
byte[] getBytes() - Devuelve un array de bytes de la Cadena
char[] getChars() - Devuelve un array de caracteres de la Cadena
void setCharAt(int posicion, char esteCaracter) - cambia el carcter
en posicion a esteCaracter
boolean endsWith(String estaCadena) - Devuelve verdadero si la
cadena actual acaba con estaCadena
boolean equals(String estaCadena) - Devuelve verdadero si la
cadena es igual a estaCadena
int indexOf(char esteCaracter) - Devuelve la posicin de la primera
coincidencia con esteCaracter
int length() - Devuelve el numero de caracteres de la cadena.
void replace(char esteCaracter, char aquelCaracter) - Sustituye
todos los caracteres que coinciden con esteCaracter por
aquelCaracter

boolean startsWith(String estaCadena) - Devuelve verdadero si la


cadena comienza con estaCadena
String substring(int inicio, int final) - Devuelve una subcadena que
comienza en la posicin inicio y acaba en la posicin final de la
cadena que estamos tratando.
void toLowerCase() - Convierte todos los caracteres en minsculas.
void toUpperCase() - Convierte todos los caracteres en maysculas.

This example is for Wiring version 1.0 build 0100+. If you have a previous version, use the examples
included with your software. If you see any errors or have comments, please let us know.
DynamicKeypad by BREVIG http://alexanderbrevig.com
*** THE KEYPAD REQUIRES PULL-UP RESISTORS ON THE ROW PINS. *** * This is a demonstration of
keypadEvents. It's used to switch between keymaps while using only one keypad. The main concepts being
demonstrated are: Using the keypad events, PRESSED, HOLD and RELEASED to simplify coding. How to use
setHoldTime() and why. Making more than one thing happen with the same key. Assigning and changing
keymaps on the fly.
Another useful feature is also included with this demonstration although it's not really one of the concepts
that I wanted to show you. If you look at the code in the PRESSED event you will see that the first section of
that code is used to scroll through three different letters on each key. For example, pressing the '2' key will
step through the letters 'd', 'e' and 'f'.

Using the keypad events, PRESSED, HOLD and RELEASED to simplify coding Very simply, the PRESSED event
occurs imediately upon detecting a pressed key and will not happen again until after a RELEASED event.
When the HOLD event fires it always falls between PRESSED and RELEASED. However, it will only occur if a
key has been pressed for longer than the setHoldTime() interval.
How to use setHoldTime() and why Take a look at keypad.setHoldTime(500) in the code. It is used to set the
time delay between a PRESSED event and the start of a HOLD event. The value 500 is in milliseconds (mS)
and is equivalent to half a second. After pressing a key for 500mS the HOLD event will fire and any code
contained therein will be executed. This event will stay active for as long as you hold the key except in the
case of bug #1 listed above.
Making more than one thing happen with the same key. If you look under the PRESSED event (case
PRESSED:) you will see that the '#' is used to print a new line, Serial.println(). But take a look at the first
half of the HOLD event and you will see the same key being used to switch back and forth between the letter

and number keymaps that were created with alphaKeys[4][5] and numberKeys[4][5] respectively.
Assigning and changing keymaps on the fly You will see that the '#' key has been designated to perform two
different functions depending on how long you hold it down. If you press the '#' key for less than the
setHoldTime() then it will print a new line. However, if you hold if for longer than that it will switch back and
forth between numbers and letters. You can see the keymap changes in the HOLD event.

In addition... You might notice a couple of things that you won't find in the Arduino language reference. The
first would be #include . This is a standard library from the C programming language and though I don't
normally demonstrate these types of things from outside the Arduino language reference I felt that its use
here was justified by the simplicity that it brings to this sketch. That simplicity is provided by the two calls to
isalpha(key) and isdigit(key). The first one is used to decide if the key that was pressed is any letter from az or A-Z and the second one decides if the key is any number from 0-9. The return value from these two
functions is either a zero or some positive number greater than zero. This makes it very simple to test a key
and see if it is a number or a letter. So when you see the following:
if (isalpha(key)) // this tests to see if your key was a letter
And the following may be more familiar to some but it is equivalent:
if (isalpha(key) != 0) // this tests to see if your key was a letter
And Finally... To better understand how the event handler affects your code you will need to remember that
it gets called only when you press, hold or release a key. However, once a key is pressed or held then the
event handler gets called at the full speed of the loop().
*** THE KEYPAD REQUIRES PULL-UP RESISTORS ON THE ROW PINS. ***
#include <Keypad.h>
#include <ctype.h>

// Define the keymaps.

The blank spot (lower left) is the space character.

char alphaKeys[4][3] = {
{ 'a','d','g' },
{ 'j','m','p' },
{ 's','v','y' },
{ ' ','.','#' }
};

char numberKeys[4][3] = {
{ '1','2','3' },
{ '4','5','6' },
{ '7','8','9' },
{ ' ','0','#' }
};

boolean alpha = false;

// Start with the numeric keypad.

char* keypadMap = (alpha == true) ? makeKeymap(alphaKeys) : makeKeymap(numberKeys);

// Connect keypad ROW0, ROW1, ROW2 and ROW3 to these pins, eg. ROW0 = Arduino pin2.
byte rowPins[] = { 9, 8, 7, 6 };

// Connect keypad COL0, COL1 and COL2 to these pins, eg. COL0 = Arduino pin6.
byte colPins[] = { 12, 11, 10 };

//create a new Keypad


Keypad keypad = Keypad(keypadMap, rowPins, colPins, sizeof(rowPins), sizeof(colPins));

const byte ledPin = 13;


on pin 13.

// Use the LED

void setup() {
Serial.begin(9600);
digitalWrite(ledPin, HIGH);
LED on.

// Turns the

keypad.addEventListener(keypadEvent);
event listener.

// Add an

keypad.setHoldTime(500);
is 1000mS

// Default

keypad.setDebounceTime(250);
is 50mS

// Default

void loop() {
char key = keypad.getKey();

if (alpha) {

// Flash the LED if we are using the letter keymap.

digitalWrite(ledPin,!digitalRead(ledPin));
delay(100);
}
}

// Take care of some special events.


void keypadEvent(KeypadEvent key) {

static char virtKey = NO_KEY;


only)

// Stores the last virtual key press. (Alpha keys

static char physKey = NO_KEY;


only)

// Stores the last physical key press. (Alpha keys

static char buildStr[12];


static byte buildCount;
static byte pressCount;

switch (keypad.getState())
{
case PRESSED:
keymap.

if (isalpha(key)) {

characters.

// This is a letter key so we're using the letter

if (physKey != key) {

// New key so start with the first of 3

pressCount = 0;
virtKey = key;
physKey = key;
}
else {

// Pressed the same key again...

virtKey++;

// so select the next character on that key.

pressCount++;

// Tracks how many times we press the same key.

}
if (pressCount > 2) {

// Last character reached so cycle back to start.

pressCount = 0;
virtKey = key;
}
Serial.print(virtKey);

// Used for testing.

}
if (isdigit(key) || key == ' ' || key == '.')
if (key == '#')

Serial.print(key);

Serial.println();

break;

case HOLD:
if (key == '#')
letters

if (alpha == true)

// Toggle between keymaps.


{

keypad.begin(*numberKeys);
alpha = false;
}

// We are currently using a keymap with


// and want to change to numbers.

else

// Or, we are currently using a keymap with

numbers
keypad.begin(*alphaKeys);

// and want to change to letters.

alpha = true;
}
}
else

// Some key other than '#' was pressed.

buildStr[buildCount++] = (isalpha(key)) ? virtKey : key;


buildStr[buildCount] = '\0';
Serial.println();
Serial.println(buildStr);
}
break;

case RELEASED:
if (buildCount >= sizeof(buildStr))
Start fresh.

buildCount = 0;

// Our string is full.

break;

}
}

// end switch-case

// end keypad events

string

Description
Text strings can be represented in two ways. you can use the String
data type, which is part of the core as of version 0019, or you can
make a string out of an array of type char and null-terminate it.
This page described the latter method. For more details on the
String object, which gives you more functionality at the cost of more
memory, see the String object page.
Examples
All of the following are valid declarations for strings.

char
char
char
char
char
char

Str1[15];
Str2[8] = {'a', 'r', 'd', 'u', 'i', 'n', 'o'};
Str3[8] = {'a', 'r', 'd', 'u', 'i', 'n', 'o', '\0'};
Str4[ ] = "arduino";
Str5[8] = "arduino";
Str6[15] = "arduino";

Possibilities for declaring strings

Declare an array of chars without initializing it as in Str1


Declare an array of chars (with one extra char) and the
compiler will add the required null character, as in Str2

Explicitly add the null character, Str3


Initialize with a string constant in quotation marks; the
compiler will size the array to fit the string constant and a
terminating null character, Str4
Initialize the array with an explicit size and string constant,
Str5
Initialize the array, leaving extra space for a larger string, Str6
Null termination
Generally, strings are terminated with a null character (ASCII code
0). This allows functions (like Serial.print()) to tell where the end of
a string is. Otherwise, they would continue reading subsequent
bytes of memory that aren't actually part of the string.
This means that your string needs to have space for one more
character than the text you want it to contain. That is why Str2 and
Str5 need to be eight characters, even though "arduino" is only
seven - the last position is automatically filled with a null character.

Str4 will be automatically sized to eight characters, one for the


extra null. In Str3, we've explicitly included the null character
(written '\0') ourselves.
Note that it's possible to have a string without a final null character
(e.g. if you had specified the length of Str2 as seven instead of
eight). This will break most functions that use strings, so you
shouldn't do it intentionally. If you notice something behaving
strangely (operating on characters not in the string), however, this
could be the problem.
Single quotes or double quotes?
Strings are always defined inside double quotes ("Abc") and
characters are always defined inside single quotes('A').
Wrapping long strings
You can wrap long strings like this:
char myString[] = "This is the first line"
" this is the second line"
" etcetera";

Arrays of strings
It is often convenient, when working with large amounts of text,
such as a project with an LCD display, to setup an array of strings.
Because strings themselves are arrays, this is in actually an
example of a two-dimensional array.

In the code below, the asterisk after the datatype char "char*"
indicates that this is an array of "pointers". All array names are
actually pointers, so this is required to make an array of arrays.
Pointers are one of the more esoteric parts of C for beginners to
understand, but it isn't necessary to understand pointers in detail to
use them effectively here.
Example
char* myStrings[]={"This is string 1", "This is string 2", "This is string 3",
"This is string 4", "This is string 5","This is string 6"};
void setup(){
Serial.begin(9600);
}
void loop(){
for (int i = 0; i < 6; i++){
Serial.println(myStrings[i]);
delay(500);
}
}

Funciones.

Segmentar el cdigo en funciones permite al programador crear


piezas modulares de cdigo que realizan una tarea definida y
vuelven a la zona del programa en la que fueron llamadas. El caso
tpico para crear un funcin es cuando uno necesita realizar la
misma accin mltiples veces dentro de un mismo programa.
Para programadores acostumbrados a utilizar BASIC las funciones
en Arduino permiten (y extienden) la utilidad de usar subrutinas
(GOSUB en BASIC).

La estandarizacin de fragmentos de cdigo en funciones tiene


diversas ventajas:

Las funciones ayudan al programador a ser organizado.


Adems ayudan a conceptualizar el programa.

Las funciones codifican una accin en un lugar, as que slo


deben ser depuradas de errores una vez.

Reducen las posibilidades de error en modificaciones, si el


cdigo debe ser cambiado.

Las funciones hacen el sketch mas pequeo y mas compacto


por que las secciones de cdigo se reutilizan varias veces.

Hacen mas fcil la reutilizacin de cdigo en otros programas


por hacerlo mas modular y, como efecto paralelo, usando funciones
se obtiene un cdigo mas legible.
Hay dos funciones necesarias en un sketch de Arduino: setup() y
loop(). El resto de funciones debe ser definido fuera de las llaves de
estas dos funciones. Como ejemplo vamos a crear una funcin muy
simple que multiplica dos nmeros.

Ejemplo

Al "invocar" a nuestra pequea funcin le pasamos parametros del


tipo de dato que ella espera.
void loop{
int i = 2;
int j = 3;
int k;
k = myMultiplyFunction(i, j); // k ahora contiene 6
}

Nuestra funcin necesita ser declarada fuera de cualquier otra


funcin, por ello "myMultiplyFunction()" puede ir antes o despues de
la funcin "loop()".
El sketch completo podra ser algo como esto:
void setup(){
Serial.begin(9600);
}
void loop{
int i = 2;
int j = 3;
int k;

k = myMultiplyFunction(i, j); // k ahora contiene 6


Serial.println(k);
delay(500);
}
int myMultiplyFunction(int x, int y){
int result;
result = x * y;
return result;
}

Otro ejemplo:
Esta funcin leer un sensor cinco veces con analogRead() y
calcular la media de las cinco lecturas. Escala los datos a 8 bits (0255), los invierte y devuelve el resultado invertido.
int ReadSens_and_Condition(){
int i;
int sval;
for (i = 0; i < 5; i++){
sval = sval + analogRead(0);
}

// sensor en pin analgico 0

sval = sval / 5; // media


sval = sval / 4; // escala a 8 bits (0 - 255)
sval = 255 - sval; // invierte el resultado
return sval;
// devuelve el resultado
}

Para llamar a nuestra funcin solo tenemos que asignarla a una


variable.
int sens;
sens = ReadSens_and_Condition();

PROGMEM

Guarda datos en la memoria flash (la de programa) en vez de en la


SRAM. Hay una descripcin de los tipos de memoriadisponible en
una placa Arduino.

La palabra PROGMEM es un modificador de variable. Debera usarse


slo con los tipos de datos definidos en pgmspace.h. Le dice al
compilador que ponga la informacin en la memoria flash en vez de
en la SRAM, que es donde normalmente se guarda.
PROGMEM es parte de la librera pgmspace.h, por ello hay que
incluir la librera al principio del sketch, de esta forma:
#include <avr/pgmspace.h>

Sintaxis
dataType variableName[] PROGMEM = {dataInt0, dataInt1, dataInt3...};

dataType: tipo de datos en la memoria de programa: cualquier


tipo de datos de variables
variableName - el nombre de la variable matriz.
Hay que tener en cuenta que PROGMEM es un modificador de
variable por lo que no hay reglas escritas sobre dnde debera ir,
por lo que el compilador acepta cualquiera de las definiciones
siguientes, que son sinnimas. Aun as, se han llevado a cabo
experimentos que han concludo que en varias versiones de Arduino
(relacionado con la versin de GCC), PROGMEM puede funcionar en
una posicin y no en otra. La tabla siguiente ha sido probada con
Arduino 13. En versiones anteriores del IDE es posible que funcione
mejor si PROGMEM se incluye despus del nombre de la variable
dataType variableName[] PROGMEM = {}; // usar esta
dataType PROGMEM variableName[] = {}; // no esta
PROGMEM dataType variableName[] = {}; // usar esta

PROGMEM puede usarse en una sola variable pero slo merece la


pena su uso en bloques ms largos de datos que necesiten ser
guardados, generalmente en un array aunque puede ser otro tipo de
estructura.
PROGMEM se usa en dos pasos. Despus de guardar los datos en la
memoria Flash, requiere mtodos especiales (funciones), definidas
tambin en la librera pgmspace.h, para leer los datos de la
memoria de programa y ponerla en SRAM, para poder usarla.
Es importante usar los tipos de datos definidos en pgmspace.h.
Pueden aparecer fallos crpticos si se usan tipos comunes para
llamadas a la memoria de cdigo. sta es una lista de tipos
disponibles. No estn soportados los nmeros en coma flotante.
prog_char
- carcter con signo (1 byte) -127 a 128
prog_uchar
- carcter sin signo (1 byte) 0 a 255
prog_int16_t - entero con signo (2 bytes) -32.767 a 32.768
prog_uint16_t - entero sin signo (2 bytes) 0 a 65.535
prog_int32_t - entero largo con signo(4 bytes) -2.147.483,648 a * 2.147.483.647.
prog_uint32_t - entero largo sin signo (4 bytes) 0 a 4.294.967.295

Ejemplo
En el siguiente cdigo se indica cmo leer y escribir caracteres sin
signo (bytes) y enteros (2 bytes) en PROGMEM.
#include <avr/pgmspace.h>
// guardar enteros sin signo
PROGMEM prog_uint16_t charSet[] = { 65000, 32796, 16843, 10, 11234};
// guardar caracteres
prog_uchar signMessage[] PROGMEM = {"I AM PREDATOR, UNSEEN COMBATANT. CREATED
BY THE UNITED STATES DEPART"};
unsigned int displayInt;
int k; // variable contador
char myChar;

// leer entero de 2 bytes


displayInt = pgm_read_word_near(charSet + k)
// leer carcter
myChar = pgm_read_byte_near(signMessage + k);

Matrices de cadenas de caracteres (arrays de strings)


Muchas veces es conveniente, al trabajar con cantidades grandes de
texto como por ejemplo en un proyecto con un LCD, definir matrices
de strings. Como los strings son matrices, en realidad son matrices
bidimensionales.
stas tienden a ser estructuras grandes por lo que ponerlas en
memoeria de programa es algo a evitar. Este cdigo ilustra la idea:
/*
PROGMEM string demo
Cmo guardar una tabla de strings en la memoria de programa (flash) y cargarla.
Informacin resumida de:
http://www.nongnu.org/avr-libc/user-manual/pgmspace.html (ingls)
Primero, definir los strings.
*/
#include <avr/pgmspace.h>
prog_char string_0[] PROGMEM
prog_char string_1[] PROGMEM
prog_char string_2[] PROGMEM
prog_char string_3[] PROGMEM
prog_char string_4[] PROGMEM
prog_char string_5[] PROGMEM

=
=
=
=
=
=

"String
"String
"String
"String
"String
"String

0"; // "String 0" etc. son strings a guardar.


1";
2";
3";
4";
5";

// Definir una tabla para guardar los strings


PROGMEM const char *string_table[] =
{
string_0,
string_1,
string_2,

string_3,
string_4,
string_5 };
char buffer[30];

// debe ser tan grande como el string ms grande.

void setup()
{
Serial.begin(9600);
}
void loop()
{
/* La funcin strcpy_P copia un string del espacio de programa a un string en RAM
("buffer").
Hay que asegurarse de que el string en RAM es suficientemente grande para recibir el
dato. */
for (int i = 0; i < 6; i++)
{
strcpy_P(buffer, (char*)pgm_read_word(&(string_table[i]))); // Casts necesarios e
inferencia
Serial.println( buffer );
delay( 500 );
}
}

String Character Functions

The String functions charAt() and setCharAt() are used to get or set the value of a character at
a given position in a String.
At their simplest, these functions help you search and replace a given character. For example, the
following replaces the colon in a given String with an equals sign:
String reportString = "SensorReading: 456";
int colonPosition = reportString.indexOf(':');
reportString.setCharAt(colonPosition, '=');
[Get Code]

Here's an example that checks to see if the first letter of the second word is 'B':
String reportString = "Franklin, Benjamin";
int spacePosition = reportString.indexOf(' ');
if (reportString.charAt(spacePosition + 1) == 'B') {
Serial.println("You might have found the Benjamins.")
}

[Get Code]

Caution: If you try to get the charAt or try to setCharAt() a value that's longer than the
String's length, you'll get unexpected results. If you're not sure, check to see that the position you
want to set or get is less than the string's length using the length() function.
Hardware Required:
Arduino Board

Circuit

There is no circuit for this example, though your Arduino must be connected to your computer
via USB.

image developed using Fritzing. For more circuit examples, see the Fritzing project page
Code
/*
String charAt() and setCharAt()
Examples of how to get and set characters of a String
created 27 July 2010
modified 2 Apr 2012
by Tom Igoe
http://arduino.cc/en/Tutorial/StringCharacters
This example code is in the public domain.

*/
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
Serial.println("\n\nString

charAt() and setCharAt():");

}
void loop() {
// make a string to report a sensor reading:
String reportString = "SensorReading: 456";
Serial.println(reportString);
// the reading's most significant digit is at position 15 in the
reportString:
char mostSignificantDigit = reportString.charAt(15);
Serial.println("Most significant digit of the sensor reading is:
" + mostSignificantDigit);
// add blank space:
Serial.println();
// you can alo set the character of a string. Change the : to a =
character
reportString.setCharAt(13, '=');
Serial.println(reportString);
// do nothing while true:
while(true);
}

string Object Constructors

The String object allows you to manipulate strings of text in a


variety of useful ways. You can append characters to Strings,
combine Strings through concatenation, get the length of a String,

search and replace substrings, and more. This tutorial shows you
how to initialize String objects.
String stringOne = "Hello String";
// using a
constant String
String stringOne = String('a');
// converting a
constant char into a String
String stringTwo = String("This is a string");
// converting a
constant string into a String object
String stringOne = String(stringTwo + " with more");// concatenating
two strings
String stringOne = String(13);
// using a
constant integer
String stringOne = String(analogRead(0), DEC);
// using an int
and a base
String stringOne = String(45, HEX);
// using an int
and a base (hexadecimal)
String stringOne = String(255, BIN);
// using an int
and a base (binary)
String stringOne = String(millis(), DEC);
// using a long
and a base
[Get Code]

All of these methods are valid ways to declare a String object. They
all result in an object containing a string of characters that can be
manipulated using any of the String methods. To see them in action,
upload the code below onto an Arduino and open the Serial Monitor.
You'll see the results of each declaration. Compare what's printed by
each println() to the declaration above it.
Hardware Required

Arduino Board
Circuit

There is no circuit for this example, though your Arduino must be


connected to your computer via USB.

image developed using Fritzing. For more circuit examples, see the Fritzing
project page
Code
/*
String constructors
Examples of how

to create strings from other data types

created 27 July 2010


modified 30 Aug 2011
by Tom Igoe
http://arduino.cc/en/Tutorial/StringConstructors
This example code is in the public domain.
*/
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}

// send an intro:
Serial.println("\n\nString Constructors:");
Serial.println();
}
void loop() {
// using a constant String:
String stringOne = "Hello String";
Serial.println(stringOne);
// prints "Hello String"
// converting a constant char into a String:
stringOne = String('a');
Serial.println(stringOne);
// prints "a"
// converting a constant string into a String object:
String stringTwo = String("This is a string");
Serial.println(stringTwo);
// prints "This is a string"
// concatenating two strings:
stringOne = String(stringTwo + " with more");
// prints "This is a string with more":
Serial.println(stringOne);
// using a constant integer:
stringOne = String(13);
Serial.println(stringOne);

// prints "13"

// using an int and a base:


stringOne = String(analogRead(A0), DEC);
// prints "453" or whatever the value of analogRead(A0) is
Serial.println(stringOne);
// using an int and a base (hexadecimal):
stringOne = String(45, HEX);
// prints "2d", which is the hexadecimal version of decimal 45:
Serial.println(stringOne);
// using an int and a base (binary)
stringOne = String(255, BIN);
// prints "11111111" which is the binary value of 255
Serial.println(stringOne);
// using a long and a base:
stringOne = String(millis(), DEC);
// prints "123456" or whatever the value of millis() is:

Serial.println(stringOne);
// do nothing while true:
while(true);
}

Vous aimerez peut-être aussi