lunes, 25 de diciembre de 2017

Raspberry Pi como Smart TV con Kodi

Hola a todos. En esta ocasion, os explicare aproximadamente como utilizar una raspberry pi para ver series o peliculas en casa por internet.

Yo tengo la raspberry por ahi tirada, porque me la compre para el modulo, con raspbian instalado, pero no la uso practicamente nada y un dia, por pura casualidad, me encontre con el dato de que se le puede instalar un sistema operativo para ver series, peliculas, videos, musica y cualquier otra cosa, por usb, y ademas, se le pueden instalar addons para poder ver series o peliculas u otras cosas por internet, sin necesidad de descargarlas. Ademas, se puede manejar la raspberry sin un raton ni un teclado, a traves del mando de la tele si teneis una conexion HDMI.

Para que os hagais una idea, yo instale un addon llamado Palantir, que sirve para ver peliculas y series en castellano y cuando termine de instalarlo, me ponia en una esquina de la pantalla un aviso que se habian añadido series y que se habian añadido algo mas de 16000 series y peliculas nuevas. En total hay muchos addons y muchas cosas distintas, yo hace solo un par de dias que hice esto y quede bastante sorprendido. Hay algunas series que estan en HD y que no se pueden ver bien por wifi porque la antena wifi de la raspberry (o al menos la que tengo yo) no tiene una velocidad muy alta de conexion, pero por cable esas series van perfectamente.

Asi que lo primero que voy a hacer es dejar por aqui el enlace de descarga de Kodi (1.4 GB), para que lo vayais descargando, mientras seguis leyendo la entrada del blog:
https://mega.nz/#!UbITjYQR!WYFSQ0NO1P6cK6EXN1jWhQBhQroCkJQu_3Dp-kHiMlc
Si buscais por ahi, seguramente tambien haya otras versiones de Kodi, esta es la version 17.0 y habra que expandirla para que funcione bien (por internet las hay ya directamente expandidas, pero yo pongo esta porque puedes meterla en cualquier memoria micro sd), pero en eso ya entrare mas adelante.

Una vez descargado, hay que formatear la microSD en formato Fat32. Si ya esta en ese formato, no hace falta formatearla. Una vez formateada, descargamos el win32diskimager (https://sourceforge.net/projects/win32diskimager/), lo instalamos y lo abrimos. Despues seleccionamos la imagen que hemos descargado y la metemos en el microsd. No explico muy detalladamente como se hace porque de verdad que no tiene perdida, el programa es muy simple. Tambien añado que os asegureis de estar grabando la imagen en la microsd, no vayais a liarla... Si teneis dudas, preguntad en los comentarios.

Lo siguiente es expandir la imagen. Se puede usar la imagen sin expandir, pero tengo entendido que puede dar problemas y lo mas importante de todo, estais desaprovechando espacio de la memoria.
Por ello, para expandir la imagen necesitais un programa llamado "gparted". es totalmente gratuito y de codigo libre, podeis descargarlo desde aqui: https://gparted.org/download.php
Esta es la parte mas complicada de todo el proceso, tanto que a mi me costo bastante lograrlo. Parece ser que no existe la opcion de utilizar el programa en windows en condiciones normales.
Para hacerlo, lo que teneis que hacer es guardar la iso en un pendrive y luego iniciar el ordenador desde el pendrive. Para hacer esto, no os lo puedo explicar mucho mejor porque cada ordenador lo hace de una manera. Una vez hecho ese paso, basta con seleccionar la microsd, seleccionais la particion mas grande y la arrastrais hasta ocupar la cantidad de memoria que querais ocupar (por lo general, todo). Luego, le dais a Aplicar y ya esta.
Por mi parte, yo lo hice de una manera distinta, porque soy un vago y nunca he iniciado el ordenador desde el USB. Lo primero que pense, fue en instalar el gparted en la raspberry con el raspbian, luego enchufe la tarjeta microsd y al intentar ampliarlo, me daba un error raro y se me cerraba el programa. Si quereis probar ese metodo podeis probarlo, no se si seria un error de instalacion o un error de la raspberry o a saber cual seria el problema...
Yo lo que hice finalmente fue darme cuenta de que tenia un linux instalado en una maquina virtual en mi ordenador, concretamente, el Wireshark. Ademas, resulto que el wireshark ya tenia instalado el gparted y no tuve ni que instalarlo aunque es muy facil de instalar en un linux, en el enlace de arriba se explica como se hace.

A partir de aqui, ya esta hecha la primera parte. Ya solo teneis que utilizar el ordenador para seguir el tutorial. El resto lo podeis hacer desde la raspberry utilizando el mando de la tele (la señal la recibe la tele y la envia por HDMI a la raspberry).

Una vez hecho esto, enchufais la raspberry a la television y deberiais ver que funciona el Kodi, con LibreELEC (LibreELEC es una especie de Kodi). Si no veis nada, es posible que sea porque el HDMI hace mal contacto en la raspberry, yo tuve problemas con ello...

Si teneis la antena wifi conectada en la raspberry, al encender por primera vez os pondra que si quereis conectar el wifi y tendreis que poner la contraseña. A mi no me funcionaba tras meter la contraseña unas 3 veces y acabe cansandome y le di a omitir. Luego, para poner la contraseña, tuve que buscar por internet donde se encontraba la opcion, porque no me aparecia por ninguna parte XD
Para hacerlo, vais al menu de configuracion, luego, haceis clic en LibreELEC y despues en Connections. Luego seleccionais la vuestra y meteis la contraseña correctamente (yo la tuve que meter como 4 veces, ya creia que no me iba a funcionar). Si os sabeis la contraseña de la vecino, tambien os vale, aunque no es muy aconsejable XD

Por ultimo, para ver las series y peliculas, teneis que añadir un addon. Yo os voy a explicar los pasos para instalar Palantir, que es para ver series y peliculas en español. Hay muchas mas por supuesto, pero para eso esta internet :)

