Está en la página 1de 12

SISTEMA DE GUIADO

DE MISILES

Memoria del proyecto

2º Ingeniería Aeroespacial
Ingeniería Electrónica
Álvaro Artola Aguado, Galliano Cantarelli
Juan Diego Marín Re, Adrián Ruiz García
Nuestro proyecto consiste en un sistema de guiado de misiles mediante un
sensor de calor.

FUNCIONAMIENTO
Para comenzar, detectamos el avión enemigo, seleccionándolo mediante dos
botones y lo confirmamos como objetivo a abatir. Observamos la velocidad del
avión enemigo en la pantalla, y según la lectura seleccionamos el tipo de misil
adecuado. Confirmamos el misil, pudiendo observar la velocidad del mismo en
la parte inferior de la pantalla y ejecutamos la orden de lanzamiento.
Una vez realizado el lanzamiento se activará un temporizador, el cual mostrará
el tiempo máximo hasta la autodestrucción del misil. Cuando éste alcanza a su
objetivo, el temporizador se resetea, encendiéndose a su vez un LED
acompañado de una señal sonora. Como se ha mencionado, si el temporizador
llega a cero, el misil se autodestruye y se enciende el LED, pero esta vez sin la
señal sonora, ya que no se ha alcanzado al objetivo.
El guiado por temperatura funciona del siguiente modo:
El misil detecta temperaturas relativas en 3 direcciones: recta, izquierda y
derecha. Dirigiéndose hacia aquella en la que mida una mayor temperatura.
Indicándonos la dirección del movimiento en el HUD del avión mediante LEDs.

CÓDIGO
Contamos con dos PICs: uno para la detección del avión, la selección y el
lanzamiento del misil; y otro para la detección de temperaturas y guiado.

Primer PIC
#include <p18f4520.h>
#include <math.h>

unsigned int i, j;
int vavion, vmisil, tiempo, tiempomax, resta, explosion, disparo, disparoant;
int contador, vavion2, vmisil2;
int nummisiles = 7; //máximo de 6 misiles disponibles
void R_Int_Alta(void);

#pragma code Vector_Int_Alta=0x08

void Int_Alta(void) {
_asm GOTO R_Int_Alta _endasm
}
#pragma code

