/******************************************************************************** * MAHE, 13.05.2002, 12H40 - now compiling as project of separated source files ********************************************************************************/ #include "pwm.h" extern unsigned char errorno; /******************************************************************************************** * Init of PWM channels * Init for PWM mode of Capcom module, p. 61 * PR2's value is calculated like that: * We need a frequency of at least 15kHz, to * avoid hearing the motors. That gives us a * period Tpwm of 6,67,e-5, the formula is on * p. 61 of the PIC16F877 documentation. * With TMR2 prescaler set to 1 it is necessary * to set PR2 to decimal 65=0x41. * Duty cycle, 10 bits: * 00 0000 0000b = 0d * 00 1111 1111b = 255d = 1/4 = default * 01 1111 1111b = 511d = 1/2 * 10 1111 1111b = 767d = 3/4 * 11 1111 1111b = 1023d * 8 MSB Bits in CCPR1L or CCPR2L: * 0011 1111 = 0x3F * 1011 1111 = 0xBF * PWM Mode for Capcom module is initialised * by setting CCP1CON and CCP2CON file bits * 3:0 to binary 11XX. ********************************************************************************************/ void initPWM(void) { /************** * Setup PR2 **************/ PR2=0x41; /**************************************** * Set duty cycle 8 MSB Bits to 0, do not * forget the 2 LSB later ! ****************************************/ CCPR1L=0x00; CCPR2L=0x00; /************************************************** * make RC2/CCP1 and RC1/CCP2 pins an output, p. 29 * by clearing the pins **************************************************/ PORTC=0x00; TRISC&=0xF9; /* 1111 1001 */ /****************************************************************** * set Timer 2 TMR2 prescale value to 1 by clearing bits 1:0, p. 55 * and start the timer by setting bit 2 * 0000 0100=0x04 ******************************************************************/ T2CON=0x04; /*********************************************************** * setup CCP1,CCP2 for PWM operation * clear 2 LSB bits 5:4, set bits 3:0 * to 1100 for PWM mode * 0000 1100=0x0C * 0x00 to clear the two LSB bits of the PWM duty cycle * 0x30 to set the two LSB bits of the PWM duty cycle * 0x0C to set PWM operation of CCP1, CCP2 module ***********************************************************/ CCP1CON=0x0C; CCP2CON=0x0C; /************************************************* * Both CCP1 and CCP2 should now be configured for * PWM operation, but the duty cycle is still set * to 0, so no signal should appear. *************************************************/ } /******************************************************************************************** * PWMChanEN * Sets or Resets the enable for PWM channel 0 or 1 ********************************************************************************************/ void PWMChanEN(char channel, char state) { /************************* * check parameters, this is * why I like objects ..... *************************/ if(channel > 1 || channel < 0 || state > 1 || state < 0 ) { /*************** * scream error ***************/ errorno=ERR_PWMCHANNELNO; } if(channel==0) { /********** * chan0 **********/ #ifdef PWMCHAN0_INVERTED state=!state; #endif PWM0ENABLE=state; } else { /********** * chan1 **********/ #ifdef PWMCHAN1_INVERTED state=!state; #endif PWM1ENABLE=state; } } /******************************************************************************************** * Sets value of Duty Cycle for PWM channel 0 or 1 ********************************************************************************************/ void setDutyCycle( const unsigned char chan, unsigned char MSB, unsigned char LSB ) { volatile char *pDutyCycleMSB; volatile char *pDutyCycleLSB; /********************** * Check parameters **********************/ if(chan<0 || chan > 1) { errorno=ERR_PWMCHANNELNO; } /********************* * Change pointers to * the correct register *********************/ if(chan==1) { #ifdef PWMCHAN1_INVERTED PWMIN12=1; #endif pDutyCycleMSB=&CCPR1L; pDutyCycleLSB=&CCP1CON; } else { /************* * Channel 0 *************/ #ifdef PWMCHAN0_INVERTED PWMIN02=1; #endif pDutyCycleMSB=&CCPR2L; pDutyCycleLSB=&CCP2CON; } /************** * MSB is easy, * just assign it **************/ *pDutyCycleMSB=MSB; /*********************** * PWM 2 LSB bits are stored * in CCPxCON<5:4> * if 2 LSB bits in LSB are * set: * LSB: 0000 0011 * CCPxCON: nn11 nnnn n->don't change * First clear the bits 5:4 * in CCPxCON. Then set to * result in LSB ***************************/ LSB&=0x03; /* 0000 0011 */ LSB=LSB<<4; (*pDutyCycleLSB)&=0xCF; /* 1100 1111 */ (*pDutyCycleLSB)|=LSB; }