|
|
View previous topic :: View next topic |
Author |
Message |
Wolf
Joined: 23 Sep 2011 Posts: 32
|
PIC16F1947 and ADC |
Posted: Sun Sep 23, 2012 10:37 pm |
|
|
Hey,
I have been trying to configure these ADC ports on the chip, I even built a basic test program to spit out to the screen what it sees and it appears to be lots of trash. Anyway before anyone asks AVss is connected to ground, and AVdd is connected to +5 volts, I am using a voltage divider of R1 = 10k Ohm, R2 = 7.15k Ohm to change 0 - 12 volts to roughly 0 to 5 volts, oh and I'm using a 32 MHz crystal cause it says it can run it at that speed in the data sheet. I can't seem to find anything simple to reference off of, can anyone help?
Code: |
//Main pin configuration
#define STATUS1_LED PIN_B1
#define ERROR1_LED PIN_B2
#define STATUS2_LED PIN_B3
#define ERROR2_LED PIN_B4
#define TRIAC1 PIN_C1
#define TRIAC2 PIN_C2
#define AC_SIGNAL PIN_B0
#define DIAG_SWITCH PIN_D3
#define ALARM PIN_D2
//RS485 pin configuration
#define RS485_RX PIN_G2
#define RS485_TX PIN_G1
#define TX_ENABLE PIN_D0
#define RX_ENABLE PIN_D1
//RS232 pin configuration
#define RS232_TX PIN_C6
#define RS232_RX PIN_C7
//Analog channel configuration
#define SIGNAL1_INPUT 0 //PIN_A0
#define SIGNAL1_MINIMUM 3 //PIN_A1
#define SIGNAL2_INPUT 2 //PIN_A2
#define SIGNAL2_MINIMUM 1 //PIN_A3
#define NTC1 4 //PIN_A5
#define NTC2 5 //PIN_F7
#define OPTION_SENSE1 6 //PIN_F1
#define OPTION_SENSE2 7 //PIN_F2
#define OPTION_SENSE3 10 //PIN_F5
//Program conditions
#define SIGNAL1 0#define SIGNAL2 1#define INPUT 0#define MINIMUM 1#define NTC 2
#include <16F1947.h>
#device ICD = TRUE;
#device ADC=10;
#fuses HS,PLL_SW,NOWDT,NOPROTECT,NOLVP
#use delay(clock=32000000) //Crystal Oscillator @ 32MHz
#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7)
void StartupSettings();
void main() {
unsigned char uchSwitchValue, uchACSignalValue, uchLoopVal;
unsigned long int uliADCValues[17];
StartupSettings();
uchSwitchValue = 0;
uchACSignalValue = 0;
output_high(STATUS1_LED);
output_high(ERROR1_LED);
output_high(STATUS2_LED);
output_high(ERROR2_LED);
delay_ms(500);
output_low(STATUS1_LED);
delay_ms(500);
output_low(ERROR1_LED);
delay_ms(500);
output_low(ERROR2_LED);
delay_ms(500);
output_low(STATUS2_LED);
delay_ms(1000);
while (1) {
uchACSignalValue = input_state(AC_SIGNAL);
uchSwitchValue = input_state(DIAG_SWITCH);
for (uchLoopVal = 0; uchLoopVal <= 16; uchLoopVal++) {
set_adc_channel(uchLoopVal);
delay_ms(10);
uliADCValues[uchLoopVal] = read_adc();
}
for (uchLoopVal = 0; uchLoopVal <= 16; uchLoopVal++) {
printf("Channel %u, Value = %Lu\n\r", uchLoopVal, uliADCValues[uchLoopVal]);
}
}
return;
}
void StartupSettings() {
set_tris_a(0x00);
set_tris_b(0x01);
set_tris_c(0x00);
set_tris_d(0x08);
set_tris_e(0x00);
set_tris_f(0x00);
set_tris_g(0x00);
setup_adc(ADC_CLOCK_INTERNAL);
setup_adc_ports(ALL_ANALOG);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_2);
return;
}
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19510
|
|
Posted: Mon Sep 24, 2012 1:04 am |
|
|
Start by re-reading the data sheet....
No, you can't run off a 32MHz crystal. The _processor_ can run to 32MHz, but requires that you use the PLL. The crystal oscillator, is rated to 20Mhz max.
Table 30-1 in the data sheet.
Ideally get yourself an 8Mhz crystal, and add the 'PLL' setting to the fuses. Then the processor will run at 32Mhz. You already have this setting, so the chip will be trying to multiply the incoming crystal frequency by 4, and going way above it's ratings.
I'd suggest this is the main problem. Often if you try to run a long way above the oscillator ratings, it'll lock onto an 'undertone'. So it is probably oscillating at perhaps 16Mhz, and hence the 'trash' on your display.
Start much simpler. A couple of line 'Hello World' program, and prove you are displaying what your expect. Only then move on to trying to use the ADC.
Add the keyword 'ERRORS' to your RS232 declaration. This _must_ be present when using the hardware RS232, unless _you_ handle hardware errors. This is becoming a 'mantra' that needs to be repeated again and again.
Then, ADC_CLOCK_INTERNAL, is _not_ recommended (it'll give inaccurate results), for a processor clock rate above 1MHz. On this chip it just says to avoid it, and that using the divider is better, but most chips have a more stringent warning about this.
Then you are setting the TRIS on the pins you are trying to use as analog inputs, to '0'. This will make them not work.
Get rid of all the TRIS lines. Unless you need to change things, the compiler _will_ handle TRIS for you, and won't make this type of mistake.
Get rid of the 'return' at the end of the main. There is nothing to return 'to'. No 'OS' sitting outside the code. If you get here, the code would be dying anyway....
Best Wishes |
|
|
Wolf
Joined: 23 Sep 2011 Posts: 32
|
|
Posted: Mon Sep 24, 2012 1:40 am |
|
|
Well here is what I get on a terminal window now
Code: |
Channel 0, Value = 1
Channel 1, Value = 5
Channel 2, Value = 3
Channel 3, Value = 2
Channel 4, Value = 4
Channel 5, Value = 4
Channel 6, Value = 3
Channel 7, Value = 3
Channel 8, Value = 4
Channel 9, Value = 3
Channel 10, Value = 4
Channel 11, Value = 3
Channel 12, Value = 4
Channel 13, Value = 1023
Channel 14, Value = 1
Channel 15, Value = 1
Channel 16, Value = 1
|
I can change the crystal right now actually, and as for the Tris...well I have 2 digital inputs and a ton of digital outputs on the same port sharing the analogs, so...whats the alternative? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19510
|
|
Posted: Mon Sep 24, 2012 1:57 am |
|
|
Either set the TRIS correctly, or let the compiler handle it. If you don't have the TRIS statements, the compiler _will_ correctly set the TRIS for you. It knows which pins you perform digital I/O on, and changes TRIS automatically. You are 'breaking' this.
That the chip runs, is a 'fluke'.....
Best Wishes |
|
|
Wolf
Joined: 23 Sep 2011 Posts: 32
|
|
Posted: Mon Sep 24, 2012 2:36 am |
|
|
Ok this is what I am seeing:
Code: |
Channel 0, Value = 255
Channel 1, Value = 189
Channel 2, Value = 127
Channel 3, Value = 74
Channel 4, Value = 44
Channel 5, Value = 25
Channel 6, Value = 5
Channel 7, Value = 4
Channel 8, Value = 2
Channel 9, Value = 2
Channel 10, Value = 3
Channel 11, Value = 4
Channel 12, Value = 4
Channel 13, Value = 1023
Channel 14, Value = 4
Channel 15, Value = 4
Channel 16, Value = 255
|
But channel 0 and 1 are only changing by 2 or 3 values, I changed the crystal to 20 MHz cause I don't have any 8 MHz crystals with me and I adjusted my code. What else am I doing wrong?
Code: |
//Main pin configuration
#define STATUS1_LED PIN_B1
#define ERROR1_LED PIN_B2
#define STATUS2_LED PIN_B3
#define ERROR2_LED PIN_B4
#define TRIAC1 PIN_C1
#define TRIAC2 PIN_C2
#define AC_SIGNAL PIN_B0
#define DIAG_SWITCH PIN_D3
#define ALARM PIN_D2
//RS485 pin configuration
#define RS485_RX PIN_G2
#define RS485_TX PIN_G1
#define TX_ENABLE PIN_D0
#define RX_ENABLE PIN_D1
//RS232 pin configuration
#define RS232_TX PIN_C6
#define RS232_RX PIN_C7
//Analog channel configuration
#define SIGNAL1_INPUT 0 //PIN_A0
#define SIGNAL1_MINIMUM 3 //PIN_A1
#define SIGNAL2_INPUT 2 //PIN_A2
#define SIGNAL2_MINIMUM 1 //PIN_A3
#define NTC1 4 //PIN_A5
#define NTC2 5 //PIN_F7
#define OPTION_SENSE1 6 //PIN_F1
#define OPTION_SENSE2 7 //PIN_F2
#define OPTION_SENSE3 10 //PIN_F5
//Program conditions
#define SIGNAL1 0
#define SIGNAL2 1
#define INPUT 0
#define MINIMUM 1
#define NTC 2
#include <16F1947.h>
#device ICD = TRUE;
#device ADC=10;
#fuses HS,PLL_SW,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000) //Crystal Oscillator @ 20MHz
#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7)
void StartupSettings();
void main() {
unsigned char uchSwitchValue, uchACSignalValue, uchLoopVal;
unsigned long int uliADCValues[17];
StartupSettings();
uchSwitchValue = 0;
uchACSignalValue = 0;
output_high(STATUS1_LED);
output_high(ERROR1_LED);
output_high(STATUS2_LED);
output_high(ERROR2_LED);
delay_ms(500);
output_low(STATUS1_LED);
delay_ms(500);
output_low(ERROR1_LED);
delay_ms(500);
output_low(ERROR2_LED);
delay_ms(500);
output_low(STATUS2_LED);
delay_ms(1000);
while (1) {
uchACSignalValue = input_state(AC_SIGNAL);
uchSwitchValue = input_state(DIAG_SWITCH);
for (uchLoopVal = 0; uchLoopVal <= 16; uchLoopVal++) {
set_adc_channel(uchLoopVal);
delay_ms(10);
uliADCValues[uchLoopVal] = read_adc();
}
for (uchLoopVal = 0; uchLoopVal <= 16; uchLoopVal++) {
printf("Channel %u, Value = %Lu\n\r", uchLoopVal, uliADCValues[uchLoopVal]);
}
printf("\n\r");
delay_ms(2000);
}
}
void StartupSettings() {
setup_adc(ADC_CLOCK_DIV_4);
setup_adc_ports(ALL_ANALOG);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_2);
return;
}
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19510
|
|
Posted: Mon Sep 24, 2012 3:26 am |
|
|
DIV_4, is too fast for the ADC with a 20MHz clock.
DIV_16, is the recommended value at this speed. Table 16-1. Note2.
Best Wishes |
|
|
Wolf
Joined: 23 Sep 2011 Posts: 32
|
|
Posted: Mon Sep 24, 2012 3:55 am |
|
|
Table 16-1 is for the DAC did you mean 15-1? Cause if thats so DIV_16 is "outside the recommended range" I have already tried all the DIV's even 32 and 8, it's forced all the ADC's to 0 when there is a voltage signal to them. There is still a problem here that I am not catching. Also there is a current to the ADC's I made sure at least 4 volts is going to the pin |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19510
|
|
Posted: Mon Sep 24, 2012 5:16 am |
|
|
No.
The DAC, does not use a clock.
In the current microchip data sheet, table 16.1, is "ADC CLOCK PERIOD (TAD) VS. DEVICE OPERATING FREQUENCIES".
I suspect you may not have the current data sheet.
/16, is the 'borderline', but can be used, it doesn't have the note for the faster rates "These values violate the minimum required TAD time". /32, and /64, are the recommended ones at 20MHz.
At 32MHz, only /32, and /64 are recommended. |
|
|
Wolf
Joined: 23 Sep 2011 Posts: 32
|
|
Posted: Mon Sep 24, 2012 10:42 am |
|
|
Well here is the updated code
Code: |
//Main pin configuration
#define STATUS1_LED PIN_B1
#define ERROR1_LED PIN_B2
#define STATUS2_LED PIN_B3
#define ERROR2_LED PIN_B4
#define TRIAC1 PIN_C1
#define TRIAC2 PIN_C2
#define AC_SIGNAL PIN_B0
#define DIAG_SWITCH PIN_D3
#define ALARM PIN_D2
//RS485 pin configuration
#define RS485_RX PIN_G2
#define RS485_TX PIN_G1
#define TX_ENABLE PIN_D0
#define RX_ENABLE PIN_D1
//RS232 pin configuration
#define RS232_TX PIN_C6
#define RS232_RX PIN_C7
//Analog channel configuration
#define SIGNAL1_INPUT 0 //PIN_A0
#define SIGNAL1_MINIMUM 3 //PIN_A1
#define SIGNAL2_INPUT 2 //PIN_A2
#define SIGNAL2_MINIMUM 1 //PIN_A3
#define NTC1 4 //PIN_A5
#define NTC2 5 //PIN_F7
#define OPTION_SENSE1 6 //PIN_F1
#define OPTION_SENSE2 7 //PIN_F2
#define OPTION_SENSE3 10 //PIN_F5
//Program conditions
#define SIGNAL1 0#define SIGNAL2 1#define INPUT 0#define MINIMUM 1#define NTC 2
#include <16F1947.h>
#device ICD = TRUE;
#device ADC=10;
#fuses HS,PLL_SW,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20M, crystal) //Crystal Oscillator @ 20MHz
#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7,ERRORS)
void StartupSettings();
void main() {
unsigned char uchSwitchValue, uchACSignalValue, uchLoopVal;
unsigned long int uliADCValues[17];
StartupSettings();
uchSwitchValue = 0;
uchACSignalValue = 0;
output_high(STATUS1_LED);
output_high(ERROR1_LED);
output_high(STATUS2_LED);
output_high(ERROR2_LED);
delay_ms(500);
output_low(STATUS1_LED);
delay_ms(500);
output_low(ERROR1_LED);
delay_ms(500);
output_low(ERROR2_LED);
delay_ms(500);
output_low(STATUS2_LED);
delay_ms(1000);
while (1) {
uchACSignalValue = input_state(AC_SIGNAL);
uchSwitchValue = input_state(DIAG_SWITCH);
for (uchLoopVal = 0; uchLoopVal <= 16; uchLoopVal++) {
set_adc_channel(uchLoopVal);
delay_ms(100);
uliADCValues[uchLoopVal] = read_adc();
}
for (uchLoopVal = 0; uchLoopVal <= 16; uchLoopVal++) {
printf("Channel %u, Value = %Lu\n\r", uchLoopVal, uliADCValues[uchLoopVal]);
}
printf("\n\r");
delay_ms(2000);
}
}
void StartupSettings() {
setup_adc(ADC_CLOCK_DIV_16);
setup_adc_ports(ALL_ANALOG);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_2);
return;
}
|
I don't know what else to, I was off a few versions in the datasheet. But it doesn't matter what DIV I use, 2, 4, 8, 16, 32, 64, or Internal...not a single one of these settings work. So what's next to try? config the chip to behave on an internal clock of 8 MHz and remove the crystal off my circuit board? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Sep 24, 2012 3:55 pm |
|
|
Make a much more simple test program. Get rid of about 90% of your
code. Put a 5K (or less) trimpot on pin AN0. Connect the ends of the
trimpot to +5v and ground, so you can supply any voltage in that range
to AN0. Make a test program similar to the one shown in this thread:
http://www.ccsinfo.com/forum/viewtopic.php?t=40279
Get that working first. Then try to make your larger program work. |
|
|
Wolf
Joined: 23 Sep 2011 Posts: 32
|
|
Posted: Mon Sep 24, 2012 4:31 pm |
|
|
Ok, now I'm starting to see some progress using this code
Code: |
#include <16F1947.h>
#device adc=10
#fuses HS,PLL_SW,NOWDT,NOPROTECT,BROWNOUT,PUT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
//=================================
void main()
{
int16 result;
setup_adc_ports(sAN0|sAN1|sAN2|sAN3|sAN4|sAN5|sAN6|sAN7|sAN10);
setup_adc(ADC_CLOCK_DIV_32);
set_adc_channel(0);
delay_us(15);
while(1)
{
result = read_adc();
printf("%LX \n\r", result);
delay_ms(500);
}
}
|
It's a bit jittery on the printf output but the POT seems to be putting out a reasonable output as far as a voltage signal goes on AN0,1,2,3 at least as for 4,5,6,7,10 I will require an external power supply to test them. It looks like the ATD's are reading properly now, I will post more on this message if an issue should surface when grafting segments of this code onto my main program, but for now, thank you all for your help I was getting frustrated and I want you to know I appreciate your assistance.
(I would send everyone a beer if I had some) |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19510
|
|
Posted: Tue Sep 25, 2012 1:07 am |
|
|
'Jittery'.
Some things to remember:
1) You are using the chip's power supply for your Vref. The result will depend on how accurate/stable this is. You may well be suffering from a supply that is a bit noisy. Have you got a capacitor with good HF blocking characteristics (ceramic, or polyester for example), right by the processor?.
2) Careful wiring to the pot. Does the ground connection go directly to the _processor_ ground pin (not somewhere else inches away on the board). Similarly for the other connections. Short, not passing near to circuits with magnetic fields (inductors etc,).
3) Nature of the pot. Some carbon pots, are inherently quite noisy (these are what used to produce the 'crackles' on the old TV/radio volume controls.
Best Wishes |
|
|
Wolf
Joined: 23 Sep 2011 Posts: 32
|
|
Posted: Tue Sep 25, 2012 1:14 am |
|
|
Thank you very much, I'll check some caps on my board ^.^ |
|
|
|
|
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
|