outputcompare_oneservo.c - Demonstrates servo control using output compare for PWM. Pulse width is set by the ADC input.ΒΆ
#include "pic24_all.h"
#include <stdio.h>
#ifndef PWM_PERIOD
#define PWM_PERIOD 20000 // desired period, in us
#endif
#define MIN_PW 600 //minimum pulse width, in us
#define MAX_PW 2400 //maximum pulse width, in us
void configTimer2(void) {
T2CON = T2_OFF | T2_IDLE_CON | T2_GATE_OFF
| T2_32BIT_MODE_OFF
| T2_SOURCE_INT
| T2_PS_1_64 ; //1 tick = 1.6 us at FCY=40 MHz
PR2 = usToU16Ticks(PWM_PERIOD, getTimerPrescale(T2CONbits));
TMR2 = 0; //clear timer2 value
_T2IF = 0;
_T2IP = 1;
_T2IE = 1; //enable the Timer2 interrupt
}
uint16_t u16_minPWTicks;
uint16_t u16_maxPWTicks;
void configOutputCompare1(void) {
u16_minPWTicks = usToU16Ticks(MIN_PW, getTimerPrescale(T2CONbits));
u16_maxPWTicks = usToU16Ticks(MAX_PW, getTimerPrescale(T2CONbits));
T2CONbits.TON = 0; //disable Timer when configuring Output compare
CONFIG_RB4_AS_DIG_OUTPUT();
CONFIG_OC1_TO_RP(RB4_RP); //map OC1 to RB4
OC1RS = 0; //clear both registers
OC1R = 0;
#ifdef OC1CON1
//turn on the compare toggle mode using Timer2
OC1CON1 = OC_TIMER2_SRC | //Timer2 source
OC_PWM_CENTER_ALIGN; //PWM
OC1CON2 = OC_SYNCSEL_TIMER2; //synchronize to timer2
#else
//older families, this PWM mode is compatible with center-aligned, OC1R=0
//as writes to OC1RS sets the pulse widith.
OC1CON = OC_TIMER2_SRC | //Timer2 source
OC_PWM_FAULT_PIN_DISABLE; //PWM, no fault detection
#endif
}
void _ISR _T2Interrupt(void) {
uint32_t u32_temp;
_T2IF = 0; //clear the timer interrupt bit
//update the PWM duty cycle from the ADC value
u32_temp = ADC1BUF0; //use 32-bit value for range
//compute new pulse width using ADC value
(max - min) * ADC/1024 + min
u32_temp = ((u32_temp * (u16_maxPWTicks-u16_minPWTicks))>> 10) + u16_minPWTicks; // >>10 is same as divide/1024
OC1RS = u32_temp; //update pulse width value
AD1CON1bits.SAMP = 1; //start next ADC conversion for next interrupt
}
int main(void) {
uint32_t u32_pw;
configBasic(HELLO_MSG);
configTimer2();
configOutputCompare1();
CONFIG_RA0_AS_ANALOG();
configADC1_ManualCH0(RA0_AN, 31, 0); //this is 10-bit mode
SET_SAMP_BIT_ADC1(); //start sampling and conversion
T2CONbits.TON = 1; //turn on Timer2 to start PWM
while (1) {
u32_pw = ticksToUs(OC1RS, getTimerPrescale(T2CONbits));
printf("PWM PW (us): %ld \n",u32_pw);
DELAY_MS(100);
}
}