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

Exacto.
Yo en mis programas separo un archivo .h para las configuraciones, otro para las funciones, otro con el método main, etc.
 
Aquí el código, solo que no se como saltar del main a los otros bloques, porque si llamo la función de CONTROL que es la que me va estar monitoreando los dos ADC me dice que

*** Error 69 "E:\Users\**\Documents\PROYECTOS MPLAB\FOLDER*\NOMBRE*.C" Line 120(1,2): Recursion not permitted [CONTROL]

Código:
#include<16F887.h>
#device ADC=10
#fuses HS,NOWDT,NOLVP,MCLR,NOPROTECT
#use delay(clock=20000000)
#define use_portb_lcd TRUE
#include<LCD.C>
#include<FUNCIONES_*****.h>
//--------------------------------------------------------------------
long int ADC;
float temp,aux;
//-------------------BLOQUES DE FUNCIONES-----------------------------

//CONFIGURACIONES

                        //ADC LDR//
void adcldr(void){
    set_tris_d(0xF0);
    set_tris_a(0x0F);
    setup_adc(ADC_CLOCK_INTERNAL|VSS_VDD);
    setup_adc_ports(sAN1);
            set_adc_channel(1);
    setup_comparator(NC_NC_NC_NC);
}

                       //ADC SENSOR//
void adcsen(void){
    set_tris_d(0xF0);
    set_tris_a(0x0F);
    setup_adc(ADC_CLOCK_INTERNAL|VSS_VDD);
    setup_adc_ports(sAN0);
            set_adc_channel(0);
    setup_comparator(NC_NC_NC_NC);
}

//FUNCIONES DE EJECUCIÓN

                       //FUNCION MAIN//
void main(void){

}
                    //FUNCION CONTROL//
void CONTROL(void){

    do{
        sensor();
            delay_ms(20);
        ldr();
            delay_ms(20);
    }while(TRUE);
}

                       //FUNCION LDR//
void ldr(void){
        adcldr();
        LUCES();
}
void LUCES(void){
        if(!input(PIN_C6)){
    delay_us(20);
        do{
            ADC=read_adc();
                delay_ms(800);
            if(ADC<=600){
                output_d(0b0000001);
            }else{
                    output_d(0x00);
                }
            if(ADC<=300){
                output_d(0b00000011);
            }else{
                    output_d(0x01);
                }
            if(ADC>600){
                output_d(0x00);
            }
                if(input(PIN_C6)){
                    output_d(0x00);
                    CONTROL();
                }
        CONTROL();

        }while(TRUE);
        }else{CONTROL();}
}                                    //>>>>>>>>>>>>>>>>>>>>>>OK

                     //FUNCION SENSOR//
void sensor(void){
    lcd_init();
            delay_ms(1000);
            lcd_gotoxy(1,1);
            lcd_putc("TEMP. & LIGHTING");
            lcd_gotoxy(1,2);
            lcd_putc(" SYSTEM  <1.0v> ");
                delay_ms(800);
            lcd_gotoxy(1,1);
            lcd_putc("    STARTING    ");
            lcd_gotoxy(1,2);
            lcd_putc("====>+~][~+<====");
                delay_ms(400);
    adcsen();
        lcd_gotoxy(1,1);
        lcd_putc("    TEMP EXT");
            delay_ms(20);
        lcd_gotoxy(1,2);
        printf(lcd_putc,"INICIANDO SENSOR");
            delay_ms(100);
            temp=read_adc();
            temp=(temp*300)/614;
            if(temp!=aux){
                lcd_gotoxy(1,2);
                printf(lcd_putc," < < < %0.0f'C > > >",temp);
                    delay_ms(100);
                lcd_gotoxy(1,2);
                printf(lcd_putc,"  - -  %0.0f'C  - -  ",temp);
                aux=temp;
            }
        CONTROL();
}
 
Última edición por un moderador:
Hola. ¿Qué tal? Estoy trabajando con tiempo real en CCS usando un PIC18F452.
La idea es hacer una aplicación con unas cuantas tareas que me permitan activar tres tareas con pulsadores, y luego desactivarlas con un comando enviado desde el hiperterminal de windows o el de isis proteus en simulación.

