# Código Robot MiniSumo Pic



## JuanGa94 (Ene 24, 2013)

Hola, he armado un código en C para mi robot minisumo, pero tengo el sig. problema: El robot cuando esta en movimiento y detecta al oponente o el borde del ring, automáticamente no inicia la subrutina hecha para cada situación, sino que espera a terminar el movimiento y recién ahí la realiza(si aun la detecta) o sino continua buscando(moviéndose). He pensado en mejorar el código usando interrupciones, pero hay de muchos tipos y no se como configurarlas. Si alguien se le ocurre otra idea o tiene experiencia con lo robots sumo-minisumo por favor comenten...
Dejo el codigo que tengo hasta ahora:

```
#include<16F628A.h>         //USO PIC 16F628A
#use delay (clock=4000000) //CRISTAL 4MHz
#define TRISB=0b11111111         //PUERTO B ENTRADA
#define TRISA=0b00000     //PUERTO A SALIDA
#FUSES XT,NOWDT
#use fast_io(A)
#use fast_io(B)
#byte portA = 5        //    se definen las direcciones de memoria         
#byte portB = 6         //    se definen las direcciones de memoria

VOID AVANZAR();      //FUNCION AVANZAR
VOID DER();          //FUNCION GIRAR A LA DERECHA
VOID IZQ();          //FUNCION GIRAR A LA IZQUIERDA
VOID ATRAS();         //FUNCION RETROCEDER
VOID VUELTA();        //FUNCION GIRA 180º A LA DERECHA
VOID SURESTE();      //FUNCION GIRAR 135º DERECHA
VOID SUROESTE();     //FUNCION GIRAR 135º IZQUIERDA
VOID DIAGODER();     //FUNCION GIRAR 45º DERECHA
VOID DIAGOIZQ();     //FUNCION GIRAR 45º IZQUIERDA

void main()
{  
   set_tris_b (0b11111111);      //DEFINE TRIS B COMO ENTRADAS 1
   set_tris_a (0b00000);         //DEFINE TRIS A COMO SALIDAS 0
   PORTA=(0x00);                 //INICIALIZA TODO EN 0
   PORTB=(0x00);

DELAY_MS(5000);                  //ESPERA 5 SEG.

WHILE(TRUE)
{
//****//****SENSORES OPONENTE****//****
   IF(INPUT(PIN_B0))          //SENSOR FRENTE
      {DELAY_MS(20);
      IF(INPUT(PIN_B0))
      AVANZAR();}
      
   ELSE IF(INPUT(PIN_B1))     //SENSOR DERECHA
      {DELAY_MS(20);
      IF(INPUT(PIN_B1))
      {DER();
      AVANZAR();
      }
      }      
   ELSE IF(INPUT(PIN_B2))     //SENSOR ATRAS
      {DELAY_MS(20);
      IF(INPUT(PIN_B2))
      {VUELTA();
      AVANZAR();
      }}
   ELSE IF(INPUT(PIN_B3))          //SENSOR IZQ
      {DELAY_MS(20);
      IF(INPUT(PIN_B3))
      {
      IZQ();
      AVANZAR();
      }
      }
//****//****SENSORES DE LINEA****//****
   ELSE IF(INPUT(PIN_B4))          //SENSOR FRONTAL IZQ
      {DELAY_MS(20);
      IF(INPUT(PIN_B4))
      {
      ATRAS();
      SURESTE();
      AVANZAR();}
      }
   ELSE IF(INPUT(PIN_B5))          //SENSOR FRONTAL DER
      {DELAY_MS(20);
      IF(INPUT(PIN_B5))
      {
      ATRAS();
      SUROESTE();
      AVANZAR();}
      } 
   ELSE IF(INPUT(PIN_B6))          //SENSOR ATRAS DER
      {DELAY_MS(20);
      IF(INPUT(PIN_B6))
      {
      AVANZAR();
      DIAGOIZQ();
      AVANZAR();
      }      
      }    
   ELSE IF(INPUT(PIN_B7))          //SENSOR ATRAS IZQ
      {DELAY_MS(20);
      IF(INPUT(PIN_B7))
      {
      AVANZAR();
      DIAGODER();
      AVANZAR();
      } 
      }
   ELSE IF(INPUT(PIN_B4)&&INPUT(PIN_B5))     //FRONTAL IZQ+DER
      {DELAY_MS(20);
      IF(INPUT(PIN_B4)&&INPUT(PIN_B5))
         {ATRAS();
         VUELTA();
         AVANZAR();
         }
      }
   ELSE IF(INPUT(PIN_B5)&&INPUT(PIN_B6))     //FRONTAL DER+ATRAS DER
      {DELAY_MS(20);
      IF(INPUT(PIN_B5)&&INPUT(PIN_B6))
         {DIAGODER();
         AVANZAR();
         }
      }
   ELSE IF(INPUT(PIN_B6)&&INPUT(PIN_B7))     //ATRAS IZQ+DER
      {DELAY_MS(20);
      IF(INPUT(PIN_B6)&&INPUT(PIN_B7))
         {DIAGODER();
         AVANZAR();
         }
      }
   ELSE IF(INPUT(PIN_B4)&&INPUT(PIN_B7))     //ATRAS IZQ+FRONTAL IZQ
      {DELAY_MS(20);
      IF(INPUT(PIN_B4)&&INPUT(PIN_B7))
         {DIAGODER();
         AVANZAR();
         }
      }
//****//****OTROS****//****
   ELSE {                  //SINO DETECTA NADA
         VUELTA();
         AVANZAR();
        }      
}
}

VOID AVANZAR()
{
   PORTA=(0b10101);
   delay_ms(3000);
   PORTA=(0b00000);
}
VOID DER()
{
   PORTA=(0b01101);
   delay_ms(3000);
   PORTA=(0b00000);
}
VOID IZQ()
{
   PORTA=(0b10011);
   delay_ms(3000);
   PORTA=(0b00000);
}
VOID ATRAS()
{
   PORTA=(0b01011);
   delay_ms(3000);
   PORTA=(0b00000);
}
VOID VUELTA()
{
   PORTA=(0b01101);
   delay_ms(6000);
   PORTA=(0b00000);
}
VOID DIAGODER()
{
   PORTA=(0b01101);
   delay_ms(1500);
   PORTA=(0b00000);
}
VOID DIAGOIZQ()
{
   PORTA=(0b10011);
   delay_ms(1500);
   PORTA=(0b00000);
}
VOID SURESTE()
{
   PORTA=(0b01101);
   delay_ms(4500);
   PORTA=(0b00000);
}
VOID SUROESTE()
{
   PORTA=(0b10011);
   delay_ms(4500);
   PORTA=(0b00000);
}
```


