View previous topic :: View next topic |
Author |
Message |
aaronik19
Joined: 25 Apr 2011 Posts: 297
|
ADC on Pic16F88 not working |
Posted: Fri Jul 28, 2017 3:26 am |
|
|
Dear Friends, I am working on PIC16F88 with crystal of 20MHz and for some reason the code is not working. I connected the potentiometer on 5V on one end and 0V on the other. The wiper is connected on AN2. I am using the below code:
Code: | #include <main.h>
int8 read_delay_analogue = 0;
void main()
{
setup_adc_ports(sAN2);
setup_adc(ADC_CLOCK_DIV_4);
set_adc_channel(2);
//Example blinking LED program
while(true)
{
delay_ms(100);
read_delay_analogue = read_adc();
}
} |
The pic is still reading 0!
Looking forward for your help |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Fri Jul 28, 2017 3:45 am |
|
|
First thing is you are clocking the ADC much too fast.
Table 12-1. ADC_CLOCK_DIV_4 is rated for 2.5MHz maximum CPU speed....
For 20Mhz, you need /32.
You don't show whether you have an ADC= line. You want #device ADC=8 for the int8 output you are using.
What is the impedance of the pot?.
The comparator should also be turned off, since it shares pins with the ADC here. |
|
|
aaronik19
Joined: 25 Apr 2011 Posts: 297
|
|
Posted: Fri Jul 28, 2017 3:49 am |
|
|
Dear Ttelmah,
Thanks for your reply. The code is below:
Code: | #include <16F88.h>
#device ADC=16 |
It was in the main.h file.
The resistance of the pot is 1Kohm. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Fri Jul 28, 2017 3:55 am |
|
|
You need ADC=8. Currently the ADC value is being left justified to an int16, and you are then taking the low 8bits of this (since you read into an int8....).
You show no fuses or clock?....
Code: |
#include <16F88.h>
#device ADC=8
#fuses HS, NOWDT, PUT, NOLVP, NOPROTECT, NOMCLR
#use delay(clock=20MHz)
|
Then change to ADC_CLOCK_DIV_32, and you have a chance of it working. |
|
|
aaronik19
Joined: 25 Apr 2011 Posts: 297
|
|
Posted: Fri Jul 28, 2017 3:57 am |
|
|
Dear Ttelmah,
This is the information:
Code: | #include <16F88.h>
#device ADC=16
#FUSES NOWDT //No Watch Dog Timer
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#use delay(crystal=20000000)
#define LED PIN_B3
#define DELAY 1000
|
Sorry but my whole program had already reached the 150 lines and I do not want to confuse someone. Just tell me what information you want and I will send you. |
|
|
aaronik19
Joined: 25 Apr 2011 Posts: 297
|
|
Posted: Fri Jul 28, 2017 4:04 am |
|
|
Dear Ttelmah,
It worked perfectly. The problem was the ADC definition. it was 16 and I put it to 8 as you suggested. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Fri Jul 28, 2017 7:22 am |
|
|
You need the ADC clock change as well, or accuracy will be foul.
Have a suspicion you may be testing with Proteus.... |
|
|
aaronik19
Joined: 25 Apr 2011 Posts: 297
|
|
Posted: Sun Aug 20, 2017 2:55 pm |
|
|
Dear Friends,
I continue to working on this project and for some reason, the ADC is not working fine. I made the 10K pot on 5V and GND and the wiper to AN0 of the PIC16F88. I am using the pot to create delay according to user request. I inserted the following lines in my code:
Code: |
setup_adc_ports(sAN0);
setup_adc(ADC_CLOCK_DIV_2);
int switch_delay = 0;
#device ADC=8
|
I used the ADC 8 because I want 0-256 range from 5V to GND and the center is 128. But still I am getting 0 in the middle of the wiper. I am seeing the value on RS232 terminal. What could be the problem please? If you need any more information please let me know. My fuses are:
Code: |
#include <16F88.h>
#device ADC=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP
#use delay(crystal=20000000) |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Aug 20, 2017 3:22 pm |
|
|
aaronik19 wrote: |
#use delay(crystal=20000000)
setup_adc_ports(sAN0);
setup_adc(ADC_CLOCK_DIV_2);
|
Look at this table, on page 118 of the 16F88 data sheet. It shows a
table of ADC clock divisors for several different PIC frequencies:
Quote: | TABLE 12-1: TAD vs. MAXIMUM DEVICE OPERATING FREQUENCIES – STANDARD DEVICES (C) |
http://ww1.microchip.com/downloads/en/DeviceDoc/30487D.pdf
What is the correct divisor for a 20 MHz PIC clock ?
Hint: It's not 2, as in your code above. |
|
|
aaronik19
Joined: 25 Apr 2011 Posts: 297
|
|
Posted: Sun Aug 20, 2017 3:28 pm |
|
|
I also compiled the program with divide 32 and 64 but still got the same result. Am i right that the variable is int since the maximum is 256? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Mon Aug 21, 2017 1:14 am |
|
|
You say:
"I inserted the following lines in my code", but give us no indication of 'where'.
You need to post a small _complete_ program. Emphasis on the 'complete'. It must be something that will compile.
Also what your compiler version number is?.
Then we have a chance of telling you what is wrong. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9246 Location: Greensville,Ontario
|
|
Posted: Mon Aug 21, 2017 5:02 am |
|
|
re:
But still I am getting 0 in the middle of the wiper.
...
Is the pot a LINEAR version and NOT a Logarithmic( audio) one ?
simple test is to confirm with a DMM that the pot is linear.
once you know, post a small program, (setup,read adc, send to PC)
Jay |
|
|
aaronik19
Joined: 25 Apr 2011 Posts: 297
|
|
Posted: Mon Aug 21, 2017 5:05 am |
|
|
Dear All,
This is the whole program.
Code: |
#include <main2.h>
#define CCP_OFF
int count_highlevel_delay = 0, count_lowlevel_delay = 0, stop_sifter_delay = 0;
byte high_level_ack = 0, low_level_ack = 0, stop_sifter_ack = 0;
unsigned int16 switch_delay;
#INT_RB
void RB_isr(void)
{
switch_delay = read_adc();
if (input(PIN_B6))
{
count_highlevel_delay = 0;
high_level_ack = 1;
stop_sifter_ack = 0;
}
else {
count_highlevel_delay = 0;
high_level_ack = 0;
stop_sifter_ack = 1;
stop_sifter_delay = 0;
}
if (input(PIN_B4))
{
count_lowlevel_delay = 0;
low_level_ack = 1;
}
else {
count_lowlevel_delay = 0;
low_level_ack = 0;
output_low(PIN_A2);
}
}
#INT_TIMER1
void TIMER1_isr(void)
{
++count_highlevel_delay;
++count_lowlevel_delay;
++stop_sifter_delay;
if (count_highlevel_delay == switch_delay & high_level_ack)
{
output_high(PIN_A1);
}
if (stop_sifter_delay == switch_delay & (!high_level_ack) & stop_sifter_ack)
{
output_low(PIN_A1);
}
if (count_lowlevel_delay == switch_delay & low_level_ack)
{
output_high(PIN_A2);
}
}
void main()
{
setup_adc_ports(sAN0);
set_adc_channel(0);
setup_adc(ADC_CLOCK_DIV_64);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8); //104 ms overflow
set_tris_a(00000001);
output_a(00000000);
delay_ms(500);
output_b(00000000);
enable_interrupts(INT_RB);
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
delay_ms(100);
//switch_delay = read_adc();
//switch_delay = 20;
//Example blinking LED program
while(true)
{
output_low(LED);
delay_ms(DELAY);
output_high(LED);
delay_ms(DELAY);
}
} |
In this code there are other functions, so please ignore them. I submitted all the program just for your interest.
The H File:
Code: |
#include <16F88.h>
#device ADC=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#use delay(crystal=20000000)
#define LED PIN_B0
#define DELAY 1000
|
|
|
|
aaronik19
Joined: 25 Apr 2011 Posts: 297
|
|
Posted: Mon Aug 21, 2017 6:11 am |
|
|
Yes the POT is linear. That is the first I checked |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Mon Aug 21, 2017 6:27 am |
|
|
Your INT_RB is never going to be called.
Code: |
set_tris_a(00000001);
output_a(00000000); //This sets the whole of portA to output
delay_ms(500);
output_b(00000000);//This does the same for portB....
|
Both port A and portB are programmed as outputs. So the ADC can't work, nor can the portB inputs...
You need:
Code: |
output_a(0b0000000); //This sets the whole of portA to output
set_tris_a(0b0000001); //switches A0 to be an input
delay_ms(500);
output_b(0b0000000);//This does the same for portB....
set_tris_b(0b0101000); //set B4 & B6 as inputs.
|
|
|
|
|