PIC 18F if statement trouble

Status
Not open for further replies.

ARandomOWl

New Member
Hello,

I am writing a program using the C18 compiler to do software PWM. It is working for the most part. Although I am having problems stopping the output from going low if the duty cycle is 255.

Here is my code:

Code:
/*
 * File:   main.c
 * Author: Adrian Wheeldon
 *
 * Created on 28 July 2012
 */

#include <p18f2458.h>
#include "config.h"

void high_isr (void);
void low_isr (void);

char pwm_count = 0;              // PWM interrupt cycle counter
volatile char pwm1_dc = 255;     // Initial duty cycles
volatile char pwm2_dc = 255;

#pragma code high_vector = 0x08
void jump_int_high (void) {
    _asm GOTO high_isr _endasm
}

#pragma code low_vector = 0x18
void jump_int_low (void) {
    _asm GOTO low_isr _endasm
}

#pragma code
#pragma interrupt high_isr
void high_isr (void) {

    // Check TMR2 interrupt enable and flag
    if (PIE1bits.TMR2IE == 1 && PIR1bits.TMR2IF == 1) {
        if (pwm_count == 0) {           // If this is the beginning of the cycle, set outputs high
            if (pwm1_dc != 0) PWM1_PIN = 1; // Unless DC is zero
            if (pwm2_dc != 0) PWM2_PIN = 1;
        }
        else {
            if (pwm_count == pwm1_dc && pwm1_dc != 255) PWM1_PIN = 0;      // Set output low if current cycle equals required DC

            if (pwm_count == pwm2_dc){
                if (pwm2_dc != 255){
                    PWM2_PIN = 0;
                }
            }
                
        }

        pwm_count ++;                   // Increment period counter
        PIR1bits.TMR2IF = 0;            // Clear TMR2 flag
    }


}

#pragma interruptlow low_isr
void low_isr (void) {

}

void setup (void) {
    PORTA = 0x00;           // Clear ports
    ADCON1 = 0x0F;          // set up PORTA to be digital I/Os
    TRISA = 0x00;           // set up all PORTA pins to be digital outputs
    
    // Enable interrupts
    INTCON = 0xC0;          // Set GIE<7> and PEIE<6>
    RCONbits.IPEN = 0;      // Disable interrupt priorities
    PIE1bits.TMR2IE = 1;    // Enable TMR2/PR2 match interrupt

    PR2 = 10;               // Set PR2 pre-load (236 for ~250kHz)
    T2CON = 4;              // Start TMR2, no prescale, no post-scale
}

void main (void) {

    setup ();
    
    while (1){
        //pwm1_dc = 230;
    }

}

I separated the PWM2 if statements to check I wasn't going crazy. The pins always go low unless I comment out "PWM2_PIN = 0;", which obviously breaks the code for any duty cycle which is not 255.

Here is my configuration, not that it should be relevant.

Code:
/* 
 * File:   config.h
 * Author: Adrian Wheeldon
 * Desc.:  Configuration Bits
 *
 * Created on 29 July 2012, 16:00
 */

#ifndef CONFIG_H
#define	CONFIG_H

#define PWM1_PIN PORTAbits.RA0      // Pins for PWM channels
#define PWM2_PIN PORTAbits.RA1

#pragma config PLLDIV = 5           // For 20MHz XTAL
#pragma config CPUDIV = OSC1_PLL2
#pragma config USBDIV = 2           // USB clock source comes from the 96 MHz PLL divided by 2
#pragma config FOSC = HSPLL_HS      // HS oscillator, PLL enabled (HSPLL)
#pragma config FCMEN = OFF          // Fail-Safe Clock Monitor disabled
#pragma config IESO = OFF           // Oscillator Switchover mode disabled
#pragma config PWRT = ON
#pragma config BOR = OFF
#pragma config VREGEN = ON          // USB voltage regulator enabled
#pragma config WDT = OFF
#pragma config CCP2MX = OFF         // CCP2 input/output is multiplexed with RB3
#pragma config PBADEN = OFF         // PORTB<4:0> pins are configured as digital I/O on Reset
#pragma config LPT1OSC = OFF        // Timer1 configured for higher power operation
#pragma config MCLRE = ON          // RE3 input pin enabled; MCLR pin disabled
#pragma config LVP = OFF

#endif	/* CONFIG_H */

Can anyone see a mistake?
 
Try this:

Code:
if (pwm_count > pwm1_dc) PWM1_PIN = 0; 
else PWM1_PIN = 1;

Or the same thing using ternary operator:
Code:
(pwm_count > pwm1_dc) ? (PWM1_PIN = 0) : (PWM1_PIN = 1);
 
Last edited:
Thanks, that looks like a nice way to do it. However, when pwm_dc = 0, the pin would still go high for the first period.

Do you know why my code does not have the desired output?
 
Well something really odd is happening. I used misterT's code so I now have the following:

Code:
/*
 * File:   main.c
 * Author: Adrian Wheeldon
 *
 * Created on 28 July 2012
 */