Hasta ahora he logrado hacerlo pero para que se ejecute una tarea se necesita de una orden desde el hiperterminal y la idea es que la activación sea independiente de la desactivación de las tareas.

Serían de gran ayuda sus aportes.
 
Hola ingdirson todo depende la las tareas que quieras ejecutar, segun ellas en algun caso se opuede trabajar en rutina principal, en otros casos con las interrupciones y otros sera mejor usar RTOS.
por lo general basta y sobra unsar las interrupciones y en casos mas complejos serán RTOS mas interrupciones.
para tu caso puedo recomendarte que te interiorices en el RTOS de CCS me imagino que con eso sera suficiente.
 
Hola ingdirson todo depende la las tareas que quieras ejecutar, segun ellas en algun caso se opuede trabajar en rutina principal, en otros casos con las interrupciones y otros sera mejor usar RTOS.
por lo general basta y sobra unsar las interrupciones y en casos mas complejos serán RTOS mas interrupciones.
para tu caso puedo recomendarte que te interiorices en el RTOS de CCS me imagino que con eso sera suficiente.

Hola. De hecho estoy trabajando con RTOS y también usé #INT_RDA, que según lo que sé es la activación de las interrupciones RDA y global, pero tal vez por que soy nuevo en este tema no las haya usado bien.

Adjunto mi proyecto. En el archivo están el código en C con PIC C Compiler de CCS, un archivo de ISIS Proteus y unas pequeñas instrucciones de uso.

PD: En éste no estoy haciendo uso de las interrupciones.

Esperaré tu comentario al respecto.
 

Adjuntos

  • Desactivar_tareas.rar
    69 KB · Visitas: 17