----------



## JuanGa94 (Ene 26, 2013)

Hola, pude agregarle a mi código las interrupciones exteriores en RB4-RB7, pero me gustaría poder saber cual de las 4 entradas se activó y no solo que una de ellas se activo, para poder ir directamente a las instrucciones correspondientes y no usar un if() para buscarlas, para hacerlo mas rápido.¿Si se activan dos interrupciones al mismo tiempo que pasa?¿puedo usarlas así o solo se usan por separado?

El compilador tira dos Warnings, ¿como los saco?
Warning 216 "MiniSumo.c" Line 195(0,1):Interrupts disabled during call to prevent re-entrancy: (@delay_ms1)
Warning 216 "MiniSumo.c" Line 195(0,1):Interrupts disabled during call to prevent re-entrancy: (AVANZAR)
PD: Mi código no tiene linea 195, llega hasta 193. Al seleccionar los dos warnings me indica la ante ultima linea, PORTA=(0b00000);

Saludos


----------



## ByAxel (Ene 26, 2013)

Hola:
- Intenta no poner delays en una interrupción.
- Si buscas optimizar el programa, intenta no hacer Delays demasiados largos en los que el PIC no hace nada. ten en cuenta esto cuando usas interrupciones ya que una interrupción sucede una por vez.
- La interrupción que usas sucede cada vez que cambia el estado en los pines RB4-RB7, ya sea de 1 a 0 o de 0 a 1, sin importar.

Lo que puedes hacer cuando sucede la interrupción es lee todo el PORTB y determinar que hacer; algo así:


```
// En la interrupción, obtiene solo los valores de RB4-RB7
// Puedes usar una variable como flag que indique el cambio
Valor = input_b() & 0xF0;

// Fuera de la interrupción, si es que el flag esta activado
// Puedes usar Switch o If para determinar que hacer

Switch(Valor){
   case 0b00010000:
        // Alguna rutina
        break;
   case 0b00110000:
        // Alguna rutina
        break;
}

// Limpias el flag
// Todo esto dentro de un bucle infinito
```

- Para evitar los delays muy largos puedes usar contadores que se incrementen cada vez que pasa por el bucle principal donde se aloja el programa principal. O también dar uso a los timer internos.

Espero se entienda.

Saludos


----------



## JuanGa94 (Ene 26, 2013)

Hola, gracias por los consejos, pero hay algunas cosas que se me va a hacer difícil cambiar como los delay en las funciones, porque son el tiempo que necesito para que los motores funcionen para girar en cierta forma o avanzar cierta distancia.En cuanto al uso de un variable Flag, es muy buen idea,la voy a usar al igual que el switch(). 
¿Sabes si se puede configurar las interrupciones rb4-7, como L_to_H, como con las interrupciones en RB0?¿O solo detectan cambio y no valores "0","1"? Me parece que voy a tener que descartar la idea del contador por lo del tiempo de los motores, pero me interesa el uso de los timer internos,¿ Podrías mostrarme como usarlos?

Saludos


----------



## ByAxel (Ene 27, 2013)

> Hola, gracias por los consejos, pero hay algunas cosas que se me va a hacer difícil cambiar como los delay en las funciones, porque son el tiempo que necesito para que los motores funcionen para girar en cierta forma o avanzar cierta distancia


Claro, no hay problema si solo va a realizar una función por vez.



> ¿Sabes si se puede configurar las interrupciones rb4-7, como L_to_H, como con las interrupciones en RB0?¿O solo detectan cambio y no valores "0","1"?



