Вы находитесь на странице: 1из 38

Sistemas Digitales II

Universidad Politcnica de Madrid Departamento de Ingeniera Electrnica E.T.S.I. de Telecomunicacin

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) Curso 2012/2013


Pimote
Autores: Sara lvarez Vinagre Alfredo Tendero Casanova

Cdigo de la pareja:

MT-10

NDICE GENERAL
1 INTRODUCCIN...................................................................................................................2 2 DIAGRAMA DE SUBSISTEMAS......................................................................................... 3 3 DESCRIPCIN DEL SUBSISTEMA HARDWARE............................................................ 4 4 DESCRIPCIN DEL SUBSISTEMA SOFTWARE............................................................10 5 PRINCIPALES PROBLEMAS ENCONTRADOS............................................................. 15 6 MANUAL DE USUARIO..................................................................................................... 16 7 BIBLIOGRAFA................................................................................................................... 17

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013

1 Introduccin 1.1 Objetivos del proyecto


El objetivo del proyecto es implementar un mando a distancia universal de aire acondicionado usando una Raspberry Pi, un circuito externo de emisin y recepcin de infrarrojos y una aplicacin web accesible desde cualquier dispositivo con internet. La Raspberry se encargar de 'aprender' el funcionamiento de cada mando, almacenndolos y administrndolos de forma que, con la ayuda de la aplicacin, desde nuestro smartphone podamos seleccionar entre los distintos modelos disponibles ofrecindonos una interfaz desde la que controlar el aparato de aire acondicionado.

El sistema es fcilmente extrapolable no slo a equipos de aire aconcionado, sino cualquier otro cuyo control remoto est basado en infrarrojos. En general podemos distinguir dos familias dentro de los mandos a distancia: con y sin memoria. Los primeros son a los que nos dedicaremos. En este tipo de mandos el emisor de la trama no se limita a enviar un cdigo asignado a cada botn, sino que reenva la configuracin completa al dispositivo, independientemente del botn pulsado. Esto entraa un grado de complejidad mayor respecto al mando sin memoria, como puede ser el de una televisin estndar. Sin embargo, aunque en este momento nos centramos en un equipo de aire acondicionado, el sistema pretende poder ser capaz en un futuro de 'aprender' y gestionar controles remotos de ambos tipos.

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013

2 Diagrama de subsistemas

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013

3 Descripcin del subsistema Hardware


El hardware est formado por dos nodos, uno operando en la sala de control y otra en la sala donde se encuentra el aire acondicionado. El nodo en la sala de control es el encargado de recoger la informacin proporcionada por el usuario (trama, tiempo de bit y frecuencia de portadora) y enviarlo va radio al nodo de la sala del aire acondicionado, siendo dicha informacin emitida por un led infrarrojo. Como novedad respecto al hito 1, con el fin de sustituir el oscilador con NE555 implementado anteriormente para generar la modulacin y ampliar la funcionalidad el proyecto, hemos utilizado dos Tulios, plataforma basada en el microcontrolador C1110 de Texas Instruments. La utilizacin de este micro nos permite aadir varias mejoras: Nodos independientes que se comunican por RF, de modo que el nodo de control (Raspberry Pi) no tiene por qu estar en la misma sala que el aire acondicionado que se quiere controlar. Mayor universalidad del proyecto, ya que al generar la modulacin desde un timer del microcontrolador podemos ser capaces de generar diferentes frecuencias de portadora (no todos los mandos a distancia utilizan la misma frecuencia).

Las especificaciones del Tulio incluyen: Comunicacin radio en 868MHz Comunicacin con dispositivos externos: UART, SPI, I2C, SMBUS Conversores analgico digitales Salidas/entradas de propsito general Temporizadores internos

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013

3.1 Nodo de sala de control

Esquema elctrico. El nodo de control consta de: Una Raspberry Pi en la cual, mediante una interfaz de usuario se podr seleccionar la trama a enviar, el tiempo de bit y la frecuencia de portadora. En l correr un servidor basado en JavaScript que proporcionar una interfaz sencilla desde la que configurar la informacin a enviar y un botn para enviarla. Un Tulio, que se comunicar con la Raspberry Pi mediante UART, recogiendo la informacin indicada por el usuario y envindola por radio al nodo del aire acondicionado. El cdigo implementado se describe en el apartado de software.

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013

Un display LCD conectado al GPIO de Raspberry que nos ser til a la hora de saber la temperatura a la que hemos configurado el aire acondicionado y la direccin IP asignada a la Raspberry una vez conectada a la red. La descripcin del software que controla lo que se muestra en el display se detallar en el apartado de software.

Justificacin de la solucin adoptada. El nodo descrito se encarga nicamente de recoger y retransmitir al nodo del aire acondicionado la informacin necesaria para reconstruir y emitir la trama que cambia la temperatura en el dispositivo. Por tanto, hemos optado por relegar el trabajo de construccin de la trama al otro nodo, quedando este con una funcionalidad bastante sencilla pero efectiva. Problemas encontrados durante la implementacin. Dada la fcil implementacin de la transmisin radio proporcionada por el fabricante del Tulio, conseguir el correcto funcionamiento de esta parte fue bastante sencillo. La instalacin del LCD no fue complicada pero hubo algunas complicaciones al usar la librera software y encontrar los smbolos adecuados.

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013

3.2 Nodo de sala de aire acondicionado

Esquema elctrico. En la sala del aire acondicionado habr un nodo compuesto por: Un Tulio, que recibe por radio la trama que deber enviar al aire acondicionado. Un circuito emisor, compuesto por un led infrarrojo y un circuito amplificador basado en un transistor (BC107).

Justificacin de la solucin adoptada. Las tramas enviadas por un mando a distancia estndar constan de pulsos modulados (usualmente a 38kHz). Por tanto, nuestro emisor debe ser capaz de modular los bits de la trama antes de ser enviados. A diferencia del primer hito y tal y como expusimos, hemos sustituido el oscilador hardware basado en NE555 por un temporizador del microcontrolador utilizado (C1110). De este modo el usuario puede configurar fcilmente desde el nodo de control la frecuencia de portadora y el tiempo de bit, permitiendo usar cualquier tipo de mando a distancia. 7

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013

Por tanto, el circuito externo al microcontrolador es sencillamente un led infrarrojo con un circuito amplificador que se comunica con el aire acondicionado. Mediante el pin P0_0 del Tulio controlamos dicho led. Justificaciones tericas de los valores adoptados para cada uno de los componentes. Para el circuito amplificador hemos utilizado un transistor NPN y una resistencia de 47 tal y como se indica a continuacin. Este montaje amplifica la seal a la salida del pin para que el led emita con mayor intensidad.

