![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
adhemp
Joined: 05 Apr 2007 Posts: 3
|
PWM control with input from ADC |
Posted: Thu Apr 05, 2007 6:06 pm |
|
|
Hey guys, I'm currently working on temperature sensing project where I would like to alter the duty cycle coming from my PIC (16F877) based on the temperature read from a thermistor. I have the thermistor as one leg of a voltage divider circuit who's voltage output is sent to an op-amp for buffering, then to the ADC of the PIC.
I'm not sure if I'm missing something simple in my ADC code or what, but if you could take a look and offer any suggestions then I'd be most appreciative...thanks!
Code: |
#include <16F877.h>
#device adc=10
#fuses HS,NOWDT,NOPROTECT,NOLVP,BROWNOUT, PUT
#use delay(clock=4000000) //4MHz
void init_ADC(void);
void main() {
int16 value, voltage; //8bit value for ADC reading
set_tris_a(0b11111111); //designate port A for thermistors as all inputs from thermistors
init_ADC();
while(TRUE)
{
delay_ms(10);
output_low(PIN_C2); // Set CCP1 output low
setup_ccp1(CCP_PWM); // Configure CCP1 as a PWM
setup_timer_2(T2_DIV_BY_16, 156, 1); // 400 Hz
value = read_ADC(); //read in voltage from thermistor
voltage=1024/value;
if (voltage>3) //switching voltage in voltage divider circuit
set_pwm1_duty(117); // 75% duty cycle on pin C2
if (voltage<3)
set_pwm1_duty(78); // 50% duty cycle on pin C2
}
}
void init_ADC(void)
{
setup_adc_ports( A_ANALOG ); //A0 A1 A2 Ref=Vdd
setup_adc( ADC_CLOCK_INTERNAL );
set_adc_channel( 0 ); //Sets A_to_D input to channel 0 (Pin 2 on PIC)
delay_us(10);
}
|
|
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Apr 05, 2007 11:26 pm |
|
|
Here is a link to a demo program that shows how to read the A/D
and display the result as a voltage.
http://www.ccsinfo.com/forum/viewtopic.php?t=28842&start=7
That program isn't 100% applicable to your problem, but it might help.
Here's a better idea. You're running the A/D in 10-bit mode, and
presumably your board is running at +5v. So the A/D value read
for a +5v input will be 1023. For a 0 volt input, it will be 0.
For 3 volts, it will be (3/5) * 1023 = approximately 614.
You don't need to convert the raw A/D value to a single digit "volts"
value. You already know that if you read 614, it's at 3.0 volts.
So you can define a constant that represents the 3v level. Then use
that constant in your code:
Code: | #define ADC_3_VOLTS 614 |
Code: |
value = read_adc();
if(value > ADC_3_VOLTS)
{
// Do something.
} |
Also, you need to look a bit more closely at your logic in the code
that sets the PWM duty cycle. What if the voltage is exactly 3 volts ?
Your code doesn't handle that state.
What if the voltage changes slightly every few milliseconds, due to
noise ? What if one moment it's 2.95 volts, and then it's 3.01 volts, etc.
Your program would constantly do fairly large changes in duty cycle.
You need to look into the concept of "hysteresis".
Lastly, do you really need 10 bits of resolution ? It's possible that the
bottom one or two bits might be noise, anyway. It might be better to
use the A/D in 8-bit mode and just read a value from 0 to 255 from it.
I don't know your requirements, so that's just a suggestion. |
|
![](templates/subSilver/images/spacer.gif) |
adhemp
Joined: 05 Apr 2007 Posts: 3
|
|
Posted: Fri Apr 06, 2007 3:35 pm |
|
|
Thanks for your help...I'm now able to switch between duty cycles based on changing voltage in the divider network. I ran into another problem today that I couldn't quite understand. The input into the ADC on the PIC is initially ~3.8 V, measured with an oscilloscope.
If I run the following code:
Code: |
if (voltage>=ADC_4_VOLTS) //switching voltage in voltage divider circuit
set_pwm1_duty(117); // 75% duty cycle on pin C2
if (voltage<ADC_4_VOLTS && voltage>=ADC_3_VOLTS)
set_pwm1_duty(78); // 50% duty cycle on pin C2
if (voltage<ADC_3_VOLTS)
set_pwm1_duty(20); // 15% duty cycle on pin C2
|
then I would expect to have a duty cycle of 50% shown initially. However, the duty cycle begins at 75% and then switches to 50% at approximately 3.4 V. Oddly, the transition between the 50 and 15% duty cycles occurs at 3 V, as expected.
Do you know why this initial duty cycle would be off but the second transition at 3 V would not be?
Thanks! |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Apr 06, 2007 4:25 pm |
|
|
1. Post the #define statements for those constants.
2. Verify that the oscilloscope is calibrated properly by checking the
A/D input voltage with a voltmeter (assuming it's a DC voltage).
3. Measure the Vdd voltage for your PIC with a voltmeter. Is it 5.0v ? |
|
![](templates/subSilver/images/spacer.gif) |
adhemp
Joined: 05 Apr 2007 Posts: 3
|
|
Posted: Sat Apr 07, 2007 3:23 pm |
|
|
Figured it out...silly mistake on my part in how I defined my constants. Thanks for your help. |
|
![](templates/subSilver/images/spacer.gif) |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|