Solo detectan el cambio. Aún así el evento es despreciable ya que se va a leer todo el PORTB en interrupción y luego comparar con cual coincide fuera de la interrupción y si no! entonces no hace nada... limpia el Flag (aviso) y continua...

La sugerencia de los Timer internos es para cuando el PIC tenga que realizar otra cosa mientras internamente va contando, esto elimina la idea que usas de realizar una función por vez.

- El PIC que utilizas tiene 3 timers internos (TMR0 de 8 bits, TMR1 de 16 bits y TMR2 8 bits generalmente usado con el módulo CCP); sugiero los dos primeros.
- Los timers tienen su Prescale o postcale utilizados para dividir la frecuencia del oscilador principal de manera que el conteo sea más lento; por ejemplo para el TMR1 con una frecuencia principal de 4Mhz y el prescale a 1:8 se obtiene 524288us o 524ms aprox. y si la interrupción por desbordamiento esta activa entonces se tiene eventos cada 1/2 segundos aprox. esto se puede utilizar para incrementar una variable a modo de contador; esta variable seria utilizada en el resto del programa...
- El tiempo que se requiere puede ser calculado haciendo uso de las formulas en el datasheet.

Saludos


----------



## JuanGa94 (Ene 27, 2013)

Hola, me parece que voy a reemplazar los delays por tiempo generado con el timer0, porque probé un código actualizado y aun tiene algunos problemas producto de estos delays durante los cuales no puedo hacer nada.
Estoy pensando en agregarle algo asi:

```
int cont=0;
int veces=0;
#int_timer0
void interr_tmr0()
{//chequeo todas las entradas
if(cont<veces)
cont++;
else{
cont=0;
disable_interrupts(int_timer0);}
set_timer0(0x-86);
}
main()
{setup_timer_0(rtcc_internal|rtcc_div_256);
set_timer0(0x-86);
//en vez de cada delay pongo enable_interrupts(int_timer0); y veces=x;
}
```
El timer0 desbordara cada 100ms para chequear todo, podre usarlo en vez de los delays contando la cantidad de veces que se activa, ej: veces=10 para un delay de 1seg. Osea que chequearía cada 100ms durante 1 seg.
La unica duda es el valor tmr0=0x-86, lo calcule asi : 100ms=4*(1/frec. cristal)*(256-tmro)*256, me da -134,625, redondeando y en hexa seria 0x-86 ¿Esta bien?

Saludos


----------



## ByAxel (Ene 28, 2013)

100ms por si solo?, seguro? ya que con 4Mhz, el TMR0 = 0 y el prescaler a 256 se desborda cada 65536us que son 65ms aprox. que es el máximo.

Revisa esto: PIC Timer Calculator , es en linea.
Compara... me parece que estas comprendiendo mal la formula.

Saludos.


----------



## JuanGa94 (Ene 28, 2013)

Hola, si tenes razón,era imposible lo que calcule, encima negativo.... Finalmente lo deje en 50ms TMR0=60=3C Prescaler=256. También pude reemplazar los delay por tiempo con el timer0, pero lamentablemente todo deja de funcionar bien cuando agrego el chequeo de entradas en la interrupción.
Dejo el Codigo, funciona bien, pero no chequea las entradas (esa parte la deje entre/**/ en la interrupción)

Espero que se entienda como lo razone, Saludos


----------



## JuanGa94 (Abr 20, 2013)

Hola, en las ultimas semanas he tratado de terminar el código para usarlo, pero no puedo hacerlo funcionar como quiero. A pesar de las mejoras(interrupciones, etc.), sigo teniendo el mismo problema: cuando el robot detecta algún cambio no reacciona hasta que termina la función que esta realizando.
Tome como base el código de arriba para mejorarlo pero no puedo,¿ algún consejo?
Pensándolo mejor empezamos por lo mas básico, que el robot avance hasta que encuentre una linea(algún sensor) y se detenga (o retroceda).Me ayudan??


----------



## mihualtecatl (May 31, 2016)

JuanGa94 dijo:


> Hola, pude agregarle a mi código las interrupciones exteriores en RB4-RB7, pero me gustaría poder saber cual de las 4 entradas se activó y no solo que una de ellas se activo, para poder ir directamente a las instrucciones correspondientes y no usar un if() para buscarlas, para hacerlo mas rápido.¿Si se activan dos interrupciones al mismo tiempo que pasa?¿puedo usarlas así o solo se usan por separado?
> 
> El compilador tira dos Warnings, ¿como los saco?
> Warning 216 "MiniSumo.c" Line 195(0,1):Interrupts disabled during call to prevent re-entrancy: (@delay_ms1)
> ...


me pasaria su simulacion para ver como esta conectado amigo


----------



## martinjavier1902 (Nov 20, 2016)

Estoy trabajando en el código de un mini sumo.
Hasta ahora sólo estoy probándolo con sensores CNY70 para que no se salga de la linea, pero no quiere correr en ninguno de los casos.

Les agradecería su ayuda.
Les anexo el archivo del código en PIC C Compiler y el archivo en proteus.


----------