#include <p18f2458.h>
#include "config.h"

void high_isr (void);
void low_isr (void);

char pwm_count = 0;              // PWM interrupt cycle counter
volatile char pwm1_dc = 128;     // Initial duty cycles
volatile char pwm2_dc = 254;

#pragma code high_vector = 0x08
void jump_int_high (void) {
    _asm GOTO high_isr _endasm
}

#pragma code low_vector = 0x18
void jump_int_low (void) {
    _asm GOTO low_isr _endasm
}

#pragma code
#pragma interrupt high_isr
void high_isr (void) {

    // Check TMR2 interrupt enable and flag
    if (PIE1bits.TMR2IE == 1 && PIR1bits.TMR2IF == 1) {
        if (pwm1_dc < pwm_count)
            PWM1_PIN = 0;
        else
            PWM1_PIN = 1;

        pwm_count ++;                   // Increment period counter
        PIR1bits.TMR2IF = 0;            // Clear TMR2 flag
    }


}

#pragma interruptlow low_isr
void low_isr (void) {

}

void setup (void) {
    PORTA = 0x00;           // Clear ports
    ADCON1 = 0x0F;          // set up PORTA to be digital I/Os
    TRISA = 0x00;           // set up all PORTA pins to be digital outputs
    
    // Enable interrupts
    INTCON = 0xC0;          // Set GIE<7> and PEIE<6>
    RCONbits.IPEN = 0;      // Disable interrupt priorities
    PIE1bits.TMR2IE = 1;    // Enable TMR2/PR2 match interrupt

    PR2 = 10;               // Set PR2 pre-load (236 for ~250kHz)
    T2CON = 4;              // Start TMR2, no prescale, no post-scale
}

void main (void) {

    setup ();
    
    while (1){
        //pwm1_dc = 230;
    }

}

"if (pwm1_dc < pwm_count)" is only evaluated as false when the two values are equal.
 
Have you tried closing the if ?

Code:
        if (pwm1_dc < pwm_count){
            PWM1_PIN = 0;
        } else {
            PWM1_PIN = 1;
        }

Also

pwm_count ++;

should not have a space

pwm_count++;

Also char pwm_count = 0; should be volatile since its constantly changing.

Try this:
Code:
/*
 * File:   main.c
 * Author: Adrian Wheeldon
 *
 * Created on 28 July 2012
 */
 
#include <p18f2458.h>
#include "config.h"
 
void high_isr (void);
void low_isr (void);
 
volatile unsigned char pwm_count = 0;              // PWM interrupt cycle counter
volatile unsigned char pwm1_dc = 128;     // Initial duty cycles
volatile unsigned char pwm2_dc = 254;
 
#pragma code high_vector = 0x08
void jump_int_high (void) {
    _asm GOTO high_isr _endasm
}
 
#pragma code low_vector = 0x18
void jump_int_low (void) {
    _asm GOTO low_isr _endasm
}
 
#pragma code
#pragma interrupt high_isr
void high_isr (void) {
 
    // Check TMR2 interrupt enable and flag
    if (PIE1bits.TMR2IE == 1 && PIR1bits.TMR2IF == 1) {
        if (pwm1_dc < pwm_count) {
            PWM1_PIN = 0;
        } else {
            PWM1_PIN = 1;
		}
		
        pwm_count++;                   // Increment period counter
        PIR1bits.TMR2IF = 0;            // Clear TMR2 flag
    }
 
 
}
 
#pragma interruptlow low_isr
void low_isr (void) {
 
}
 
void setup (void) {
    PORTA = 0x00;           // Clear ports
    ADCON1 = 0x0F;          // set up PORTA to be digital I/Os
    TRISA = 0x00;           // set up all PORTA pins to be digital outputs
 
    // Enable interrupts
    INTCON = 0xC0;          // Set GIE<7> and PEIE<6>
    RCONbits.IPEN = 0;      // Disable interrupt priorities
    PIE1bits.TMR2IE = 1;    // Enable TMR2/PR2 match interrupt
 
    PR2 = 10;               // Set PR2 pre-load (236 for ~250kHz)
    T2CON = 4;              // Start TMR2, no prescale, no post-scale
}
 
void main (void) {
 
    setup ();
 
    while (1){
        //pwm1_dc = 230;
    }
 
}
 
I have tried closing the if.

I wasn't aware that there shouldn't be a space, however when debugging, the variable increments fine.

I'm not entirely sure why pwm_count should be volatile, but I have tried that anyway. I made pwm1_dc volatile so that I could change the value in main without the compiler optimizing it out.

Thanks for pointing out the char, I missed that. Using char would default to signed char. Looking at the variables during debugging, the values range from 0x00 to 0xFF, but in that case I expect they are the raw values, and not the signed equivalent. Is that correct?

Thank you for your suggestions, I will try them out
 
No problem, i hope its the unsigned char giving you the issues. Volatile = constant change variable
 
Good to see you again Jason...... I thought you'd left us....
 
Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…