Buenas, me presento como nuevo usuario en este foro.
He estado escudriñando el foro en busca de problemas similares y los he encontrado, es un problema bastante común que se debe a que la gente que programamos en C con la ayuda del CCS realmente no sabemos como funciona el lenguaje ensamblador ni como esta estructurado un micro de microchip tipo PIC. No sabemos realmente todos los registros, cambios de bancos, paginas...Nos acomodamos con el CCS y este tipo de errores luego no podemos resolverlos.
El caso es que estoy desarrollando un proyecto relaccionado con la medida de varios sensores. Basicamente es un programa que muestra un menu que permite calibrar los sensores, o mostrar y enviar las medidas. El problema esta en que tengo una ocupacion del 80% de ROM, y al incluir DOS operaciones que MARCO EN NEGRITA EN EL CODIGO, me salta OUT OF ROM.
Hago uso de las directivas SEPARATE pero no sé si sirven de algo en mi caso, la verdad que no puedo ponerme a estudiar toda la estructura del PIC (bancos, paginas, registros) asi que si alguien ducto en el tema, que será algo obvio para el me puede ayudar, le estaré eternamente agradecido.
El problema esta en la rutina calibrar() al hacer uso de las operaciones matematicas con la variable float RPOV y bnull.
Aquí hay gente que controla claramente.
Pego aki el codigo y en negrita las dos sentencias que me den el OUT OF ROM:
#include "C:\Users\José\Desktop\proyecto\programa2\programa.h"
#include "math.h"
#include "lcd_ATE4A.c"
#byte PORTA = 0x05 // Se definen los puertos
#byte PORTC = 0x07 // y bits a utilizar.
#byte TRISA=0x85 // CONFIGURACIÓN PUERTO A
#byte TRISC=0x87 // CONFIGURACIÓN PUERTO C
#bit ECHO=PORTC.2 // BIT DE ECO SENSOR ULTRASONIDOS
#bit TRIGGER=PORTC.5 // BIT DE TRIGGER SENSOR ULTRASONIDOS
#bit RA4=PORTA.4 // Se define el bit asociado al pulsador.
#bit RA5 = PORTA.5
int sel;
char key;//VARIABLES PARA EL CONTROL DEL LCD EN EL MENU PRINCIPAL
int16 distancia=0; // ENTERO DE 16 BITS QUE INDICA LA DISTANCIA EN CM
int1 fallo_ultra=0;//VARIABLE PARA CUANDO SE PRODUZCA FALLO EN EL SENSOR MOSTRARLO AL USUARIO
int ad=0;//VARIABLE QUE SIRVE PARA EL CAMBIO DE CANAL DE CONVERSION
int16 valor=0;//VARIABLE USADA EN LA FUNCION DE CONVERSION
int cont=0;//VARIABLE PARA LAS TEMPORIZACIONES DE TIMER0 CON EL ANCHO DE BANDA
//VARIABLES DEL ACELEROMETRO
int16 cero_h=541;
int16 ganancia_h=779;
int16 cero_v=541;
int16 ganancia_v=779;
int16 milivoltios_h=0;
int16 milivoltios_v=0;
float arc_h=0.0;
float arc_v=0.0;
//VARIABLES DEL GIROSCOPO
float giroscopo=200.0;
float cero_giroscopo=2500.0;
int16 cero_giroscopo0=2500;
int16 temperatura0=2500;
int16 cero_giroscopo1=2500;
int16 temperatura1=2500;
int16 cero_giroscopo2=2500;
int16 temperatura2=2500;
const int sensibilidad=5;//SENSIBILIDAD NOMINAL DEL GIROSCOPO PREFIJADA LA NO PODER CALIBRARLA
int16 temp=201;
float tempf=202.0;
float anull;//PARA LAS FORMULAS ED HARVEY
float bnull;//PARA LAS FORMULAS ED HARVEY
float PROV;
//VARIABLES PARA LA TRANSMISION DE TRAMAS
const int final=123;
const int final2=124;
const int final3=125;
const int final4=126;
char num_trama=0;
const int numero_de_tramas=100;
//ESTRUCTURA DE TIPO TRAMA PARA LA TRANSMISION
struct trama {
int arc_v;
int arc_h;
int16 giroscopo;
int16 temp;
int16 distancia;
};
#SEPARATE
void transmite (struct trama *ptr, int longitud)
{
if(num_trama==numero_de_tramas)num_trama=0;//LAS TRAMAS SON NUMERADAS DEL 0 al 99
if(num_trama==final){putc(final2);putc(final3);}
else if(num_trama==final2){putc(final2);putc(final4);}
else putc(num_trama);
while(longitud)
{
if((int)*ptr==final)
{
putc(final2);
putc(final3);
}
else if ((int)*ptr==final2)
{
putc(final2);putc(final4);
}
else putc(*ptr);//CASO NORMAL
longitud--;
ptr=(int)ptr+1;
}//FIN DEL WHILE
num_trama++;
//TRANSMITIMOS EL FINAL
putc(final);
}
//FIN DE FUNCION
#SEPARATE
//INTERRUPCION PARA EL MANEJO DEL DETECTOR DE ULTRASONIDOS Y SUS FALLOS
#int_TIMER1
void overflow()
{
lcd_putc('\f');
printf(lcd_putc,"TIMER1");
delay_ms(100);
fallo_ultra=1;//MARCAMOS EL FLAG DE QUE SE HA PRODUCIDO UN FALLO, SEA CUAL SEA
if(echo==1)echo=0;//SI DESBORDA PORQUE ESTAMOS EN EL BUCLE DE TIEMPO DE DISTANCIA PONEMOS ECHO A 0 PARA SALIR, RESETEAMOS CONTADOR Y MARCAMOS FALLO
else echo=1;//SI ENTRAMOS PORQUE ESTAMOS ESPERANDO POR EL ECO Y HAN PASADO 262ms(tiempo al que desborda TIMER1
}
#SEPARATE
//FUNCION PARA EL CONVERSION ANALOGICO/DIGITAL SEGUN EL CANAL DE CONVERSION Y CON EL TIEMPO DE ADQUISICIÓN CALCULADO
int16 toma_adc(void)
{
if(ad==0) set_adc_channel(0);
else set_adc_channel(1);
delay_ms(1);
valor=read_adc();
delay_ms(1);
return valor;
}
#SEPARATE
//FUNCION QUE SIRVE TANTO PARA MOSTRAR LAS MEDIDAS POR EL LCD COMO PARA ENVIARLAS POR EL PUERTO RS232 AL OTRO TERMINAL
void escribe (float uno, float dos,float tres, float cuatro, float cinco)
{
struct trama tram;
lcd_putc('\f');
//ENVIAMOS EL ARCOSENO VERTICAL
printf(lcd_putc,"X=");
printf(lcd_putc,"%d",(int)uno);
printf(lcd_putc," ");
tram.arc_v=(int)uno;
//ENVIAMOS EL ARCOSENO HORIZONTAL
printf(lcd_putc,"Y=");
printf(lcd_putc,"%d",(int)dos);
printf(lcd_putc," ");
tram.arc_h=(int)dos;
//ENVIAMOS LA DISTANCIA DEL ULTRASONIDOS
if(fallo_ultra)printf(lcd_putc,"ERROR");
else{
printf(lcd_putc,"%Lu",(long)cinco);
printf(lcd_putc,"cm.");}
tram.distancia=(long)cinco;
//PARTE DEL GIROSCOPO.....
tram.giroscopo=(long)tres;
tram.temp=(long)cuatro;
//ENVIO DE LA TRAMA POR EL USART
transmite(&tram,8);
}//FIN DE LA FUNCION ESCRIBE
#SEPARATE
#int_TIMER0 //SE ENCARGA DE HACER LAS MEDIDAS Y ENVIARLAS CADA 10*32ms=320ms para cumplir el criterio de Nyquist al tener un ancho de banda de 1Hz.
void temporizacion_diez_milisegundos()
{
disable_interrupts(int_timer0);
disable_interrupts(global);
cont++;
lcd_putc('\f');
printf(lcd_putc,"TIMER0");
if(cont=10)
{
cont=0;
lcd_init(); //RUTINA DE INICIACION DEL LCD POR SI LA DESCONECTO Y VUELVO A CONECTARLA
ad=0;//EMPEZAMOS CON LA MEDIDA HORIZONTAL
milivoltios_h=toma_adc();//PROBLEMA TOMO TODA LA SENSIBILIDAD CONSTANTE LINEALMENTE EN EL FONDO DE ESCALA Y NO ES CIER
arc_h=ASIN((milivoltios_h-(float)(cero_h*1.0))/(ganancia_h-(float)(cero_h*1.0)))*180.0/PI;
ad=1;//EMPEZAMOS CON LA MEDIDA VERTICAL
milivoltios_v=toma_adc();
arc_v=ASIN((milivoltios_v-(float)(cero_v*1.0))/(ganancia_v-(float)(cero_v*1.0)))*180.0/PI;
//EMPEZAMOS A MEDIR LA PARTE DEL GIROSCOPO
ad=2;
giroscopo=toma_adc()*5000/1024;
delay_us(20);
ad=3;
temp=toma_adc();
PROV=(temp-temperatura0)*5000/1024;
cero_giroscopo=cero_giroscopo0*5000/1024;
cero_giroscopo=cero_giroscopo+anull*PROV;
cero_giroscopo=cero_giroscopo+bnull*PROV*PROV;
temp=temp-512;//5000//Le resto el 0 que es fijo en este caso a 2.5v
tempf=(temp*8.4)-273;//Lo adapto a grados centigrados
giroscopo=giroscopo-cero_giroscopo;//Le resto el 0 calibrado previamente por software
giroscopo=giroscopo/sensibilidad;
//PARTE DEL DETECTOR DE ULTRASONIDOS
// GENERACIÓN DE PULSO DISPARO DE 20 us //
TRIGGER=1; // PONE A 1 EL TRIGGER
delay_us(20); // ESPERA 20 us
TRIGGER=0; // PONE A 0 EL TRIGGER
// FIN GENERACIÓN DE PULSO DISPARO //
// ESPERA A QUE COMIENCE LA SEÑAL DE ECO //
enable_interrupts(int_timer1);
enable_interrupts(global);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_4); //CONFIGURA TIMER 1 CON RELOJ INTERNO Y PRESCALER DE 4
// TIMER SE INCREMENTA A 4000000/4/4=250000HZ
// 1/250000=4 us
// POR LO TANO SE INCREMENTA CADA 4 us
SET_TIMER1(0);
while(echo==0);
// HA LLEGADO LA SEÑAL DE ECO SE COMIENZA A MEDIR SU DURACIÓN //
SET_TIMER1(0); //TIMER 1 A CERO PARA EMPEZAR A MEDIR LA DISTANCIA CON EL DETECTOR
while (echo==1); // ESPERA A QUE ACABE LA SEÑAL DE ECO //
// SE HA ACABADO LA SEÑAL DE ECO //
if(fallo_ultra==1)distancia=0;
else distancia=get_timer1()*4/58; // SE PASA EL VALOR DE TIMER 1 A CM SIEMPRE QUE NO HAYA HABIDO FALLOS, SI HA HABIDO FALLOS SE QUEDA SIN ACTUALIZAR
setup_timer_1(T1_DISABLED);//LO DESACTIVAMOS
disable_interrupts(int_timer1);//Y SUS INTERRUPCIONES
enable_interrupts(GLOBAL);//Y LAS GLOBALES
//ENVIAMOS TODA LA INFORMACION CON LA FUNCION ESCRIBE
escribe(arc_v, arc_h, giroscopo, tempf, distancia);
}
enable_interrupts(int_timer0);//REACTIVAMOS LAS INTERRUPCIONES DEL TIMER0
enable_interrupts(global);//Y LAS GLOBALES
set_TIMER0(0x83);//RECARGAMOS TIMER 0
}
//////////////////////////////////////////PARTE DEL CALIBRAJEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
void calibrar(void){
//PARTE DE CALIBRAJE RELACCIONADA AL GIRÓSCOPO
lcd_putc('\f');
ad=2;
printf(lcd_putc,"temp0 reposo y RA4");
while(RA4); // Se espera a que se pulse RA4.
delay_ms(20); // Espera para evitar rebotes.
lcd_putc('\n');
cero_giroscopo0=toma_adc();
ad=3;
temperatura0=toma_adc();
printf(lcd_putc,"Null0 calibrado");
delay_ms(200);
lcd_putc('\f');
ad=2;
printf(lcd_putc,"temp1 reposo y RA4");
while(RA4); // Se espera a que se pulse RA4.
delay_ms(20); // Espera para evitar rebotes.
lcd_putc('\n');
cero_giroscopo1=toma_adc();
ad=3;
temperatura1=toma_adc();
printf(lcd_putc,"Null1 calibrado");
delay_ms(200);
lcd_putc('\f');
ad=2;
printf(lcd_putc,"temp2 reposo y RA4");
while(RA4); // Se espera a que se pulse RA4.
delay_ms(20); // Espera para evitar rebotes.
lcd_putc('\f');
cero_giroscopo2=toma_adc();
ad=3;
temperatura2=toma_adc();
printf(lcd_putc,"GIRO CALIBRADO");
delay_ms(200);
lcd_putc('\f');
//FORMULAS DE AJUSTE SEGUN HARVEY
bnull=(cero_giroscopo1-cero_giroscopo0)/(temperatura1-temperatura0);
PROV=cero_giroscopo2-temperatura0;
//PROV=PROV/(temperatura2-temperatura0);
//bnull=bnull-PROV;
bnull=bnull/((temperatura1-temperatura2)*(5000/1024));
anull=(cero_giroscopo1-cero_giroscopo0)/((temperatura1-temperatura0)-bnull*(temperatura1-temperatura0));
//PARTE DE CALIBRAJE DEL ACELEROMETRO, CERO Y GANANCIA EXCLUSIVAMENTE VÍA SOFTWARE
lcd_putc('\f');
ad=0;
printf(lcd_putc,"Acel_Horizontal y RA4");
while(RA4); // Se espera a que se pulse RA4.
delay_ms(20); // Espera para evitar rebotes.
lcd_putc('\f');
cero_h=toma_adc();
ad=1;
cero_v=toma_adc();
printf(lcd_putc,"Null calibrado");
delay_ms(200);
lcd_putc('\f');
ad=0;
printf(lcd_putc,"90º_horizontal y RA4");
while(RA4); // Se espera a que se pulse RA4.
delay_ms(20); // Espera para evitar rebotes.
lcd_putc('\f');
ganancia_h=toma_adc();
printf(lcd_putc,"gan_horizontal calibrada");
delay_ms(200);
lcd_putc('\f');
ad=1;
printf(lcd_putc,"90º_vertical y RA4");
while(RA4); // Se espera a que se pulse RA4.
delay_ms(20); // Espera para evitar rebotes.
lcd_putc('\f');
ganancia_v=toma_adc();
printf(lcd_putc,"TODO CALIBRADO");
delay_ms(400);
lcd_putc('\f');
}//FIN DE FUNCION
//////////////////////////////////////////PARTE DE LAS MEDIIIIIIIIIIIIIIIIIIIIIIIIIDASSSSSSSSSSSSSSSSSSSSSSSS
//EL MENUUUUUUUU
#SEPARATE
void main()
{
lcd_init(); //RUTINA DE INICIACION DEL LCD
delay_ms(100);
setup_adc_ports(AN0_AN1_AN3);
setup_adc(ADC_CLOCK_INTERNAL); //configura el converso
disable_interrupts(GLOBAL);
TRISC=0b10011111; // CONFIGURA PUERTO C PARA MANEJO DEL ULTRASONIDOS Y PARA TRANSMISION RECEPCION CON EL RS2323
TRISA=0b11111111; // CONFIGURA PUERTO A COMO TODO ENTRADAS
setup_timer_1(T1_DISABLED);
sel=1; /* Opción seleccionada */
key='0'; /* Identificación de la tecla pulsada */
lcd_gotoxy(1,1); // Se muestra el menú inicial que
lcd_putc("* Calibrar"); // permite seleccionar uno de
lcd_gotoxy(1,2); // los efectos visuales de que
lcd_putc(" Medidas"); // se dispone. Por defecto está
// seleccionado el primero.
while (TRUE) /* Bucle continuo de ejecución */
{
while (RA4 && RA5); // Se espera a que se pulse una tecla.
delay_ms(20); // Espera para evitar rebotes.
if (RA4==0) key='A'; // Si se pulsó RA4, key<-'A'.
else if (RA5==0) key='B'; // Si se pulsó RA5, key<-'B'.
else key='0'; // Para otros casos, key<-'0'.
/* Si la tecla pulsada es RA4, se mueve el asterisco en el LCD. Si
es la tecla RA5, se va al subprograma de tratamiento de la opción
seleccionada. Para cualquier otro valor, no se hace nada. */
switch(key)
{
case 'A': if (sel==1)
{
lcd_gotoxy(1,1);
lcd_putc(' ');
lcd_gotoxy(1,2);
lcd_putc('*');
sel=2;
break;
}
if (sel==2)
{
lcd_gotoxy(1,1);
lcd_putc('*');
lcd_gotoxy(1,2);
lcd_putc(' ');
sel=1;
break;
}
case 'B': if (sel==1) calibrar();
else medidas();
lcd_putc('\f'); // Borra el LCD.
lcd_gotoxy(1,1);
lcd_putc("* Calibrar");
lcd_gotoxy(1,2);
lcd_putc(" Medidas");
sel=1;
} /* Fin switch */
while (!RA4 || !RA5); // Se espera a que se suelte la tecla.
delay_ms(20); // Espera para evitar rebotes.
} /* Fin bucle infinito */
} //FIN DEL MAIN
//FUNCION QUE SE OCUPA DE TOMAR LAS MEDIDAS Y TRATARLAS
void medidas (void)
{
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256);
enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL);
set_TIMER0(0x83); //inicializa el timer0
//el bucle infinito es necesario ya que si el micro entra en sleep
//desactiva la interrupción del TMR0
while(true);
}//FIN DE MEDIDAS