En esta parte del código declaramos la librería del PIC y la de los cálculos
matemáticos. Definimos las variables que se van a utilizar, hemos declarado la
subrutina de tratamiento de alta prioridad y la vectorización de las
interrupciones de alta prioridad.
void main(void) {
//DEFINIMOS ENTRADAS Y SALIDAS
eleccionavion:
TRISA = 1;
TRISC = 0;
TRISB = 0;
TRISD = 0;
TRISEbits.RE0 = 0; //SALIDA DEL LED DE AVISO
TRISEbits.RE1 = 0; //SALIDA DEL BUZZER DE AVISO
TRISEbits.RE2 = 0;
ADCON1 = 0x3F;
//DEFINIMOS CONDICIONES INICIALES GLOBALES
tiempomax = 50;
INTCONbits.GIE = 0; //DESACTIVAMOS LAS INTERRUPCIONES HASTA NUEVO AVISO
INTCONbits.TMR0IE = 0;

Aquí se define el puerto A como entrada y los puertos B, C y D como salida.


Las salidas del puerto E se ponen a cero ya que se utilizarán luego como
salidas del LED de aviso y el Buzzer de aviso.
Establecemos un valor inicial para el tiempo máximo del temporizador
(tiempomax) y desactivamos las interrupciones.

while (PORTAbits.RA3 == 0) {
if (PORTAbits.RA0 == 1 && PORTAbits.RA1 == 0) {
vavion = 19;
}
if (PORTAbits.RA0 == 0 && PORTAbits.RA1 == 1) {
vavion = 24;
}
if (PORTAbits.RA0 == 1 && PORTAbits.RA1 == 1) {
vavion = 29;
}
if (PORTAbits.RA0 == 0 && PORTAbits.RA1 == 0) {
vavion = 0;
}
}
if (vavion == 0) {
goto velocidadavion;
}
vavion2 = (vavion / 10) * 16 + (vavion % 10);
PORTC = vavion2; //Display de la velocidad del avion enemigo

Mientras no se haya confirmado ningún avión podemos elegir el tipo de avión


detectado, dependiendo de si los botones están en estado bajo o alto. Este
bucle acaba cuando fijamos la velocidad del avión, ya la entrada RA3 pasará a
ser 1. Si después de fijar el avión es igual a cero, es decir, no se ha
seleccionado ninguno. Volvemos a la sentencia velocidadavion, ejecutando el
bucle while otra vez.

Para mostrar en el display la velocidad, convertimos a hexadecimal su valor,


sacándolo por el puerto C.

tipomisil:
while (PORTAbits.RA2 == 0) {
if (PORTAbits.RA5 == 1 && PORTAbits.RA6 == 0) {
vmisil = 31;
tiempomax = 30;
}
if (PORTAbits.RA5 == 0 && PORTAbits.RA6 == 1) {
vmisil = 22;
tiempomax = 60;
}
if ((PORTAbits.RA5 == 0 && PORTAbits.RA6 == 0) || (PORTAbits.RA5 == 1 &&
PORTAbits.RA6 == 1)) {
vmisil = 28;
tiempomax = 50;
}
}
if (vmisil == 0) {
goto tipomisil;
}

Esta parte del código es similar a la anterior. En ella se selecciona el tipo de


misil del mismo modo. Pero además definimos el tiempo máximo (tiempomax)
de vuelo de cada misil, es decir, el tiempo hasta la autodestrucción si no se
alcanza el objetivo.

//ACTIVAMOS INTERRUPCIONES
INTCONbits.GIE = 1; //Activamos interrupciones generalmente.
INTCONbits.TMR0IE = 1;
//DEFINIMOS EL TIMER PARA UN SEG
T0CON = 0x83; // Timer 0 modo temp. de 16 bits. Prescalar activado (1:16).
TIMER ON
TMR0H = 0x0B; // Se carga el valor de TMR0H y TMR0L para un intervalo de 1s
TMR0L = 0xDC;

Aquí activamos las interrupciones y definimos el valor de T0CON, para un timer


de 16 bits y un preescalar de 1:16. Finalmente se carga el valor para TMR0H y
TMR0L para un intervalo de un segundo, ya que es una cuenta atrás.

resta = vmisil - vavion;


tiempo = (180 / (resta));
//DISPLAYS
vmisil = (vmisil / 10) * 16 + (vmisil % 10);
PORTB = vmisil;
PORTD = (tiempomax / 10)*16 + (tiempomax % 10); //Display del misil
if (tiempo > tiempomax) {
tiempo = tiempomax;
}

En esta parte calculamos el tiempo de impacto en función de las velocidades


del avión y del propio misil. También transformamos el valor de la velocidad del
misil al sistema hexadecimal y lo sacamos por el puerto B, y por el puerto D
sacamos el tiempo de impacto o autodestrucción, habiéndolo transformado
antes.
En el último comando se establece la condición de autodestrucción.
void R_Int_Alta(void) {
if (INTCONbits.TMR0IF == 1) // Se comprueba si la interrupción es por
desbordamiento del temp. 0
{
INTCONbits.TMR0IF = 0; // Se pone a 0 el flag de desbordamiento del temp.
TMR0H = 0x0B; // Se carga el valor de TMR0H y TMR0L para un intervalo de
1s
TMR0L = 0xDC; // TMR0=65536-(TINT*FOSC/4*PRES)=65536-
(1s*4*10^6)/4*16)=3036 =0x0BDC

tiempomax--;

if (tiempo < 0) {
tiempo = tiempomax;
}
if (tiempo <= 0 && explosion == 1) {
tiempo = 0;
}
PORTD = (tiempomax / 10) * 16 + (tiempomax % 10);
tiempo--;
if (tiempo == 0) {
PORTEbits.RE0 = 1;
explosion = 1;
}

}
}

Antes de entrar en el bucle principal, explicamos la interrupción. Si se


encuentra activada se pone el flag a cero para que no se vuelva a activar, se
cargan los valores de los timers (TMR0=65536-(TINT*FOSC/4*PRES)=65536-
(1s*4*10^6)/4*16)=3036 =0x0BDC), y se le resta 1 al tiempo del contador. Si la
variable tiempo es menor que 0, tomará el valor de tiempoomax, y si tiempo es
menor o igual a 0 y ha ocurrido la explosión, el tiempo se pone a 0.
Sacamos por el puerto D el valor de tiempomax en hexadecimal y restamos 1 a
tiempo. Si el tiempo ha llegado a cero significa que la explosión ha ocurrido, por
tanto, se activará el LED de aviso y establecemos el valor de la explosión en
uno.
while (nummisiles>0) {
if ((PORTAbits.RA4 == 1 || disparo > 0) && PORTEbits.RE0 == 0 && vavion >
0) //CONDICIONES DE LANZAMIENTO DE MISIL
{
if (disparoant == 0) {//Se comprueba si se ha disparado recientemente
un misil
disparo++; //Se almacena el numero de disparos realizados
disparoant = 1;

}
T0CONbits.TMR0ON = 1; // Se activa el temporizador

} else {
T0CONbits.TMR0ON = 0;
}
if (tiempo == 0 && explosion == 1) {
//SI EL MISIL HA IMPACTADO O EXPLOTADO.
disparoant = 0; //Se puede volver a disparar un misil.
explosion = 0;
T0CONbits.TMR0ON = 0;
PORTD = 0;
PORTC = 0;
disparo = 0;
//Parpadeo de indicador de impacto o explosión.
for (j = 0; j <= 2; j++) {
PORTEbits.RE2 = 1;
PORTEbits.RE0 = 1;
PORTEbits.RE1 = 1;
i = 0; // Bucle de espera
while (i < 20000) {
i++;
}
PORTEbits.RE0 = 0;
PORTEbits.RE1 = 0;
i = 0; // Bucle de espera
while (i < 20000) {
i++;
}
PORTEbits.RE0 = 1;
PORTEbits.RE1 = 1;
i = 0; // Bucle de espera
while (i < 20000) {
i++;
}
PORTEbits.RE0 = 0;
PORTEbits.RE1 = 0;
PORTEbits.RE2 = 0;
}
goto eleccionavion;

}
}
}

