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.