En el subforo de C, yo puse un ejemplo hace ya mucho tiempo, con la librería completa para usar un LCD 2x16 con números grandes, y el ejemplo para probarlo.
Si los descomprimen en una carpeta, pueden verlo en Proteus.
No es la librería que ven en el ejemplo que puse, la que hoy utilizo, pero pueden sacar la experiencia de allí, sin problemas.
Eso es mucho mas que lo que yo tuve de información inicial para hacerlo...je..je.. :D :D :D
En el subforo de C, yo puse un ejemplo hace ya mucho tiempo, con la librería completa para usar un LCD 2x16 con números grandes, y el ejemplo para probarlo.
Si los descomprimen en una carpeta, pueden verlo en Proteus.
No es la librería que ven en el ejemplo que puse, la que hoy utilizo, pero pueden sacar la experiencia de allí, sin problemas.
Eso es mucho mas que lo que yo tuve de información inicial para hacerlo...je..je.. :D :D :D
Amigo aun tendras el ejemplo del convertidor A/D que tenias en el subforo c que ya no esta disponible para la descarga.
Te pongo el ejemplo con el ADC.
Espero te sirva... :mrgreen: :mrgreen:
Pero por lo que veo no aparece ( flecha izquierda) ni ( flecha derecha) ,que en el formato original tampoco aparece ,y la otra cosa es que los caracteres de la linea de arriba y los de abajo estan cortados ,le falta la linea de pixeles de abajo pero no me doy cuenta donde tengo que tocar para acomodar esto ,dejo una foto para que se entienda mejor lo que quiero explicar
#include <16f876a.h>
#device adc=10
#use delay(clock=4000000)
#fuses HS,NOWDT,NOPROTECT,NOLVP,PUT,NODEBUG,BROWNOUT,NOCPD,NOWRT
#include <lcd.c>
#include <NumGran.C>
#include <internal_eeprom.c>
#use fast_io(B)
#use fast_io(c)
#use fast_io(a)
//****variables del cuneta vueltas***//
int16 contador=0,RPM,i;
float ajuste=10,e;
//****variables del cuneta horas***//
int8 Segundos=0,SegundosParcial=0,Minuto=0,MinutoParcial=0;
int menu=0,sw;
int16 b,service=1,corte, Hora=0,cont=0, HoraParcial=0,mantenimiento=0;
//*********Funciones**************************
int menus(void)
{
if (input(pin_c2)==1)
{
if (menu==0) //Cambia a programacion
return('1');
if (menu==1) //Info proximo service
return('2');
if (menu==2) //Cambia el tiempo del proximo service
return('3');
if (menu==3) //Calibra RPM
return('4');
if (menu==4) //Reset cuenta horas toatl
return('5');
if (menu==5) //Reset cuenta horas parcial
return('6');
if (menu==6) //Vuelve al comienzo del menu
return('7');
}
}
void corte_alimentacion(void) // si la alimentacion es menor que 4,5 Volt
{ if (corte<920) // Guarda valores en eeprom
{
write_int16_eeprom(0x227, Hora);
delay_ms(15);
write_int16_eeprom(0x230, HoraParcial);
delay_ms(15);
write_eeprom(0x236, Minuto);
delay_ms(15);
write_eeprom(0x238, MinutoParcial);
delay_ms(15);
}
}
#int_timer1
void timer1_isr(void)
{ cont++;
if (cont==2)
{
contador=get_timer0();
set_timer0(0);
cont=0;
if (rpm>600)
{
Segundos++;
SegundosParcial++;
}
//*********Cuenta Horas Total**********************************/
if(Segundos == 60)
{
Minuto++;
Segundos=0;
if(Minuto == 60)
{
Hora++;
Minuto=0;
}
}
/**********Cuenta Horas Parcial*********************************/
if(SegundosParcial == 60)
{
MinutoParcial++;
SegundosParcial=0;
if(MinutoParcial == 60)
{
HoraParcial++;
MinutoParcial=0;
}
}
}
set_timer1(3036);
}
//***************************************************
void main()
{
set_tris_a(0b00010011);
output_a (0b00000000);
set_tris_c(0b01111110);
output_c (0b00000000);
setup_timer_0(rtcc_ext_h_to_l | rtcc_div_2);
setup_timer_1(t1_internal | t1_div_by_8);
set_timer0(0);
set_timer1(3036);
enable_interrupts(int_timer1);
enable_interrupts(global);
//****************ADC**************************
setup_adc_ports(AN0_AN1_AN3);
setup_adc (ADC_CLOCK_INTERNAL);
//*************Lectura de eeprom *****************************
Hora=read_int16_eeprom(0x227);
delay_ms(15);
HoraParcial=read_int16_eeprom(0x230);
delay_ms(15);
Minuto=read_eeprom(0x236);
delay_ms(15);
MinutoParcial=read_eeprom(0x238);
delay_ms(15);
e=read_float_eeprom(0x240);
delay_ms(15);
service=read_int16_eeprom(0x245);
delay_ms(15);
mantenimiento=read_int16_eeprom(0x250);
delay_ms(15);
//*************************************************************
lcd_init();
NumGran_Init();
lcd_gotoxy(1,1);
lcd_putc(" PROYECTO \n RPM Y HORIMETRO ");
delay_ms(2000);
lcd_gotoxy(1,1);
lcd_putc(" GRACIAS TODOPIC \n SALUDOS!!! ");
delay_ms(2000);
lcd_putc("\f");
while(1)
{
set_adc_channel(1); //Lee la tension de alimentacion
delay_ms(10); // del pic ,si baja de 4,5volt
corte=read_adc(); //
corte_alimentacion();// actua esta funcion
mantenimiento=read_int16_eeprom(0x250);
delay_ms(15);
service=read_int16_eeprom(0x245);
delay_ms(15);
e=read_float_eeprom(0x240);
delay_ms(15);
RPM= contador*e;
if (input(pin_c2)==0) // Funcionamiento normal
{
menu=0;
if ( Minuto<mantenimiento)// ATENCION: cambiar Minuto por horas
{
output_low(pin_c7);
i =RPM;
lcd_send_byte(0,1);delay_us(2);
NumGran(i);
printf(lcd_putc,"RPM");
delay_ms(80);
i = RPM;
delay_ms(300);
printf(lcd_putc," %04lu ",i);
if(input(pin_c6))
{
delay_ms(50);
while(input(pin_c6)==0);
lcd_gotoxy(1,1);
printf(lcd_putc," RPM %lu " ,RPM);
lcd_gotoxy(1,2);
printf(lcd_putc,"Par %05lu:%02u:%02u",HoraParcial,MinutoParcial,SegundosParcial);
delay_ms(3000);
lcd_gotoxy(1,2);
printf(lcd_putc,"Tot %05lu:%02u:%02u",Hora,Minuto,Segundos);
delay_ms(3000);
}
}
//********************************************************************************
if ( Minuto>=mantenimiento&&mantenimiento>0)//ATENCION cambiar Minuto por horas
{
output_high(pin_c7); // Aviso luminoso de mantenimiento
lcd_gotoxy(1,1); //
lcd_putc(" ATENCION \n MANTENIMIENTO ");
if (input(pin_c6))
{ delay_ms(50);
while(input(pin_c6)==0);//hasta q no suelta no graba
mantenimiento=mantenimiento+1;
write_int16_eeprom(0x250,mantenimiento); // escribe en la memoria
delay_ms(15); // tiempo para escritura
lcd_gotoxy(1,1); //
lcd_putc(" SE POSPUSO \n + 1 HORA ");
delay_ms(2000);
lcd_gotoxy(1,1); //
lcd_putc("INGRESE AL MENU \n PARA CAMBIARLO ");
delay_ms(2000);
}
}
}//cierra funcionamiento normal
/***********************ENTRA AL MENU*************************************/
if (input(pin_c2)==1)//
{ menus();
if (input(pin_c3)==1)
{ delay_ms(50);
while(input(pin_c3));
{
menu++;
if (menu>7)
menu=0;
}
}
sw=menus();
switch (sw)
{
case '1':
lcd_gotoxy(1,1);
printf(lcd_putc," Uds A INGRESADO \n AL MENU ");
delay_ms(1000);
menu++;
break;
case '2':
service=read_int16_eeprom(0x245);
delay_ms(15);
lcd_gotoxy(1,1);
printf(lcd_putc,"Proximo Service \n %4lu Horas ",service);
break;
case '3': //Service
lcd_gotoxy(1,1);
printf(lcd_putc,"Programe Service");
if (input(pin_c4)==1)
{ delay_ms(50); // antirebote
while(input(pin_c4));
b+=1;
}
if (input(pin_c5)==1) // Boton que decrementa
{ delay_ms(50);
while(input(pin_c5));
b-=1;
}
lcd_gotoxy(1,2);
printf(lcd_putc," Horas %4lu ",b);
if (input(pin_c6)==1)
{ delay_ms(50);
while(input(pin_c6));
write_int16_eeprom(0x245, b); // escribe en la memoria
delay_ms(25);
service=read_int16_eeprom(0x245);
delay_ms(15);
mantenimiento=Minuto+service;//ATENCION cambiar Minuto por hora
write_int16_eeprom(0x250,mantenimiento); // escribe en la memoria
delay_ms(15);
mantenimiento=read_int16_eeprom(0x250);
delay_ms(15);
lcd_gotoxy(1,1);
printf(lcd_putc," PROXIMO \nMANT:%05lu Horas ",mantenimiento ) ;
delay_ms(2000);
}
break;
case '4': //CALIBRA RPM
e=read_float_eeprom(0x240);
delay_ms(15);
RPM= contador*e;
lcd_gotoxy(1,1);
printf(lcd_putc,"Actual RPM %lu ",RPM);
if (input(pin_c4)==1)
{
delay_ms(150);
ajuste+=0.02; // Incremento
}
if (input(pin_c5)==1)
{
delay_ms(150);
ajuste-=0.02; //Decremento
}
if (input(pin_c6)==1)
{ delay_ms(50);
while(input(pin_c6));
write_float_eeprom(0x240, ajuste);
delay_ms(15);
}
RPM= contador*ajuste;
lcd_gotoxy(1,2);
printf(lcd_putc,"Ajuste RPM %lu ",RPM);
break;
case '5':
lcd_gotoxy(1,1);
printf(lcd_putc," RESET TOTAL ");
lcd_gotoxy(1,2);
printf(lcd_putc," %05lu:%02u:%02u ",Hora,Minuto,Segundos);
if (input(pin_c6)==1) // Reset de cuenta horas parcial
{ delay_ms(100);
Hora=00000;
write_int16_eeprom(0x227, Hora);
delay_ms(15);
Minuto=00;
write_eeprom(0x236, Minuto);
delay_ms(15);
}
break;
case '6':
lcd_gotoxy(1,1);
printf(lcd_putc," RESET PARCIAL ");
lcd_gotoxy(1,2);
printf(lcd_putc," %05lu:%02u:%02u ",HoraParcial,MinutoParcial,Segundos);
if (input(pin_c6)==1) // Reset de cuenta horasparcial
{ delay_ms(50);
HoraParcial=00000;
write_int16_eeprom(0x230, HoraParcial);
delay_ms(15);
MinutoParcial=00;
write_eeprom(0x238, MinutoParcial);
delay_ms(15);
}
break;
case '7':
menu=1;
break;
}
}
}
}
Esta es la foto como se ven los numeros correctamente:No puedo creer como se simplifico la funcion del menu :D el que sabe sabe ......
sw=menus();
switch (sw)
{
case '1':
switch (menu+1)
{
case 1:
estaba grabando constantemente los valores en la memoriaSi siguen funcionando por las dudas segui con los mismos lugares de memoria, si ya encontras problemas o algo por el estilo, cambias los lugares de las memorias, ya que con tantas grabaciones se pueden haber roto. Una ves que lo tengas como "final" y arreglado todo tambien podes cambiarle la posicion de memoria si es que no lo habias cambiado antes.
La otra forma de hacerlo que sugeris(es lo que se me ocurre pensar desde mi ignorancia)es en vez de usar los delays usar la base de tiempo que ya voy llevando con los segundos ? .
Mi próximo desafió, aunque por ahora no tengo tiempo, es hacerlo en LCD del tipo OLED, que tienen otro driver diferente al estándar.
bueno estuve haciendo algunas pruebas y les cuento, lo de la interrupcion por ccp funcionó perfecto en realidad no note ningun cambio a lo anterior que era la interrupcion por timer1, pero si de esa manera es mejor entonces asi quedará ,una cosa mas aprendida vamos todavia
Dejando las escrituras dentro de la interrupcion y aún quitando los delays no funcionaba , yo tenia entendido que cuendo se hacian varias escrituras seguidas era recomendable los delays , es esto cierto?No entiendo por que no. Escribir la EEPROM no se hace instaneamente como uno escribiria en la RAM por ejemplo, sino que tarda un tiempito mas ( no voy a poner el ASM para no complicarte la vida ), vos cuando le das a escribir al dato, pones un bit en 1, recien se termina de escribir cuando se pone en 0. Pienso que CCS deberia tener en su funcion un control de este bit, o esperando que termine de grabar cuando envia el dato, o cuando se le da la orden de grabar que espere a la anterior orden que termine. Pienso que deberia hacerlo asi.
No se si la manera en que lo hice es buena , de todos modos pensé en ponerlo al principio del while para que sea lo primero que chequee despues de la interrupcion , pero no sirve de nada por que despues de la interrupcion el programa vuelve a donde había quedado ,no?Exacto, cuando sale de la interrupcion va a donde estaba, si estaba en la mitad de un delay de 3segundos ( 1.5s ) y ocurre la interrupcion, cuando salga de la interrupcion todavia le queda 1.5s + todo el otro codigo que tengas.
En la plaqueta de pruebas todavia no tengo hecho un circuito que me detecte la falta de alimentacion y me ponga Rb0 a 0 esta prueba la hice a mano solo para ver si grababa en la memoria ,y sí , lo hacía .Tampoco tengo claro que circuito tendría que hacer exactamente algo de lo mas sencillo y especifico posible ,solo lo del comparador que dijo KILLERJC y supongo que será algo parecido a lo que me explicó chaly29 aca http://www.todopic.com.ar/foros/index.php?topic=15702.15 si tienen algun circuito o algo especifico se los agradeceré.
Las escrituras eeprom necesitan que NO se realicen otras acciones mientras ocurren, porque se malogran y el solo hecho de grabar un byte en eeprom, presupone 18 mseg con un reloj de 4 mhz.
Como el CCS ejecuta una interrupción y al momento borra las banderas (flags) de interrupción, queda listo para ejecutar otra vez la misma interrupción aun estando en ejecución el código de la anterior interrupción (en este caso la escritura en eeprom), lo que ocasiona recursividad, que esta prohibido en un PIC, por eso te avisa el compilador que desactivara esa interrupción para evitar una nueva entrada (reentrancy disabled).
En palabras simples, si entra en esa interrupción y deshabilita, no vas a tener comunicaciones serie por interrupciones, se entiende??Cuando se entra la interrupcion se deshabilita solo las interrupciones globales, el RETFIE es quien las habilita nuevamente. Pero si misteriosamente usas una funcion como escribir en la EEPROM que posee las instrucciones de desactivar y activar las interrupciones dentro como para poder usarlas en el loop while por ejemplo, entonces ahi SI vas a tener problemas y va a ser reentrante. Y es a esto a lo que estoy apuntando.
No tengo muy en claro cuando hablan de flag supongo que es una señal, un parametro ,una palabra a la que se le asigna un valor ? o simplemente una variable y la llaman flag ,se supone que esto ya lo debería saber pero bue en algun momento lo tenía que preguntar :oops: disculpame pero no tengo muy incorporado el termino .
Respecto a eso, creo que hay un tema de Marioguillote donde hizo un circuito + software que le permitía detectar la perdida de energía y grabar un montón de bytes en eeprom antes de apagar el circuito (en realidad no recuerdo si lo apagaba o lo dormía).
Tengo partes dentro del switch (case 6,7,8,9 ) donde configuro parametros ,aca tambien tendría que hacer funciones fuera del main y luego llamarlas en los case ? tiene algun sentido ?
Tengo dudas en las partes en las que leo la memoria ya sea para luego imprimir en pantalla o para hacer cuentas con ese dato es necesario siempre aclarar :service=read_int16_eeprom(150);antes de usarlo( en este caso service)o con que este declarado dentro del void main() ya esta y no tengo que volver a llamarlo?
corren al mismo tiempo los dos desde cero hasta 99.
NumGran(Msegundos, 1, 3);
NumGran(Segundos, 7, 3);
Entonces necesito agregar variables a las funciones que hiciste.
- Modificar alguna de las flechas (que no vas a usar) para que queden como puntos De esa forma imprimirlos aparte.
- Crear la funcion para imprimir los puntos