Autor Tema: Ejemplito 16F876A: Cómo variar un ancho de pulso generado con RTCC mediante la RS232  (Leído 3937 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5415
    • Picmania by Redraven
Este ejemplito nos muestra cómo podemos realizar el ultrafamoso led parpadeando, pero realizado con la interrupción RTCC del Timer0, y recibiendo ordenes vía RS232 para poder modificar el ancho del pulso, o la separación entre dos pulsos sucesivos.



Conceptos, ideas y técnicas utilizadas:

- Cada vez que salta la interrupción RTCC cambiamos de LOW a HIGH, ó de HIGH a LOW, el pin RB0. Para ello utilizamos la variable Led que nos indica cual fue el último cambio para poder hacer el complementario.

- El ancho máximo de nuestro pulso depende del divisor, Preescaler, seleccionado para la Interrupción RTCC, que para un cristal de 4 Mhz es:

:2   -> 512  uS (al mínimo preescaler posible)
:4   -> 1.0  mS
:8   -> 2.0  mS
:16  -> 4.0  mS
:32  -> 8.1  mS
:64  -> 16.3 mS
:128 -> 33.3 mS
:256 -> 66.6 mS (al máximo preescaler posible)

- Cada vez que realizamos dicho cambio de LOW a HIGH, o de HIGH a LOW, cargamos el contador del Timer0 con un valor variable que podemos ajustar externamente: OffsetL para el semiperiodo LOW y OffsetH para el semiperiodo HIGH

(Si OffsetL y OffsetH son igual a cero, como es el caso cuando acabamos de resetear el micro, tenemos una onda cuyo periodo es exactamente igual a 2 * RTCC: Una RTCC completa donde ponemos RB0 en HIGH y otra RTCC completa en la que ponemos RB0 en LOW)

- Recibimos distintas ordenes, desde el RS232 mediante la interrupción RDA, con las cuales modificamos los valores de la variables OffsetH y OffsetL.

- Cualquier valor mayor que 0 en OffsetH o en OffsetL hace que al producirse la correspondiente interrupción RTCC, que como sabéis salta al pasar el Timer0 de FFh a 00h, se carge el Timer0 con dicho valor: Por lo que la siguiente interrupción será mas corta, y de forma directamente proporcional al valor cargado, ya que en vez de tener que esperar a que Timer0 recorra todo su contador de 00h a FFh lo va ha hacer solamente desde OffsetH, u OffsetL, hasta FFh.

* Cuanto mayor sea OffsetH menos tiempo va a estar RB0 en HIGH.
* Cuanto mayor sea OffsetL menos tiempo va a estar RB0 en LOW

- Si OffsetH y OffsetL tienen el mismo valor la onda producida tendrá iguales ambos semiperiodos, con valores distintos será por ende distintos ambos y por ello nos variará la frecuencia. Para mantener la frecuencia constante, o el periodo constante, debemos ampliar o disminuir complementariamente ambos Offset. Lo que se incremente uno de ellos debemos disminuir el otro, o viceversa.

- Hemos incluido una variable Onda con la que podemos ordenarle a qué parte de nuestro pulso va a afectar la siguiente orden: "C" (de cuadrada para ambos semiperiodos) "H" para el semiperiodo Alto y "L" para el semiperiodo Bajo.

Este ejemplito es básicamente un PWM realizado por Software que puede ser facilmente adaptado a cualquier micro PIC, por ejemplo para manejar un Servo.

Codigo:

#include <16f876a.h>
#fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT
#use delay(clock=4000000)
#use standard_io(b)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)


int  Led=0x00;
int  Offseth=0x00;
int  Offsetl=0x00;
char Onda="C";
char Keypress=" ";

void eco_offset(void);

#int_rda
void rda_isr() {

   Keypress=0x00;
   if(kbhit()){
      Keypress=getc();
   }
}

#int_RTCC
RTCC_isr(){

   // RB0
   Switch(Led){
      Case 0: output_high(PIN_B0);
              set_timer0(Offseth);
              break;
      Case 1: output_low(PIN_B0);
              set_timer0(Offsetl);
              break;
   }
   if(++Led>1){
      Led=0;
   }
}

void main() {

   setup_counters(RTCC_INTERNAL,RTCC_DIV_2); // TEST

   enable_interrupts(int_rda);
   enable_interrupts(global);


   printf("
PWM (RTCC) OS
" );
   
   Onda="C";
   Offseth=0x00;
   Offsetl=0x00;

   enable_interrupts(INT_RTCC);


   do {

      if(Keypress!=0x00){


         switch(Keypress){
            // Tipo de Onda
            case "c": Onda="C";
                      break;
            case "h": Onda="H";
                      break;
            case "l": Onda="L";
                      break;
            // Incrementando y decrementando periodos
            case "+": if(Onda=="C"){ ++Offseth; ++Offsetl; }
                      if(Onda=="H"){ ++Offseth; }
                      if(Onda=="L"){ ++Offsetl; }
                      break;
            case "-": if(Onda=="C"){ --Offseth; --Offsetl; }
                      if(Onda=="H"){ --Offseth; }
                      if(Onda=="L"){ --Offsetl; }
                      break;
            // Periodos Prefijados
            case "1": if(Onda=="C"){ Offseth=0; Offsetl=0; }
                      if(Onda=="H"){ Offseth=0; }
                      if(Onda=="L"){ Offsetl=0; }
                      break;
            case "2": if(Onda=="C"){ Offseth=128; Offsetl=128; }
                      if(Onda=="H"){ Offseth=128; }
                      if(Onda=="L"){ Offsetl=128; }
                      break;
            case "4": if(Onda=="C"){ Offseth=192; Offsetl=192; }
                      if(Onda=="H"){ Offseth=192; }
                      if(Onda=="L"){ Offsetl=192; }
                      break;
         }
         eco_offset();

         Keypress=0x00;
      }


   } while (TRUE);

}

void eco_offset(void){
   printf("
Onda %c h%u l%u
",Onda,Offseth,Offsetl);
}


Espero que os sirva este pequeño ejemplito.

Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania