-1
\$\begingroup\$

I have been working with pic microcontroller but this is my first time working with PWM to achieve breathing/fading effect on pin rb0. Please help me in achieving fading LED functionality on rb0. I have gone trough every possible way to troubleshoot the error but failed to achieve same. According to me the code is almost correct and I have checked every setting but the led at rb0 is keep glowing solid with no PWM fading effect. My timer 2 isr is also working great in order to check that I have also used LED at rb1 as a debug led so that I know when the isr is functional or not but rb1 is toggling great which means isr is working. Please guide me where in my code I'm going wrong so that LED at rb0 glows with fading effect. I'm using 32 MHz external oscillator. I'm sharing my code below.

#include <xc.h> #include <libpic30.h> // For __delay_ms() #pragma config FNOSC = PRIPLL // Primary Oscillator Mode #pragma config POSCMOD = HS // High-Speed Oscillator #pragma config FCKSM = CSDCMD // Clock switching and monitoring disabled #pragma config FWDTEN = OFF // Watchdog Timer disabled #define FCY 3200000UL // FRC default frequency #define PWM_FREQ 1000 // 1 kHz PWM volatile unsigned int duty = 0; volatile int step = 40; void __attribute__((interrupt, no_auto_psv)) _T2Interrupt(void) { static unsigned int counter = 0; IFS0bits.T2IF = 0; LATBbits.LATB1 ^= 1; // Blink for debug counter++; if (counter >= 20) { // Change duty every 20 ms counter = 0; duty += step; if (duty >= PR2) { duty = PR2; step = -step; } else if (duty <= 0) { duty = 0; step = -step; } OC1RS = duty; } } void PWM_Init(void) { AD1PCFG = 0xFFFF; // All analog pins set to digital TRISBbits.TRISB1 = 0; // RB1 (debug toggle) LATBbits.LATB1 = 0; AD1PCFGbits.PCFG0 = 1; // RB0 as digital TRISBbits.TRISB0 = 0; // Set RB0 as output LATBbits.LATB0 = 0; // Start low // Disable ADC AD1CON1bits.ADON = 0; // Disable ADC // ===== MAP OC1 TO RB0 (RP0) ===== __builtin_write_OSCCONL(OSCCON & ~(1 << 6)); // Unlock PPS RPOR0bits.RP0R = 18; // Map OC1 to RP0 (RB0) __builtin_write_OSCCONL(OSCCON | (1 << 6)); // Lock PPS // Timer2 for PWM base T2CON = 0; T2CONbits.TCKPS = 0b00; // 1:1 prescaler PR2 = FCY / PWM_FREQ - 1; // For 1 kHz PWM TMR2 = 0; // OC1 PWM Setup OC1CON1 = 0; duty = PR2 / 2; // Start at 50% OC1R = duty; OC1RS = duty; OC1CON1bits.OCTSEL = 0b000; // Timer2 as source OC1CON2bits.SYNCSEL = 0b11111; // No sync OC1CON1bits.OCM = 0b110; // Edge-aligned PWM IFS0bits.T2IF = 0; // Clear Timer2 interrupt flag IEC0bits.T2IE = 1; // Enable Timer2 interrupt IPC1bits.T2IP = 4; // Priority level 4 T2CONbits.TON = 1; __builtin_enable_interrupts(); } int main(void) { PWM_Init(); // Set everything up while (1); // Everything is handled in ISR return 0; } 
\$\endgroup\$
4
  • \$\begingroup\$ Your shift key seems stuck: Please don't YELL. Put code blocks in "fences": put a line containing just ~~~ before & after. \$\endgroup\$ Commented Apr 6 at 8:03
  • 2
    \$\begingroup\$ Please define every possible way you have used to troubleshoot this. Maybe the problem isn't in the ways of troubleshooting but interpreting what to do with the troubleshooting results. Also please fix your shift key and format the post, then maybe someone reads it. \$\endgroup\$ Commented Apr 6 at 8:18
  • \$\begingroup\$ I removed all the SHOUTING and fixed the code formatting. OP needs to apply proper capitalisation and punctuation to the text of the post. \$\endgroup\$ Commented Apr 6 at 8:20
  • \$\begingroup\$ "According to me the code is almost correct" Another way to phrase that is that the code is wrong. \$\endgroup\$ Commented Apr 7 at 8:28

1 Answer 1

0
\$\begingroup\$

else if (duty <= 0) It's an unsigned variable so it can never be negative.

I'd get rid of the brittle signed arithmetic and use a boolean flag to keep track of the direction instead. This code is assuming 8/16 bit int:

// use stdint.h types in professional programming static volatile uint16_t duty = 0; static const uint16_t step = 40; static bool increasing = true; ... uint16_t pr2 = PR2; // assuming PR2 is a register, then only read it once. if(increasing) { if(pr2 - step > duty) // about to hit max { duty = pr2; increasing = false; } else { duty += step; } } else // decreasing { if(duty <= step) // about to hit zero { duty = 0; increasing = true; } else { duty -= step; } } OC1RS = duty; 
\$\endgroup\$

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.