Para instalar Palantir, teneis que ir, en Configuracion, a administrar archivos (el icono con forma de carpeta que esta abajo a la derecha). Despues añadimos una fuente, haciendo clic en "add source" y le metemos la url: http://canalnereo.com/canalnereo/ Asi, tal cual. Luego ponedle un nombre que os convenga, yo le deje el nombre que me puso por defecto de Canal Nereo (o algo similar). A continuacion, volveis al menu principal, a Addons (o complementos), en el icono que tiene una especie de cajita abierta, le dais a instalar archivo desde zip, seleccionais canal nereo, luego vais a la carpeta plugin, y seleccionais uno que se llama plugin.video.palantir-xxx.zip
Una vez que se haya instalado, para entrar teneis que ir al menu principal, al apartado de Addons y alli se encontrara disponible.

Por ultimo, tambien se puede poner en español, pero yo por ahora no lo he necesitado ni se como se hace. Si lo descubro ya lo añadire por aqui, aunque es posible que lo deje como esta, ya que tampoco es que este en un nivel de ingles muy alto ni nada por el estilo. Ademas, el Palantir esta completamente en castellano.

Si teneis cualquier duda de lo que sea, decidmelo en los comentarios, intentare no tardar en responder. Ademas, aprovechare esa duda para corregirlo en el texto y que quede todo mejor explicado, para que haya menos gente que tenga esa duda, por lo que no dudeis en preguntar!

sábado, 16 de diciembre de 2017

Introduccion a LabVIEW

El objetivo de esta entrada es el de hacer una introduccion rapida y simple a LabVIEW. Yo utilizo el 2014, pero todas las versiones funcionan igual.

Una vez que el LabVIEW esta instalado, lo que hacemos es abrirlo. Una vez abierto, hacemos clic en File > New VI. Ahi se abren dos ventanas (o una, puede que depende de la version y luego hay que abrir la otra desde ahi). Para pasar de una ventana a otra (o abrir la otra en caso de que no se haya abierto), hay dos formas muy simples con el teclado. Una es pulsar ctrl+E. La otra, es pulsar ctrl+T. Os recomiendo probar ambas y que veais la diferencia vosotros.

sábado, 18 de noviembre de 2017

Disminucion de temperatura mediante el efecto Peltier

Como ultimamente ando algo mal de tiempo, os dejo por aqui un trabajo que hice hace un par de semanas para clase relacionado con la disminucion de temperatura utilizando una celda Peltier. Espero que os guste:
https://drive.google.com/drive/folders/1U4ItOw86IXBwE-RRhR5LrfspywmtcRht?usp=sharing

En cuanto tenga un rato, hare que se pueda leer desde aqui directamente, sin necesidad de descargarlo.

martes, 17 de octubre de 2017

Lector de partituras a partir de una imagen

Esta vez, se me ha ocurrido hacer un lector de partituras a partir de una imagen (jpg o cualquier cosa me vale) y como salida, lo convertire a codigo para arduino (en un txt). Esta es la idea original, a saber que sale al final, si es que sale algo. He decidido escoger una partitura bastante sencilla. En concreto, esta del himno de la alegria:


