|
|
View previous topic :: View next topic |
Author |
Message |
Linxroot
Joined: 16 May 2011 Posts: 17
|
Problem with AD PIC12F683 |
Posted: Tue Jun 16, 2015 6:07 pm |
|
|
I have a 6 years of experience in PIC programing C CCS and I have had a problem with a particular device: PIC12F683. I connected a potentiometer in A/D input (AN3) and got the result to use in a PWM OUT and it works fine! zero potentiometer... zero PWM OUT, max potentiometer, max PWM OUT. But when i try comparate the value of AD at runtime, the max value of A/D (10 bits) is 65534 instead 1023, however, the PWM keeps running.
At 2.5V rms in oscilloscope the ADC value is 1024 and the pwm is 50% in the PWM OUT
The simple code I used to test.
Code: |
#include <12F683.h>
#device ADC=10
#FUSES NOWDT //No Watch Dog Timer
#FUSES NOBROWNOUT //No brownout reset
#use delay(internal=8000000)
#DEFINE min_led pin_a1
#DEFINE max_led pin_a0
int16 teste=0;
#INT_AD
void AD_isr(void)
{
if (teste>1020)
{
output_high(max_led);
}else
output_low(max_led);
}
void main()
{
setup_adc_ports(sAN3);
setup_adc(ADC_CLOCK_DIV_2);
enable_interrupts(INT_AD);
enable_interrupts(GLOBAL);
output_high(max_led);
delay_ms(300);
setup_timer_2(T2_DIV_BY_4,255,1);
setup_ccp1(ccp_pwm);
while(TRUE)
{
set_adc_channel(3);
teste=(read_adc(ADC_START_AND_READ));
set_pwm1_duty(teste);
}
} |
I knew a few bugs in the .h file some devices, if you guys can help me the versions of my compiller is CCS PCM C Compiler, Version 5.015. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Jun 16, 2015 8:11 pm |
|
|
Quote: | the max value of A/D (10 bits) is 65534 instead 1023 |
Where in your program do you get the value of 65534 ?
I don't see any printf statement to display the ADC value.
Why do you think the ADC returns a value of 65534 ? |
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Wed Jun 17, 2015 5:00 am |
|
|
You are trying to clock the ADC at 4MHz. This is way too fast. About 1MHz is the max for most PIC ADCs (dsPIC ones go faster). The datasheet, on page 62, recommends using dividing the clock by 16 or 32.
The ADC interrupt will fire when the ADC completes its conversion. That is BEFORE the read_adc() function returns. That means teste will not be set (it will, in fact have the value it had the last time it was set). Either set teste in the ISR, and use ADC_START_ONLY in the call to read_adc(), or better, forget about the ISR completely and just use the result returned by read_adc().
It is rare to need, or be able to properly use ADC ISRs. About the only time I've wanted to was to implement continuous self-scanning ADCs, where the ISR got the last result and started the next conversion in a never-ending loop. The idea was that the main program just read the buffered results and knew it was only ever one loop time out of date. It sort of worked, but took up a disproportional amount of processor time and was wasteful when many things, such as temperature and power supply voltages, changed slowly.
Your comments about the pot slightly surprise me. Many pots only have at most about 85% usable travel, that's to say they never quite get to 0 and full, they a several percent short at each end due to the way the pots that can turn through a complete circle (they were used for wind direction sensing) but even they only had 355 degrees of active travel, with the 5 degrees just west of north being "dead". |
|
|
Linxroot
Joined: 16 May 2011 Posts: 17
|
|
Posted: Wed Jun 17, 2015 5:29 am |
|
|
PCM programmer wrote: | Quote: | the max value of A/D (10 bits) is 65534 instead 1023 |
Where in your program do you get the value of 65534 ?
I don't see any printf statement to display the ADC value.
Why do you think the ADC returns a value of 65534 ? |
Yes, you're right in this part of the code:
Code: |
if (teste>1020)
{
output_high(max_led);
}else
output_low(max_led);
}
|
I changed to 65534 and the led lit near full position of potentiometer.
I will check the waveform in the led output right now to know if have a oscillating value. |
|
|
Linxroot
Joined: 16 May 2011 Posts: 17
|
|
Posted: Wed Jun 17, 2015 5:31 am |
|
|
To simplify the tests and eliminate variables I created another code, compiled in another version of CCS (4.068) and with another PIC (PIC12F675).
The problem continues...
Code: | #include <12F675.h>
#device adc=16
#FUSES NOWDT, INTRC_IO, NOCPD, PROTECT, NOMCLR, NOPUT, BROWNOUT// NOIESO,// NOFCMEN
#use delay(clock=4000000)
#define max_led pin_a0
int16 teste=0;
void main()
{
setup_adc_ports(sAN3|VSS_VDD);
setup_adc(ADC_CLOCK_DIV_32);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_comparator(NC_NC);
setup_vref(FALSE);
// setup_oscillator(OSC_4MHZ);
while (true)
{
set_adc_channel(3);
delay_ms(200);
teste=read_adc();
if (teste>1024)output_high(max_led); else output_low(max_led);
//The LED lighting at 120mV RMS on ADC input
//In the part PIC12F683 at 8Mhz freq osc and //"setup_adc(ADC_CLOCK_INTERNAL);" the LED lights up 2.5 V Rms
//The adc input was checked and going 60mV Rms to 5,07 V Rms
//All of setup_adc modes were tested
The ADC works fine if I use INTRC OR RC, but the clock out in the adc input, even though the ADC conversion its ok, but the part warms because the potentiometer in some positions cause short circuit to clock out. My power supply is limited in 10 mA for obvious reasons.
}
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jun 17, 2015 4:14 pm |
|
|
Quote: | //the LED lights up 2.5 V Rms
//The adc input was checked and going 60mV Rms to 5,07 V Rms
//All of setup_adc modes were tested
|
Are you connecting an AC signal to the A/D input pin (AN3) ?
The peak voltage of a 5.07 Vrms signal would be higher than +5.3v and
would violate the Absolute Maximum Ratings of voltage limits for the PIC's
i/o pins.
Does the AC voltage also go below -0.3 volts ? That also would be a
violation of the Absolute Maximum Ratings given in the Electrical
Specifications section of the 12F675 data sheet.
What is the frequency of your AC signal ?
------------
In the note that you tacked onto the other thread, you said:
Quote: | The VDD is 5,07 V RMS |
PICs don't use AC signals for their Vdd. They use DC. Do you know
what RMS means ? It means Root-mean-square. It's a term used to
describe the average voltage of an AC signal. I think you are probably
really using 5vdc for your PIC's Vdd voltage, but you are wrongly using
"V rms" to describe it. I also wonder if maybe you are really using a
DC voltage on the A/D pin.
-------------
Also, doing this does not make the 12F675 magically have a 16-bit A/D:
Quote: | #include <12F675.h>
#device adc=16
|
It still has a 10-bit A/D converter, but the output is left justified instead
of being right justified. Example:
With #device adc=10 the read_adc() function will return values
from 0 to 1023. With #device adc=16 , it will return 0 as the
lowest result, but the next lowest will be 64, and the maximum is 65472.
Don't use #device adc=16, unless you know exactly why you are doing it.
It does not make the PIC magically have a 16-bit A/D. |
|
|
Linxroot
Joined: 16 May 2011 Posts: 17
|
|
Posted: Wed Jun 17, 2015 5:44 pm |
|
|
Thank You PCM programmer to reply, the voltage is +5V DC to the pic and 0 to 5.07 DC (from the potentiometer) to AD. I know what is RMS, in my previous project I was using AC and my oscilloscope was in AC mode, and understand the issue, the tension really needs to be DC. thank you to ask me, often we do not realize simple mistakes and alternating voltage could be really a problem.
and all the times I wrote RMS was DC voltage , so that little ambiguity. I wrote wrong!
I Used #device adc=16 to try justify the bits in the var and some things changed: the pwm lost the linearity and stability of frequency. I am reading the datasheet of device to know the registers address and I will try to read the values directly, or clear the bits 10 to 15 from the var teste to test. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jun 17, 2015 5:56 pm |
|
|
Here is sample code to control the PWM duty cycle with a trimpot:
http://www.ccsinfo.com/forum/viewtopic.php?t=40222&start=1
This example is for a 16F877 with a 4 MHz crystal, but you can also
use it with a 12F683 with the internal (INTRC_IO) 4 MHz oscillator. |
|
|
Linxroot
Joined: 16 May 2011 Posts: 17
|
|
Posted: Wed Jun 17, 2015 6:20 pm |
|
|
I do not know exactly what's going on but I cleaned the bits 10-15 of the teste var and it worked fine! it's ok! The PWM and the value of var test have the same
The code was:
bit_clear(teste,10);
bit_clear(teste,11);
bit_clear(teste,12);
bit_clear(teste,13);
bit_clear(teste,14);
bit_clear(teste,15);
the bits of high (00000000) and 2 bits (00) from the low... the rest seems being filled with 1 thereby : ADC Value(10 bits):0000000000+1111 of the 16bits var.
What is happen for it do this? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jun 17, 2015 7:02 pm |
|
|
Quote: | The code was:
bit_clear(teste,10);
bit_clear(teste,11);
bit_clear(teste,12);
bit_clear(teste,13);
bit_clear(teste,14);
bit_clear(teste,15);
|
Post the full test program that has those lines in it. Post the compiler
version you are using for this test. |
|
|
Linxroot
Joined: 16 May 2011 Posts: 17
|
Problem with AD PIC12F683 Solved! |
Posted: Thu Jun 18, 2015 5:59 am |
|
|
The problem was in the unused bits of the 6 var test ( int16 ) que was filled with 1 instead 0. Its unknown why, but I used a bitmask to correct this.
Here is the complete code:
Code: |
#include <12F683.h>
#device ADC=10;
#fuses INTRC_IO,NOWDT,PROTECT, NOMCLR
#use delay(internal=8000000,RESTART_WDT)
#include <internal_eeprom.c>
#DEFINE min_led pin_a1
#DEFINE max_led pin_a0
//timer
int time=0;
int base_sec=0;
int base_led=0;
//fim timer
//DAC
int8 offset=0; //adjust of minimal voltage of sensor
int16 lco=200; //Low current output
int16 hco=1000; //High current output
float span=0;
int16 DAC=0;
unsigned int16 teste=0;
int32 x=0;
int16 s=0;
//adc
int32 adc=0;
// fim adc
void keys(void);
#int_timer2
void timing_dsy()
{
time++;
keys();
if (time>12) //timebase 12ms
{
time=0;
base_sec++;
base_led++;
}
if (base_led>4) //timebase 64ms 15.6 Hz
{
base_led=0;
if (teste>1022)
{
output_toggle(max_led);
}
output_toggle(min_led);
}
if (base_sec>99)//timebase 1s
{
time=0;
base_sec=0;
}
}
void keys(void)
{
if (!input(pin_a3))
{
output_high(max_led);
}
if (!input(pin_a5))
{
output_high(min_led);
}
}
void main() // Função principal
{
setup_adc(ADC_CLOCK_DIV_2);
setup_adc_ports(sAN3 | VSS_VDD); // Configura analógicos
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1); // Configura Timer 0
setup_timer_1(T1_DISABLED);
setup_comparator(NC_NC_NC_NC);
setup_timer_2(T2_DIV_BY_4,255,1);
setup_ccp1(ccp_pwm);
enable_interrupts(int_timer2);
// enable_interrupts(int_ad);
enable_interrupts(global);
while (true)
{
set_adc_channel(3);
teste=(read_adc(ADC_START_AND_READ));
//This can be used
/*
bit_clear(teste,10);
bit_clear(teste,11);
bit_clear(teste,12);
bit_clear(teste,13);
bit_clear(teste,14);
bit_clear(teste,15);
*/
//or
// teste=teste & 0b0000001111111111;
//or
// teste=teste & 0x3FF;
//its a simple bitmask that clear the unused 6 bits of the var teste
//and done!
teste=teste & 0x3FF;
set_pwm1_duty(teste);
delay_ms(1);
}
} |
Thank you very much! |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Jun 18, 2015 12:31 pm |
|
|
Your clock divisor is too small, resulting in a ADC clock that is 8 times
faster than allowed.
Quote: |
#use delay(internal=8000000,RESTART_WDT)
setup_adc(ADC_CLOCK_DIV_2);
|
The 12F683 data sheet tells you what clock divisor to use in this table:
Quote: | TABLE 9-1: ADC CLOCK PERIOD (TAD) VS. DEVICE OPERATING FREQUENCIES (VDD > 3.0V
|
http://ww1.microchip.com/downloads/en/DeviceDoc/41211D_.pdf
Also,
pcm programmer wrote: | Post the compiler version you are using for this test. |
|
|
|
Linxroot
Joined: 16 May 2011 Posts: 17
|
|
Posted: Tue Jun 23, 2015 7:54 am |
|
|
PCM programmer wrote: | Your clock divisor is too small, resulting in a ADC clock that is 8 times
faster than allowed.
Quote: |
#use delay(internal=8000000,RESTART_WDT)
setup_adc(ADC_CLOCK_DIV_2);
|
The 12F683 data sheet tells you what clock divisor to use in this table:
Quote: | TABLE 9-1: ADC CLOCK PERIOD (TAD) VS. DEVICE OPERATING FREQUENCIES (VDD > 3.0V
|
http://ww1.microchip.com/downloads/en/DeviceDoc/41211D_.pdf
Also,
pcm programmer wrote: | Post the compiler version you are using for this test. |
|
Code: | #include <12F683.h>
#device ADC=10;
#fuses INTRC_IO,NOWDT,PROTECT, NOMCLR
#use delay(internal=8000000,RESTART_WDT)
#include <internal_eeprom.c>
#DEFINE min_led pin_a1
#DEFINE max_led pin_a0
//timer
int time=0;
int base_sec=0;
int base_led=0;
//fim timer
//DAC
int8 offset=0; //adjust of minimal voltage of sensor
int16 lco=200; //Low current output
int16 hco=1000; //High current output
float span=0;
int16 DAC=0;
unsigned int16 teste=0;
int32 x=0;
int16 s=0;
//adc
int32 adc=0;
// fim adc
void keys(void);
#int_timer2
void timing_dsy()
{
time++;
keys();
if (time>12) //timebase 12ms
{
time=0;
base_sec++;
base_led++;
}
if (base_led>4) //timebase 64ms 15.6 Hz
{
base_led=0;
if (teste>1022)
{
output_toggle(max_led);
}
output_toggle(min_led);
}
if (base_sec>99)//timebase 1s
{
time=0;
base_sec=0;
}
}
void keys(void)
{
if (!input(pin_a3))
{
output_high(max_led);
}
if (!input(pin_a5))
{
output_high(min_led);
}
}
void main() // Função principal
{
setup_adc(ADC_CLOCK_DIV_32);
setup_adc_ports(sAN3 | VSS_VDD); // Configura analógicos
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1); // Configura Timer 0
setup_timer_1(T1_DISABLED);
setup_comparator(NC_NC_NC_NC);
setup_timer_2(T2_DIV_BY_4,255,1);
setup_ccp1(ccp_pwm);
enable_interrupts(int_timer2);
// enable_interrupts(int_ad);
enable_interrupts(global);
while (true)
{
set_adc_channel(3);
teste=(read_adc(ADC_START_AND_READ));
//This can be used
/*
bit_clear(teste,10);
bit_clear(teste,11);
bit_clear(teste,12);
bit_clear(teste,13);
bit_clear(teste,14);
bit_clear(teste,15);
*/
//or
// teste=teste & 0b0000001111111111;
//or
// teste=teste & 0x3FF;
//its a simple bitmask that clear the unused 6 bits of the var teste
//and done!
teste=teste & 0x3FF;
set_pwm1_duty(teste);
delay_ms(1);
}
} | CCS PCM C Compiler, Version 5.015 |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jun 24, 2015 1:59 pm |
|
|
I installed compiler vs. 5.015 and shortened your program down to the
essential parts to read and display the ADC results. It worked. The
upper 6 bits are set to 0 by the compiler without any masking needed.
I slowly turned the trimpot and got ADC output from 0000 to 03FF.
That's correct operation:
Code: |
0000
0000
0000
0058
00d3
0104
012a
015c
0193
01ff
0260
02a8
0300
0362
03a0
03ff
03ff
03ff |
I don't know how you could possibly get an ADC result with all the upper
bits set to 1. It's not caused by the compiler. Your program below has
some minor bugs, but for this test, they are not important. They don't
affect the result.
Code: | #include <12F683.h>
#device ADC=10 //; *** COMMENTED OUT the ';'
#fuses INTRC_IO, NOWDT
#use delay(internal=8000000,RESTART_WDT)
#use rs232(baud=9600, xmit=PIN_A2) // *** ADDED ***
unsigned int16 teste=0;
void main()
{
setup_adc(ADC_CLOCK_DIV_32);
setup_adc_ports(sAN3 | VSS_VDD);
while(TRUE)
{
set_adc_channel(3);
teste=(read_adc(ADC_START_AND_READ));
printf("%lx \n\r", teste); // *** ADDED ***
teste=teste & 0x3FF;
//set_pwm1_duty(teste); // *** COMMENTED OUT
delay_ms(1000); // *** SET to 1000
}
} |
|
|
|
Linxroot
Joined: 16 May 2011 Posts: 17
|
|
Posted: Sun Jun 28, 2015 4:19 pm |
|
|
PCM programmer wrote: | I installed compiler vs. 5.015 and shortened your program down to the
essential parts to read and display the ADC results. It worked. The
upper 6 bits are set to 0 by the compiler without any masking needed.
I slowly turned the trimpot and got ADC output from 0000 to 03FF.
That's correct operation:
Code: |
0000
0000
0000
0058
00d3
0104
012a
015c
0193
01ff
0260
02a8
0300
0362
03a0
03ff
03ff
03ff |
I don't know how you could possibly get an ADC result with all the upper
bits set to 1. It's not caused by the compiler. Your program below has
some minor bugs, but for this test, they are not important. They don't
affect the result.
|
In my report states that the problem to occur there must be three conditions:
The ADC must be activated;
The PWM too;
The oscillator config must be one that not use the CLK OUT pin;
The clock out pin is the same pin of the ADC input. Curiously If the clock out is actived the adc convertions works fine, but the microcontroller warms because the pot cause short circuit to the signal of clock out. |
|
|
|
|
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
|