Ejecución de varias rutinas a la vez en un PIC

No hay posibilidad de programacion paralela en un PIC, pero podes usar programacion concurrente via interrupciones a pedal o usar un RTOS como el de CCS.
 
No se puede en paralelo porque va ejecutando tus lineas de código una tras otra.
Si fuera programación de hardware si se podría,pero ya hablamos de otras cosas.

La solución a esto es el uso de interrupciones.

Puedes usar interrupción externa,la mayoria de los pics tienes pines dedicados a esta función marcados como "INT1,INT2,INT..."
Usar la interrupción por cambio de estado de X puerto. ( IOC interrupt on change)

Saludos!
 
Dr. Zoidberg dijo:
No hay posibilidad de programacion paralela en un PIC, pero podes usar programacion concurrente via interrupciones a pedal o usar un RTOS como el de CCS.

Lo de las interrupciones sí estoy al tanto, el problema para mí es que mi PIC al menos, tiene sólo el RB0 como interrupción "Específica". En qué consiste lo de RTOS?


electroconico dijo:
No se puede en paralelo porque va ejecutando tus lineas de código una tras otra.
Si fuera programación de hardware si se podría,pero ya hablamos de otras cosas.

La solución a esto es el uso de interrupciones.

Puedes usar interrupción externa,la mayoria de los pics tienes pines dedicados a esta función marcados como "INT1,INT2,INT..."
Usar la interrupción por cambio de estado de X puerto. ( IOC interrupt on change)

Saludos!

En teoría, usando "rb_int" y "if (input(pin_bx)==0)" dentro de la interrupción, uno para cada entrada deseada, debería funcionar?

TRILO-BYTE dijo:
o quitar los delays y hacer una base de tiempo

A qué te refieres con una base de tiempo?:confused:

Muchas gracias a todos por sus respuestas!! :D:aplauso:
 
VMAN dijo:
Lo de las interrupciones sí estoy al tanto, el problema para mí es que mi PIC al menos, tiene sólo el RB0 como interrupción "Específica". En qué consiste lo de RTOS?
RTOS = Real Time Operating System ==> Sistema Operativo de Tiempo Real
Te permite programar funciones para ejecutarlas a intervalos precisos predefinidos... entre otras cosas.
 
No creo que un RTOS en un pic16f sea lo más conveniente, primero por una cuestión de tamaño y segundo que es demasiado para ejecutar algo tan sencillo como leer entradas y parpadear un led.

VMAN, depende de tu experiencia, ¿utilizaste interrupciones alguna vez?.
Voy a suponer que no.
Desde un punto de vista estricto no se ejecuta nada en paralelo en ningún procesador, pero si tenes:

Código:
while(1)
{
  tarea1();
  tarea2();
  tarea3();
}

Se puede pensar como que tarea1/2/3 se ejecutan en paralelo, siempre y cuando no compartan variables (algo que casi nunca pasa). Pero bueno, la idea es dar una intro lo más sencilla/breve posible, eso es lo que se conoce como "multitarea cooperativo", porque si tarea1 se queda colgada (un while(1) por ejemplo) no hay nada que interrumpa la ejecución de tarea1 y le pase tiempo de micro a tarea2 y 3.

Yendo a tu caso particular serían 2 tareas: leerEntradas, parpadearLed. En cuanto a la base de tiempo, para hacerlo simple por ahora usamos una variable tick que se incrementa con cada loop del while(1). Solo para no complicarla, porque esta lejos de ser lo ideal. Podria quedar asi:

Código:
unsigned int hayQueParpadearLed, tickPeriodoLed, tick;
const unsigned int periodoLed = 1000; //cambiar de acuerdo a carga del micro, un embole

void main(void)
{
    Inicializar();
    tick = 0;
    tickPeriodoLed = periodoLed;
    while(1)
    {
        leerEntradas();
        parpadearLed();
        tick++;
    }
}

void parpadearLed()
{
    if (hayQueParpaderLed)
    {
        if(tick==tickPeriodoLed)
        {
            output_toggle( );        
            tickPeriodoLed += periodoLed;
        }
    }        
}

void leerEntradas(void)
{
    if(condicion para parpadear)
    {
        hayQueParpadearLed = 1;
        tickPeriodoLed =  tick + periodoLed;
        output_high(pinLed);        
    }

    if(condicion para no parpadear)
    {
        hayQueParpadearLed = 0;
        output_low(pinLed);        
    }
}