Para hacerlo, utilizare LabVIEW. Concretamente, comenzare utilizando el Vision Builder.

Lo primero que he hecho (aparte de introducir la imagen de prueba en el programa), es detectar objetos. La idea mia ha sido detectar cada uno de los pentagramas individualmente y tratarlos por separado mas adelante.




A continuacion, escojo el primer punto de referencia en el primer pentagrama detectado, para trabajar sobre el.


A continuacion, aunque en este caso tal vez os parezca innecesario y es posible que creais que no tiene mucho sentido, extraigo la capa roja. Con esto, basicamente lo que hago es quitar el color a la imagen y dejarla en blanco y negro. Aunque la imagen ya estaba en blanco y negro, esta tonteria me ha ayudado bastante en un paso bastante mas adelante, a la hora de detectar objetos (mas adelante explicare en que consiste).


El mayor problema con diferencia que he tenido hasta este punto, es que la localizacion del punto de referencia de cada uno de los pentagramas es ligeramente distinto. Segun he estado investigando, eso es porque el Vision Builder utiliza como centro el punto medio de la suma de los pixeles utilizados. Por decirlo de otra manera, el punto medio no es el punto medio del area verde que podeis ver en la imagen (que es lo que cabria esperar), sino el punto medio de la suma de cada uno de los pixeles detectados a color negro. Por ello, el punto medio de cada uno de las areas se encuentra en un punto ligeramente distinto y esto me ha ocasionado bastantes problemas a la hora de localizar las notas.

Para solucionar esto, he tenido que utilizar como referencia el punto de referencia hallado anteriormente y a partir de el, localizar dos lineas rectas en la imagen. La primera, la linea superior horizontal del pentagrama (podia haber escogido la de abajo, me daria igual) y la segunda, la linea vertical derecha (Esta ya no da igual, la he escogido porque es una linea recta facil de localizar). Como punto de referencia voy a escoger el vertice superior derecho del pentagrama.



Lo siguiente que hago es crear una geometria para localizar la interseccion de las dos rectas que acabo de localizar y, a continuacion, establezco ese punto como punto de referencia.



Con esto que he hecho, ya me es bastante facil localizar el area donde se encuentran las notas del pentagrama.


Por ahora, no he conseguido localizar bien las notas. Por ejemplo, la nota blanca no la detecta y voy a tener que ponerme a "jugar" con los umbrales de deteccion. En cuanto tenga un rato, seguire con ello y a ver si logro avanzar. Creo que este paso me va a llevar un rato...

miércoles, 27 de septiembre de 2017

El baile de los pajaritos con un Arduino (Cancion)

Esta vez os traigo el baile de los pajaritos, de Maria Jesus y su Acordeon, hecho con un arduino. En esta ocasion, el codigo ha sido hecho por mi completamente, a partir de la partitura de la cancion. Espero que os guste:


Partitura:



Enlace para descargar el codigo: https://drive.google.com/drive/folders/0B20kHfrc3NnpUXpLNjgxa3hVLXM?usp=sharing

Nota: conectar el zumbador al Pin 2 del Arduino

CODIGO:

/*
//////////////////////////////////////////////////////////////////////////////////////////////
//    AUTOR: Marcos Gonzalez Perez                                             Septiembre/2017
//////////////////////////////////////////////////////////////////////////////////////////////
//    PROGRAMA: Notas musicales                                             VERSION: 1.0
//    DISPOSITIVO: ATMEGA328P                                               COMPILADOR: AVR
//    Entorno IDE: 1.6.0                                                    SIMULADOR:
//    TARJETA DE APLICACION: ARDUINO UNO                                    DEBUGGER:
//////////////////////////////////////////////////////////////////////////////////////////////
Programa que hace una la cancion de los pajaritos
https://www.youtube.com/watch?v=CgYD3ChlVMA

//////////////////////////////////////////////////////////////////////////////////////////////
*/
//////////////////////////////////////////////////////////////////////////////////////////////
// LIBRERIAS /////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////////////////
// VARIABLES GLOBALES ////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////////////////
// FUNCIONES /////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////////////////
// CONFIGURACION /////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////

//Notas en clave de Sol:
const int Do = 261;
//Do sostenido o re bemol
const int DoS = 277;
const int ReB = 277;
const int Re = 294;
//Re sostenido o Mi bemol
const int ReS = 311;
const int MiB = 311;
const int Mi = 329;

