PWM på PIC10F320

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
bos
Inlägg: 2275
Blev medlem: 24 februari 2007, 23:29:15
Kontakt:

PWM på PIC10F320

Inlägg av bos »

Jag har använt PIC i snart 17 år men aldrig använt PWM tidigare, så nu har jag fått för mig att jag ska testa det. På sida 101 i databladet finns en checklista att gå igenom för att ställa in PWM (PWM1 i mitt fall) och denna har jag följt efter bästa förmåga och räknat ut frekvens / pulsbredd / dutycycle enligt formlerna som finns:

f = 1 / [ (PR2 + 1) x 4 x (1/16MHz) x Prescale]

(PR2 = 1, prescale = 1 => frekvens = 2 MHz)

w = PWMxDC x (1/16MHz) x Prescale (10 bit)

(PWMxDC = 800, Prescale = 1 => pulsbredd = 50 us)

dc = PWMxDC / [ 4 x (PR2 + 1) ]

(PWMxDC = 800, PR2 = 1 => duty cycle = 100)

När jag kör min testkod så ser jag något tiotal pulser (med mycket tomrum emellan) på oscilloskopet och därefter förblir utgången hög. Jag har med andra ord missförstått något i min setup, alternativt killgissat helt fel i formlerna. Det sitter en potentiometer på RA2 och min grundtanke är att justera PWM beroende på hur potentiometern är inställd (0-100%).


Koden:

Kod: Markera allt

/* 
 * Created on March 22, 2024, 7:19 PM
 */

// CONFIG
#pragma config FOSC = INTOSC    // Oscillator Selection bits (INTOSC oscillator: CLKIN function disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable (Brown-out Reset disabled)
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = ON       // MCLR Pin Function Select bit (MCLR pin function is MCLR)
#pragma config CP = OFF         // Code Protection bit (Program memory code protection is disabled)
#pragma config LVP = OFF        // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)
#pragma config LPBOR = OFF      // Brown-out Reset Selection bits (BOR disabled)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)

#include <xc.h>

#define ADC_VALUE_MAX 255
#define ADC_VALUE_MIN 0

// (PWM_DUTY_CYCLE_MAX / ADC_VALUE_MAX)
// Max value according to formula: 800
// Max value after scaling it with ADC-value; 256 * 3 = 768
#define PWM_DUTY_CYCLE_MAX 800
#define PWM_DUTY_CYCLE_MAX_CALCULATED 768


/*
 * PWM1 - RA0
 * PWM2 - RA1
 * POT  - RA2
 */

void PWM_set_duty_cycle(unsigned char value) {
    unsigned int duty_cycle;

    // Value is from ADC, which is 8-bit, and needs to
    // be converted into 10-bit to match the duty cycle. We
    // therefore multiply the value with 3.
    duty_cycle = (unsigned int) 3 * value;

    if (duty_cycle > PWM_DUTY_CYCLE_MAX_CALCULATED)
        duty_cycle = PWM_DUTY_CYCLE_MAX_CALCULATED;
    
    // dc  = 0b------nnnnnnnnmm
    // DCH = 0bnnnnnnnn
    // DCL = 0bmm------
    PWM1DCH = (unsigned char) (duty_cycle >> 2);
    PWM1DCL = (unsigned char) ( (duty_cycle & 0b11) << 6 );
}

void PWM_enable() {
    PWM1OE = 1;
}

void PWM_disable() {
    PWM1OE = 0;
}

void PWM_init() {
    // Steps mentioned on page 101 in datasheet

    // 1. Disable PWM1 output driver
    TRISA0 = 1;

    // 2. Clear PWMCON
    PWM1CON = 0;

    // 3. Period-value -> PR2
    PR2 = 1;
    
    // 4. Clear PWM1DCH and PWM1DCL<7:6>
    PWM1DCH = PWM1DCL = 0;
    
    // 5. Config and start Timer2
    TMR2IF = 0;
    T2CON = 0b00000000;
    TMR2ON = 1;
    
    // 6. Enable PWM output pin and wait for Timer2-overflow
    PWM_enable();
    while (!TMR2IF) {};

    // 7. Enable PWM1
    TRISA0 = 0;
    
    // 8. Configure PWM1CON with appropriate values
    // PWM1DC = 800 / 0x320 / 11001000 00
    PWM_set_duty_cycle(ADC_VALUE_MAX);

    PWM1EN = 1;     // Start PWM
    PWM1OE = 1;     // Output Enable
    PWM1POL = 0;    // Active high
}

void ADC_init() {
    // RA2 input for ADC, reading potentiometer
    ANSELA = 0b00000100;

    // Setup and enable AD-module: Fosc/16, AN2
    ADCON = 0b10101001;
}

unsigned char ADC_get() {
    // Start ADC
    GO_nDONE = 1;

    // Wait for ADC to finish
    while (!GO_nDONE) {}

    // Return ADC-value
    return ADRES;
}

void MCU_init() {
    OSCCON = 0b01110000;        // 16 MHz INTOSC
    TRISA  = 0b11111111;
}

void main() {
    unsigned char adc_value;

    MCU_init();
    PWM_init();
    ADC_init();
    PWM_enable();

    while(1) {
        NOP();
    }
}

Finns det något uppenbart tokfel i koden och/eller formlerna?
H.O
Inlägg: 5718
Blev medlem: 19 mars 2007, 10:11:27
Ort: Ronneby

Re: PWM på PIC10F320

Inlägg av H.O »

Från bakhuvudet men...
Med PR2=1 och prescaler 1:1 så har du bara fyra dutycycle-värden att välja på: 0,1,2,3 men du försöker sätta det till 255.
bos
Inlägg: 2275
Blev medlem: 24 februari 2007, 23:29:15
Kontakt:

Re: PWM på PIC10F320

Inlägg av bos »

Tack, PR2 var boven. Med PR2 = 255 funkade allt som smäck!
Skriv svar