Última edición por un moderador:
Hola ingdirson, te comento que no hay una buena conceptualización de las tareas que tienes.
En este fragmento de código hay un problema:
void leer()
{ int a,b,c;
dato=getc(); //****** esta instrucción "traba" a la tarea y se queda en bucle infinito****
lcd_init();
.
.
.
Adjunto un ejemplo del como podria plantearse algo mejor las tareas.

Los pulsadores activan las tareas individuales y estas tareas se desactivas mediante comandos revividos por el puerto serie: 'r' desactiva la tarea 1, 'v' desactiva la tarea 2, 'a' desactiva la tarea 3 y 'c' desactiva todas las tareas.

Código:
#include <18f452.h>
#fuses HS,NOWDT
#use delay(clock=20000000)
#use rs232(baud=19200,xmit=PIN_c6,rcv=PIN_c7,bits=8,parity=N)
#use RTOS(timer=0, minor_cycle=10ms)
#include <lcd.c>

#task (rate=10ms,max=1ms)
void puerto_serie();
#task (rate=100ms,max=1ms)
void leer_pulsadores();
/******************************************************************************
Tareas a ejectar
******************************************************************************/
#task (rate=100ms,max=1ms,enabled=false)  //la terea no inicia automatocamente
void tarea1();
#task (rate=250ms,max=1ms,enabled=false)  //la terea no inicia automatocamente
void tarea2();
#task (rate=350ms,max=1ms,enabled=false)  //la terea no inicia automatocamente
void tarea3();
/*****************************************************************************/
void main()
{ 
   lcd_init();
   lcd_putc("T: | 1 | 2 | 3 |\n");
   lcd_putc("   |off|off|off|");
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   rtos_run();
}
/******************************************************************************
Lee el estado del puerto serie
******************************************************************************/
void puerto_serie()
{
   char  dato_rx;
   rtos_await(kbhit());
   dato_rx=getc();
   switch(dato_rx)
   {
      case 'r':  
      {
         rtos_disable(tarea1);
         output_low(pin_b0);
         lcd_gotoxy(5,2);
         lcd_putc("off");
         putc(dato_rx);
         break;
      }
      case 'v':
      {
         rtos_disable(tarea2);
         output_low(pin_b1);
         lcd_gotoxy(9,2);
         lcd_putc("off");
         putc(dato_rx);
         break;
      }
      case 'a':
      {
         rtos_disable(tarea3);
         output_low(pin_b2);
         lcd_gotoxy(13,2);
         lcd_putc("off");
         putc(dato_rx);
         break;
      }
      case 'c':
      {
         rtos_disable(tarea1);
         rtos_disable(tarea2);
         rtos_disable(tarea3);
         output_low(pin_b0);
         output_low(pin_b1);
         output_low(pin_b2);
         lcd_gotoxy(1,2);
         lcd_putc("   |off|off|off|");
         putc(dato_rx);
         break;
      }
   }
}
/******************************************************************************
Lee los pulsadores y segun el caso habilita las tareas
******************************************************************************/
void leer_pulsadores()
{
   if(input(pin_b4))
   {
      rtos_enable(tarea1);
      lcd_gotoxy(5,2);
      lcd_putc("on ");
   }
   if(input(pin_b5))
   {
      rtos_enable(tarea2);
      lcd_gotoxy(9,2);
      lcd_putc("on ");
   }
   if(input(pin_b6))
   {
      rtos_enable(tarea3);
      lcd_gotoxy(13,2);
      lcd_putc("on ");
   }
}
void tarea1()
{
   output_toggle(PIN_b0); 
}
void tarea2()
{
   output_toggle(PIN_b1);
}
void tarea3()
{
   output_toggle(PIN_b2);
}
Dibujo.PNG
 

Adjuntos

  • notacorte2_2.rar
    69.2 KB · Visitas: 20
Código:
******************************************************************************/
#task (rate=100ms,max=1ms,enabled=false)  //la terea no inicia automatocamente
void tarea1();
#task (rate=250ms,max=1ms,enabled=false)  //la terea no inicia automatocamente
void tarea2();
#task (rate=350ms,max=1ms,enabled=false)  //la terea no inicia automatocamente
void tarea3();
:eek:


Hola saint_. Te cuento que el archivo de isis funciona muy bien, pero al intentar compilar el archivo de ccs me presenta un error en las líneas que cito.
No sé si es mi versión del compilador, la que uso es 4.104.
Adjunto imagen del error.

Por otro lado, me gustaría, si puedes, que me expliques lo que hace este comando:
rtos_await(kbhit()); , la parte del await(kbhit());

Saludos.
Gracias.
 

Adjuntos

  • Error_ccs.jpg
    Error_ccs.jpg
    39.7 KB · Visitas: 10
Última edición por un moderador:
hola ingdirson, el error que se presenta quizá podría ser como tu dices por la version, yo hice el programa en CCS v5.xxx lo mas seguro es que el hecho de declarar una tarea sin que inicie automáticamente sea de otro modo, en el Help de CCS seguro que encuentras las solución.
Respecto de rtos_await(kbhit());

la función kbhit(); retorna true si existe un dato recibido por el puerto serie, para leer ese dato se usa la función getc();, también getc(); espera en bucle infinito hasta que haya un dato en el puerto serie. Para evitar que el PIC se quede esperando "toda la vida" hasta que le llegue un dato se usa primero kbhit(); para verificar si existe algún dato, si existe se lo lee con getc();.
la funcion await(xxx); espera a que xxx sea verdadero, mientras "espera" deja el control de la cpu para que otras tareas puedan ejecutarse "si es que les toca su turno".
rtos_await(kbhit());, espera a que este disponible un dato en el buffer del puerto serie, mientras tanto deja que se ejecuten otras tareas.
 
Hola Saint, gracias por tu ayuda me ha sido muy útil, intentare descargar o conseguir la versión del compilador que usaste para trabajar con ella. De nuevo gracias.

Hasta la próxima...
Saludos...
 
De todo lo que he leído, esto es lo que me interesa:

"Exacto. Yo en mis programas separo un archivo .h para las configuraciones, otro para las funciones, otro con el método main, etc."

Pero no sé hacerlo. Si realizo un código donde sólo hay funciones el compilador no lo admite.
Este programa es el más sencillo que he podido hacer para explicar todo lo que quiero.

Lo que me gustaría es que la función FUERA(); No estuviese fuera del programa principal, otro módulo, otro código escrito aparte y que el programa principal pueda acceder a éste.

Agradecería un ejemplo visual de estos dos códigos escritos aparte y que a la vez puedan comunicarse.

PHP:
#include <16f877.h>
#FUSES NOWDT, XT, PUT, NOPROTECT, BROWNOUT, NOLVP, NOCPD, NOWRT, NODEBUG 
#use delay(clock=4M)
#DEFINE use_portd_lcd TRUE
//#DEFINE use_portb_kbd TRUE  (declarado en kbd.c)
#include <lcd.c>
#include <kbd.c>
#include <stdio.h>
#BYTE PORTC=0x07  
#BYTE TRISC=0XFF 
#BYTE PORTD=0X08 
#BYTE TRISD=0X88 

int  FUERA(int cont); ///DONDE TIENE QUE ESTAR ESTAR DECLARADA?
int glooball; ///ESTA VARIABLE DEBE RECONOCERLA TANTO programa-principal Y TODOS LOS PROGRAMAS A LOS QUE LLAME
   void main(){///programa-principal
int con,recogerdefuera;///
lcd_init();
kbd_init();
port_b_pullups(false);
   while(true){///while true

recogerdefuera=FUERA(15);

for (con=0;10>con;con++){
printf(lcd_putc,"\fse recogio de FUERA(); es %d",recogerdefuera);
 delay_ms(300);
} 
if (glooball<100) { glooball++; } else { glooball=0; }
}///while true
}///programa-principal
  
////QUIERO SABER COMO ESCRIBIR ESTA FUNCION EN OTRO PROGRAMA Y QUE progama-principal PUEDA ////HACER USO DE ELLA LA RECONOZCA
FUERA(int cont) {
int co;
for (co=0;cont>co;co++){
lcd_putc("\fEsto codigo tiene que estar fuera del"); lcd_gotoxy(1,2);
printf(lcd_putc,"programa principal llamado PRUEBA %d",glooball);
 delay_ms(300);
}
co=Input_c ();
return co;
}
////QUIERO SABER COMO ESCRIBIR ESTA FUNCION EN OTRO PROGRAMA Y QUE progama-principal PUEDA ////HACER USO DE ELLA



Perdón. "funcion FUERA(); No estuviese fuera del programa-principal"
Quise decir, "funcion FUERA(); Estuviese fuera del programa-principal"
 
Última edición por un moderador:
Pero esto que preguntas es cuestión del compilador que uses. De que permite y que no permite hacer.
Puedes compilar con un main casi vacío para ves si van y luego quitarlo y linkarlo a otro programa, aunque no se como se hace eso, pero lo he visto hacer.
En ensamblador yo lo hacia pero depende del compilador que se haga de una forma u otra.
 
Ya. Pero yo nunca he hecho esto en C. ¿Qué es lo que tengo que estudiar para hacer esto?
Si esto es general en todo C, Genial.
¿Podrías ponerme un ejemplo visual de dos pequeños programas hechos en C que puedan acceder a sus
funciones y variables respectivamente?

¿CCS PIC C compiler 5.0?
No me acuerdo exactamente. No me lo dice cuando pincho en propiedades.
 
Última edición por un moderador:
Hola, Albererto. Saludos desde Colombia.
Creo entender que es lo que quieres hacer.
Primero, te recomiendo el libro "Compilador CCS y simulador Proteus"
Allí puedes encontrar ejemplos y teoría sobre funciones y características de CCS.
PHP:
#include <18f452.h>
#fuses XT,NOWDT,NOPROTECT,WDT128,NOBROWNOUT  
#use delay(clock=4000000)
#use rs232(baud=9600,xmit=PIN_c6,rcv=PIN_c7,bits=8, parity=N)   // declaracion de uso de protocolo rs232
#include <lcd.c>

#use standard_io(B)

char dato=0;
int val=0;                         // las variables y funciones que se declaran de forma GLOBAL podran ser accedidas desde 
void recibe(char datos);           // cualquier parte del codigo, siempre que esten llamadas por debajo de la declaracion.

#INT_RDA
void  RDA_isr(void) 
{
dato= getc();                // interrupcion por recepcion de datos por rs232
    recibe(dato);
   
}

void main()
{
 lcd_init();
 enable_interrupts(INT_RDA);
 enable_interrupts(GLOBAL);
 lcd_gotoxy(2,1);                               // programa principal
 printf(lcd_putc,"BIENVENIDO ");
 delay_ms(600);
 while(true)
{ 
 if(val==1)
  {
   printf(" esto es lo que quieres?\r\r");    // aqui se verifica la condicion del caso "1"
   val=0;
  }

 }
 
}

 void recibe(datos)
 {
 if (datos!='1' && datos!='a')
    {
    printf(" Dato no valido...\r");                // funcion.
    printf(lcd_putc,"\f");
    printf(lcd_putc,"Dato invalido!");
    
    }
 
 switch(datos)
 {
  case '1':
        lcd_gotoxy(1,1);
        printf(lcd_putc,"\f");
        printf(lcd_putc,"recivido: %c",datos);
        output_high(PIN_B0);
        printf("\rled encendido!!\r");
        val=1;              // Esta es la variable que se prodra llamar desde cualquier lugar del programa.
        break;
 case 'a':
       lcd_gotoxy(1,1);
       printf(lcd_putc,"\f");
       printf(lcd_putc,"recivido: %c",datos);
       output_low(PIN_B0);
       printf("\rled apagado!!\r");
 }
 }
Nota: El programa está diseñado para usar el protocolo RS-232, pero en las líneas comentadas puedes ver lo que necesitas.
Para simular sólo montas el circuito en ISIS y conectas el terminal virtual de forma cruzada Rx a Tx y Tx a Rx, cargas el código y simulas.

PD: Espero esta sea la solución a tu duda.

Saludos.
 
Última edición por un moderador:
No estoy seguro, ingdirson.
Al parecer lo que he leído del protocolo RS-232, se refiere a una comunicación del PIC con interrupciones.

Yo también quiero ésto.

Código:
while(true)  {/// whil
if(val==1)
{   printf(" esto es lo que quieres?\r\r");    val=0;    }      // aqui se verifica la condicion del caso "1"
}  //whil
No debería funcionar porque el bucle está encerrado donde sólo pregunta por la variable "vall", nunca la modifica.
Por lo poco que he leído, tú pareces hacerlo de una manera física, mientras que yo quiero cambiar la variable "vall" desde otro código.

Y ahora lo primero que se me ocurre:

Código:
#INT_RDA
void RDA_isr(void)
{
otroprograma(); // Me serviria esto si "otroprograma()" Tratase la variable vall
}
 
Última edición por un moderador:
Hola, AlberertO. ¿Cuando dices, "otro código", te refieres a?

Lo del protocolo es sólo porque era lo que tenía a mano.
Lo que quería mostrarte es la parte que has citado.
#INT_RDA, sólo es para interrupciones por datos en el búfer de recepción y transmisión en el protocolo RS-232

Si lo que quieres decir, es que si tuvieses otra función y en ella modificases la variable "VAL", ya sea por un dato externo, es decir, por una entrada en pin o un dato recibido o por software, es decir, a partir de una condición del programa, podrías conocer ese cambio desde el main y/o otra función en el mismo código.

Te digo que si es posible, primero declarando val de forma global, segundo usando banderas, es decir, variables que cambien un estado a partir de una condición.

Éxitos.
 
Última edición por un moderador:
hola alberto, te recomiendo limpiar las variables cada que termines un proceso, en ocaciones esto genera que el codigo se sature y sobrecargue la memoria de tu microcontrolador. lo que te digo es reiniciar a 0 cualquier variable que hayas usado, siempre y cuando esta informacion no sea necesaria mas adelante en el proceso.
Exitos..
 
El problema está desde el inicio.
Me he fijado que hay bastantes variables que sólo necesitaban ser booleanas.
Sustituyendo int por int1, consigo reducir la RAM pero no la ROM como yo esperaba
Ésta, al parecer depende de la cantidad de código escrito.
Dos microcontroladores es lo que me conviene la próxima vez, con sus .hex correspondientes.

El éxito es A.C. Actualmente no pasa a D.C.

Saludos.
 
Última edición por un moderador:
Podrías estimar la posibilidad de un PIC con mayor memoria.
También podrías optimizar código evitando desbordes de memoria, revisar los ciclos que no se hagan infinitos, es decir, que nunca se están rompiendo.

Por otro lado, imagino que debes estar implementando algo bien complejo para que requiera de tantas líeneas.
P
odrías también usar las librerías, ya que éstas traen dentro el código necesario para algunos dispositivos.

Saludos...
 
Última edición por un moderador:
Atrás
Arriba