PIC18F4550 y timer0 en CCS

#1
Buenas amigos!

Hace tiempo que leo estos foros, la verdad es que he encontrado soluciones útiles para muchos de mis problemas... hasta ahora :(

Les explico: estoy haciendo un proyecto con PIC18F4550 y tengo 8 displays que, evidentemente, necesitan visualización dinámica, por lo que uso 3 pines del pic + DEMUx 3 a 8 para controlarlos a todos. El problema es que no puedo usar delays porque el programa necesita hacer más tareas, y los displays deben estar SIEMPRE encendidos. Por lo tanto, mi solución pasa por usar el timer0 y hacerlo desbordar cada 5 ms para cambiar de display.

Haciendo cálculos con unas formulitas que encontré en más de una página web, obtuve que 5 ms = inicializar el timer0 a 0xEB (trabajando en modo 8 bits). Pues bien, por más pruebas que haga y más cambios en el código, no consigo visualizar dos displays - solo se enciende uno. Cabe decir que estoy haciendo las pruebas con un número estático y sólo dos displays, ya que luego es fácil extrapolar a los 8.

Acá les dejo el código que tengo, espero que me puedan ayudar.

Código:
#include D:\\...\\prova_comptador.h

//variables globals
unsigned int8 comptador0=34;     //comptadors
unsigned int8 d0,u0;                      //desenes i unitats de cada comptador

//definició dels bytes amb nom propi (pg 70 datasheet pic)
#byte portd=0xF83                         //direccio on hi ha el portd 
#byte porte=0xF84                         //direccio del portE
//--------------------------------------------------------------------------------------------------------------
void config_ports (void)
{
 set_tris_d(0x00);                   //tot el port D de sortida
 set_tris_e(0x00);                   //tot el port E de sortida
}
//---------------------------------------------------------------------------------------------------------------
unsigned int8 conversio_bcd (unsigned int8 comptador,*u,*d)        //desenes i unitats són punters
{  
  unsigned int8 comptador_updated;
  
  if (comptador<=99)
  {
  *d = comptador/10;                     //guardo a \'d\' la primera xifra
  *u = comptador%10;                  //guardo a \'u\' el residu (2a xifra)
  return(comptador);
  }
  
  else 
  {
  comptador_updated = 0;
  *d = 0;
  *u = 0;
  return (comptador_updated);
  }
}

//----------------------------------------------------------------------------------------------------------------          
#int_TIMER0
void TIMER0_isr ()  
{  
   set_TIMER0(0xEB);                       //inicialitza el timer0 a 5 ms (EB)--> fer-ho només un cop!!
      
   porte = 0x01;                          //2n display
   portd = d0;                            //mostro les desenes
   clear_interrupt(INT_TIMER0);      // clears the timer0 interrupt flag
      
   porte = 0x00;                           //seleccio 1r display
   portd = u0; 
  clear_interrupt(INT_TIMER0);      // clears the timer0 interrupt flag
}
//-----------------------------------------------------------------------------------------------------------------
void main(void)
{ 
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256|RTCC_8_bit);       //internat counter, prescaler 256, 8 bits
   enable_interrupts(INT_TIMER0);
   enable_interrupts(GLOBAL);
   set_TIMER0(0xEB);                      //inicializa el timer0 a EB
      
   config_ports();                  //crida a la rutina de configurar ports
 
   while(1)
   {
   comptador0 = conversio_bcd(comptador0,&u0,&d0);    //si he arribat a 99, reinicio el comptador a 0
   }
}

y el .h:

Código:
#include <18F4550.h>
#device adc=8

