software pwm con pic16F628A y XC8

0

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.

    
pregunta Wall-E

2 respuestas

0

Su código es bueno, pero la entrada del Timer0 en las partes del Microchip es el tiempo del ciclo de instrucción, que es la frecuencia del oscilador / 4. Así que con su configuración actual, está ejecutando con una frecuencia de entrada de 1 Mhz en lugar de 4Mhz. Después de pasar por su prescaler, ha bajado a 125 KHz, y como está contando desde 250, está recibiendo una interrupción a una velocidad de 500 Hz. Como enciende y apaga el LED cada 20 interrupciones, está bajando a 25 Hz, que es lo que puede ver. Intente un prescaler de uno. Esto acelerará el pwm a 200 Hz, pero también reducirá el tiempo de desvanecimiento. Puede aumentar el número de fadeCounter > = a 192 (24 * 8) para compensar y hacer que desaparezca a la misma velocidad. Si aún se está desvaneciendo demasiado rápido, cambie fadeCounter de un carácter sin signo a un entero de 16 bits para que pueda usar un número mayor que 255. ¡Diviértase!

    
respondido por el John Birckhead
0

Después de mirar tu código, if (ledActualBrightness <= ledTargetBrightness) ledActualBrightness = ledTargetBrightness; debería ser ledActualBrightness = 20; (o use el alias para ese valor).

El código que tenías escrito simplemente lo mantuvo bloqueado a cero brillo. Al final de su código, debe restablecerlo a su brillo total para que pueda desvanecerse nuevamente.

Duplique ese código (otro bucle), pero invierta las cuentas de altibajos y obtendrá una luz que sube, luego baja, luego sube, luego baja, etc.

En cuanto al ruido, tal vez sea una interrupción en el bucle lo que hace que parpadee un LED. Un LED puede encender y apagar miles de veces por segundo. Una alternativa es utilizar una red RC para controlar el LED con pulsos limpiados.

El código no tiene piedad con el programador. Los bichos pequeños pueden tener vapor saliendo de tus oídos. Buena suerte.

    
respondido por el Sparky256

Lea otras preguntas en las etiquetas