/* Para utilizar con compilador CCS y el pic16F873A */
#include <16f876.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP,PUT
#use delay(clock=20000000,restart_wdt)
#define pedalfreno PIN_C7 //entrada pedal freno,
// a través de una resistencia para limtar la corriente, viene de 12V
// mejor si también se añade un zener de 5V1
#define PWM3 PIN_B5 // controla la pata del transistor MOSFET,
// puede ser necesario una resistencia a +12V si es canal N
// o algo más si es canal P
unsigned long duty3, dutyPWM3; // como la interrupción puede venir en culquier momento,
// y el temporizador son 2 bytes, quizá pille a medias el cambio,
// por eso es necesario usar dos variables para lo mismo, una solo se usa para la interrupción
// la otra es la que gastamos "normal"
#define valorposicion 0x200
// de este valor dependerá la luminosidad cuando no esté pisado el freno
// 0x200 es la mitad de 0x3FF, si el led fuera lineal, se iluminaría la mitad.
// este valor habrá que calcularlo a ojimetro, para que ilumine como "posición"
// teniendo en cuenta que, por ejemplo
// 25% = 0x100
// 50% = 0x200
// 75% = 0x300
// 100% = 0x3FF ó más
#INT_TIMER0 // esta directiva le dice al compilador que se trata de la función que se debe ejecutar cuando
void overflowTM0(void) // interrumpa el timer0, es el que marca la frecuencia PWM
{
if (duty3!= 0) // si está a cero, nada
{
output_high(PWM3); // si tiene algún valor, activo la salida y empiezo a contar el duty
set_timer1(dutyPWM3); // el duty lo fijo aquí
ArrancaTimer1(); // y el timer (empiezo a contar) aquí
BorraIRQT1(); // por si se ha metido una interrupción mientras estamos aquí, la borro
enable_interrupts(INT_TIMER1); // para que no interrumpa y gaste tiempo, la paramos cada vez,
} // hay que ponerla en marcha otra ves, rendundante, pues al parar el timer no interrumpirá
} // al salir de la interrupción, el propio compilador borra el flag correspondiente.
#INT_TIMER1 // lo mismo que antes, en esta ocasión para el timer1, que marca el duty
void overflowTM1(void)
{
if (duty3<=0x3FF) // en realidad no es necesario, por un truco que explico después,
{ // pero si está a tope, no hay que tocar nada
output_low(PWM3); // lo pongo a cero, se acabo el duty
disable_interrupts(INT_TIMER1); // desactivo la interrupcion del timer, a la espera de un nuevo valor.
ParaTimer1(); // y lo paro, redundante.
}
} // al salir de la interrupción, el flag correspondiente se borra solo.
// estas funciones se pueden hacer también con ordenes en C, pero para que se vea que el ensamblador se puede usar también.
void BorraIRQT1(void) // es una función muy simple, que borra el bit correspondiente al timer 1, en ensamblador
{
#asm
BCF 0xc, 0 ; Borro la interrupción del timer1
#endasm
}
void ParaTimer1(void) // en este caso, paro el timer1
{
#asm
BCF 0x10, 0 ; Paro el Timer1
#endasm
}
void ArrancaTimer1(void) // y aquí lo arranco
{
#asm
BSF 0x10, 0 ; Arranco el Timer1
#endasm
}
void set_pwm3_duty(unsigned long duty)
{
disable_interrupts(GLOBAL); // esto debe hacerse para que no cambie a medias, al ser dos bytes, no se puede hacer en una instrucción.
dutyPWM3= (0xFFF0)-(duty3); // como el timer cuenta hacía arriba, a más valor de duty3, mayor será la resta, y más tarde interrumpirá
enable_interrupts(GLOBAL); // esto es para que coincida que a más valor, más luz.
//Minimo Valor, 0xFFE0, que asegura que podrá volver antes de que se acabe la cuenta
}
void main (void)
{
output_low(PWM3);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_1); // Este controla el corte del PWM, 16 bits, con reloj interno
ParaTimer1(); // Para no activar la salida, será el timer 0 el que la active, si toca
duty3= 0x00; // empezamos a 0.
setup_timer_0(RTCC_INTERNAL | RTCC_DIV_32); // Este controla el inicio de la cuenta, salen unos 1000 hercios, aunque sea de 8 bits.
// nunca se para.
enable_interrupts(INT_TIMER1);
enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL);
while (1)
{
if (!pedalfreno)
{
duty3= 0x3FF; // esto hace que se ilumine a tope,
//porque no alcanza nunca el valor asignado a valor posición
}
else
{
duty3= valorposicion; // valor calculado para que se encienda más o menos a medias.
}
set_pwm3_duty(duty3);
}
// este bucle se puede mejorar bastante, no es necesario cambiar cada vez el valor de duty, se puede dejar "dormido"
// con los valores de "posición" y que se despierte cuando se pise el pedal de freno.
// he aprovechado mucho código de la otra aplicación, por eso está en otro compilador, y tiene nombres diferentes.
}