El bucle principal solo se ejecuta si el número de misiles disponibles es


superior a 0, es decir tenemos misiles disponibles para disparar.
Establecemos la condición para que el misil pueda ser disparado comprobando
si la entrada RA4 está en estado alto o la variable disparo es mayor que cero, y
el puerto RE0 está en estado bajo, es decir, el misil no está explotando,
comprobando también que hay un avión (vavion>0). Se activa el temporizador
después de pasar por el siguiente if.
En el primer if, ponemos un or entre el puerto RA4 y la variable disparo>0
porque al tener un botón para disparar, su valor sólo es 1 en el momento de
pulsado del botón. Sin embargo, necesitamos que siga activo a pesar de no
tenerlo pulsado.
Si no se acaba de producir un disparo, es decir, la variable disparoant es igual
a cero, se suma uno a la variable disparo para poder dejar de pulsar el botón.
Ponemos ahora disparoant en estado alto para impedir que se lance otro misil
mientras se encuentra uno en vuelo.
Si la condición de que el misil se dispare no se cumple, se desactiva el
temporizador, se pone a cero.
Si el misil ha explotado entramos en la última ejecución. Permitimos volver a
disparar estableciendo de nuevo las condiciones inciales iniciales de disparo.
Por último, programamos el funcionamiento del LED de aviso de impacto o
explosión. Se activan el LED y el buzzer, realizando tres bucles para establecer
el parpadeo. Cuando termina, se vuelve al comienzo del programa principal.

Segundo PIC
#include <p18F4520.h>// Declaración de librería
#include <math.h>
int entrada, t, unidades, decenas, i,j, misilenaire, misilconfirmado,
avionconfirmado;
int temperaturas[3] = {0, 0, 0};
int temp;