Se entiende la idea?, la tarea leerEntradas() mira las entradas y cambia una variable global "hayQueParpadearLed", y la tarea parpadearLed() mira esa variable global, si está activa mira si se cumplió el período de tiempo, y de ser así conmuta la salida del led.
Luego la base de tiempo se puede mejorar, porque no hay una relación entre tick tiempo real. Para eso hay que usar un timer (el timer0 por ejemplo) con entrada = reloj del sistema. Pero ya es un tema aparte. Después vemos que modificaciones hacer, pero primero digerí esta parte.
Este es un tema con el que los usuarios del delay_ms() tienen muchísimos problemas, cuando se trata de usar un periférico.
 
Gracias Ardogan, sí, entiendo al menos conceptualmente la ídea. Aunque para comprenderla de mejor manera, transcribí el código a PIC C Compiler. Reemplacé las variables necesarias pero... y disculpa mi ignorancia, no sé como solucionar el mensaje de error "Undefined identifier" que me tira con cada función excluyendo el Main.

Según entiendo ese mensaje de error es cuando no encuentra declaradas las variables, pero sí las veo declaradas, exceptuando por "Inicializar" :S.

Adjunto el código final:

Código:
void main(){

   // TODO: USER CODE!!
   
   // Eliminar Ruido
   
   output_low(pin_b1);
   output_low(pin_b2);

   
 Inicializar();
    tick = 0;
    tickPeriodoLed = periodoLed;
    while(1){
        leerEntradas();
        parpadearLed();
        tick++;
    }
}

void parpadearLed(){

    if (hayQueParpaderLed){
        if(tick==tickPeriodoLed)
        {
            output_toggle(pin_b1);        
            tickPeriodoLed += periodoLed;
        }
    }        
}

void leerEntradas(){

    if(input(pin_b7)==0){
        hayQueParpadearLed = 1;
        tickPeriodoLed =  tick + periodoLed;
        output_high(pin_b1);        
    }

    if(input(pin_b6)==0){
        hayQueParpadearLed = 0;
        output_low(pin_b1);        
    }
}
 
lo unico que lograran haser usando el RTOS es aprender a programar de una forma bien marrana pues no se esta aprendiendo bien yo sugiero que usen una base de tiempo

se puede haser con un delay muy corto o usando interrupcion del timer
 
lo unico que lograran haser usando el RTOS es aprender a programar de una forma bien marrana pues no se esta aprendiendo bien yo sugiero que usen una base de tiempo
se puede haser con un delay muy corto o usando interrupcion del timer
:eek: :eek: :eek: :eek:

Si necesitás procesamiento concurrente NO ES NINGUNA MARRANADA, y a menos que quieras terminar el desarrollo para cuando finalice la próxima era glacial, es la solución más rápida a la pregunta original. El RTOS ya usa un timer interno, tiene un scheduler para despacho COOPERATIVO de tareas (no es preemptivo) y tiene un montón de cosas adicionales que pueden ayudar a evitar deadlocks.... entre otras cosas importantes.

Un tema aparte es que entiendan para que sirve y como trabaja...
 
Gracias Ardogan, sí, entiendo al menos conceptualmente la ídea. Aunque para comprenderla de mejor manera, transcribí el código a PIC C Compiler. Reemplacé las variables necesarias pero... y disculpa mi ignorancia, no sé como solucionar el mensaje de error "Undefined identifier" que me tira con cada función excluyendo el Main.

Según entiendo ese mensaje de error es cuando no encuentra declaradas las variables, pero sí las veo declaradas, exceptuando por "Inicializar" :S.

Adjunto el código final:

Código:
void main(){

   // TODO: USER CODE!!
   
   // Eliminar Ruido
   
   output_low(pin_b1);
   output_low(pin_b2);

   
 Inicializar();
    tick = 0;
    tickPeriodoLed = periodoLed;
    while(1){
        leerEntradas();
        parpadearLed();
        tick++;
    }
}

void parpadearLed(){

    if (hayQueParpaderLed){
        if(tick==tickPeriodoLed)
        {
            output_toggle(pin_b1);        
            tickPeriodoLed += periodoLed;
        }
    }        
}

