Mi conocimiento actual de PIC se limita actualmente a un simple parpadeo de LED con y sin el uso de interrupciones y temporizadores en código C con XC8, MPLAB IDE y Pickit 3. Tengo problemas para implementar este software pwm en un PIC16F628A basado en las instrucciones para otras fotos de la familia PIC18F en esta página: software PWM para la familia PIC18F y cuya implementación original no tuvo ningún sentido. cualquiera.
Aquí está mi versión:
#pragma config FOSC = INTOSCIO // Oscillator Selection bits (INTOSC oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is digital input, MCLR internally tied to VDD)
#pragma config BOREN = OFF // Brown-out Detect Enable bit (BOD disabled)
#pragma config LVP = OFF // Low-Voltage Programming Enable bit (RB4/PGM pin has digital I/O function, HV on MCLR must be used for programming)
#pragma config CPD = OFF // Data EE Memory Code Protection bit (Data memory code protection off)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
#include <xc.h>
#define _XTAL_FREQ 4000000
unsigned char pwmCounter = 0;
unsigned char ledActualBrightness = 20;
unsigned char ledTargetBrightness = 0;
unsigned char fadeCounter = 0;
void initialize (){
// Tri-state registers. Sets all pins to outputs
TRISA = 0;
TRISB = 0;
// Turn off all comparators
CMCON = 7;
PORTA = 0;
PORTB = 0;
GIE = 1;
T0IE = 1;
T0CS = 0;
PSA = 0;
PS0 = 0;
PS1 = 1;
PS2 = 0;
TMR0 = 255 - 250;
}
void main(void) {
initialize();
while (1){
}
}
void interrupt isr(void){
if (T0IF){
GIE = 0;
T0IE = 0;
T0IF = 0;
// Perform the PWM brightness control
if (ledActualBrightness > pwmCounter)
RB0 = 1; else RB0 = 0;
pwmCounter++;
if (pwmCounter > 19) pwmCounter = 0;
// Perform fading control
if (ledActualBrightness <= ledTargetBrightness)
ledActualBrightness = ledTargetBrightness;
else
{
fadeCounter++;
if (fadeCounter >= 24)
{
ledActualBrightness--;
fadeCounter = 0;
}
}
TMR0 = 255 - 250;
GIE = 1;
T0IE = 1;
}
}
Este código solo hace que el LED se desvanezca completamente solo una vez, después de lo cual permanece completamente atenuado (o apagado), en contra de lo que estaba apuntando: tener el LED desvaneciéndose repetidamente. Además, puedo ver una oscilación de alta frecuencia del brillo a simple vista mientras se desvanece lentamente (el desvanecimiento se produce durante aproximadamente 0,5 segundos).
Con respecto a la versión original en el enlace provisto, además de la configuración de PIC, cambié mi prescaler para tener una relación de 1: 8, pensando que me da 250 temporizadores para cronometrar 1000 microsegundos con el oscilador interno de 4Mhz. También cambié el ledTargetBrightness
de 0 a 20. Tenerlo a cero como en el código original no tenía sentido (y, de hecho, no funcionó en absoluto, el LED se mantuvo apagado todo el tiempo).
Me gustaría entender por qué mi versión solo está apagando el LED una vez y no periódicamente cada ~ 0.5 segundos, y cómo puede solucionarse mientras se mantiene la misma estrategia (hacerlo dentro de esta interrupción).
En algún momento pensé que podría ser un mal manejo de los indicadores de interrupción, no se estableció o borró en la secuencia correcta o en el lugar correcto, pero la lectura de la hoja de datos mostró que parece que está bien la forma en que los uso: T0IF está borrado antes de volver a habilitar la interrupción a través de TOIE = 1 (y GIE = 1, aunque no es obvio si es útil hacerlo en el bloque de código de interrupción).
[EDITAR] Siguiendo los consejos dados en el comentario, el LED que no se enciende nuevamente se debe a un reinicio incorrecto en la instrucción if. En lugar de restablecer el valor de brillo inicial de 20, lo dejé como estaba en el código original, donde en realidad solo se establece en 0, lo que obliga a que el LED se apague. Si cambio la sentencia if a:
if (ledActualBrightness <= ledTargetBrightness)
ledActualBrightness = 20;
El apagado se repite. Sin embargo, todavía veo una oscilación de encendido / apagado de alta frecuencia mientras se desvanece, lo que todavía no entiendo. El tiempo debe ser lo suficientemente rápido como para no darse cuenta de esto.