En esta parte del código declaramos la librería del PIC y la de los cálculos
matemáticos. Definimos las variables que se van a utilizar y establecemos las
condiciones iniciales.
void main(void) // Programa Principal
{
ADCON0 = 0x01; // Se activa el A/D y se selecciona el canal AN0
ADCON1 = 0x0E; //
ADCON2 = 0xBC; //
TRISC = 0; // Puerto C de salida
TRISB = 0xF0; // Puerto B de salida
TRISD=1;
TRISA = 0x01; // RA0 de entrada.

Entramos en el programa principal. Seleccionamos el canal de conversión AN0


(RA0) y ponemos el bit de inicio y de monitorización del estado de la
conversión, y se habilita el A/D.
En el ADCON1 conectamos VREF a la línea física RA3 y definimos entradas y
salidas digitales, a excepción de la entrada RA0, que será la entrada del voltaje
(valor de la temperatura acondicionado). En el ADCON2 activamos la
justificación a derechas.
Configuramos la mitad de los puertos B y el puerto C como salidas y el puerto
D junto con RA0 como entradas.
while (1) {
if (PORTDbits.RD0 == 1) {
misilenaire = 0;
misilconfirmado = 0;
avionconfirmado = 0;
PORTC=0;
}
if (PORTBbits.RB6 == 1) {
avionconfirmado = 1;
}
if (PORTBbits.RB5 == 1 && avionconfirmado == 1) {
misilconfirmado = 1;
}
if (PORTBbits.RB7 == 1 && misilconfirmado == 1 && avionconfirmado == 1) {
misilenaire = 1;
}

if (misilenaire == 1) {
PORTB = 1;
i = 1;
while (i < 4) {

ADCON0bits.GO = 1; // Se inicia la conversión


while (ADCON0bits.GO == 1); // Se espera al final de la
conversión
entrada = ADRESH * 256 + ADRESL;
t = (0.195503421 * entrada); // Rango de temperatura desde -50º
hasta 150º partido por la resolucion de bits 2^10-1
temp = t - 50;

temperaturas[i - 1] = temp;
PORTB = pow(2, i);
i++;
}

if (temperaturas[0] != temperaturas[1] || temperaturas[0] !=


temperaturas[2] || temperaturas[1] != temperaturas[2]) {
if (temperaturas[0] > temperaturas[1] && temperaturas[0] >
temperaturas[2]) {
PORTCbits.RC0 = 1;
j = 0; // Bucle de espera
while (j < 20000) {
j++;
}
PORTCbits.RC0 = 0;
j = 0; // Bucle de espera
while (j < 20000) {
j++;
}
PORTCbits.RC0 = 1;
j=0;
} else PORTCbits.RC0 = 0;

if (temperaturas[1] > temperaturas[0] && temperaturas[1] >


temperaturas[2]) {
PORTCbits.RC1 = 1;
j = 0; // Bucle de espera
while (j < 20000) {
j++;
}
PORTCbits.RC1 = 0;
j = 0; // Bucle de espera
while (j < 20000) {
j++;
}
PORTCbits.RC1 = 1;
j=0;
} else PORTCbits.RC1 = 0;

if (temperaturas[2] > temperaturas[1] && temperaturas[2] >


temperaturas[0]) {
PORTCbits.RC2 = 1;
j = 0; // Bucle de espera
while (j < 20000) {
j++;
}
PORTCbits.RC2 = 0;
j = 0; // Bucle de espera
while (j < 20000) {
j++;
}
PORTCbits.RC2 = 1;
j=0;
} else PORTCbits.RC2 = 0;
}else PORTCbits.RC2 = 1;
}
}
}

Cuando el LED de aviso está parpadeando, ponemos las variables y el puerto


C a cero para resetear las variables cuando el misil explote y apagar los LEDs
de dirección.
Una vez hemos confirmado la presencia de un avión enemigo y hemos
seleccionado y lanzado un misil, se activa misilenaire para permitir la ejecución
del guiado por temperatura.
El puerto B es igual a 1 por tanto solo está cerrado el interruptor 1 y por los
demás no circular corriente. Se ejecuta un bucle que inicia la conversión del
valor analógico a digital y se calcula el valor de la temperatura en función del
valor del voltaje convertido.
Se guarda el valor de la temperatura en el vector temperaturas y se define el
valor del puerto B como 2 elevado a i, y se añade 1 a i para que continúe el
bucle.
Si no se detectan dos temperaturas iguales, comienzan a ejecutarse los
comandos encargados de realizar la comparación de las temperaturas.
Explicamos uno de ellos:
Si el primer valor del vector de temperaturas es mayor que los otros dos, el
puerto RC0 se activa encendiendo los LEDs que indican la dirección a seguir, y
se hace parpadear el LED con los bucles de espera. Si no se cumple la
condición, esos LEDs estarán apagados.
Si todas las temperaturas detectadas son iguales el avión avanzara en la
dirección inicial y los LEDs de dirección no parpadean.
SIMULACIÓN EN PROTEUS
La simulación del código se ha hecho mediante el programa Proteus, a
continuación explicaremos las partes y su función.

En esta imagen observamos el primer PIC, el cual ha sido explicado


previamente.
En la parte superior izquierda nos encontramos la selección del tipo de avión,
que se realiza mediante los botones ahí localizados. Una vez seleccionado el
avión se confirma mediante el pulsador, tras lo cual vemos la velocidad del
avión seleccionado a la derecha en el display.
Del mismo modo funciona la selección del misil y su confirmación, el cual se
encuentra en la zona inferior a la de selección del avión, mostrando su
velocidad en la parte inferior del display. A su vez se muestra en el
temporizador el tiempo máximo de vuelo del misil.
Una vez confirmado el misil se efectúa el lanzamiento usando el pulsador de la
izquierda.
En ese momento comienza la cuenta atrás en el temporizador. Si el avión
impacta o se autodestruye se activa el LED situado en la parte inferior
izquierda, acompañado del sonido reproducido por el buzzer de al lado.
Aquí observamos el segundo PIC, el cual lleva conectado tres detectores de
temperatura con acondicionamientos de señales, uno para cada una de las
direcciones (recto, derecha o izquierda).

Por último, nos encontramos con los LEDs encargados de indicar la dirección
que debe seguir el misil para llevar a cabo el impacto.
Para hacer más cómoda la visualización de la simulación, la hemos incluido en
el HUD de un avión.

También podría gustarte