void leerEntradas(){

    if(input(pin_b7)==0){
        hayQueParpadearLed = 1;
        tickPeriodoLed =  tick + periodoLed;
        output_high(pin_b1);        
    }

    if(input(pin_b6)==0){
        hayQueParpadearLed = 0;
        output_low(pin_b1);        
    }
}

Inicializar es una función que no definí, lo puse como para decir que en algún lado se inicializan los puertos de entrada/salida, módulos, etc, etc.
En tu caso particular sería inicializar los botones como entradas y el pin del led como salida. Eso te lo dejo a vos. Podés no usar una función y ponerlo antes del while(1), como te guste.

Después antes del main hay que declarar los prototipos de las funciones
void leerEntradas(void);
void parpadearLed(void);
El compilador lee el programa línea a línea, llega a leerEntradas() en el main, y dice "esto no me dijeron donde esta", por eso tira error.
No pretendía dar un código que funcionara al hacer copy-paste, solo plantear una primera idea.
 
pero eso quiere hacer el compañero la ley del minimo esfuerzo

por eso decia que es una marranada usar RTOS

no estoy en contra de RTOS para quienes quieran arrancarse los pelos del coraje

NO estoy viendo que no quiere pensar esa es mi opinion
 
Gracias nuevamente a todos. En mi caso no se trata del mínimo esfuerzo, sin embargo, ya que no soy un erudito el área y recién estoy saliendo del nido, prefiero ir tomando escalón por escalón para procurar entender todo desde las raíces. Nuevamente gracias a todos por darse el tiempo de responder de manera tan completa y útil!
 
Ambos micros me convienen en un momento dado que sean master o slave.
L
a función que falla es; recoge(); (es aquí donde se atascan) ambos la utilizan para leer cuando son slave y tienen otra de escritura llamada refresco(,,,) para escribir al otro cuando son master.

No consigo ver el problema, pic1 tiende a atascarse en el la lectura.
No debería, ya que dentro de esta función; recoge(); una vez que empieza a leer, no hay manera de que se quede encerrado dentro de ella.

PHP:
///originalmente micro1 siempre era master
///Hay un jaleo en la combersion pic1-master--->pic1-slave CONCEPTO RECIVIDO es ENVIO  ENVIO es RECIVIDO
void protSlave(){///protocolo de recivo vajo SPI pic2SLAVE
output_high(PIN_C6);//S.envio=true -----> pic2_b7_MASTER/E.envio
delay_ms(7); ///valido (8)
output_low(PIN_C6);
delay_ms(7); 
}
Hay algo malo. No utilizo interrupciones.
El slave se queda esperando en recoge(); sin hacer nada más hasta que master le diga que tiene que empezar a leer.
En una comunicación y conversión continua, lo hacen bien pero no consigo ver porque falla cuando la espera es larga.
En principio la acción es la misma.

El código es lioso pero adjunto el proyecto para que se vea lo que pretendo hacer.
Me gustaría saber qué tengo que elegir cuando realice un proyecto de este tipo.
Todo lo que elijo es por defecto cuando creo un wizard.
Creo que también será mejor utilizar un cristal para que en todos los micros coincidan el clock de flanco de subida y bajada.