const int Fa = 349;
//Fa sostenido o Sol bemol
const int FaS = 370;
const int SolB = 370;
const int Sol = 392;
//Sol soltenido o La bemol
const int SolS = 415;
const int LaB = 415;
const int La = 440;
//La sostenido o Si Bemol
const int LaS = 466;
const int SiB = 466;
const int Si = 493;
//Do agudo
const int DO = 522;
const int RE = 587;
const int MI = 659;


#define Redonda  4000
#define Blanca 2000
#define Negra 1000
#define Corchea 500
#define Semicorchea 250
#define Fusa 125
#define Semifusa 62.5
//Nota: el punto equivale a la mitad del tiempo de la nota (la nota vale 1.5 veces su tiempo normal)
#define Punto 1.5

const int buzzerPin = 2;

void setup() {
pinMode(buzzerPin, OUTPUT);

}


//////////////////////////////////////////////////////////////////////////////////////////////
//PRINCIPAL///////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////

//Partitura: Chicken Dance: http://www.freesheetmusic.net/folktunes1/ChickenDance.pdf

void loop() {
  for(int x=0; x<2; x++){ //repeticion de todo
  for(int y=0; y<2; y++){ //repeticion parte 1
  //linea 1
  tone(buzzerPin, Sol, Semicorchea-10);
  delay(Semicorchea);
  tone(buzzerPin, Sol, Semicorchea-10);
  delay(Semicorchea);
  tone(buzzerPin, La, Semicorchea-10);
  delay(Semicorchea);
  tone(buzzerPin, La, Semicorchea-10);
  delay(Semicorchea);
  tone(buzzerPin, Mi, Semicorchea-10);
  delay(Semicorchea);
  tone(buzzerPin, Mi, Semicorchea-10);
  delay(Semicorchea);

  tone(buzzerPin, Sol, Corchea-10);
  delay(Corchea);
  tone(buzzerPin, Sol, Semicorchea-10);
  delay(Semicorchea);
  tone(buzzerPin, Sol, Semicorchea-10);
  delay(Semicorchea);
  tone(buzzerPin, La, Semicorchea-10);
  delay(Semicorchea);
  tone(buzzerPin, La, Semicorchea-10);
  delay(Semicorchea);
  tone(buzzerPin, Mi, Semicorchea-10);
  delay(Semicorchea);
  tone(buzzerPin, Mi, Semicorchea-10);
  delay(Semicorchea);

  tone(buzzerPin, Sol, Corchea-10);
  delay(Corchea);
  tone(buzzerPin, Sol, Semicorchea-10);
  delay(Semicorchea);
  tone(buzzerPin, Sol, Semicorchea-10);
  delay(Semicorchea);
  tone(buzzerPin, La, Semicorchea-10);
  delay(Semicorchea);
  tone(buzzerPin, La, Semicorchea-10);
  delay(Semicorchea);
  tone(buzzerPin, DO, Semicorchea-10);
  delay(Semicorchea);
  tone(buzzerPin, DO, Semicorchea-10);
  delay(Semicorchea);

  tone(buzzerPin, Si, Corchea-10);
  delay(Corchea);
  //silencio de corchea
  delay(Corchea);
  //silencio de negra
  delay(Negra);

  //silencio de corchea
  delay(Corchea);
  tone(buzzerPin, Fa, Semicorchea-10);
  delay(Semicorchea);
  tone(buzzerPin, Fa, Semicorchea-10);
  delay(Semicorchea);
  tone(buzzerPin, Sol, Semicorchea-10);
  delay(Semicorchea);
  tone(buzzerPin, Sol, Semicorchea-10);
  delay(Semicorchea);
  tone(buzzerPin, Re, Semicorchea-10);
  delay(Semicorchea);
  tone(buzzerPin, Re, Semicorchea-10);
  delay(Semicorchea);

  //Linea 2
  tone(buzzerPin, Fa, Corchea-10);
  delay(Corchea);
  tone(buzzerPin, Fa, Semicorchea-10);
  delay(Semicorchea);
  tone(buzzerPin, Fa, Semicorchea-10);
  delay(Semicorchea);
  tone(buzzerPin, Sol, Semicorchea-10);
  delay(Semicorchea);
  tone(buzzerPin, Sol, Semicorchea-10);
  delay(Semicorchea);
  tone(buzzerPin, Re, Semicorchea-10);
  delay(Semicorchea);
  tone(buzzerPin, Re, Semicorchea-10);
  delay(Semicorchea);

  /////////////////////////////////////////////////////////////
  if (x==0){
    tone(buzzerPin, Fa, Corchea-10);
    delay(Corchea);
    tone(buzzerPin, Fa, Semicorchea-10);
    delay(Semicorchea);
    tone(buzzerPin, Fa, Semicorchea-10);
    delay(Semicorchea);
    tone(buzzerPin, Sol, Semicorchea-10);
    delay(Semicorchea);
    tone(buzzerPin, Sol, Semicorchea-10);
    delay(Semicorchea);
    tone(buzzerPin, Si, Semicorchea-10);
    delay(Semicorchea);
    tone(buzzerPin, Si, Semicorchea-10);
    delay(Semicorchea);
 
    tone(buzzerPin, La, Corchea-10);
    delay(Corchea);
    //silencio de corchea
    delay(Corchea);
    //silencio de negra
    delay(Negra);
    //silencio de corchea
    delay(Corchea);
  }
  }

  if (x==1){
    tone(buzzerPin, Mi, Corchea-10);
    delay(Corchea);
    tone(buzzerPin, Fa, Corchea-10);
    delay(Corchea);
    tone(buzzerPin, Sol, Corchea-10);
    delay(Corchea);
    tone(buzzerPin, La, Corchea-10);
    delay(Corchea);
 
    tone(buzzerPin, Si, Blanca+Corchea-10);
    delay(Blanca+Corchea);
  }

    tone(buzzerPin, Sol, Semicorchea-10);
    delay(Semicorchea);
    tone(buzzerPin, SolB, Semicorchea-10);
    delay(Semicorchea);
    tone(buzzerPin, Mi, Semicorchea-10);
    delay(Semicorchea);
 
    //Linea 3
    tone(buzzerPin, Mi, Negra*Punto-10);
    delay(Negra*Punto);
    tone(buzzerPin, Sol, Corchea-10);
    delay(Corchea);
    tone(buzzerPin, MI, Negra*Punto-10);
    delay(Negra*Punto);
    tone(buzzerPin, RE, Corchea-10);
    delay(Corchea);
 
    tone(buzzerPin, RE, Negra-10);
    delay(Negra);
    tone(buzzerPin, DO, Negra+Corchea-10);
    delay(Negra+Corchea);
    tone(buzzerPin, Sol, Corchea-10);
    delay(Corchea);
    tone(buzzerPin, SolB, Corchea-10);
    delay(Corchea);
    tone(buzzerPin, Fa, Corchea-10);
    delay(Corchea);
 
    tone(buzzerPin, Mi, Negra*Punto-10);
    delay(Negra*Punto);
    tone(buzzerPin, Sol, Corchea-10);
    delay(Corchea);
 
    tone(buzzerPin, RE, Negra*Punto-10);
    delay(Negra*Punto);
    tone(buzzerPin, DO, Corchea-10);
    delay(Corchea);
 
    tone(buzzerPin, Si, Blanca+Corchea-10);
    delay(Blanca+Corchea);
    tone(buzzerPin, Sol, Corchea-10);
    delay(Corchea);
    tone(buzzerPin, Sol, Corchea-10);
    delay(Corchea);
    tone(buzzerPin, SolB, Corchea-10);
    delay(Corchea);
 
    //Linea 4
    tone(buzzerPin, Fa, Negra*Punto-10);
    delay(Negra*Punto);
    tone(buzzerPin, Sol, Corchea-10);
    delay(Corchea);
    tone(buzzerPin, RE, Negra*Punto-10);
    delay(Negra*Punto);
    tone(buzzerPin, DO, Corchea-10);
    delay(Corchea);
 
    tone(buzzerPin, DO, Negra-10);
    delay(Negra);
    tone(buzzerPin, Si, Negra+Corchea-10);
    delay(Negra+Corchea);
    tone(buzzerPin, RE, Corchea-10);
    delay(Corchea);
    tone(buzzerPin, RE, Corchea-10);
    delay(Corchea);
    tone(buzzerPin, DO, Corchea-10);
    delay(Corchea);
 
    tone(buzzerPin, DO, Negra-10);
    delay(Negra);
    tone(buzzerPin, Si, Negra+Corchea-10);
    delay(Negra+Corchea);
 
    tone(buzzerPin, Si, Corchea-10);
    delay(Negra);
    tone(buzzerPin, DO, Corchea-10);
    delay(Corchea);
    tone(buzzerPin, RE, Corchea-10);
    delay(Corchea);
 
    tone(buzzerPin, DO, Blanca+Corchea-10);
    delay(Blanca+Corchea);
 
  }


noTone(buzzerPin);
delay(5000);

}

