Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

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 :)
 
Status
Not open for further replies.

New Articles From Microcontroller Tips

Back
Top