Problemas encontrados durante la implementacin. Los principales problemas vinieron a raz de que, al estar trabajando con SDCC, no disponamos de la funcin sleep() de C, necesaria para generar el tiempo de bit. Esto nos llev a plantearnos maneras alternativas, y decidimos usar un timer del Tulio. En primera instancia se utiliz el temporizador n2, especializado para controlar slots de tiempo. Sin embargo, no fuimos capaces de hacerlo funcionar, y revisando los ficheros de la librera encontramos que el chip de nuestro modelo no soportaba dicho timer. Otro de los problemas fue decidir cmo controlar el pin de salida de la trama: mediante PWM o haciendo oscilar directamente el pin. Para evitar usar dos temporizadores (uno para generar el tiempo de bit y otro para la frecuencia de portadora), optamos por hacer oscilar directamente el pin. Aqu el problema fue implementar correctamente el cdigo para poder generar, a partir de un solo timer, la frecuencia de portadora y el tiempo de bit.

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013

4 Descripcin del subsistema Software 4.1 Proceso del programa principal


Cdigo implementado Nodo de la sala de control scriptLCD.sh Este es un script en Python encargado de mostrar en el display LCD la informacin acerca del estado del aire acondicionado as como la IP de la Raspberry. De este modo el usuario puede ver en cualquier momento cul es el estado del sistema, y conocer a simple vista la IP para conectarse a la interfaz web de usuario. Se encuentra en la carpeta usr/sbin, y es controlado por un daemon de la carpeta init.d. Adems est configurado para que arranque con el sistema, de modo que el usuario tenga siempre disponible la informacin.
#!/usr/bin/python # # # # # # # # # # # # # # # # # The 1 : 2 : 3 : 4 : 5 : 6 : 7 : 8 : 9 : 10: 11: 12: 13: 14: 15: 16: wiring for the LCD is as follows: GND 5V Contrast (0-5V)* RS (Register Select) R/W (Read Write) - GROUND THIS PIN Enable or Strobe Data Bit 0 - NOT USED Data Bit 1 - NOT USED Data Bit 2 - NOT USED Data Bit 3 - NOT USED Data Bit 4 Data Bit 5 Data Bit 6 Data Bit 7 LCD Backlight +5V** LCD Backlight GND

#import import RPi.GPIO as GPIO import time from datetime import datetime from Adafruit_CharLCD import Adafruit_CharLCD from subprocess import * from time import sleep, strftime # Define LCD_RS = LCD_E = LCD_D4 = LCD_D5 = LCD_D6 = LCD_D7 = GPIO to LCD mapping 7 8 25 24 23 18

# Define some device constants

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013


LCD_WIDTH = 16 LCD_CHR = True LCD_CMD = False # Maximum characters per line

LCD_LINE_1 = 0x80 # LCD RAM address for the 1st line LCD_LINE_2 = 0xC0 # LCD RAM address for the 2nd line # Timing constants E_PULSE = 0.00005 E_DELAY = 0.00005

def main(): # Main program block GPIO.cleanup() GPIO.setmode(GPIO.BCM) GPIO.setup(LCD_E, GPIO.OUT) GPIO.setup(LCD_RS, GPIO.OUT) GPIO.setup(LCD_D4, GPIO.OUT) GPIO.setup(LCD_D5, GPIO.OUT) GPIO.setup(LCD_D6, GPIO.OUT) GPIO.setup(LCD_D7, GPIO.OUT) # Initialise display lcd_init() # Send some test lcd_byte(LCD_LINE_1, LCD_CMD) lcd_string("P i m o t e") lcd_byte(LCD_LINE_2, LCD_CMD) lcd_string("Alfredo y Sara")

# # # # # # #

Use BCM GPIO numbers E RS DB4 DB5 DB6 DB7

time.sleep(3) # 3 second delay # Send some text while 1: lcd_byte(LCD_LINE_1, LCD_CMD) # lcd_string(datetime.now().strftime('%b %d %H:%M:%S\n')) cmd2 = "cat /home/pi/pimoteserver/temp.txt" estado = run_cmd(cmd2) lcd_string(estado) lcd_byte(LCD_LINE_2, LCD_CMD) cmd = "ip addr show eth0 | grep inet | awk '{print $2}' | cut -d/ -f1 | tr -d '\n'" ipaddr = run_cmd(cmd) if ipaddr == "": lcd_string("Sin conexion") else: lcd_string('IP %s' % ( ipaddr )) def run_cmd(cmd): p = Popen(cmd, shell=True, stdout=PIPE) output = p.communicate()[0] return output def lcd_init(): # Initialise display lcd_byte(0x33,LCD_CMD) lcd_byte(0x32,LCD_CMD) lcd_byte(0x28,LCD_CMD) lcd_byte(0x0C,LCD_CMD) lcd_byte(0x06,LCD_CMD) lcd_byte(0x01,LCD_CMD)

10

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013


def lcd_string(message): # Send string to display message = message.ljust(LCD_WIDTH," ") for i in range(LCD_WIDTH): lcd_byte(ord(message[i]),LCD_CHR) def # # # # lcd_byte(bits, mode): Send byte to data pins bits = data mode = True for character False for command

GPIO.output(LCD_RS, mode) # RS # High bits GPIO.output(LCD_D4, False) GPIO.output(LCD_D5, False) GPIO.output(LCD_D6, False) GPIO.output(LCD_D7, False) if bits&0x10==0x10: GPIO.output(LCD_D4, True) if bits&0x20==0x20: GPIO.output(LCD_D5, True) if bits&0x40==0x40: GPIO.output(LCD_D6, True) if bits&0x80==0x80: GPIO.output(LCD_D7, True) # Toggle 'Enable' pin time.sleep(E_DELAY) GPIO.output(LCD_E, True) time.sleep(E_PULSE) GPIO.output(LCD_E, False) time.sleep(E_DELAY) # Low bits GPIO.output(LCD_D4, False) GPIO.output(LCD_D5, False) GPIO.output(LCD_D6, False) GPIO.output(LCD_D7, False) if bits&0x01==0x01: GPIO.output(LCD_D4, True) if bits&0x02==0x02: GPIO.output(LCD_D5, True) if bits&0x04==0x04: GPIO.output(LCD_D6, True) if bits&0x08==0x08: GPIO.output(LCD_D7, True) # Toggle 'Enable' pin time.sleep(E_DELAY) GPIO.output(LCD_E, True) time.sleep(E_PULSE) GPIO.output(LCD_E, False) time.sleep(E_DELAY) if __name__ == '__main__': main() GPIO.cleanup()

11

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013

raspi_wd.sh Este shell script se encarga de monitorizar el fichero de texto que se actualiza cada vez que el usuario quiere realizar alguna accin sobre el aire acondicionado. Para no acaparar todos los recursos de la mquina con un bucle utiliza la herramienta inotifywait. Se encuentra en la carpeta usr/sbin, y es controlado por un daemon de la carpeta init.d. Adems est configurado para que arranque con el sistema, de modo que el sistema est operativo desde el arranque.
#! /bin/sh ### BEGIN INIT INFO # Provides: # Required-Start: # Required-Stop: # Default-Start: # Default-Stop: # Short-Description: # Description: ### END INIT INFO

watchdog del archivo arg.txt $all $all 2 3 4 5 0 1 6 Short script description Longer script description.