viernes, 25 de agosto de 2017

Alarma con Arduino, sensor PIR y Marcha Imperial

Aqui teneis:




Codigo:

//Autor: Marcos Gonzalez
//https://www.youtube.com/watch?v=OE-aBv4Ph0o

//zumbador en el pin 5
//Patilla de enmedio del PIR (sensor de movimiento) al pin 2



int led = 13; // led que avisara cuando detecte movimiento.
int PIR = 2; //pin donde esta la salida del sensor.

const int c = 261;
const int d = 294;
const int e = 329;
const int f = 349;
const int g = 391;
const int gS = 415;
const int a = 440;
const int aS = 455;
const int b = 466;
const int cH = 523;
const int cSH = 554;
const int dH = 587;
const int dSH = 622;
const int eH = 659;
const int fH = 698;
const int fSH = 740;
const int gH = 784;
const int gSH = 830;
const int aH = 880;

const int buzzerPin = 5;
const int ledPin1 = 9;
const int ledPin2 = 10;

int counter = 0;


void setup() {
    pinMode(buzzerPin, OUTPUT);
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
 

pinMode(PIR,INPUT);
delay(10000); // tiempo de espera para inicializar el sensor.
}

void loop() {

if (digitalRead(PIR) == LOW) {
digitalWrite(led,HIGH);


delay(10);
}
else {
    //Play first section
  firstSection();

  //Play second section
  secondSection();

  //Variant 1
  beep(f, 250);
  beep(gS, 500);
  beep(f, 350);
  beep(a, 125);
  beep(cH, 500);
  beep(a, 375);
  beep(cH, 125);
  beep(eH, 650);

  delay(500);

  //Repeat second section
  secondSection();

  //Variant 2
  beep(f, 250);
  beep(gS, 500);
  beep(f, 375);
  beep(cH, 125);
  beep(a, 500);
  beep(f, 375);
  beep(cH, 125);
  beep(a, 650);

  delay(650);
}



delay (10);
}


