View previous topic :: View next topic |
Author |
Message |
Neutone
Joined: 08 Sep 2003 Posts: 839 Location: Houston
|
|
Posted: Thu Feb 22, 2007 12:11 pm |
|
|
sonicfire wrote: | Okay, here's a new problem. I've been informed that I need to output a 500KHz PWM signal, instead of a 20KHz signal. I manipulated the code a little bit and was able to get an output of 500KHz, but now the output is unstable again and very sensitive to the analog input. In other words, if I input as little as .5V, the duty cycle is now 100% (where as for the 20KHz, 5V would max out at 50%). I also tried introducing a 500uS delay into the loop, with little added benefit. Here's the code:
Code: | #if defined(__PCM__)
#include <16F877.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=10000000)
//#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, BRGH1OK)
#elif defined(__PCH__)
#include <18F452.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=10000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, BRGH1OK)
#endif
void main() {
INT16 value;
setup_ccp1(CCP_PWM); // Configure CCP1 as a PWM
setup_timer_2(T2_DIV_BY_1, 4, 1); //output at 500KHz
setup_port_a(ALL_ANALOG);
setup_adc(adc_clock_internal);
set_adc_channel( 0 );
while( TRUE ) {
value=read_adc();
set_pwm1_duty(value); // This sets the time the pulse is
// high each cycle. We use the A/D
// input to make a easy demo.
// the high time will be:
// if value is LONG INT:
// value*(1/clock)*t2div
// if value is INT:
// value*4*(1/clock)*t2div
// for example a value of 30 and t2div
// of 1 the high time is 12us
// WARNING: A value too high or low will
// prevent the output from
// changing.
}
} |
|
This is a scaling issue. you need to scale the value you read from the ADC before you load it into the PWM. Your ADC is configured to return a value ranging from 0 to 1023 representing 0 to 100%. The PWM is configured to accept a value ranging from 0 to 19 representing 0 to 100%.
The scaling factor is 20/1024 or 0.01953125
To scale without using floating point math:
change
value=read_adc();
to
value=(read_adc()*20)/1024; |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Feb 22, 2007 12:50 pm |
|
|
His A/D is not configured for 10-bit mode. The compiler defaults to
8-bit mode.
Here's the code from the .LST file for the posted program
The A/D is configured for left-justified output. Then, only
the MSB of the result is read, from the ADRESH register.
This discards the lower two bits. The posted program
puts this 8-bit result into the LSB of a 16-bit variable.
The code below clears the MSB of the variable.
Code: | ...... value=read_adc();
002F: BSF ADCON0.2
0030: BTFSC ADCON0.2
0031: GOTO 030
0032: MOVF ADRESH,W
0033: CLRF value+1
0034: MOVWF value |
|
|
|
sonicfire
Joined: 11 Feb 2007 Posts: 19 Location: Cedar Rapids
|
|
Posted: Thu Feb 22, 2007 1:05 pm |
|
|
I now understand why the PWM only accepts values from 0 to 19, but I'm not sure why the A/D converter returns a number 0 to 1023. I tried implementing the change with no success. The scope output is unintelligible. I can manually set the A/D value from 0 to 20 and get satisfactory results, but I can't seem to read an input voltage (0 to 5V from a 5K pot) with the same success.
If my A/D converter is defaulting to 8bit read, how can I change it to read 10bits in my C code? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Feb 22, 2007 1:32 pm |
|
|
Quote: | how can I change it to read 10bits in my C code? |
Code: |
#include <16F877.H>
#device adc=10 // Add this line in this exact location.
|
|
|
|
sonicfire
Joined: 11 Feb 2007 Posts: 19 Location: Cedar Rapids
|
|
Posted: Thu Feb 22, 2007 1:33 pm |
|
|
thanks |
|
|
sonicfire
Joined: 11 Feb 2007 Posts: 19 Location: Cedar Rapids
|
|
Posted: Thu Feb 22, 2007 1:40 pm |
|
|
You guys were both dead on! I now understand the scaling factor and that works quite well. The 10bit adc seems to have fixed a lot of problems as well. Thank you. |
|
|
|