pwm_dac.c - Demonstrates a PWM DACΒΆ
Demonstrates a PWM DAC - connect an RC filter on the OC1 output and vary the pulse width of the PWM signal, and monitor the DC value on the capacitor. The RC time constant should be at least 10x greater than the PWM period. Examples values used for testing were R=6.8k, C = 1.0u, PWM period= 500 us In this code, the pulse width of the PWM signal is varied by reading an analog voltage generated by a potentiomer, same as in the ledpwm.c example. So, this duplicates the input voltage on the output of the PWM DAC.
#include "pic24_all.h"
#include <stdio.h>
#ifndef PWM_PERIOD
#define PWM_PERIOD 500 // desired period, in us
#endif
void configTimer2(void) {
T2CON = T2_OFF | T2_IDLE_CON | T2_GATE_OFF
| T2_32BIT_MODE_OFF
| T2_SOURCE_INT
| T2_PS_1_8 ; //1 tick = 1.6 us at FCY=40 MHz
PR2 = usToU16Ticks(PWM_PERIOD, getTimerPrescale(T2CONbits)) - 1;
TMR2 = 0; //clear timer2 value
_T2IF = 0;
_T2IP = 1;
_T2IE = 1; //enable the Timer2 interrupt
}
void configOutputCompare1(void) {
T2CONbits.TON = 0; //disable Timer when configuring Output compare
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 that is 0 to 99% of PR2
pulse width (PR2) * ADC/1024
u32_temp = (u32_temp * (PR2))>> 10 ; // >>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) {
uint16_t u16_oc1rs;
uint32_t u32_pw;
float f_dacV;
configBasic(HELLO_MSG);
configTimer2();
configOutputCompare1();
CONFIG_RA0_AS_ANALOG();
configADC1_ManualCH0(RA0_AN, 31, 0);
SET_SAMP_BIT_ADC1(); //start sampling and conversion
T2CONbits.TON = 1; //turn on Timer2 to start PWM
while (1) {
u16_oc1rs = OC1RS;
u32_pw= ticksToUs(u16_oc1rs, getTimerPrescale(T2CONbits));
f_dacV = u16_oc1rs;
f_dacV = f_dacV * 3.3/(PR2+1);
printf("PWM PW (us): %ld, PWM DAC voltage: %4.2f\n",u32_pw, (double) f_dacV);
DELAY_MS(100);
}
}