📈 Qu'est-ce que le PWM ?

Le PWM (Pulse Width Modulation — Modulation de Largeur d'Impulsion) consiste à faire varier le rapport cyclique d’un signal rectangulaire pour contrôler la puissance moyenne délivrée à un composant.

Au lieu de fournir une tension continue (ex : 2,5V), le PIC alterne rapidement entre 0V et 5V. Avec un rapport cyclique de 50%, la charge reçoit en moyenne ~2,5V. En faisant varier ce rapport de 0% à 100%, on contrôle la luminosité d'une LED ou la vitesse d'un moteur.

Le PIC12F683 intègre un module CCP1 (Capture/Compare/PWM) capable de générer un PWM matériel, sans “charger” le processeur.

✅ Sortie PWM sur PIC12F683

Sur le PIC12F683, le PWM matériel CCP1 sort généralement sur la broche GP2 (fonction alternative CCP1). Pense à mettre la broche en sortie via TRISIO et à configurer le mode analogique si besoin.

⚙️ Configuration CCP1 en PWM (PIC12F683)

Registres utilisés

RegistreRôle
CCP1CONMode CCP1 (PWM = 0b00001100) + 2 bits LSB du duty
PR2Période PWM (Timer2)
CCPR1LDuty cycle (8 bits MSB)
T2CONPrescaler / activation de Timer2
TRISIODirection des broches (GP2 en sortie)
ANSELMode analogique/numérique (selon usage)

⚠️ Point important (broches et fonctions)

  • Le PIC12F683 n’a pas PORTC/TRISC : tout passe par GPIO et TRISIO.
  • La broche GP3 est entrée uniquement (souvent MCLR selon config).

📝 Exemple complet : Contrôler la luminosité d'une LED (PWM matériel CCP1)

But : sortir un PWM sur GP2/CCP1 et faire un effet “respiration” (fade in / fade out).

C (XC8) — PIC12F683
/*
 * Projet : PWM matériel CCP1 sur PIC12F683 (GP2)
 * Auteur : JLQDeveloppement
 * Compilateur : XC8
 */

#include <xc.h>
#define _XTAL_FREQ 4000000

// (Optionnel) Ajoute tes #pragma config selon ton projet

static void initPWM_CCP1(void) {
    // Oscillateur interne 4 MHz (exemple)
    OSCCON = 0b01100000;

    // Désactiver l'analogique si tu veux 100% numérique (recommandé ici)
    ANSEL = 0;

    // GP2 en sortie (CCP1), le reste selon besoin
    // TRISIO: 1 = entrée, 0 = sortie
    TRISIObits.TRISIO2 = 0;  // GP2 sortie

    // Période PWM via Timer2
    // Exemple : PR2 = 249, prescaler 1:4 -> ~1kHz à Fosc=4MHz
    PR2 = 249;

    // Duty initial ~50% (10 bits : 0..1023)
    CCPR1L = 125;                // 8 bits MSB
    CCP1CONbits.DC1B = 0;        // 2 bits LSB

    // Activer CCP1 en PWM
    CCP1CONbits.CCP1M = 0b1100;

    // Timer2 ON, prescaler 1:4
    T2CONbits.T2CKPS = 0b01;  // 01 = 1:4
    T2CONbits.TMR2ON = 1;

    // Petite attente pour stabiliser Timer2/PWM
    __delay_ms(10);
}

static void setDuty10bits(unsigned int duty) {
    // duty : 0..1023 (10 bits)
    if(duty > 1023) duty = 1023;

    CCPR1L = duty >> 2;             // 8 bits MSB
    CCP1CONbits.DC1B = duty & 0x03; // 2 bits LSB
}

void main(void) {
    initPWM_CCP1();

    unsigned int i;

    while(1) {
        // Fade in
        for(i = 0; i <= 1023; i += 6) {
            setDuty10bits(i);
            __delay_ms(5);
        }

        // Fade out
        for(i = 1023; i > 0; i -= 6) {
            setDuty10bits(i);
            __delay_ms(5);
        }
    }
}

⚠️ Erreurs fréquentes

  • Oublier Timer2 : sans TMR2ON=1, pas de PWM.
  • Oublier TRISIO : la broche doit être en sortie (TRISIO2=0).
  • Analogique actif : selon ton usage, pense à gérer ANSEL (souvent ANSEL=0 pour une LED).

🧮 Calcul de la fréquence PWM (Timer2)

Formule (PWM via Timer2)

FPWM = Fosc / (4 × Prescaler × (PR2 + 1))

Exemple : Fosc = 4 MHz, Prescaler = 4, PR2 = 249 :

F = 4 000 000 / (4 × 4 × 250) = 1000 Hz (1 kHz)

Le rapport cyclique est sur 10 bits (0–1023), soit 1024 niveaux de réglage.

🔧 Applications courantes du PWM