void beep(int note, int duration)
{
  //Play tone on buzzerPin
  tone(buzzerPin, note, duration);

  //Play different LED depending on value of 'counter'
  if(counter % 2 == 0)
  {
    digitalWrite(ledPin1, HIGH);
    delay(duration);
    digitalWrite(ledPin1, LOW);
  }else
  {
    digitalWrite(ledPin2, HIGH);
    delay(duration);
    digitalWrite(ledPin2, LOW);
  }

  //Stop tone on buzzerPin
  noTone(buzzerPin);

  delay(50);

  //Increment counter
  counter++;
}

void firstSection()
{
  beep(a, 500);
  beep(a, 500);  
  beep(a, 500);
  beep(f, 350);
  beep(cH, 150);
  beep(a, 500);
  beep(f, 350);
  beep(cH, 150);
  beep(a, 650);

  delay(500);

  beep(eH, 500);
  beep(eH, 500);
  beep(eH, 500);
  beep(fH, 350);
  beep(cH, 150);
  beep(gS, 500);
  beep(f, 350);
  beep(cH, 150);
  beep(a, 650);

  delay(500);
}

void secondSection()
{
  beep(aH, 500);
  beep(a, 300);
  beep(a, 150);
  beep(aH, 500);
  beep(gSH, 325);
  beep(gH, 175);
  beep(fSH, 125);
  beep(fH, 125);  
  beep(fSH, 250);

  delay(325);

  beep(aS, 250);
  beep(dSH, 500);
  beep(dH, 325);
  beep(cSH, 175);
  beep(cH, 125);
  beep(b, 125);
  beep(cH, 250);

  delay(350);
}

martes, 18 de julio de 2017

Ensamblador vs. C

Hola a todos. Esta primera entrada he decidido dedicarla a comparar ensamblador con C. Para ello, tengo dos programas que hacen exactamente lo mismo, en el mismo microcontrolador (PIC16F84 o PIC16F84A).

ENUNCIADO:

La figura muestra un PIC16F84 al que estan conectados un convertidor analogico-digital ADC0801, y dos displays de 7 segmentos TDS11, mediante dos latch tipo D 74HC374:


Se desea muestrear la señal analogica a una frecuencia de 1 KHz y mostrar en los displays el valor de la conversion A/D en hexadecimal. Para la temporizacion debemos usar interrupciones.