case "$1" in start) echo "Iniciando raspi_wd... " while inotifywait -e close_write /home/pi/pimoteserver/arg.txt; do cd /home/pi/enviatramas; PAR=`cat /home/pi/pimoteserver/arg.txt` ; ./raspibase $PAR; done ;; stop) echo "Deteniendo raspi_wd..." kill -9 `ps -ef|grep -v grep |grep raspi_wd.sh| awk '{print $2}'` ;; *) echo "Modo de empleo: /etc/init.d/raspi_wd.sh {start|stop}" exit 1 ;; esac exit 0

server.sh Este shell script tiene la funcin de arrancar la interfaz de usuario web automticamente. Se encuentra en la carpeta usr/sbin, y es controlado por un daemon de la carpeta init.d. Adems est configurado para que arranque con el sistema, de modo que el servidor est operativo cuando el dispositivo se enciende.
#! /bin/sh ### BEGIN INIT INFO # Provides: # Required-Start: # Required-Stop: # Default-Start: # Default-Stop: # Short-Description: # Description: ### END INIT INFO

pimote server $all $all 2 3 4 5 0 1 6 Short script description Longer script description.

case "$1" in start) echo "Iniciando server Pimote... " cd /home/pi/quiz_edit nodejs ./quiz.js &

12

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013


;; stop) echo "Deteniendo server Pimote..." kill -9 `ps -ef | grep -v grep | grep nodejs | awk '{print $2}'` ;; *) echo "Modo de empleo: /etc/init.d/server.sh {start|stop}" exit 1 ;; esac exit 0

pimote_server.js Este fichero es el ncleo de la aplicacin web programada en NodeJS. Con ella proporcionamos una interfaz de usuario sencilla para que el sistema completo sea cmodo de usar. No incluimos en esta memoria los cdigos HTML5 pero en su lugar mostramos la siguiente captura de la aplicacin, ms representativa de dicho cdigo.

var var var var var

HTTP URL QS MIME FS

= = = = =

require('http'); require('url'); require('querystring'); require('mime'); require('fs');

