//#define PWM_TEST // Import Libraries #include <S12C32bits.h> #include <hidef.h> #include <mc9s12e128.h> #include <stdio.h> #include "PWM.h" /*----------------------------- Module Defines ----------------------------*/ // Define Maximum channels to be 3 #define MAX_CHANNELS 5 // Define Min Duty Cycle to 0 #define PWMS12_MIN_DC 0 // Define Max Duty Cycle to 100 #define PWMS12_MAX_DC 100 // Define PWM Error/OK Constants #define PWMS12_ERR -1 #define PWMS12_OK 0 /*---------------------------- Module Variables ---------------------------*/ // Create a module variable containing the Duty Cycle register of each PWM channel static unsigned char * const DutyRegisters[] = { &PWMDTY0, &PWMDTY1, &PWMDTY2, &PWMDTY3, &PWMDTY4}; /*------------------------------ Module Functions ------------------------------*/ // PWMPeriod: Takes in an unsigned long value representing the frequency, returns nothing void PWMFrequency(unsigned char group, unsigned long frequency){ unsigned char PreScalingPower = 0; unsigned char PreScaleValue = 1; unsigned char ScalerValue; unsigned long ScalingFactor; // Multiply input frequency by 2 frequency *= 2; // Create a scaling factor number which will be the desired product of the prescaler and scaler ScalingFactor = 120000/frequency; // While Scaling factor can be divided by 2 while (ScalingFactor % 2 == 0){ // Divide the scaling factor by 2 and store it into the scaling facor ScalingFactor = ScalingFactor/2; // Count how many times the scaling factor can be divided by 2 PreScalingPower++; } // Set the Scaler Value to be the current value of the ScalingFactor ScalerValue = (unsigned char)ScalingFactor; if(group == 0) { // Set pre-scaler for clock A PWMPRCLK &= ~(_S12_PCKA0 | _S12_PCKA1 | _S12_PCKA2); } else if(group == 1) { // Set pre-scaler for clock B PWMPRCLK &= ~(_S12_PCKB0 | _S12_PCKB1 | _S12_PCKB2); } if (group == 0) { // Take the the prescaling power and apply the correct bit values to set to the prescaler register switch (PreScalingPower){ case 0: // divide by 1 break; case 1: // divide by 2 PWMPRCLK |= _S12_PCKA0; break; case 2: // divide by 4 PWMPRCLK |= _S12_PCKA1; break; case 3: // divide by 8 PWMPRCLK |= (_S12_PCKA0|_S12_PCKA1); break; case 4: // divide by 16 PWMPRCLK |= _S12_PCKA2; break; case 5: // divide by 32 PWMPRCLK |= (_S12_PCKA0|_S12_PCKA2); break; case 6: // divide by 64 PWMPRCLK |= (_S12_PCKA1|_S12_PCKA2); break; case 7: // divide by 128 PWMPRCLK |= (_S12_PCKA0 | _S12_PCKA1 | _S12_PCKA2); break; } } else if (group == 1) { switch (PreScalingPower){ case 0: // divide by 1 break; case 1: // divide by 2 PWMPRCLK |= _S12_PCKB0; break; case 2: // divide by 4 PWMPRCLK |= _S12_PCKB1; break; case 3: // divide by 8 PWMPRCLK |= (_S12_PCKB0|_S12_PCKB1); break; case 4: // divide by 16 PWMPRCLK |= _S12_PCKB2; break; case 5: // divide by 32 PWMPRCLK |= (_S12_PCKB0|_S12_PCKB2); break; case 6: // divide by 64 PWMPRCLK |= (_S12_PCKB1|_S12_PCKB2); break; case 7: // divide by 128 PWMPRCLK |= (_S12_PCKB0 | _S12_PCKB1 | _S12_PCKB2); break; } } if(group == 0) { // Use scaled clock A for group A PWMCLK |= (_S12_PCLK0 | _S12_PCLK1 | _S12_PCLK4); // Set the ScalerValue for the Scaled Clock PWMSCLA = ScalerValue; } else if(group == 1) { // Use scaled clock B for group B PWMCLK |= (_S12_PCLK2 | _S12_PCLK3); // Set the ScalerValue for the Scaled Clock PWMSCLB = ScalerValue; } } // PWMDutyCycle: Takes in two chars representing DutyCycle and channel, // returns a char representing error or OK signed char PWMDutyCycle(unsigned char channel, unsigned char dutyCycle){ // If DutyCycle and Channel Number exceed the maximum, return error if ((channel >= MAX_CHANNELS) || (dutyCycle > PWMS12_MAX_DC)) return PWMS12_ERR; else // Otherwise, change the Duty Cycle in the DutyCycle register for the respective channel, return OK *DutyRegisters[channel] = dutyCycle; return PWMS12_OK; } // PWM Polarity: Takes a char representing the channel, and a char representing the direction of polarity and sets the polarity void PWMPolarity(char Ch, char Dir){ switch (Dir){ case 1: // If Active HI desired if (Ch == 0) // If Channel 0 (LEFTWHEEL) PWMPOL |= _S12_PPOL0; // Set Channel 0 to active HI else if (Ch == 1) // If Channel 1 (RIGHTWHEEL) PWMPOL |= _S12_PPOL1; // Set Channel 1 to active HI else if (Ch == 2) // If Channel 1 (RIGHTWHEEL) PWMPOL |= _S12_PPOL2; // Set Channel 2 to active HI else if (Ch == 3) // If Channel 1 (RIGHTWHEEL) PWMPOL |= _S12_PPOL3; // Set Channel 3 to active HI else if (Ch == 4) // If Channel 1 (RIGHTWHEEL) PWMPOL |= _S12_PPOL4; // Set Channel 4 to active HI break; case 0: // If Active LO desired if (Ch == 0) // If Channel 0 (LEFTWHEEL) PWMPOL &= ~_S12_PPOL0; // Set Channel 0 to active LO else if (Ch == 1) // If Channel 1 (RIGHTWHEEL) PWMPOL &= ~_S12_PPOL1; // Set Channel 1 to active LO else if (Ch == 2) // If Channel 1 (RIGHTWHEEL) PWMPOL &= ~_S12_PPOL2; // Set Channel 2 to active LO else if (Ch == 3) // If Channel 1 (RIGHTWHEEL) PWMPOL &= ~_S12_PPOL3; // Set Channel 3 to active LO else if (Ch == 4) // If Channel 1 (RIGHTWHEEL) PWMPOL &= ~_S12_PPOL4; // Set Channel 4 to active LO break; default: break; } } // PWMOnOff: Takes 3 chars corresponding to channel 0,1,2. // A value of 0 disables the PWMsubsystem on that channel // A value of 1 enables the PWMsubsystem on that channel // Sets PWMsubsystem to an initial period // Returns nothing. void PWMOnOff(char Ch0, char Ch1, char Ch2, char Ch3, char Ch4){ unsigned char i; // Turn off PWM and don't map any ports to PWM PWME = 0; MODRR = 0; // Set Polarity for each PWM channel (output initially high) PWMPOL = (_S12_PPOL0 | _S12_PPOL1 | _S12_PPOL2 | _S12_PPOL3| _S12_PPOL4); // Ser PWMPeriod to have 100 count resolution PWMPER0 = PWMPER1 = PWMPER2 = PWMPER3 = PWMPER4 = PWMS12_MAX_DC; // For each PWM channel for ( i=0; i< MAX_CHANNELS; i++) { // Initialize the channel to 0% Duty Cycle (void)PWMDutyCycle(i, 0); } // If Ch0 is to be turned on if (Ch0 == 1){ // Enable Map of PWM to PortT0 MODRR |= _S12_MODRR0; // Enable PWM subsystem on Channel 0 PWMCAE |= _S12_CAE0; PWME |= _S12_PWME0; } // If Ch0 is to be turned off else if (Ch0 == 0){ // Disable Map of PWM to PortT0 MODRR &= ~_S12_MODRR0; // Disable PWM subsystem on Channel 0 PWME &= ~_S12_PWME0; } // If Ch1 is to be turned on if (Ch1 == 1){ MODRR |= _S12_MODRR1; PWMCAE |= _S12_CAE1; PWME |= _S12_PWME1; } // If Ch1 is to be turned off else if (Ch1 == 0){ MODRR &= ~_S12_MODRR1; PWME &= ~_S12_PWME1; } // If Ch2 is to be turned on if (Ch2 == 1){ MODRR |= _S12_MODRR2; PWMCAE |= _S12_CAE2; PWME |= _S12_PWME2; } // If Ch2 is to be turned off else if (Ch2 == 0){ MODRR &= ~_S12_MODRR2 ; PWME &= ~_S12_PWME2; } // If Ch3 is to be turned on if (Ch3 == 1){ MODRR |= _S12_MODRR3; PWMCAE |= _S12_CAE3; PWME |= _S12_PWME3; } // If Ch3 is to be turned off else if (Ch3 == 0){ MODRR &= ~_S12_MODRR3 ; PWME &= ~_S12_PWME3; } // If Ch4 is to be turned on if (Ch4 == 1){ MODRR |= _S12_MODRR4; PWMCAE |= _S12_CAE4; PWME |= _S12_PWME4; } // If Ch4 is to be turned off else if (Ch2 == 0){ MODRR &= ~_S12_MODRR4; PWME &= ~_S12_PWME4; } } #ifdef PWM_TEST void main(){ PWMOnOff(1,1,1,1,1); PWMFrequency(0,50); PWMFrequency(1,5000); PWMDutyCycle(10,0); PWMDutyCycle(25,1); PWMDutyCycle(50,2); PWMDutyCycle(75,3); PWMDutyCycle(95,4); while(1); } #endif // PWM_TEST