# PIC18F4550 y timer0 en CCS



## patata (Mar 24, 2014)

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.


```
#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:


```
#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  ...


----------



## ByAxel (Mar 24, 2014)

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.


----------



## Saint_ (Mar 24, 2014)

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.


----------



## patata (Mar 24, 2014)

ByAxel dijo:


> 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.



Saint_ dijo:


> 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! 


```
#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! ^.^


----------