HTTP.createServer(function(request, response) { var MODEL = { show: function (button, action) { FS.readFile('arg.txt','utf-8', function(err, arg) { if (!err) { arg = arg.replace(new RegExp(button + ':.*\n', 'g'), ''); } else { action(err); }; }); FS.readFile('buttons.txt', 'utf-8', function(err, buttons) { if (!err) {

13

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013


var bt = buttons.match(new RegExp('^'+button+': .*$','m')); var b_t = bt.join().split(": "); FS.writeFile('arg.txt',b_t[1], 'utf-8', function (err) { action(err); }); if(b_t[0] == "OFF"){ FS.writeFile('temp.txt',"Aire apagado", 'utf-8', function (err) { action(err); }); }else{ FS.writeFile('temp.txt',"Encendido " + b_t[0] +"\xDFC", 'ascii', function (err) { //0xDF action(err); }); } } else {action(err); }; }); }, find_bot_arch: function (button, action) { FS.readFile('buttons.txt', 'utf-8', function(err, buttons) { var preg_respuesta = buttons.match(new RegExp('^'+button+': .*$','m')); var preg_y_resp_array = preg_respuesta.join().split(": "); action(err, preg_y_resp_array ); }); }, all_questions: function (action) { FS.readFile('buttons.txt', 'utf-8', function(err, buttons) { action(err, buttons.replace(/^(.*): .*$/mg, '<option>$1</option>')); }); }, delete: function (button, action) { FS.readFile('buttons.txt','utf-8', function(err, buttons) { if (!err) { buttons = buttons.replace(new RegExp(button + ':.*\n', 'g'), ''); FS.writeFile('buttons.txt', buttons, 'utf-8', function (err) { action(err); }); } else { action(err); }; }); }, create: function (button, action) { FS.open('./buttons.txt', 'a', function( e, id ) { FS.write(id, button+'\n', null, 'utf8', function(){ FS.close(id, function(){ console.log('file closed'); }); }); }); var btt = button.split(": "); FS.writeFile('escucha.txt', btt[1], 'utf-8', function (err) { action(err); }); }, update: function (button, action) { FS.readFile('buttons.txt','utf-8', function(err, buttons) { if (!err) { var boton = button.split(":")[0]; buttons = buttons.replace(new RegExp(boton + ':.*\n', 'g'), button + '\n');

14

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013


FS.writeFile('buttons.txt', buttons, 'utf-8', function (err) { action(err); }); } else { action(err); }; }); } } var VIEW = { render: function (file, r1) { FS.readFile(file, 'utf-8', function(err, data) { if (!err) { var data = data.replace(/<%r1%>/g, r1); if (r1.length==2){ data = data.replace(/<%r2%>/g, r1[0]); data = data.replace(/<%r3%>/, r1[1]); } response.writeHead(200, { 'Content-Type': 'text/html', 'Content-Length': data.length }); response.end(data); } else { VIEW.error(500, "Server operation Error_r"); }; }); }, error: function(code,msg) { response.writeHead(code); response.end(msg);}, file: function(file) { FS.readFile(file, function(err, data) { if (!err) { response.writeHead(200, { 'Content-Type': MIME.lookup(file), 'Content-Length': data.length }); response.end(data); } else { VIEW.error (500, file + " not found"); }; }); } } var CONTROLLER = { index: function () { MODEL.all_questions (function(err, all_questions) { if (!err) VIEW.render('index.html', all_questions); else VIEW.error(500, "Server bbdd Error_a"); }); }, send: function () { MODEL.all_questions (function(err, all_questions) { if (!err) VIEW.render('show.html', all_questions); else VIEW.error(500, "Server bbdd Error_a"); }); }, new: function () { VIEW.render ('new.html', ""); }, file: function() { VIEW.file(url.pathname.slice(1)); }, edit: function () { MODEL.find_bot_arch(button, function(err, find_bot_arch) { if (!err) VIEW.render('edit.html',find_bot_arch); else VIEW.error(500, "Server bbdd Error_b"); }); }, create: function () {

15

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013


MODEL.create(button, function(err) { if (!err) CONTROLLER.index(); // redireccin a 'GET quiz/index' else VIEW.error(500, "Server bbdd Error_c"); }); }, remove: function() { MODEL.all_questions (function(err, all_questions) { if (!err) VIEW.render('remove.html', all_questions); else VIEW.error(500, "Server bbdd Error_d"); }); }, delete: function () { MODEL.delete (button, function(err) { if (!err) VIEW.render('show.html',find_bot_arch); else VIEW.error(500, "Server bbdd Error_e"); }); },

show: function () { MODEL.show(button, function(err, resp) { if (!err) CONTROLLER.send(); // redireccin a 'GET quiz/index' else VIEW.error(500, "Server bbdd Error_b"); }); }, update: function () { MODEL.update(button, function(err) { if (!err) CONTROLLER.index(); // redireccin a 'GET quiz/index' else VIEW.error(500, "Server bbdd Error_c"); }); } } var url = URL.parse(request.url, true); var post_data = ""; request.on('data', function (chunk) { post_data += chunk; }); request.on('end', function() { post_data = QS.parse(post_data); // "question" variable global -> visible en controlador button = (post_data.preg || url.query.preg); //question = (post_data.preg + (post_data.resp == null ? "" : ": " + post_data.resp) || url.query.preg); if(post_data.resp != null){ button += ": " + post_data.resp; } var route = (post_data._method || request.method) + ' ' + url.pathname; switch (route) { case 'GET /index' : CONTROLLER.index() ; break; case 'GET /show' : CONTROLLER.show() ; break; case 'GET /new' : CONTROLLER.new() ; break; case 'GET /edit' : CONTROLLER.edit() ; break; case 'PUT /update' : CONTROLLER.update() ; break; case 'POST /create' : CONTROLLER.create() ; break; case 'GET /remove' : CONTROLLER.remove() ; break; case 'DELETE /delete' : CONTROLLER.delete() ; break; default: { if (request.method == 'GET') CONTROLLER.file() ; else VIEW.error(400, "Unsupported request"); } }

16

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013


}); }).listen(3000);

emisor.c Este fichero, ejecutado en el Tulio situado en la sala de control, se encarga de recibir la informacin por la UART y reenviarla va radio. Para recibir informacin por el puerto serie, chequea de manera peridica si hay datos en el pin mediante un buffer circular. Para emitir datos va radio utilizamos la funcionalidad aportada por el fabricante, con lo que basta ejecutar la funcin cc1110_tx(source, destination, data, data_length, type). Adems de todo esto, cabe destacar que el microcontrolador entra en reposo cuando no se estn recibiendo datos.
/ ************************************************************************* ********* Filename: emisor.c Description: Codigo para transmitir una trama recibida por UART del nodo base al nodo del a/c. Comments: El dispositivo enva los datos al nodo del a/c. Despus de enviarlo se pone en modo de ahorro de energa. ************************************************************************* **********/ #include "hal_main.h" #include "libcc1110.h" #define TX_ADD 10 #define RX_ADD 20 #define SLEEP_PERIOD 1 #define UART_TX_PERIOD 5 // Sleep Timer period #define UART_BUFFER_SIZE 150 //******** Variables for this app volatile UINT8 current_232_data = 0; // byte to store rs232 received data volatile UINT8 current_232_pos = 0; // current position of buffer to store data volatile UINT8 rs232_buf[UART_BUFFER_SIZE]; // buffer where data is stored volatile Buffer_cir rs232_buf_cir; //******** Flags and triggers volatile UINT8 flag_ST = 0; // Sleep Timer flag volatile UINT8 flag_UART = 0; // Uart RX flag //******** Configuracion RF ******************** //estas tres variables siempre deben estar definidas***** //********************************************* UINT8 rf_power = RF_POWER_P10; UINT8 rf_channel = 0x01; // Configuracion del canal RF network_address netAdd; // network address structure void main(void) { BYTE status = 0;

17

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013


// Inicializacin de leds del Tulio INIT_RLED(); INIT_GLED(); RLED = LED_OFF; GLED = LED_OFF; /*********************************************************** * Estas dos instrucciones deben estar juntas al principio de cualquier aplicacin de Tulio. */ SET_MAIN_CLOCK_SOURCE(CRYSTAL); // Elige el cristal oscilador como reloj del sistema cc1110_init(); // AWD HW init enable_wdt (SEC_1); // Configura watchdog con periodo 1 seg // Configura direccion RF netAdd.my_address = TX_ADD; // Al venir de bajo consumo se vuelve a configurar el cristal como reloj del sistema SET_MAIN_CLOCK_SOURCE(CRYSTAL); // Configuracin de los datos a enviar por RF // Comprueba nuevos datos en la UART con un buffer circular data_len = buffer_cir_get (&rs232_buf_cir, app_data, UART_BUFFER_SIZE); if (data_len > 0) { // Enva datos // cc1110_tx(UINT16 src, UINT16 dst, BYTE* Buffer_add, BYTE data_len, BYTE com_type) status = cc1110_tx(netAdd.my_address, RX_ADD, app_data, sizeof(app_data)-6, CO); // Leds lucen segn estado de transmisin switch (status) { case TX_OK: GLED = !GLED; break; case TX_FAIL: case TX_FAIL_CONFIG: case TX_FAIL_ACK: case TX_FAIL_CHANNEL_BUSY: RLED = !RLED; break; } // Se apaga la radio reset_radio(); // Entra en POWER_MODE_2 durante SLEEP_PERIOD segundos set_idle_mode_ST (SLEEP_PERIOD, POWER_MODE_2); } return; } /*==== FUNCIONES PRIVADAS =====================================================*/ //#pragma vector=ST_VECTOR //__interrupt void stIrq(void) void stIrq(void) __interrupt(ST_VECTOR) { IRCON &= 0x7F; WORIRQ &= 0xFE; SLEEP &= 0xFC; }

18

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013

raspi_base.c Este fichero es ejecutado en la Raspberry Pi, y se encarga de leer la informacin de un fichero .txt con la informacin a enviar con el fin de transmitirla a continuacin por el puerto serie.
/ ***************************************************************************** ****** Filename: raspi_base.c Description: Enva los datos seleccionados por el usuario al Tulio para configurar el aire acondicionado via radio. Important: Advierta que los pines estn configurados a 3.3V y las especificaciones de RS232 son para 12V. Si conecta esto a un dispositivo RS232 podra daar su Raspberry Pi. ***************************************************************************** ******/ #include #include #include #include #include <stdio.h> <unistd.h> <fcntl.h> <termios.h> <errno.h>

//Used for UART //Used for UART //Used for UART

int main(int argc, char *argv[]) { //------------------------//----- SETUP UART -------//------------------------int uart0_filestream = -1; unsigned char tx_buffer[700]; unsigned char *p_tx_buffer; int i; int palabras; struct termios options; unsigned int speed = B115200; uart0_filestream = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY); //Open in non blocking write mode if (uart0_filestream == -1) { //ERROR - CAN'T OPEN SERIAL PORT perror("Error - Unable to open UART. Ensure it is not in use by another application\n"); } tcgetattr(uart0_filestream, &options); options.c_cflag = CS8 | CLOCAL | CREAD; options.c_iflag = IGNBRK; //IGNPAR | ICRNL; options.c_oflag = 0; options.c_lflag = 0; cfsetospeed(&options, speed); cfsetispeed(&options, speed); tcflush(uart0_filestream, TCIOFLUSH); tcsetattr(uart0_filestream, TCSANOW, &options); //----- TX BYTES ----//tx_buffer[] = {header, header, header, header, header, header, //<Set baud rate

19

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013


//words ,tbit1, tbit2(useg), carrier(kHz), data, data,...,end code} // unsigned char buffer[] = {0,0,0,0,0,0, //TX header // 0, 0x02, 0x13, 0x1A, // 0b01010001}; //Trama a enviar if(argc!=2) { printf("introduzca el nombre del fichero con su extensin.\n"); return 0; } FILE *f; unsigned char buffer[700]; int n; f = fopen(argv[1], "rb"); if (f){ n = fread(buffer, 1, sizeof(buffer), f); printf("n: %i\n", n); } else { printf("ERROR\n"); return 0; } unsigned char mask = 0x80; unsigned char j = 0; for (i = 0; i < n; i++) { if (buffer[i] == '1') { tx_buffer[j] |= mask; } else if (buffer[i] == '0') { tx_buffer[j] &= ~mask; } else { break; } mask >>= 1; if (! mask) { j++; mask = 0x80; } } tx_buffer[j++] = '\n'; printf("New tx_buffer: "); for ( i = 0; i < j; i++) { printf ("0x%x", tx_buffer[i]); } if (uart0_filestream != -1){ int count = write(uart0_filestream, tx_buffer,j); if (count < 0){ printf("UART TX error\n"); } } sync(); fflush(stdout); sleep(1); //----- CLOSE THE UART ----close(uart0_filestream); }

20

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013

Nodo de la sala de aire acondicionado receptor_ac.c Este cdigo, ejecutado por el Tulio de la sala de aire acondicionado, es el ms complejo de todos los expuestos, puesto que es el que genera la trama modulada en uno de sus pines. Para empezar, un buffer circular chequea si llega nueva informacin va radio.
buffer_cir_get (&buf_rx, radio_buf, BUFFER_SIZE)

Cuando esto ocurre, se recorre el array radio_buf y se guarda en diferentes variables la informacin correspondiente a tiempo de bit y de portadora. Con ellos se configura el timer 3 (ajustado a frecuencia de portadora) y se calcula el nmero de iteraciones del mismo que conforman un tiempo de bit (variable veces). A continuacin, un bucle for recorre slo los elementos de radio_buf que corresponden a la trama que se debe enviar al aire acondicionado. Dentro de dicho bucle se recorre cada bit de la trama con una mscara, encendiendo o apagando el pin P0_0 en funcin de su valor (0 o 1). Para asegurarnos de que el tiempo de bit es el adecuado, se comprueba mediante el bucle while(counter < veces) que se han producido el nmero de iteraciones del timer 3 necesarias para que haya transcurrido el tiempo de bit. Para contar las iteraciones se comprueba el valor del registro TIMIF, en el cual el bit 0 corresponde al flag de overflow del timer 3.
/ ***************************************************************************** ***** Filename: receptor_ac.c Description: Comments: Cdigo de prueba para transmitir una trama recibida por radio desde el nodo base al a/c.

El dispositivo recibe los datos del nodo base y los enva al a/c. Despus de enviarlo se pone en modo de ahorro de energa. ***************************************************************************** ******/ #include #include #include #include "hal_main.h" "libcc1110.h" "hal_timer.h" "hal_defines.h"

#define LED_TOGGLE() \ do { \ GLED = LED_ON; RLED = LED_ON; halWait(200); GLED = LED_OFF; RLED = LED_OFF; } while (0) #define PORT_0 #define PORT_1 #define PORT_2 0 1 2

\ \ \ \ \

21

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013


#define PULL_UP #define PULL_DOWN #define RISING_EDGE #define FALLING_EDGE #define TX_ADD #define RX_ADD 10 20 0 1 0 1

//******** Configuracion RF ******************** //estas tres variables siempre deben estar definidas***** //********************************************* UINT8 rf_power = RF_POWER_P10; // TX Power Output UINT8 rf_channel = 0x01; // RF channel configuration network_address netAdd; // network address structure //********Buffer circular RF******************** //********************************************* extern Buffer_cir buf_rx; void main(void){ //Tiempo de bit en useg UINT32 tbit = 0; //Periodo de portadora en miliseg. UINT8 tcarrier = 0; //El periodo fijado en el timer debe ser la mitad que tcarrier UINT8 tadaptada = 0; UINT8 veces = 0; UINT8 counter = 0; UINT8 index = 0; UINT8 mask; /***Rx de datos***/ //Radio Buffer (ver includes para ms informacin) UINT8 radio_buf[BUFFER_SIZE]; //direccion UINT16 dst_add = 0; // Configura direccion de la fuente netAdd.my_address = RX_ADD; // Inicializacin de leds del Tulio INIT_RLED(); INIT_GLED(); RLED = LED_OFF; GLED = LED_OFF; /*********************************************************** * Estas dos instrucciones deben estar juntas al principio de cualquier aplicacin de Tulio. */ SET_MAIN_CLOCK_SOURCE(CRYSTAL); // Elige el cristal oscilador como reloj del sistema cc1110_init(); // AWD HW init // Radio como receptor set_rx(); // Bucle principal while (1) { // chequea nueva informacin por radio en buffer circular

22

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013


while (buffer_cir_get (&buf_rx, radio_buf, BUFFER_SIZE) > 0) { // Comprueba si direccion de destino es mi direccion. Evita procesar mensajes enviados a otros destinatarios. dst_add = (radio_buf[4] << 8) + radio_buf[5]; if (dst_add == RX_ADD) { LED_TOGGLE(); //P0_0 como pin de salida IO_DIR_PORT_PIN(0,0,IO_OUT); //Configuracin del timer 3 para generar portadora tcarrier = radio_buf[9]; tadaptada = tcarrier/2; Module_Running_Timer_34 (tadaptada, 3); TIMER3_RUN(TRUE); tbit = (radio_buf[7] << 8) + radio_buf[8]; //Nmero de vueltas del timer 3 que conforman el tiempo de bit veces = tbit/tadaptada; for (index = 10; index < 10+radio_buf[6]; index++) { for (mask=0x80; mask; mask >>=1) { counter = 0x00; P0_0 = 0; if(mask & radio_buf[index]){ while(counter < veces){ P0_0 ^= (!!mask); while(!(TIMIF&0x01)){} counter++; TIMIF &= 0xFE; //Limpia flag } }else{ while(counter < veces){ P0_0 = 0; while(!(TIMIF&0x01)){} counter++; TIMIF &= 0xFE; //Limpia flag } } } } } } TIMER34_INIT(3); } } /*==== FUNCIONES PRIVADAS =====================================================*/ //#pragma vector=URX0_VECTOR //__interrupt void urx0_isr (void) void urx0_isr (void) __interrupt(URX0_VECTOR){}

Justificacin de la solucin adoptada Tal y como se explic anteriormente, generar la trama mediante un temporizador del microcontrolador fue la alternativa ante la imposibilidad de utilizar la funcin sleep(), necesaria para generar el tiempo de bit, adems de servir para eliminar el oscilador hardware anteriormente utilizado. Adems se ha procurado usar un solo temporizador en lugar de dos 23

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013

para generar tanto la oscilacin de la trama modulada como el tiempo de bit, con el fin de no sobrecargar el micro. Plan de pruebas Para comprobar el correcto funcionamiento del cdigo implementado, fijamos una trama de prueba y su correspondiente tiempo de bit y frecuencia de portadora. Los datos son: Trama: 01010000 01100101 01101110 01100101 Tiempo de bit terico: 531 s Frecuencia de portadora: 1/26 s => 38 kHz

A la salida del pin del sistema Tulio tenemos la siguiente trama:

En la segunda captura vemos en detalle uno de los bits a la salida del pin. En el se puede comprobar que la frecuencia de portadora y el tiempo de bit se aproximan a los calculados tericamente.

24

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013

Comparando, a la salida del receptor de infrarrojos obtenemos la siguiente trama demodulada:

25

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013

5 Principales problemas encontrados


Tal y como se ha venido recalcando a lo largo de la memoria, los principales problemas han sido a raz de la falta de documentacin acerca del aire acondicionado estudiado. Esto nos ha llevado a destinar mayor tiempo del que se esperaba a buscar informacin al respecto y probar a 'descifrar' el funcionamiento del mando. Sin embargo, una vez pasado este escollo nos hemos desenvuelto con normalidad, y esperamos que en el futuro la informacin recabada hasta ahora nos permita continuar con el proyecto con mayor facilidad. Adems, en el segundo hito, nos encontramos con ciertas complicaciones relacionadas con el manejo de los CC1100 tales como las limitaciones con respecto a los timers anteriormente comentadas y el protocolo de comunicacin va radio, que aada bit espreos al final de nuestra trama. Finalmente, el tercer hito se ha caracterizado por la mejora de la interfaz de usuario, que mediante un sistema de ficheros actualizables permite una comunicacin tranparente con el aire acondicionado. Hacer que esto funcionase de manera estable y sin fallos llev algo de tiempo, pues fue necesario hacer uso de expresiones regulares integradas en el servidor node.js para poder leer y procesar adecuadamente los parmetros fijados por el usuario. Por otro lado, uno de los logros que queramos conseguir en este hito era el aprendizaje de tramas. Tal y como se expuso en el hito 2, el cdigo para detectar eventos y muestrear la seal de entrada procedente de un led infrarrojo ya lo tenamos implementado para entonces. El cdigo Python es el siguiente:
#!/usr/bin/python import sys import RPi.GPIO as GPIO import timeit import time GPIO.setmode(GPIO.BCM) #setup pin as inputs and put the pull down resistor on it to avoid any issues GPIO.setup(11, GPIO.IN, pull_up_down=GPIO.PUD_UP) #Raw photodiode GPIO.setup(12, GPIO.IN, pull_up_down=GPIO.PUD_UP) #IR decoder #create list to store data data = [] #create list to store bit time tbit = [] #create list to store carrier period tcarrier = [] # # # # # # # # # int int int int int int int int int t_bit_start t_bit_end t_bit_min t_carrier_start t_carrier_end t_carrier_min diff_tbit diff_tcarrier cociente

#the function called by the interrupt on pin 17 def capture_data(channel):

26

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013


if GPIO.input(channel): print('Input was HIGH') data.append(0) t_bit_start = timeit.timeit() #check start time while GPIO.input(channel) == GPIO.HIGH: pass #wait t_bit_end = timeit.timeit() #check time at the end diff_tbit = t_bit_end - t_bit_start print('Bit time: '+diff_tbit) tbit.append(diff_tbit) else: print('Input was LOW') data.append(1) t_bit_start = timeit.timeit() #check start time while GPIO.input(channel) == GPIO.LOW: pass #wait t_bit_end = timeit.timeit() #check time at the end diff_tbit = t_bit_end - t_bit_start print('Bit time: '+diff_tbit) tbit.append(diff_tbit)

# def capture_data(channel): # if GPIO.input(channel): # print('Input was HIGH') # data.append(1) # t_carrier_start = timeit.timeit() #check time at beginning # GPIO.add_event_detect(22, GPIO.RISING, callback=capture_tcarrier) # t_carrier_start = timeit.timeit() #reset start time for next cycle # # # # # # # # else: print('Input was LOW') data.append(0) t_bit_end = timeit.timeit() #check time at the end diff_tbit = t_bit_end - t_bit_start print('Bit time: '+diff_tbit) tbit.append(diff_tbit) t_bit_start = timeit.timeit() #reset start time for next cycle

#the function called by the interrupt on pin 18 def capture_tcarrier(channel): t_carrier_start = timeit.timeit() #check start time while GPIO.input(channel) == GPIO.HIGH: pass #wait t_carrier_end = timeit.timeit() #check time at the end diff_tcarrier = 2*(t_bit_end - t_bit_start) print('Carrier period: '+diff_tcarrier) tcarrier.append(diff_tcarrier) #initialize the interrupt print('Detecting signal') try: print('entro') GPIO.add_event_detect(11, GPIO.RISING, callback=capture_data) GPIO.add_event_detect(12, GPIO.RISING, callback=capture_tcarrier) print('por aqui ando') except KeyboardInterrupt:

27

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013


print('key interrupt') GPIO.cleanup() t_bit_min = 0 t_carrier_min = 0 for t in tbit: t_bit_min = 0 if t<t_bit_min: t_bit_min = t for t in tcarrier: t_carrier_min = 0 if t<t_carrier_min: t_carrier_min = t # Write mode creates a new file or overwrites the existing content of the file. # Write mode will _always_ destroy the existing contents of a file. try: # This will create a new file or **overwrite an existing file**. f = open("buttons.txt", "w") try: tbitstring = str(t_bit_min) #stringify tbit tcarrstring = str(t_carrier_min) #stringify tcarrier f.write(tbitstring) f.write(tcarrstring) for index,item in enumerate(data): cociente = tbit(index)/t_bit_min cocienteint = int(cociente) #force cociente to int for x in range(0,cocienteint): itemstring = str(item) #stringify item f.write(itemstring) # Write bit value to file #f.writelines(lines) # Write a sequence of strings to a file f.write('\n') finally: f.close() print('Button added') sys.exit() except IOError: print('ERROR while reading file')

Sin embargo al hacer pruebas nos topamos con que al ser un programa en espacio de usuario, no tena la suficiente rapidez para capturar todas las interrupciones al verse interrumpido por otros procesos del sistema. Por tanto nos dispusimos a la opcin ms fiable en cuanto a lo que tiempo y rapidez de atencin se refiere: hacer un driver. Para la realizacin de dicho driver utilizamos ampliamente el libro de referencia Linux Device Drivers de la editorial O'Reilly, puesto que era la primera vez que nos enfrentabamos a una tarea similar. El principal problema a la hora de implementar el driver estaba en que los fabricantes de Raspberry Pi no dan soporte para ciertas funcionalidades como por ejemplo el muestreo del GPIO a nivel hardware. Es decir, se puede implementar, pero no est documentado en detalle. El primer escollo a superar fue encontrar los valores de los registros para poder escribir y leer de ellos, as como la manera de hacerlo. Finalmente, el driver que hemos desarrollado es capaz de muestrear la seal entrante de por un pin, y almacenarlo en un buffer que ser posteriormente pasado al espacio de usuario para ser interpretado. El cdigo es el que se detalla a continuacin: 28

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013

/* * PIMOTE driver */ #include #include #include #include #include #include #include #include #include <linux/module.h> <linux/kernel.h> <linux/fs.h> <linux/init.h> <linux/io.h> <linux/ioport.h> <linux/interrupt.h> <linux/timer.h> <linux/gpio.h>

#define MAJOR_NUMBER 70 //Function Select Registers //FSELn = 000 --> Pin n is an input //FSELn = 001 --> Pin n is an output #define GPFSEL0 0x20200000 #define GPFSEL1 0x20200004 #define GPFSEL2 0x20200008 #define GPFSEL3 0x2020000C #define GPFSEL4 0x20200010 #define GPFSEL5 0x20200014 //Pin Level Registers //LEVn = 0 --> Pin n is low //LEVn = 1 --> Pin n is high #define GPLEV0 0x20200034 #define GPLEV1 0x20200038 //Pin Output Set Registers //SETn = 0 --> No effect //SETn = 1 --> Set GPIO pin n #define GPSET0 0x2020001C #define GPSET1 0x20200020 //Pin Output Clear Registers //CLRn = 0 --> No effect //CLRn = 1 --> Clear GPIO pin n #define GPCLR0 0x20200028 #define GPCLR1 0x2020002C //Event Detect //EDSn = 0 --> //EDSn = 1 --> #define GPEDS0 #define GPEDS1 Status Registers Event not detected on pin n Event detected on pin n 0x20200040 0x20200044

//Rising Edge Detect Enable Registers //RENn = 0 --> Rising edge detect disabled on pin n //RENn = 1 --> Rising edge detect enabled on pin n (sets corresponding bit in EDSn) #define GPREN0 0x2020004C #define GPREN1 0x20200050 //Falling Edge //FENn = 0 --> //FENn = 1 --> #define GPFEN0 #define GPFEN1 Detect Enable Registers Falling edge detect disabled on pin n Falling edge detect enabled on pin n (sets corresponding bit in EDSn) 0x20200058 0x2020005C

#define GPIO_INT0 49 #define GPIO_INT1 50

29

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013


ssize_t pimote_read (struct file *filep, char *buf, size_t count, loff_t *f_pos); ssize_t pimote_write (struct file *filep, const char *buf, size_t count, loff_t *f_pos); int pimote_open (struct inode *inode, struct file *filp); int pimote_close (struct inode *inode, struct file *filp); static struct file_operations pimote_fops = { //.owner = THIS_MODULE, .read = pimote_read, .write = pimote_write, .open = pimote_open, .release = pimote_close, }; char data_buffer [512]; //Buffer to collect data char t_data_buffer [521]; //Buffer to collect data times char t_carrier_buffer [512]; //Buffer to collect tcarrier int data_pos; //Position of data_buffer to put data int t_data_pos; //Position of t_data_buffer to put time int t_carrier_pos; //Position of time_buffer to put time int finish; //Flag for finished capture int irq_17; //Set interrupt for GPIO pin 17 irq_handler_t capture_data(int irq, void *dev_id, struct pt_regs *regs) { char* ptr; unsigned int mask; int data_value; int event_detect; printk("He llegado a capture_data"); if (! request_mem_region(GPFSEL0, 0x40, "GPFSEL0")) { printk(KERN_INFO "CAPTURE_DATA: Error request_mem_region"); //return 1; } //Point GPFSEL0 ptr = ioremap_nocache(GPFSEL0, 0x40); if (ptr) { printk(KERN_INFO "CAPTURE_DATA: remap 0x%X to 0x%X\n", GPFSEL0, (unsigned int)ptr); } else { printk(KERN_INFO "CAPTURE_DATA: Can't remap 0x%X\n", GPFSEL0); //return 1; } //Leer y limpiar GPEDS0. Imprimir por pantalla. mask = ioread32(ptr+0x40); //Read GPFSEL0 value printk(KERN_INFO "CAPTURE_DATA: GPSED0 antes de limpiar = %x\n",mask); iowrite32(mask,ptr+0x40); mask = ioread32(ptr+0x40); //Read GPFSEL0 value printk(KERN_INFO "CAPTURE_DATA: GPSED0 despues de limpiar = %x\n",mask); finish = 1; //Read event detect status event_detect = ioread32(ptr+0x34); //Read GPLEV0 value event_detect &= 0x00020000; //0000 0000 0000 0010 0000 0000 0000 0000 if(event_detect == 0x00020000) { //Level is high data_value = 1; } else { //Level is low data_value = 0;

30

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013


} //Save data_value in data_buffer data_buffer[data_pos] = data_value; data_pos++; iounmap(ptr); release_mem_region(GPFSEL0, 0x40); return IRQ_HANDLED; } int pimote_init (void) { int result; unsigned int mask; char* ptr; unsigned int irq_flags_17; //Register device result = register_chrdev (MAJOR_NUMBER, "aprende", &pimote_fops); if (result < 0) { printk(KERN_ALERT "PIMOTE not registered as char device\n"); } printk(KERN_INFO "PIMOTE registered as char device\n"); //Request memory if (! request_mem_region(GPFSEL0, 0x40, "GPFSEL0")) { printk(KERN_INFO "PIMOTE_INIT: Error request_mem_region"); } //Point GPFSEL0 ptr = ioremap_nocache(GPFSEL0, 0x40); if (ptr) { printk(KERN_INFO "PIMOTE_INIT: remap 0x%X to 0x%X\n", GPFSEL0, (unsigned int)ptr); } else { printk(KERN_INFO "PIMOTE_INIT: Can't remap 0x%X\n", GPFSEL0); } mask = ioread32(ptr); //Read GPFSEL0 value mask &= 0xFFFF8FFF; //Pin 4: bits 12 to 14 = 000 on GPFSEL0 iowrite32(mask,ptr); //Set pin 4 as input mask = ioread32(ptr+0x04); //Read GPFSEL1 value mask &= 0xFF1FFFFF; //Pin 17 bits 21 to 23 on GPFSEL1 iowrite32(mask,ptr+0x04); //Set pin 17 as input //Rising edge detect enable on pin 4 //Bit 4 = 1 on GPREN0 //GPREN0 |= 0x00000010; mask = ioread32(ptr+0x4C); //Read GPREN0 value mask |= 0x00000010; //Pin 4: bit 4 = 1 on GPREN0 iowrite32(mask,ptr+0x4C); //Write on GPREN0 //Falling edge detect enable on pin 17 //Bit 17 = 1 on GPFEN0 //GPFEN0 |= 0x00020000; mask = ioread32(ptr+0x58); //Read GPFEN0 value mask |= 0x00020000; //Pin 17: bit 17 = 1 on GPFEN0 iowrite32(mask,ptr+0x58); //Write on GPFEN0 //Rising edge detect enable on pin 17 //Bit 17 = 1 on GPREN0 //GPREN0 |= 0x00020000; mask = ioread32(ptr+0x4C); //Read GPREN0 value mask |= 0x00020000; //Pin 17: bit 17 = 1 on GPREN0 iowrite32(mask,ptr+0x4C); //Write on GPREN0

31

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013


/* request_irq: allocate a given interrupt line */ //Interrupt from raw photodiode (pin 4) //Prueba esto, y si no prueba con irq_flags = 0; //Leer y limpiar GPEDS0. Imprimir por pantalla. mask = ioread32(ptr+0x40); //Read GPFSEL0 value printk(KERN_INFO "PIMOTE_INIT: GPSED0 antes de limpiar = %x\n",mask); iowrite32(mask, ptr+0x40); mask = ioread32(ptr+0x40); //Read GPFSEL0 value printk(KERN_INFO "PIMOTE_INIT: GPSED0 despues de limpiar = %x\n",mask); iounmap(ptr); release_mem_region(GPFSEL0, 0x40); irq_17=gpio_to_irq(17); printk(KERN_INFO "irq_17: %d\n",irq_17); irq_flags_17 = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; finish = 0; if(request_irq(irq_17, (irq_handler_t) capture_data, irq_flags_17, "capture_data", NULL)){ printk(KERN_INFO "PIMOTE_READ: request_irq failed: pin 17"); } printk(KERN_INFO "He terminado el init\n"); return 0; } void pimote_exit (void) { char* ptr; int i = 0; if (! request_mem_region(GPFSEL0, 0x40, "GPFSEL0")) { printk(KERN_INFO "PIMOTE_EXIT: Error request_mem_region"); } //Point GPFSEL0 ptr = ioremap_nocache(GPFSEL0, 0x40); if (ptr) { printk(KERN_INFO "PIMOTE_EXIT: remap 0x%X to 0x%X\n", GPFSEL0, (unsigned int)ptr); } else { printk(KERN_INFO "PIMOTE_EXIT: Can't remap 0x%X\n", GPFSEL0); } free_irq(irq_17, NULL); printk(KERN_INFO "PIMOTE_EXIT: Trama capturada \n"); for(i = 0; i < 512; i++) { printk("%d ", data_buffer[i]); } unregister_chrdev (MAJOR_NUMBER, "aprende"); printk(KERN_INFO "PIMOTE unregistered\n"); iounmap(ptr); release_mem_region(GPFSEL0, 0x40); } int pimote_open(struct inode *inode, struct file *filp) { // 4 --> Raw Photodiode (12 to 14 bits on GPFSEL0 = 000)

32

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013


// 17 --> IR demod. (21 to 23 bits on GPFSEL1 = 000) char* ptr; //unsigned int mask; //unsigned int irq_flags_17; printk(KERN_INFO "Open Pimote driver..."); if (! request_mem_region(GPFSEL0, 0x40, "GPFSEL0")) { printk(KERN_INFO "PIMOTE_OPEN: Error request_mem_region"); } //Point GPFSEL0 ptr = ioremap_nocache(GPFSEL0, 0x40); if (ptr) { printk(KERN_INFO "PIMOTE_OPEN: remap 0x%X to 0x%X\n", GPFSEL0, (unsigned int)ptr); } else { printk(KERN_INFO "PIMOTE_OPEN: Can't remap 0x%X\n", GPFSEL0); } iounmap(ptr); release_mem_region(GPFSEL0, 0x40); return 0; } ssize_t pimote_read(struct file *filep, char *buf, size_t count, loff_t *f_pos) { char* ptr; printk(KERN_INFO "Read Pimote driver..."); if (! request_mem_region(GPFSEL0, 0x40, "GPFSEL0")) { printk(KERN_INFO "PIMOTE_READ: Error request_mem_region"); } //Point GPFSEL0 ptr = ioremap_nocache(GPFSEL0, 0x40); if (ptr) { printk(KERN_INFO "PIMOTE_READ: remap 0x%X to 0x%X\n", GPFSEL0, (unsigned int)ptr); } else { printk(KERN_INFO "PIMOTE_READ: Can't remap 0x%X\n", GPFSEL0); } iounmap(ptr); release_mem_region(GPFSEL0, 0x40); return 0; } ssize_t pimote_write(struct file *filep, const char *buf, size_t count, loff_t *f_pos) { //int mask; //int* ptr; printk(KERN_INFO "PIMOTE_WRITE: Nothing to be done.\n"); return 0; } int pimote_close(struct inode *inode, struct file *filp) { char* ptr; printk(KERN_INFO "Closing Pimote driver...");

33

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013


if (! request_mem_region(GPFSEL0, 0x40, "GPFSEL0")) { printk(KERN_INFO "PIMOTE_CLOSE: Error request_mem_region"); } //Point GPFSEL0 ptr = ioremap_nocache(GPFSEL0, 0x40); if (ptr) { printk(KERN_INFO "PIMOTE_CLOSE: remap 0x%X to 0x%X\n", GPFSEL0, (unsigned int)ptr); } else { printk(KERN_INFO "PIMOTE_CLOSE: Can't remap 0x%X\n", GPFSEL0); } copy_to_user(data_buffer); iounmap(ptr); release_mem_region(GPFSEL0, 0x40); return 0; } module_init(pimote_init); module_exit(pimote_exit); MODULE_DESCRIPTION("Pimote GPIO driver"); MODULE_AUTHOR("Alfredo & Sara"); MODULE_LICENSE("GPL");

34

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013

6 Manual de usuario
Para controlar el sistema implementado hasta ahora deberemos seguir los siguientes pasos: En primer lugar encendemos la Raspberry Pi conectndola a la corriente a travs del puerto micro-USB y alimentamos los Tulios conectndolos a un equipo/Raspberry a travs del puerto USB. En el sistema receptor, adems del Tulio, debemos alimentar el circuito que contiene el led infrarrojo que le enva la trama al aire acondicionado. Para ello conectamos los pines de alimentacin y masa del Tulio a la placa de insercin y el pin0 a la entrada del circuito amplificador. (Comprobamos que el led verde esta encendido, si esto no ocurriese, comprobar las conexiones entre la placa y el Tulio) Una vez alimentados nos conectamos al servidor de la Raspberry para acceder a la interfaz de usuario del sistema. En un navegador introducimos la direccin IP asignada a la Raspberry seguido del puerto 3000 y /index que nos llevar a la pgina principal
host:3000/index

donde host es la direccin IP asignada al dispositivo (Esta direccin aparecer reflejada en el display)

35

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013

Una vez en el servidor seleccionamos lo que queremos enviar en el spinner disponible en la pgina principal y pulsamos el botn enviar. La temperatura enviada aparecer en el display y se habr enviado

Adicionalmente, si quiere guardar una nueva trama, deber introducir el fichero de texto con la informacin de la trama en la carpeta enviatramas situada en el directorio home/pi/ de Raspberry y despus pulsar en guardar nueva trama en el servidor, donde nos aparecer una sencilla interfaz en la que introducir el nombre del botn (en maysculas) y el nombre del fichero .txt al que hace referencia dicho botn (Para ello es importante mantener la extensin del fichero cuando guardemos el botn). Por ejemplo:
OFF: tramaoff.txt

Tras esto pulsamos el botn para guardarlo y ya dispondremos del nuevo botn en el spinner de la pgina principal.

Anlogamente dispone de una interfaz para editar o borrar botones de la lista de botones disponibles. 36

Memoria del proyecto desarrollado en Sistemas Digitales II (SDII) curso 2012/2013

7 Bibliografa
Informacin sobre drivers en Linux: Third Edition of Linux Device Drivers, by Jonathan Corbet, Alessandro Rubini, and Greg Kroah-Hartma. LIRC GPIO driver: http://aron.ws/projects/lirc_rpi/ Informacin sobre los pines del GPIO: http://elinux.org/RPi_Low-level_peripherals Agradecimientos a Guy Palmer. Datasheet del CC1110 por Texas Instruments Agradecimientos al equipo de Temp-LSI

37

Вам также может понравиться