#FUSES HS                        //Afegit per mi
#FUSES NOWDT                   //---negat a NOWDT - l\'original era WDT1 - Watch Dog Timer uses 1:1 Postscale
#FUSES XT                       //Crystal osc <= 4mhz
#FUSES NOPROTECT                //Code not protected from reading
#FUSES BROWNOUT                 //Reset when brownout detected
#FUSES BORV20                   //Brownout reset at 2.0V
#FUSES PUT                      //------------desnegat -- No Power Up Timer
#FUSES NOCPD                    //No EE protection
#FUSES STVREN                   //Stack full/underflow will cause reset
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOLVP                    //-----------negat--- Low Voltage Programming on B3(PIC16) or B5(PIC18)
#FUSES NOWRT                    //Program memory not write protected
#FUSES NOWRTD                   //Data EEPROM not write protected
#FUSES IESO                     //Internal External Switch Over mode enabled
#FUSES FCMEN                    //Fail-safe clock monitor enabled
#FUSES NOPBADEN                 //---negat--PORTB pins are configured as analog input channels on RESET
#FUSES NOWRTC                   //configuration not registers write protected
#FUSES NOWRTB                   //Boot block not write protected
#FUSES NOEBTR                   //Memory not protected from table reads
#FUSES NOEBTRB                  //Boot block not protected from table reads
#FUSES NOCPB                    //No Boot Block code protection
#FUSES MCLR                     //Master Clear pin enabled
#FUSES LPT1OSC                  //Timer1 configured for low-power operation
#FUSES NOXINST                  //-------------negat--Extended set extension and Indexed Addressing mode enabled
#FUSES PLL12                    //Divide By 12(48MHz oscillator input)
#FUSES CPUDIV1                  //-----canviat a CPUDIV1 enlloc de 4 -- System Clock by 4
#FUSES USBDIV                   //USB clock source comes from PLL divide by 2
#FUSES VREGEN                   //USB voltage regulator enabled
#FUSES NOICPRT                  //-----------negat---ICPRT enabled

#use delay(clock=4000000)

Mil gracias por su tiempo :) ...
 
Última edición por un moderador:
#2
Hola.
Usas transistores para activar display de cátodo común? si, entonces no cuadra la línea porte = 0x00; de la interrupción, con eso ningún display está activo... necesitas un 0x02 para activar el 1er display.

En la int. también lo usual es limpiar el flag al final de todo (clear_interrupt) y no varias veces en el proceso... y el set_TIMER0 ántes de salir de la interrupción... bueno eso por experiencia.
Saludos.
 
#3
Hola patata, viendo el código, específicamente en la interrupción, "veo" que PORTE que es el que debería estar conectado al demux 3 a 8 solo cambia de 1 a 0 y para hacer el multiplexado se necesitaría que cambie 0,1,2,3,4,5,6,7 de modo que el incremento sea en cada interrupción del temporizador.
 
#4
Hola.
Usas transistores para activar display de cátodo común? si, entonces no cuadra la línea porte = 0x00; de la interrupción, con eso ningún display está activo... necesitas un 0x02 para activar el 1er display
Hola ByAxel: la verdad es que no uso ningún transistor, simplemente la salida del DEMUX es a nivel bajo y entonces me da el '0' necesario para prender los displays.

Hola patata, viendo el código, específicamente en la interrupción, "veo" que PORTE que es el que debería estar conectado al demux 3 a 8 solo cambia de 1 a 0 y para hacer el multiplexado se necesitaría que cambie 0,1,2,3,4,5,6,7 de modo que el incremento sea en cada interrupción del temporizador.
Sí Saint_, la verdad que eso sólo era una prueba con 2 displays...

Al fin lo he resuelto con un switch. El código de la interrupción queda así, y funciona! :)

Código:
#int_TIMER0
void TIMER0_isr ()  
{  
 set_TIMER0(0xEB);                       
 porte = display;
 
 if (display<7)                          
  {
   switch (display)
   {
   case 0: portd = u0; break;
   case 1: portd = d0; break;
   case 2: portd = u1; break;
   case 3: portd = d1; break;
   case 4: portd = u2; break;
   case 5: portd = d2; break;
   case 6: portd = u3; break;
   case 7: portd = d3; break;
   }
  display++;
 }
 else 
  display = 0;
}
Gracias! ^.^
 
Arriba