PHP:
//////////////////RECOGE 
void recoge(){//0-1-2 IDEN 4 peti,salir,cliente,target[cliente]
output_low(PIN_C6);///S.envio  0 = pic2_B7_MASTER/E.envio
//output_high(PIN_C1);//RS TRUE
int8 co;
int1 muta=0;
//if (Input(PIN_C0)==1) { }
while (Input(PIN_C0)==0) { } 
//while(!spi_data_is_in()){ output_low(PIN_C1); delay_ms(2); output_high(PIN_C1); delay_ms(2); }
output_high(PIN_C1);//RS TRUE ESTE PIN DEBERIA PASAR A FALSE pero micro1 se suele quedar aqui atrapado
grp2=spi_read();
//if (peti==101) { output_high(PIN_C6); delay_ms(4); }
protSlave();  
grp3=spi_read();///gp[2] = int1_gp3_Master refresco(x,x,1,x,x)
protSlave();
if (grp2==1) {////**per 2 (estado-salidas pic1)
for (co=0;5>co;co++){
ladra[co]=spi_read();   
protSlave();
}
}////**per 2
if (grp3==1) {////**per 3
peti=spi_read();// int8 peti
protSlave();
salir=spi_read();// salir
protSlave();
cliente=spi_read();// cliente
protSlave();
target[cliente]=spi_read();// int1 targe[ ]  
protSlave();
tarje=spi_read();// int1 tarje   
protSlave();
union UNI M32;//int32 mony
   for(co=0;co<4;co++){ 
      M32.bytes[co] = spi_read();  
      protSlave(); }
mony=M32.dat32; 
}////**per 3
muta=spi_read();// *cliente
output_high(PIN_C6);//S.envio=true -----> pic2_b7_MASTER/E.envio
if (grp2==1) {
if (ladra[0]) { output_high(PIN_a0); } else { output_low(PIN_a0); } delay_ms(1); //delay_ms(2);
if (ladra[1]) { output_high(PIN_a1); } else { output_low(PIN_a1); } delay_ms(1);
if (ladra[2]) { output_high(PIN_a2); } else { output_low(PIN_a2); } delay_ms(1);
if (ladra[3]) { output_high(PIN_a3); } else { output_low(PIN_a3); } delay_ms(1);
if (ladra[4]) { output_low(PIN_a4);  } else { output_high(PIN_a4);  } delay_ms(1);//neg
} else {
delay_ms(5); }
delay_ms(2);
output_low(PIN_C6);
output_low(PIN_C1);//RS FIN
if (muta) { COMBERSION(1);  delay_ms(16); }
}
Utilizo la siguiente función para hacer la conversión:
Este es el caso de micro1, cada uno tiene un sec_tris diferente según les convenga

PHP:
void COMBERSION(int1 Soy){
if (Soy){
MASTER=1; set_tris_c(208); delay_ms(2);// 1101 0000 /// "C5_S C4_E C3_S  01 0"
setup_spi(spi_master | spi_l_to_h | spi_clk_div_16); delay_ms(4);//| SPI_XMIT_L_TO_H); //);// | SPI_XMIT_L_TO_H);  
output_high(PIN_c7);
} else {
MASTER=0; set_tris_c(240);  delay_ms(2); // 1111 0000 /// "C5_E C4_E C3_S  11 0"
setup_spi(spi_slave | spi_l_to_h | spi_clk_div_16); delay_ms(2);//| SPI_XMIT_L_TO_H); //);// | SPI_XMIT_L_TO_H);  
output_low(PIN_c7);
}
MASTER es una int1 que coincide a True cuando el micro es master, siempre se pasa este valor "muta"en refresco(muta,x,x) por si es conveniente la conversión.
 

Adjuntos

  • ElProyecto.rar
    63.5 KB · Visitas: 9
Última edición por un moderador:
Hola. Tengo una duda.
¿Cómo hacer que el circuito 1 y 2 estén en el mismo PIC16F628A?
Estoy usando el programa mikroC Pro For PIC.

Les dejo una simulación en vídeo de éste circuito, junto con los archivos de programación.

 

Adjuntos

  • BOTON2.5.rar
    20.5 KB · Visitas: 7
Algo sencillo, usando la interrupción externa por RB0 para el caso 1 y para el caso del circuito 2 en el mismo microcontrolador, lo ejecutas en el bucle del void main.

Ahora que si quieres hacerlo de forma un poco más complicada, utiliza los timers y también las interrupciones.
 
es que no les gusta buscar en el foro

hubo uno que tenia dudas, busco en el foro un codigo viejo que explique hace un tiempo, me pego el pedazo de codigo que no entendio y me pregunto dudas

eso es tener perseverancia
hay que buscar
 
Estuve buscando por el foro pero no encuentraba la respuesta de hecho aun sigo trabajando en buscar una solucion pero en los Timer como me dijo D@rkbytes para asi hacer lo que pido en el video.
 
A ver, por partes: Los leds siempre necesitan resistencia y los pulsadores no necesitan resistencia porque el micro ya lleva un dentro que se puede activar por software. Número cien mil millones de billones que se repite en el foro.

Borro el resto por que estaba un tanto subida de tono la respuesta.

De verdad que no comprendo donde está la dificultad de hacer cosas tan tan pero tan tontas a la vez.
Borrad de vuestra mente el maldito delay de las narices y veréis la luz.
 
Última edición:
Atrás
Arriba