0
\$\begingroup\$

I have bread boarded the following proteus proffessional project:

Air cooler circuit schematic

The idea is that the rotary switch controls the speed of the 2 DC fans, the high option results in 100% duty cycle, Med 75%, and Low is 50%. The tutorial I followed to configure the PWM module of the PIC16F877A gives this image taken from the IC's manual about how the PWM mode of the MCU basically works:

PMM operation of PIC16F877A

PWM Signal Generation: Once the PWM is configured and Timer2 is enabled, TMR2 starts incrementing depending on the prescalar. Once the TMR2 value is equal to dutyCycle(CCPR1L+CCP1CON<5:4>) the PWM pin will be pulled LOW. The timer still continues to increment till it matches with the period PR2. After which the PWM pin will be pulled HIGH and TMR2 is reset for next cycle. Source

And so I wrote some code in mikroC where I configure both CCP modules since I need a PWM signal to control the speed of two fans. Here is the snippet of code which is supposed to configure the PWM mode of these CCP registers:

TRISC.RC1 = 0;
TRISC.RC2 = 0;
CCP1CON = 0x0F; // Select the PWM mode.
CCP2CON = 0x0F;
TMR2ON = 1;
PR2 = 100; // Set the Cycle time to 100 for varying the duty cycle from 0-100
CCPR1L = 0; // By default set the dutyCycle to 0
CCPR2L = 0;

When I run the simulation it works in proteus. When I try to upload it to the MCU using my Pick kit 3 I am not getting a PWM signal on PORTC1-2. I have checked that the switch is working using a multimeter and have probed the crystal and found that it is oscillating. The switching mechanism doesn't seem to have a notable effect on the signals on PORTC1-2 apart from maybe some slight glitch when the switch position changes.

Here is a screenshot of what the signal looks like where I am supposed to be getting a PWM wave (PORTC1).

PORTC1

PORTC2 looks the same. Like I said I have monitored the switching mechanism, probed the crystal and the PWM ports. I can't think why this won't work when it does in simulation. Maybe somebody could help me debug this. The rest of the C code is shown here:

 int solenoid_state = 0;
 void main() 
 {
 //TRISB = 0x0F; // Configure PORTB
 TRISB.RB0 = 1;
 TRISB.RB1 = 1;
 TRISB.RB2 = 1;
 TRISB.RB3 = 1;
 TRISD.RD0 = 0;
 TRISD.RD1 = 0;
 TRISC.RC1 = 0;
 TRISC.RC2 = 0;
 CCP1CON = 0x0F; // Select the PWM mode.
 CCP2CON = 0x0F;
 TMR2ON = 1;
 PR2 = 100; // Set the Cycle time to 100 for varying the duty 
 cycle from 0-100
 CCPR1L = 0; // By default set the dutyCycle to 0
 CCPR2L = 0;
 //solenoid_state = 0;
 while(1){
 if(RB0_bit == 0) // Off state
 {
 delay_ms(300);
 if(RB0_bit == 0)
 {
 CCPR1L = 0;
 CCPR2L = 0;
 RD0_bit = 0;
 RD1_bit = 0;
 }
 while(RB0_bit == 0) //Do nothing until switch status changes
 {
 }
 }
 else
 {
 solenoid_state = 1;
 //RD0_bit = 1;
 //RD1_bit = 1;
 }
 while(solenoid_state == 1)
 {
 if(RB1_bit == 0) // Low state
 {
 delay_ms(300);
 if(RB1_bit == 0)
 {
 CCPR1L = 50;
 CCPR2L = 50;
 }
 while(RB1_bit == 0) //Do nothing until switch status changes
 {
 }
 }
 else if(RB2_bit == 0) // Med state
 {
 delay_ms(300);
 if(RB2_bit == 0)
 {
 CCPR1L = 75;
 CCPR2L = 75;
 }
 while(RB2_bit == 0) //Do nothing until switch status changes
 {
 }
 }
 else if(RB3_bit == 0) // High state
 {
 delay_ms(300);
 if(RB3_bit == 0)
 {
 CCPR1L = 100;
 CCPR2L = 100;
 }
 while(RB2_bit == 0) //Do nothing until switch status changes
 {
 }
 }
 else
 {
 //RD0_bit = 0;
 //RD1_bit = 0;
 solenoid_state = 0;
 }
 }
 }
 }

Any tips/hints appreciated,

Simon.

asked Jul 31, 2018 at 4:38
\$\endgroup\$
2
  • 1
    \$\begingroup\$ I would take your CCPR1L and CCPR2L assignments and stick them in an area without conditions (such as right before your while loop) and comment everything else out to make sure the PWM itself is working. Then you know if you have a logic error or truly a PWM problem. \$\endgroup\$ Commented Jul 31, 2018 at 5:15
  • 1
    \$\begingroup\$ Have you set the configuration bits properly? Take special attention to the oscillator. \$\endgroup\$ Commented Jul 31, 2018 at 10:39