Nota: el ADC no es mas que un conversor analogico-digital de 8 bits, que recibe una señal de entrada de tension entre 0V y Vcc y muestra una salida en funcion del valor de entrada. El 74HC374 no es mas que un conversor binario-BCD, para sacar el valor de entrada por el display de 7 segmentos. Podeis descargar la documentacion al final de esta entrada.

SOLUCION EN ENSAMBLADOR:


ENSAMBLADOR:

   LIST p=16F84A
   INCLUDE "P16F84A.INC"
 
   WTEMP   EQU    0x0C
   VALOR   EQU    0x0D
 
   ORG    0x00
   GOTO    INICIO
   ORG    0X04 ;El vector de interrupcion, que esta en la pos. de memoria 4
   GOTO    INTMR0


 
 
INICIO    bcf    STATUS,RP0 ;banco 0
   CLRF    PORTA
   CLRF    PORTB
 
   movlw   b'00000011'
   movwf   PORTA
 
   bsf    STATUS,RP0 ;banco 1
 
   clrf    TRISA ;salida
   clrf    TRISB ;salida
 
   bsf    TRISA,RA2 ;ra2=entrada
 
   movlw   b'00000001'
   movwf   OPTION_REG ;Prescaler 1:4
 
   bcf    STATUS,RP0 ;banco 0 (porque el tmr0 esta en este banco)
 
   movlw   0x05 ;250*4=1000 ciclos de instruccion
;1 ciclo de instruccion=1 micro segundo
;Valor inicial del timer a 5 para que salte a los 10ms
   movwf   TMR0
 
   movlw   b'10100000'
   movwf   INTCON
 
LOOP  
   movlw   VALOR
   andlw   0x0F ;quitamos la parte alta del numero
   call    DISPLAY
   movwf   PORTB ;parte baja al bus
 
   bsf    PORTA,RA4 ;almacenamos en el latch el valor
   bcf    PORTA,RA4
 
 
 
   swapf   VALOR,W ;dejamos la parte alta del valor
   andlw   0x0F
   call    DISPLAY
   movwf   PORTB ;parte baja al bus
 
   bsf    PORTA,RA3 ;almacenamos en el latch el valor
   bcf    PORTA,RA3
 
 
   GOTO LOOP
 
 
DISPLAY  
            addwf   PCL,F
            retlw   b'00111111'     ;valor 0
            retlw   b'00000110'     ;valor 1
            retlw   b'01011011'     ;valor 2
            retlw   b'01001111'     ;valor 3
            retlw   b'01100110'     ;valor 4
            retlw   b'01101101'     ;valor 5
            retlw   b'01111101'     ;valor 6
            retlw   b'00000111'     ;valor 7
            retlw   b'01111111'     ;valor 8
            retlw   b'01100111'     ;valor 9
   retlw   b'01110111'     ;valor A
   retlw   b'01111100'     ;valor B
   retlw   b'00111001'     ;valor C
   retlw   b'01011110'     ;valor D
   retlw   b'01111001'     ;valor E
   retlw   b'01110001'     ;valor F
 
 
INTMR0
   movwf   WTEMP ;Guardamos el W a un registro temporal (mover a registros generales)
 
   bcf    STATUS,RP0 ;banco 0
 
   bcf    PORTA,RA0 ;iniciamos conversion
   bsf    PORTA,RA0
 
CONV
   BTFSC   PORTA,RA2 ;mientras ra2 sea 1, no saltamos
   GOTO    CONV
 
   BCF    PORTA,RA1 ;iniciamos lectura
 
   BSF    STATUS,RP0 ;banco 1
   COMF    TRISB ;el comp hace el complementario (cambia unos por ceros y viceversa)
;puerto b como entrada (es otra forma de hacerlo)
 
   bcf    STATUS,RP0 ;BANCO 0
   movlw   PORTB
   movwf   VALOR
 
   BSF    PORTA,RA1 ;acabamos lectura
 
   BSF    STATUS,RP0 ;banco 1
   COMF    TRISB ;puerto b como salida
 
   BCF    STATUS,RP0 ;banco 0
   movlw   0x05
   movwf   TMR0
 
   bcf    INTCON,T0IF
 
   movlw   WTEMP
 
 
   RETFIE

 
 
    end





SOLUCION EN C:

/*

Solucion en C
Compilador utilizado: XC8

 */

