Control Inalámbrico de Iluminación (RF)
[edit] INTEGRANTES.
Daniel Cárdenas Toro. 261377 1.0
Juan Sebastián Pachón Arango. 261418 .5
William Eduardo Calderón Castillo 261178 .6
[edit] Calificación
Porcentaje | Presentación 20% | Informe 30% | Funcionamiento 50% |
---|---|---|---|
1 Entrega 10% | 0.5 | 0.5 | 0.5 NO ASISTIERON A LA ENTREGA |
2 Entrega 30% | 1.8 | 1.8 | 1.8 |
3 Entrega 30% | 2 | 2 | 5
|
4 Entrega 40% | 5 | 5 | 5 |
[edit] DESCRIPCIÓN GENERAL.
El proyecto consiste en hacer un sistema inalámbrico que permita controlar a distancia la iluminación de un interior. El diseño contará con una interfaz gráfica en la que se visualizará un plano sencillo del lugar con el estado de cada bombillo del sistema.
[edit] VIDEO FUNCIONAMIENTO
[edit] TAREAS SW Y HW.
HardWare.
La FPGA estará encargada de controlar el modulo RF que trabajara como transmisor en el control remoto. Por lo tanto debe manejar la máquina de estados de este dispositivo, configurarlo en el modo TX para transmitir datos o en STANDBY cuando no se esté transmitiendo para disminuir el consumo de energía. Los pulsadores que se utilizaran para manejar las luces estarán conectados directamente a la FPGA y esta se encargara de enviar las secuencias adecuadas al modulo RF que finalmente enviara la información a los receptores (uno en cada bombillo). A su vez la FPGA debe mandar la información al procesador para que pueda actualizarse la información en la interfaz grafica. El módulo RF sera un RFM22B.
Cada modulo receptor se conecta a un microcontrolador, que se encarga de configurar el modulo en estado receptor, a su vez se implementara un botón de reset en cada uno de estos módulos para reconfigurar por si hay algún problema o se descarga completamente la batería y se desconfigura. Los microcontroladores (PIC16F877A) serán programados en C++ en CCS.
SoftWare.
Para dar mayor comodidad del usuario, se realizará una parte gráfica que se realizará con el programa QT y sus librerías para el manejo de gráficos. Se implementará la ejecución de los archivos en QT en el procesador, para que sea posible cargar nuestro programa. Este programa tendrá como finalidad mostrar en el lcd del SIE, un sencillo plano del lugar, en el que se muestran los diferentes bombillos y su estado (prendido o apagado) y la opción de modificar dicho estado, por medio de los módulos RF.
[edit] BLOQUES.
1. Interfaz Gráfica. Desarrollada en QT, se muestra en el LCD los lugares de la casa en la cual se desea prender o apagar la luz. Al mover el slider horizontal se prendería o se apagaría la luz y la indicación de esto se mostraría en la caja de giro.
2. Driver. El módulo RFM22B utiliza comunicación SPI, por lo tanto se implementará en la FPGA (HardWare)un módulo SPI con su respectivo Driver en linux (SoftWare).
3. Comunicación RF. Es necesario controlar la comunicación inalambrica, determinar si los datos que llegan son correctos.
4. Configuración de RX. Un microcontrolador esta encargado de configurar el modulo receptor en su modo de operación adecuado.
5. Potencia. Debido a que el microcontrolador no puede suministrar potencia necesaria al bombillo, se adapta una etapa de potencia
[edit] DIAGRAMAS.
[edit] ESQUEMATICOS.
[edit] PCB. V1
[edit] PCB. V2. Layout
[edit] PCB V3.
[edit] COMUNICACIÓN XBURST--RFM22B
Cuando se crea un puntero que apunta a la dirección virtual de la fpga y se le asigna un valor "X" el procesador se comporta de la siguiente forma:
Por lo tanto, para un proceso de escritura, se parte de la condición en que CSn y WEn son iguales a cero, en este punto se verifica si el periferico está ocupado por medio de la señal "busy", si el periferico está ocupado se ignora el dato, de lo contrario se envia el dato. En este caso se ha tomado como base el archivo ADC.v y se ha reemplazado la memoria por un periferico SPI.
EL diagrama de tiempo de trabajo del rfm22b se muestra en la siguiente figura:
Debido a que el bus de datos es de 8 bits, se deben enviar dos secuencias, la primera con un bit de r/w y la dirección y la segunda con el dato a escribir en el registro. la simulación del módulo se muestra a continuación:
El diagrama de flujo del control de escritura se muestra en el siguiente diagrama
[edit] Periféricos
Para este proyecto, se tienen dos periféricos en la FPGA, en el caso del transmisor, se tiene el módulo SPI y el pad de botones, y para el caso del receptor se tiene el módulo SPI y el pad de leds. Por lo tanto es necesario agregar un control de periféricos.
// Peripherals control
wire [1:0] csN;
wire [7:0] rdBus0, rdBus1:
assign csN = buffer_addr[11]? 4'b0010:4'b0001;
assign rdBus = buffer_addr[11]? rdBus1:rdBus0;
[edit] Button Pad
Debido a que el reloj de la FPGA es bastante rápido, al pulsar un botón, la fpga asume que este fue presionado varias veces, por lo tanto se crea un bloque para solucionar el problema. Consiste en tres registros (uno para cada pulsador) PB1d, PB2d, PB3d. Estos regustros se activan una ves se presiona el boton.
always @(posedge clk)
begin
if(reset)
begin
PB1d<=1;
count1<=0;
end
else if(~PB1)
count1<=count1+1;
if(count1==50000)
PB1d<=0;
if(addr==2000)
begin
PB1d<=1;
count1<=0;
end
end
Una vez que el el procesador ha leído el pulsador a través de la FPGA y ha realizado su labor, envía una señal de vuelta a la FPGA y con esto los registros PB1d, PB2d, PB3d se desactivan, con esto se logra que cada que se presiona un pulsador, solo se ejecuta una ves la accion deseada a menos que el boton se mantenga pulsado.
[edit] Led Pad
Para probar el funcionamiento del proyecto se utilizan 3 leds incorporados en la tarjeta del receptor, adicionalmente en esta tarjeta se dejan las salidas disponibles para conectar una etapa de potencia e implementar el proyecto en bombillos reales.
always @(posedge clk)
if(reset)
begin
led1<=0;
led2<=0;
led3<=0;
end
else if(we & cs1)
begin
if(addr==120)
led2<=~led2;
else if(addr==80)
led1<=~led1;
else if(addr==40)
led3<=~led3;
end
El funcionamiento de este bloque es bastante sencillo, ya que simplemente cuando se activa el we y el cs1, se prende o apaga algún led, dependiendo de la dirección enviada por el usuario y del estado actual de dicho led.
[edit] SPI
El módulo de SPI es el módulo más importante del proyecto, ya que se encarga de comunicar el procesador con el módulo RFM22B, este modulo cuenta con 128 registros a los cuales se puede acceder utilizando este protocolo.
Inicialmente se tiene un bloque de control que genera un pulso en la señal "SPI_wr"
// CONTROL
always @(posedge clk)
begin
if(reset)
begin
{w_st0, SPI_wr} <= 0;
end
else
begin
case (w_st0)
0: begin
if(we & cs & ~busy)
SPI_wr <= 1;
if(SPI_wr)
begin
w_st0 <=1;
end
end
1: begin
SPI_wr <= 0;
w_st0 <=0;
end
endcase
end
end
En la línea 178 se observa que el pulso se genera cuando se activa "we", "cs" y "~busy", la señal "busy" es necesaria debido a que si el procesador envía un dato mientras el bloque SPI está enviando otro dato, entonces se creará un conflicto y se enviarían valores errados al módulo RF.
Adicionalmente se tiene el bloque SPI CONTROL que se encarga de manejar todas las señales necesarias para el protocolo SPI.
// SPI Control
always @(posedge clk)
if(reset)
begin
{w_st1, pulsecount, clkdiv_en, busy} <= 0;
end else
begin
case (w_st1)
0: begin
if(SPI_wr)
begin
clkdiv_en <= 1;
load_in <= 1;
w_st1 <= 1; busy <= 1;
end
end
1: begin
load_in <= 0;
if(pulse)
begin
if (pulsecount == 32)
begin
clkdiv_en <= 0; busy <= 0;
w_st1 <= 0; pulsecount <= 0;
end
else pulsecount <= pulsecount + 1;
end
end
endcase
end
Se utilizan además los bloques SPI CLOCK GENERATOR, SPI RECEPTOR Y SPI TRANSMITTER utilizados en el ADC.
El bloque Write Control se encarga de tomar los datos provenientes del procesador y enviarlos de forma serial.
// REGISTER BANK: Write control
always @(posedge clk)
begin
if(reset)
{RFM_REG} <= 0;
else
if(we & cs & ~busy)
begin
RFM_REG[15:0] <= {addr[9:2],wrBus[7:0]};
end
end
Como se puede ver en la línea 148, el dato que se enviará de forma seríal "RFM_REG" se compone de la dirección desplazada dos bits a la izquierda y el dato. El desplazamiento de la dirección es necesario debido a que el bus de direcciones que sale del procesador, llega a la fpga multiplicado por 4.
Finalmente el bloque de lectura.
// REGISTER BANK: Read control
always @(posedge clk)
if(reset)
{rdBus0, rdBus1} <= 0;
else
if(~we & cs)
begin
if(addr==40)
rdBus0 <= nSEL;
else
rdBus0<=out_buffert;
end
else
if(~we & cs1)
begin
if(addr==120)
begin
rdBus1 <= PB3d;
end
else if(addr==40)
rdBus1 <= PB1d;
else if(addr==80)
rdBus1 <= PB2d;
end
Dependiendo de cual CS esté activado, el procesador estará leyendo datos del módulo SPI o del pad de botones, en el caso del SPI, dependiendo de la dirección que envíe el procesador, se lee la señal "nSEL" que es utilizada por el procesador para determinar el momento en que el módulo SPI termino de enviar un dato para poder enviar el siguiente, por otro lado se tiene el registro "out_buffert" en el cual se ha almacenado el valor de algún registro del RFM22B obtenido a través de la señal "SDOUT".
Por otro lado si está activo el "cs1" se lee el pad de botones.
La señal "nSEL" del SPI tiene un tiempo de establecimiento mas alto que el resto de las señales, por eso fue necesario crear una maquina de estados que se encargara de manejar este tiempo.
always @(posedge clk)
case (w_st2)
0: begin
if(SPI_wr)
nSEL<=0;
if(pulsecount==32)
w_st2<=1;
end
1:begin
if(pulsecount==0)
w_st2<=2;
end
2:begin
count<=count+1;
if(count==5)
nSEL<=1;
if(count==6)
begin
w_st2<=0;
count<=0;
end
end
endcase
[edit] Antena WLP434
El módulo RFM22B no cuenta con una antena para la transmisión de datos, por lo tanto es necesario adaptar úna externa, para este fin se escogio la antena WLP434 ya que trabaja a 434MHz y tene una impedancia de 50 ohm. Para verificar estos valores, se caracterizó la antena en el laboratorio de comunicaciones de la Universidad Nacional de Colombia (CMUN), verificando los valores mencionados anteriormente como se muestra en las siguientes figuras.
[edit] REGISTROS DE CONFIGURACIÓN DEL RFM22B
El RFM22B cuenta con 128 registros de configuración utilizados para seleccionar la frecuencia, el tamaño de los paquetes, tipo de modulación, Header, Potencia de salida de la antenna, configuración de GPIO's, modo de operación (TX, RX, Sleep, Shut Down). En la siguiente tabla se encuentran algunos de los registros modificados para configurar tanto en modo receptor como en modo transmisor.
Dirección | Descripción | valor RX | valor TX |
---|---|---|---|
0x06 | Interrupt Enable 2 | 0x00 | 0x00 |
0x07 | Operating & Function Coontrol 1 | 0x09 | 0x9 |
0x09 | Crystal Oscilator Load Capacitance | 0x7f | 0x7f |
0x0a | Microcontroller Output Clock | 0x05 | 0x05 |
0x0b | GPIO0 Configuration | 0xf4 | 0xf4 |
0x0c | GPIO1 Configuration | 0xfd | 0xef |
0x0d | GPIO2 Configuration | 0xfd | 0xfd |
0x0e | I/O Port Configuration | 0x00 | 0x00 |
0x70 | Modulation Mode Control 1 | 0x20 | 0x20 |
0x6e | TX Data Rate 1 | xxxx | 0x13 |
0x6f | TX Data Rate 0 | xxxx | 0xa9 |
0x1d | AFC | 0x00 | xxxx |
0x1c | IF Filter Bandwidth | 0x1d | xxxx |
0x20 | Clock Recovery Oversampling Ratio | 0x41 | 0x7f |
0x21 | Clock Recovery offset 2 | 0x60 | 0x7f |
0x22 | Clock Recovery offset 1 | 0x27 | 0x7f |
0x23 | Clock Recovery offset 0 | 0x52 | 0x7f |
0x24 | Clock Recovery Timing Loop Gain 1 | 0x00 | 0x7f |
0x25 | Clock Recovery Timing Loop Gain 0 | 0x06 | 0x7f |
0x2a | AFC Limiter | 0x1e | 0x7f |
0x30 | Data Access Control | 0x8c | 0x8c |
0x32 | Header Control 1 | 0xff | 0xff |
0x33 | Header Control 2 | 0x42 | 0x42 |
0x34 | Preamble Length | 64 | 64 |
0x35 | Preamble Detection Control | 0x20 | 0x7f |
0x36 | Sync Word 3 | 0x2d | 0x2d |
0x37 | Sync Word 2 | 0xd4 | 0xd4 |
0x38 | Sync Word 1 | 0x00 | 0x00 |
0x39 | Sync Word 0 | 0x00 | 0x7f |
0x3a | Transmit Header 3 | 0x00 | 's' |
0x3b | Transmit Header 2 | xxxx | 'o' |
0x3c | Transmit Header 1 | 0x00 | 'n' |
0x3d | Transmit Header 0 | xxxx | 'g' |
0x3e | Transmith Packet Length | 1 | 1 |
0x3f | Check Header 3 | 's' | 0x7f |
0x40 | Check Header 2 | 'o' | 0x7f |
0x41 | Check Header 1 | 'n' | 0x7f |
0x42 | Check Header 0 | 'g' | 0x7f |
0x43 | Header Enable 3 | 0xff | 0x7f |
0x44 | Header Enable 2 | 0xff | 0x7f |
0x45 | Header Enable 1 | 0xff | 0x7f |
0x46 | Header Enable 0 | 0xff | 0x7f |
0x6d | TX Power | xxxx | 0x0f |
0x79 | Frequency Hopping Channel Select | 0x00 | 0x00 |
0x7a | Frequency Hopping Step Size | 0x00 | 0x00 |
0x71 | Modulation Mode Control 1 | 0x22 | 0x22 |
0x72 | Frequency Deviation | xxxx | 0x38 |
0x73 | Frequency offset 1 | 0x00 | 0x00 |
0x74 | Frequency offset 2 | 0x00 | 0x00 |
0x75 | Frequency Band Select | 0x53 | 0x53 |
0x76 | Nominal Carrier Frequency 1 | 0x64 | 0x64 |
0x77 | Nominal Carrier Frequency 0 | 0x00 | 0x00 |
Despues de configurar los registros como se muestra en la tabla anterior, el proceso de transmisión se reduce a escribir y leer las FIFO's de transmisión del módulo.
Una operación de escritura sobre el registro 0x7f es una operación de escritura sobre la FIFO de transmisión, por otro lado si se lee este registro (0x7f) se esta leyendo la FIFO de Recepción del módulo. Cada fifo cuenta con 64 bytes de espacio, el momento en q se transmiten los datos depende de un registro de configuración que determina si se envia cada 1, 2, 3 ... o 64 bytes escritos en la FIFO de transmisión.
Es importante aclarar que el módulo rfm22b tiene un protocolo de comunicación incorporado, por lo que no es necesario agregar uno, el rfm22b cuenta con un Header (Encabezado) que se envia previo al dato que se desea transmitir, este Header es configurable y cada uno de los receptores puede configurarse para responder ante un Header diferente.
[edit] DRIVER
Con el fin de modificar los valores que vienen por defecto en los registros del RFM22B se crea un driver para el transmisor y uno para el receptor. Estos drivers se encargan de enviar los datos necesarios al SPI para que este los envíe de forma serial al RFM22B. Para enviar estos datos desde espacio de kernel no es necesario remapear la memoria física en memoria virtual, ya que las funciones "outb(data, address)" pone directamente el dato que se pase como argumento en la direción física "address". Sin embargo el mapeo se puede hacer de la siguiente forma:
ioaddress = __ioremap(FPGA_BASE, 0x4000,_CACHE_UNCACHED);
Adicionalmente es necesario configurar el CS, para esto se utiliza la siguiente función:
#define CS2_PIN JZ_GPIO_PORTB(26)
jz_gpio_set_function(CS2_PIN, JZ_GPIO_FUNC1);
Despues de esto se puede escribir y leer de la siguiente forma:
//write process
outb(0x00, ioaddress+(4*(0x06 + 0x80)));
//read process
test=inb(ioaddress+40);
En el proceso de escritura, la dirección a la que se envía el dato se compone de la siguiente forma (según el ejemplo), el valor "0x06" es el registro que se desea modificar, a este valor se le suma "0x80" (decimal 128), con el fin de habilitar el bit "RDWR" (primer bit de la trama del SPI) para realizar una operación de escritura. finalmente este valor se multiplica por 4 para tener el mismo funcionamiento que en espacio de usuario.
A continuación se muestra una parte del driver:
static int __init qem_init(void)
{
int res;
printk(KERN_INFO "FPGA module is Up.\n");
jz_gpio_set_function(CS2_PIN, JZ_GPIO_FUNC1);
Major = register_chrdev(0, DEVICE_NAME, &fops);
if (Major < 0) {
printk(KERN_ALERT "Registering char device failed with %d\n", Major);
return Major;
}
printk(KERN_ALERT "I was assigned major number %d. To talk to\n", Major);
printk(KERN_ALERT "the driver, create a dev file with\n");
printk(KERN_ALERT "'mknod /dev/%s c %d 0'.\n", DEVICE_NAME, Major);
ioaddress = __ioremap(FPGA_BASE, 0x4000,_CACHE_UNCACHED);
outb(0x00, ioaddress+(4*(0x06 + 0x80)));
while(test==0)
test=inb(ioaddress+40);
outb(0x01, ioaddress+(4*(0x07 + 0x80)));
test=0;
while(test==0)
test=inb(0xb5000000+40);
outb(0x05, ioaddress+(4*(0x0A + 0x80)));
test=0;
while(test==0)
test=inb(0xb5000000+40);
outb(0xf4, ioaddress+(4*(0x0B + 0x80)));
test=0;
while(test==0)
test=inb(0xb5000000+40);
outb(0xfd, ioaddress+(4*(0x0c + 0x80)));
Despues de enviar cada dato, el driver se queda leyendo la señal "nSEL" al leer la dirección 40 de la FPGA, esta señal se mantiene normalmente en -1-, cuado seva a enviar un dato la señal baja a -0-, y cuando el dato se ha enviado la señal vuelve a -1-, por lo tanto el driver no debe mandar un dato hasta que la señal sea de nuevo -1- (!=0).
Debido a que el sistema tiene reset, es necesario que el driver pueda reescribir los registros una ves esta arriba, por lo tanto se crea la misma rutina realizada en __init, en la funcion device_write".
static ssize_t
device_write(struct file *filp, const char *buff, size_t count, loff_t * off)
{
const char cmd = buff[0];
if(cmd=='W')
{
outb(0x00, ioaddress+(4*(0x06 + 0x80)));
while(test==0)
test=inb(0xb5000000+40);
outb(0x01, ioaddress+(4*(0x07 + 0x80)));
test=0;
while(test==0)
test=inb(0xb5000000+40);
outb(0x05, ioaddress+(4*(0x0A + 0x80)));
test=0;
while(test==0)
test=inb(0xb5000000+40);
outb(0xf4, ioaddress+(4*(0x0B + 0x80)));
test=0;
while(test==0)
test=inb(0xb5000000+40);
outb(0xfd, ioaddress+(4*(0x0c + 0x80)));
Para por utilizar esta función, es necesario crear el nodo para comunicarse con el driver.
$ mknod /dev/setRX c 252 0
$ mknod /dev/setTX c 252 0
Una ves se ha creado el nodo, se pueden reescribir los registros con el siguiente comand:
$ echo "W">/dev/setRX
[edit] RECEPTOR
Inicialmente se propuso implementar el receptor en un microcontrolador, sinembargo finalmente se decide implementarlo en otra plataforma SIE con el fin de facilitar la programación y dejando la posibilidad de tener ambas plataformas como emisor/receptor tan solo con variar algunos registros de configuración.
[edit] COMUNICACIÓN INALÁMBRICA
Se realiza la comunicación inalámbrica obteniendo una distancia de alcance de aproximadamente 100 mts, inicialmente se envia un byte de información el cual es recibido correctmente gracias al protocolo de comunicación interno del RFM22B, posteriormente se configura tanto el transmisor como el receptor para transferir 8 bytes. Con esto se envía un contador de 1 a 8 obteniendo siempre los datos correctamente.
El RFM22B tiene una señal de interrupción que se activa cada que se recibe un dato, por lo tanto se conecta esta señal al procesador a través de la FPGA con el fin de imprimir cada dato que llega al receptor. Aunque desde espacio de usuario no se pueden manejar interrupciones, el pin C15 del procesador puede ser definido como una entrada y ser leido constantemente.
[edit] DIAGRAMAS DE FLUJO DE LOS MODOS TX Y RX
[edit] INTERFAZ GRÁFICA
Con el fin de que el usuario pueda decidir cual led (bombillo) desea prender, se crea una interfaz gráfica utilizando el programa QTcreator. Para esto se parte por el diseño gráfico de la interfaz modificando el archivo "mainwindow.ui" (esto se puede hacer gráficamente).
Luego se modifica el archivo mainwindow.h en el cual se declaran las variables que se van a utilizar.
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "jz47xx_mmap.h"
#include "jz47xx_gpio.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#define CS2_PORT JZ_GPIO_PORT_B
#define CS2_PIN 26
#define TEST_PORT JZ_GPIO_PORT_C
#define TEST_PIN 15
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
JZ_PIO *initGPIO_LED();
JZ_REG *initFPGA_RAM();
private:
Ui::MainWindow *ui;
JZ_PIO *LED;
JZ_REG *RAM;
int iter, count, led1, led2, led3;
unsigned char i, test;
unsigned char a, b, c;
protected:
void timerEvent(QTimerEvent*);
};
#endif // MAINWINDOW_H
Teniendo definidas las variables necesarias, se crea el archivo mainwindow.cpp, inicialmente se debe configurar el CS y se debe mapear la memoria física de la FPGA en memoria virtual, para esto se utiliza la siguiente función:
JZ_REG *
MainWindow::initFPGA_RAM()
{
JZ_PIO *pio;
JZ_PIO *pio1;
JZ_REG *virt_addr;
pio = jz_gpio_map (CS2_PORT);
jz_gpio_as_func (pio, CS2_PIN, 0);
pio1 = jz_gpio_map (TEST_PORT);
jz_gpio_as_input(pio1, TEST_PIN);
virt_addr = (JZ_REG *) (jz_mmap(0x13010000) + 0x18);
if (*virt_addr != 0x0FFF7700)
{
*virt_addr = 0x0FFF7700;
printf ("ADC: Configuring CS2 8 bits and 0 WS: %08X\n", *virt_addr);
}
else
printf ("ADC: CS2, already configured: %08X\n", *virt_addr);
virt_addr = (JZ_REG *) jz_mmap (0x14000000);
return virt_addr;
}
Finalmente como se tiene mapeada la dirección dela FPGA y se tienen las variables necesarias, se genera la función MainWindow::timerEvent(QTimerEvent*), en la cual está el motor de la interfaz gráfica.
Para la visualización se crearon 6 label: boton led1, led 2 y led3, y un label para mostrar el estado d cada led. para hacer la interfaz un poco mas agradable a la vista, se decidio utilizar la función
setPixmap(QPixmap("imagen.jpg"));
para esto se deben copiar todas las imagenes que se quieran utilizar a la tarjeta SIE utilizando el comando:
$ scp imagen.jpg oot@192.168.254.101:
se crea entonces un contador que define el led que está selecciónando el usuario, dicho contador aumenta con un pulsador de la tarjeta hija y disminuye con otro. cada que se actualiza el valor del contador se cambian las imágenes de cada uno de os label dependiendo el led que este seleccionado:
c=RAM[512 + 20];
b=RAM[512 + 10];
else if (b==0x00)
{
if(count<1)
count=2;
else
count--;
RAM[500]=0;
usleep (15000);
}
else if (c==0x00)
{
if(count>1)
count=0;
else
count++;
RAM[500]=0;
usleep (15000);
}
switch(count){
case 0:{
ui->label->setPixmap(QPixmap("led1set.jpg"));
ui->label_2->setPixmap(QPixmap("led2.jpg"));
ui->label_3->setPixmap(QPixmap("led3.jpg"));
}
break;
case 1:{
ui->label->setPixmap(QPixmap("led1.jpg"));
ui->label_2->setPixmap(QPixmap("led2set.jpg"));
ui->label_3->setPixmap(QPixmap("led3.jpg"));
}
break;
case 2:{
ui->label->setPixmap(QPixmap("led1.jpg"));
ui->label_2->setPixmap(QPixmap("led2.jpg"));
ui->label_3->setPixmap(QPixmap("led3set.jpg"));
}
break;
}
Las imagenes led1set.jpg, led2set.jpg y led3set.jpg, son los mismos botones led1.jpg, led2.jpg y led3.jpg pero desplazados hacia la derecha para que se evidencie el led seleccinado.
las variables b y c, están siendo constantemente actualizadas leyendo el valor de los pulsadores a través de la FPGA.
finalmente la sección encargada de enviar los datos se muestra a continuación:
if(a==0x00)
{
printf ("Writing Register..\n");
RAM[500]=0;
while(test==0)
test=RAM[10];
RAM[0x7f + 0x80]=count;
test=0;
while(test==0)
test=RAM[10];
RAM[0x05 + 0x80]=0x04;
test=0;
while(test==0)
test=RAM[10];
RAM[0x03 + 0x00]=0x04;
test=0;
while(test==0)
test=RAM[10];
RAM[0x04 + 0x00]=0x04;
test=0;
while(test==0)
test=RAM[10];
RAM[0x07 + 0x80]=0x09;
test=0;
usleep (150000);
switch(count){
case 0:{
led1=~led1;
if(led1)
ui->label_5->setPixmap(QPixmap("on.png"));
else
ui->label_5->setPixmap(QPixmap("off.jpg"));
}
break;
case 1:{
led2=~led2;
if(led2)
ui->label_6->setPixmap(QPixmap("on.png"));
else
ui->label_6->setPixmap(QPixmap("off.jpg"));
}
break;
case 2:{
led3=~led3;
if(led3)
ui->label_7->setPixmap(QPixmap("on.png"));
else
ui->label_7->setPixmap(QPixmap("off.jpg"));
}
break;
default:plain_text="OUT";
break;}
}
Esta sección se encarga de escribir en el registro "0x7f" (dirección de la FIFO de salida) el valor de "cont", con esto se enviará un valor diferente para cada led seleccionado. A su vez en esta sección se actualiza el estado en pantalla de cada uno de los leds. Teniendo esto, en el receptor sólo es necesario una condición para prender o apagar un led dependiendo del valor enviado inalambricamente (cont).
Receptor:
RAM[0x7f] =0;
usleep (500);
i=RAM[0x7f];
if(i==0x01)
{
RAM[512 + 20]=0;
}
else if(i==0x02)
{
RAM[512 + 30]=0;
}
else if(i==0x00)
{
RAM[512 + 10]=0;
}
RAM[0x03 + 0x00]=0x00;
test=0;
while(test==0)
test=RAM[10];
RAM[0x04 + 0x00]=0x00;
test=0;
while(test==0)
test=RAM[10];
test=0;
RAM[0x07 + 0x80]=0x05;
while(test==0)
test=RAM[10];
Para leer el dato recibido, se debe leer la FIFO de entrada (registro 0x7f) como se ve en las lineas 122-124. La linea 122 se encarga de enviar al RFM22B un "rdwr=0" y la dirección que se quiere leer (0x7f), luego es necesario esperar un tiempo mientras el módulo devuelve el valor de este registro para ejecutar la linea 124.
El dato recibido inalámbricamente siempre está entre 0 y 2, por lo tanto cada uno de estos valores corresponde a un led o bombillo del receptor, al escribir en la posición 10, 20 y 30 del cs2, se está escribiendo sobre el pad de leds, invirtiendo el estado actual de cada led respectivamente.
Después de recibir cada dato se envía una secuencia de datos al RFM22B para limpiar la FIFO de entrada como se ve en la linea 139 en adelante.
[edit] ESTUDIO ECONÓMICO
Inicialmente se tuvo en cuenta el trabajo de los estudiantes de la siguiente forma:
2 horas de trabajo diarias por cada uno durante 14 semanas -> 140 horas en total cada estudiante. Con lo cual el trabajo suma 420 horas. Tomando un valor de $40.000 pesos la hora da un total de $16'800.000 pesos en mano de obra.
Se tiene en cuenta que este tiempo incluye el proceso de diseño del prototipo, por lo tanto para fabricación en masa, este tiempo se reduce al tiempo de producción.
Gastos Adicionales
- Servicios públicos $20.000 pesos mes -> $80.000 pesos
Componentes del Prototipo
- 2 tarjetas SIE a $200.000 pesos c/u ---------------> $400.000 pesos.
- 2 tarjetas hijas a $32.000 pesos c/u ----------------> $64.000 pesos.
- 2 Antenas a $24.000 pesos c/u ----------------------> $48.000 pesos.
- 2 Módulos RFM22B a $10.000 pesos c/u --------> $20.000 pesos.
- Componentes pasivos -----------------------------------> $10.000 pesos.
- Total prototipo -------------------------------------------> $542.000 pesos.
Es importante tener en cuenta que si se va a producir en masa, se puede modificar la tarjeta SIE, dejando solo los componentes necesarios para el proyecto. Adicionalmente se considera que la tarjeta SIE no tiene muchos GPIOS disponibles, lo cual limita la cantidad de bombillos que se pueden controlar, por esta razón dependiendo de la cantidad de bombillos del sistema se deben agregar más receptores aumentando los costos de producción.