View previous topic :: View next topic |
Author |
Message |
CCS_Kid
Joined: 22 Jun 2010 Posts: 17
|
ADC and PWM Problem |
Posted: Wed Jun 23, 2010 2:57 am |
|
|
Guys im new at ccs. I downloaded the demo version of ccs which is on the official website. Version is 4.102. I was using some other compiler but i had to change my compiler for this project.
I need to use ADC and PWM in my code. I work at 4Mhz with 16F877A. I use AN0 as analog input just to read voltage value by the help of the potentiometer. Voltage can vary between 0-5V. What i want to do is, get that ADC value (8bit ADC) and use it (8 bit) PWM channel. By looking at the position of a switch i need to give PWM signal to the chosen led.
On the pcb i can read only a few voltage values at AN0 pin. For example i keep turning potentiometer but it jumps from 500mV to 5V. Why is this happening? Can you please tell me how adc settings are done ?
I use those setting lines:
Code: |
setup_adc_ports(AN0);
setup_adc(ADC_CLOCK_DIV_32);
//setup_adc ( ADC_CLOCK_INTERNAL );
set_adc_channel(0);
....
//and the code is simply like that
do{
value = read_adc() ; //this variable is defined like this-> long value;
....
if (condition1 occurs){
setup_ccp1(CCP_PWM);
set_pwm1_duty(led_res);
Delay_ms(100);
}
if (condition2 occurs){
setup_ccp2(CCP_PWM);
set_pwm2_duty(led_res);
Delay_ms(100);
}
}while(1); |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Wed Jun 23, 2010 3:43 am |
|
|
You leave out some bits 'needed' to see what may be happening. Timer2 setup, is 'critical', since this sets the available resolution on the PWM.
Do you have a #device ADC= line?. (You don't need it, since it'll default to 8bit, but if there is one present, it'll affect things).
You do realise that the loop speed will change radically when conditions are 'met'. This will make the response somewhat erratic.
ADC_CLOCK_DIV_32, is unnecessarily 'slow' for 4MHz operation. Recommended value is /8. This will degrade the ADC accuracy, and make the conversion take longer than it should.
Best Wishes |
|
|
CCS_Kid
Joined: 22 Jun 2010 Posts: 17
|
|
Posted: Wed Jun 23, 2010 4:10 am |
|
|
Here u can see timer settings. I dont use timer0 so i made command line.
Code: | void main()
{
setup_adc_ports(AN0);
setup_adc(ADC_CLOCK_DIV_8); // Here u can see -> i made it 8us
//setup_adc ( ADC_CLOCK_INTERNAL );
set_adc_channel(0);
setup_psp(PSP_DISABLED);
setup_spi(SPI_SS_DISABLED);
//setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DIV_BY_16,124,1);
setup_ccp1(CCP_PWM);
setup_ccp2(CCP_PWM);
set_pwm1_duty(0);
set_pwm2_duty(0);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
// TODO: USER CODE!!
output_a(0x00);
output_b(0x00);
output_c(0x00);
output_d(0x00);
output_e(0x00);
|
Also about 8 bit ADC, programme created header file itself. Here is the content of file :
#include <16F877A.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES XT //Crystal osc <= 4mhz for PCM/PCH , 3mhz to 10 mhz for PCD
#FUSES NOPUT //No Power Up Timer
#FUSES NOPROTECT //Code not protected from reading
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection
#FUSES NOWRT //Program memory not write protected
#FUSES RESERVED //Used to set the reserved FUSE bits
#use delay(clock=4000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8) |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Wed Jun 23, 2010 5:24 am |
|
|
OK.
Now first thing, you talk about a PWM resolution of '8bits'. This is not what you have.
The PWM, has a range from 0 to ((Timer2_max+1)*4)-1 counts. So with 124 in the timer2 setup, 0 to 499. Not '8 bits'.
To get an 8bit Timer2 resolution, needs 63 in the second value of the timer2 setup.
You don't need to reselect the CCP as PWM, when you change the duty. Once setup, it stays setup.
What you describe should work with:
Code: |
do{
value = read_adc() ; //this variable is defined like this-> long value;
....
if (switch1){
set_pwm1_duty(value);
}
else {
set_pwm2_duty(value);
}
delay_ms(100);
}while(1);
|
Best Wishes |
|
|
CCS_Kid
Joined: 22 Jun 2010 Posts: 17
|
|
Posted: Wed Jun 23, 2010 6:44 am |
|
|
Ok. I wrote 63 instead of 124. But i think that my problem is in adc. I created a new project and tried only adc.
Code: |
#include <ctype.h>
#include <float.h>
#include <stddef.h>
#include <stdlib.h>
int value=0;
unsigned led_res=0;
void main()
{
setup_adc_ports(AN0);
setup_adc(ADC_CLOCK_DIV_8);
setup_psp(PSP_DISABLED);
setup_spi(SPI_SS_DISABLED);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
// TODO: USER CODE!!
output_a(0x00);
output_b(0x00);
output_c(0x00);
output_d(0x00);
output_e(0x00);
do {
checkpoint:
value = adc_done();
if (value==1) {
delay_us(10);
led_res = read_adc();
output_D(led_res);
}
else goto checkpoint;
}while(1);
} |
Here is the header file content :
Code: | #include <16F877A.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES HS //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#FUSES NOPUT //No Power Up Timer
#FUSES NOPROTECT //Code not protected from reading
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection
#FUSES NOWRT //Program memory not write protected
#FUSES RESERVED //Used to set the reserved FUSE bits
#use delay(clock=4000000)
|
Here u can download isis file and see potentiometer problem:
http://www.2shared.com/file/i_0ZknVs/adc_design.html
http://rapidshare.com/files/401986155/adc_design.rar.html |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Wed Jun 23, 2010 7:17 am |
|
|
You originally said you had 'value' declared as long. You now have it declared as an int. This changes _everything_ change it to long. The PWM function _changes the way it works according to the type of the number used_.
Don't test adc_done. Not wanted/needed. You don't even trigger the conversion till you call read_adc....
Leave the delay in the loop. The ADC needs time to charge between samples.
Best Wishes |
|
|
CCS_Kid
Joined: 22 Jun 2010 Posts: 17
|
|
Posted: Wed Jun 23, 2010 7:31 am |
|
|
Also can u plz tell me how can i see adcon1 register bits in ccs ? |
|
|
CCS_Kid
Joined: 22 Jun 2010 Posts: 17
|
|
Posted: Wed Jun 23, 2010 7:46 am |
|
|
I'm sorry i was trying those and i forgot them before copying. I have changed the code as u told me. Here is the new one :
Code: | #include <ctype.h>
#include <float.h>
#include <stddef.h>
#include <stdlib.h>
int value=0;
long led_res=0;
void main()
{
setup_adc_ports(AN0);
setup_adc(ADC_CLOCK_DIV_8);
setup_psp(PSP_DISABLED);
setup_spi(SPI_SS_DISABLED);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
// TODO: USER CODE!!
output_a(0x00);
output_b(0x00);
output_c(0x00);
output_d(0x00);
output_e(0x00);
do {
//checkpoint:
//value = adc_done();
//if (value==1) {
delay_us(10);
led_res = read_adc();
output_D(led_res);
//}
delay_ms(100);
//else goto checkpoint;
}while(1);
|
|
|
|
CCS_Kid
Joined: 22 Jun 2010 Posts: 17
|
|
Posted: Wed Jun 23, 2010 8:20 am |
|
|
I realize that my potentiometer is the problem. When i apply any voltage level to AN0 pin without potentiometer, there is no problem with adc. But with pot, it doesnt apply linear voltage level and adc is converting applied voltage level correctly. Why does it happening? It does the same thing in pcb too |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jun 23, 2010 10:16 am |
|
|
What is the resistance value of your trimpot in ohms ? |
|
|
CCS_Kid
Joined: 22 Jun 2010 Posts: 17
|
|
Posted: Wed Jun 23, 2010 1:56 pm |
|
|
I am using 1k but I saw the same problem at 10k and 500 ohms too |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jun 23, 2010 2:16 pm |
|
|
Quote: |
output_a(0x00);
output_b(0x00);
output_c(0x00);
output_d(0x00);
output_e(0x00);
|
I just looked at your code. You're clobbering PortA and any other Ports
that you're using, such as the UART. You are setting the TRIS to all
outputs on all the ports. Don't do this. Delete those lines.
Get rid of this stuff too. It's Wizard code and it doesn't do anything
useful, and it can do some harm. For example, the setup_spi()
statement is actually configuring the SPI module. You don't need it.
Delete all these lines.
Quote: |
setup_psp(PSP_DISABLED);
setup_spi(SPI_SS_DISABLED);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE); |
|
|
|
CCS_Kid
Joined: 22 Jun 2010 Posts: 17
|
|
Posted: Fri Jun 25, 2010 3:12 am |
|
|
Thank you very much PCM programmer. My problem is solved at isis Today ill try it on hardware i hope there wont be a problem too
By the way what does clobbering means? I didn't understand that. Can you please explain its meaning
Also i thought that following lines are using for clearing ports. Am i wrong ? Are those lines assigning tris values ?
Quote: | output_a(0x00);
output_b(0x00);
output_c(0x00);
output_d(0x00);
output_e(0x00); |
|
|
|
CCS_Kid
Joined: 22 Jun 2010 Posts: 17
|
|
Posted: Fri Jun 25, 2010 5:28 am |
|
|
I tried it in hardware. ADC works Then i tried my first code ADC+PWM. That code was actually driving leds with pwm. I saw there little pwm duration increasement but it happens very rarely. Then i deleted delay lines and tried again. I saw led doesn't blink anymore.
In conclusion i think that delay_ms or delay_us commands affect pwm. Is that true I'll use buttons in my code. Because of debounce issue i need delay command there. Also for ADC conversion time i need too. What do u suggest me ? Should i use nop as writing asm ? Is that gonna be a solution ? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Jun 25, 2010 11:51 am |
|
|
Quote: | Also i thought that following lines are using for clearing ports. Am i wrong ? Are those lines assigning tris values ?
output_a(0x00);
output_b(0x00);
output_c(0x00);
output_d(0x00);
output_e(0x00);
|
Yes, in Standard I/O mode (the default mode), the compiler also sets
the TRIS to be all outputs when you use the output_x() functions.
Quote: |
By the way what does clobbering means?
|
"Clobbered" means damaged or destroyed or hurt. In this case, it
means the contents of the TRIS registers have been changed, so the
CCS library code may not work anymore.
Quote: | I saw led doesn't blink anymore.
|
Post a very short compilable program that shows the problem. |
|
|
|