//podemos usar cualquiera de las dos cabeceras siguientes:
//#include <xc.h>
#include <pic16f84a.h>

//variables globales
unsigned char VALOR=0;

//rutina de servicio a la interrupcion
//un void no tiene retorno
void interrupt rsi()
{
    //iniciamos la conversion
    RA0=0;
    RA0=1;
 
    //bucle: esperamos a que acabe la conversion
    while(RA2==1)
    {
     
    }
 
    //iniciamos la lectura
    RA1=0;
    //pueto b como entrada
    TRISB=0b11111111; //TRISB=0xFF; //TRISB=255;
    VALOR=PORTB;
    //finalizamos la lectura
    RA1=1;
    TRISB=0b00000000;
    //reseteamos TMR0
    TMR0=0x05;
    T0IF=0;
    //otra forma de hacer lo anterior:
    //INTCONbits.T0IF=0;
    return;
}

//rutina del display (entrada: dato; salida: char)
unsigned char display7s(unsigned dato)
{
    unsigned char Result;
    //aqui haremos cosas
    switch(dato)
    {
        case 0: Result=0b00111111; break; //digito 0
        case 1: Result=0b00000110; break; //digito 1
        case 2: Result=0b01011011; break; //     ;valor 2
        case 3: Result=0b01001111; break; //     ;valor 3
        case 4: Result=0b01100110; break; //     ;valor 4
        case 5: Result=0b01101101; break; //     ;valor 5
        case 6: Result=0b01111101; break; //     ;valor 6
        case 7: Result=0b00000111; break; //     ;valor 7
        case 8: Result=0b01111111; break; //     ;valor 8
        case 9: Result=0b01100111; break; //     ;valor 9
   case 10: Result=0b01110111; break; //     ;valor A
   case 11: Result=0b01111100; break; //     ;valor B
   case 12: Result=0b00111001; break; //     ;valor C
   case 13: Result=0b01011110; break; //     ;valor D
   case 14: Result=0b01111001; break; //     ;valor E
   case 15: Result=0b01110001; break; //     ;valor F
        default: Result=0; break;
    }
 
    return Result;
}

//rutina principal
void main(void) {
    //variables locales
    unsigned char aux;
 
    //configuramos el PIC
    PORTA=0b00000011;
    PORTB=0b00000000;
 
    //a partir de aqui lo he hecho yo (no fiarse)
    TRISA=0b00000100;
    TRISB=0b00000000;
 
    OPTION_REG=0b00000001;  //otra forma: OPTION_REGbits.PS0=1
    TMR0=0x05;
    INTCON=0b10100000;
 
    //loop
    while(1)
    {
        aux=VALOR;
        aux=aux&0x0F; //dejamos la parte baja del bit
        PORTB=display7s(aux);
 
        PORTAbits.RA4=1;    //almacenamos en el latch el valor
        PORTAbits.RA4=0;
 
        //parte alta
   aux=VALOR;
        aux=aux>>4;     //movemos los bits a la parte baja
        aux=aux&0x0F; //dejamos la parte baja del bit
        PORTB=display7s(aux);
 
        PORTAbits.RA3=1;    //almacenamos en el latch el valor
        PORTAbits.RA3=0;       //tambien vale RA3=0;
    }
    return;
}

//Fin del programa

Para un esquema de conexion, habria que conectarlo asi:


A primera vista, parece algo complicado de ver, ya que el simulador en el que lo he conectado tiene algunas limitaciones, pero basta con seguir el esquema del enunciado para ver como habria que conectarlo correctamente. Ademas, hay un pequeño detalle que hay que tener en cuenta a la hora de conectarlo y que a mi me dio muchos problemas. Para poder usar el pin RA4 como una salida, hay que conectarle una resistencia de pull-up (en este caso R2), ya que el PIC16F84 (o el PIC16F84A) no lo tiene incorporado por defecto.

¿ASSEMBLER O C?
Pues en mi opinion, la decision no es dificil. Para el 99% de los casos, lo recomendable seria usar C, ya que es mas rapido, facil y sirve para multitud de microcontroladores distintos. Sin embargo, si lo que quieres es aprovechar los recursos de un microcontrolador al 100%, no te queda mas remedio que programarlo en ensamblador, aunque esto no suele ser necesario casi nunca, siempre depende de lo que quieras hacer con el chip.


Enlaces de descarga de la documentacion y los programas:
https://drive.google.com/drive/folders/0B20kHfrc3NnpLWdHcDlza3JnQ3c?usp=sharing