1 Answer 1

1
\$\begingroup\$

Others suspect that your problems with the real hardware lie in the part of your code that MikroC makes very hard for you to show to others.

There are the settings for the PIC configuration words and the start up initialization of the Analog to Digital Converter and Comparator function blocks.

For simple projects like the one described it is handy to disable the ADC and Comparator functions then set or clear all of the bits in the configuration words to sensible values.

Here is your code changed to compile with the free XC8 compiler from Microchip:

/*
 * file: main.c
 * target: PIC16F877A
 * compiler: XC8 v1.45
 *
 * description:
 * Configure for PWM output ib CCP1 and CCP2.
 * Selector inputs from RB0, RB1, RB2, RB3.
 *
 */
#include <xc.h>
#pragma config FOSC = HS // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = ON // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
#define _XTAL_FREQ 20000000
int solenoid_state = 0;
void main() 
{
 INTCON = 0; // disable interrupts
 ADCON1 = 0x06; // disable ADC
 CMCON = 0x07; // disable Comparators
 //TRISB = 0x0F; // Configure PORTB
 TRISBbits.TRISB0 = 1;
 TRISBbits.TRISB1 = 1;
 TRISBbits.TRISB2 = 1;
 TRISBbits.TRISB3 = 1;
 TRISDbits.TRISD0 = 0;
 TRISDbits.TRISD1 = 0;
 TRISCbits.TRISC1 = 0;
 TRISCbits.TRISC2 = 0;
 CCP1CON = 0x0F; // Select the PWM mode.
 CCP2CON = 0x0F;
 T2CON = 0x01; // Set TIMER2 prescale as 1:4
 TMR2ON = 1;
 PR2 = 99; // Set the Cycle time to 100 for varying the duty cycle from 0-100
 CCPR1L = 0; // By default set the dutyCycle to 0
 CCPR2L = 0;
 solenoid_state = 0;
 while(1)
 {
 if(PORTBbits.RB0 == 0) // Off state
 {
 __delay_ms(300);
 if(PORTBbits.RB0 == 0)
 {
 CCPR1L = 0;
 CCPR2L = 0;
 PORTDbits.RD0 = 0;
 PORTDbits.RD1 = 0;
 }
 while(PORTBbits.RB0 == 0) //Do nothing until switch status changes
 {
 }
 }
 else
 {
 solenoid_state = 1;
 //PORTDbits.RD0 = 1;
 //PORTDbits.RD1 = 1;
 }
 while(solenoid_state == 1)
 {
 if(PORTBbits.RB1 == 0) // Low state
 {
 __delay_ms(300);
 if(PORTBbits.RB1 == 0)
 {
 CCPR1L = 50;
 CCPR2L = 50;
 }
 while(PORTBbits.RB1 == 0) //Do nothing until switch status changes
 {
 }
 }
 else if(PORTBbits.RB2 == 0) // Med state
 {
 __delay_ms(300);
 if(PORTBbits.RB2 == 0)
 {
 CCPR1L = 75;
 CCPR2L = 75;
 }
 while(PORTBbits.RB2 == 0) //Do nothing until switch status changes
 {
 }
 }
 else if(PORTBbits.RB3 == 0) // High state
 {
 __delay_ms(300);
 if(PORTBbits.RB3 == 0)
 {
 CCPR1L = 100;
 CCPR2L = 100;
 }
 while(PORTBbits.RB2 == 0) //Do nothing until switch status changes
 {
 }
 }
 else
 {
 //PORTDbits.RD0 = 0;
 //PORTDbits.RD1 = 0;
 solenoid_state = 0;
 }
 }
 }
}

Perhaps all your code needs are these lines:

 INTCON = 0; // disable interrupts
 ADCON1 = 0x06; // disable ADC
 CMCON = 0x07; // disable Comparators
answered Aug 1, 2018 at 23:49
\$\endgroup\$
3
  • \$\begingroup\$ The problem was actually just the writing to the T2CON register. I just needed to send a byte to this register to properly configure the prescale and the post scale bits. I will post the solution later only now I have another problem where the PWM signal on the CCP1-2 pins is only 0.5 Volts-not enough to switch on the FETS. It should be at least 3.8V. No idea what is causing this problem. \$\endgroup\$ Commented Aug 2, 2018 at 2:41
  • \$\begingroup\$ Most often this is some kind of circuit wiring error, next are blown FETs, lastly blown PIC outputs. Without the PIC in the circuit how much current does it take to actually drive the FET gate input to 5.0 volts? \$\endgroup\$ Commented Aug 2, 2018 at 3:34
  • 3
    \$\begingroup\$ This was a problem caused by the probe. It was a 10:1 probe and so the voltage on this pin was 5V all along. \$\endgroup\$ Commented Aug 30, 2018 at 6:18

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.