|
|
View previous topic :: View next topic |
Author |
Message |
pieter
Joined: 16 Jan 2011 Posts: 27
|
Pic24 a-d problem |
Posted: Sun Jan 16, 2011 1:11 pm |
|
|
The code below displays the first 10 a-d channels in hex on a lcd but it reads nothing. I measure the input voltages on the pins but the code yields nothing. Please see where the mistake may be?
Thanks, Pieter
Code: |
#include <c:\mpc\devices\24HJ64GP204.h>
#device ADC=8
//////// Fuses: WRTB,NOWRTB,BSSH8K,BSSS8K,NOBSS,PROTECT,NOPROTECT,WRT,NOWRT
//////// Fuses: FRC,FRC_PLL,PR,PR_PLL,NOCKSFSM,CKSFSM,SOSC,LPRC,OSCIO
//////// Fuses: NOOSCIO,EC,HS,NOPR,WDT,NOWDT,WINDIS,NOWINDIS,WPRES128
//////// Fuses: WPRES32,WPOSTS1,WPOSTS2,WPOSTS3,WPOSTS4,WPOSTS5,WPOSTS6
//////// Fuses: WPOSTS7,WPOSTS8,WPOSTS9,WPOSTS10,WPOSTS11,WPOSTS12,WPOSTS13
//////// Fuses: WPOSTS14,WPOSTS15,WPOSTS16,NOPUT,PUT2,PUT4,PUT8,PUT16,PUT32
//////// Fuses: PUT64,PUT128,XT,FRC_PS,IESO,NOIESO,PROTECTH,NORSS,RSS256
//////// Fuses: RSS2048,RSS4096,NOSSS,SSSS32K,SSSH32K,WRTSS,NOWRTSS,NORBS
//////// Fuses: RBS128,RBS256,RBS1024,DEBUG,NODEBUG,JTAG,NOJTAG,ICSP1,ICSP2
//////// Fuses: ICSP3,CKSNOFSM,BSSH4K,BSSS4K,BSSH1K,BSSS1K,SSSH16K,SSSS16K
//////// Fuses: SSSH8K,SSSS8K,PROTECT_HIGH
#FUSES WDT //No Watch Dog Timer
#FUSES NOWRTB //Boot block not write protected
#FUSES NOBSS //No boot segment
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOWRT //Program memory not write protected
#FUSES FRC_PLL //Internal Fast RC Oscillator with PLL Enabled
//#FUSES NOCKSFSM //Clock Switching is disabled, fail Safe clock monitor is disabled
#FUSES NOOSCIO //OSC2 is general purpose output
#FUSES NOPR //Pimary oscillaotr disabled
//#FUSES NOWINDIS //Watch Dog Timer in Window mode
#FUSES WPRES128 //Watch Dog Timer PreScalar 1:128
#FUSES WPOSTS16 //Watch Dog Timer PostScalar 1:32768
#FUSES PUT128 //Power On Reset Timer value 128ms
//#FUSES IOL1WAY //Allows only one reconfiguration of peripheral pins
#FUSES NOIESO //Internal External Switch Over mode disabled
#FUSES NORSS //No secure segment RAM
#FUSES NOSSS //No secure segment
#FUSES NOWRTSS //Secure segment not write protected
#FUSES NORBS //No Boot RAM defined
#FUSES NODEBUG //No Debug mode for ICD
//#FUSES NOCOE //Device will reset into operational mode
#FUSES NOJTAG //JTAG disabled
//#FUSES ICSP3 //ICD uses PGC3/PGD3 pins
//#FUSES NOALTI2C //I2C mapped to alternate pins
#use delay(clock=40000000, RESTART_WDT)
#use rs232(baud=4800, xmit=PIN_b11, rcv=PIN_b10) // baud=38400
#id 0x0001
#PRAGMA ZERO_RAM
#include <RM_Disp.c>
//
// Software Versions:
//
//
//
//*****************************************************************************
//
// GLOBAL VARIABLES
//
//*****************************************************************************
//
//*****************************************************************************
//
#define Led Pin_B9
//
// vartiables
//
//**********************************************************************************
//
int Rch;
int Rcl;
long Rcx;
int Rdl;
long cursor; // cursor position: 0xXXdY xx=1 to 20 y=1 to 4 y=0 for < else > cursor
long lcdcfc; // lcd curser flash counter
int ledcnt;
int t1test;
int1 tdone;
int Vad[12];
int16 adval;
int adcnt;
//
//**********************************************************************************
//
#int_Timer1 // clock div 2, div bt 2^16, div set timer prescale
void Timer1_handler(void)
{
t1test++;
if (t1test==38)
{
t1test=0;
ledcnt++;
tdone=1;
}
}
#int_Adc1 // a-d int reads the input and saves it in ram
void Adc_handler(void)
{
adval=read_adc(adc_read_only);
Vad[adcnt]=adval;
adcnt++;
if (adcnt > 11) adcnt=0;
set_adc_channel(adcnt);
read_adc(adc_start_only);
}
//
//**********************************************************************************
//
//Byte Const MenuS1[54]= { 6,80, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25, Main menu
// 26,27,28,29,30,31,32,33,34,35,36,37,87,38,39,40,41,42,43,44,
// 45,46,47,48,49,50,51,52,53,82,83,84,85,86};
void printStart() // print strings
{
printf(lcd_putc, "\f"); // clear lcd
delay_ms(40); // 20
printf(lcd_putc, "\f Hello World ");
printf(lcd_putc, "\n Start Message ");
}
//
//**********************************************************************************
//
//
//**********************************************************************************
//
//
//**********************************************************************************
//
main()
{
RESTART_WDT();
SET_TRIS_A(0xfb7f); // 1111 1011 0111 1111
SET_TRIS_B(0x0c1f); // 0000 1100 0001 1111
SET_TRIS_C(0xffc3); // 1111 1111 1100 0011
Output_A(0x0000);
Output_B(0x0000);
Output_C(0x0000);
Output_High(Led);
delay_ms(500);
//
lcd_init(); // init the LCD.
printf(lcd_putc, "\f"); // clear lcd
delay_ms(500);
printstart();
Cursor=0x0114;
delay_ms(100);
//
printf("Hello World");
//
setup_comparator(nc_nc_nc_nc);
//
setup_adc(adc_clock_internal | adc_clock_div_16); // | adc_tad_mul_16); //
setup_adc_ports(all_analog); // san2 | san3); // tried every possible setting here
enable_interrupts(int_adc1); // the interrups on a-d complete works
set_adc_channel(0); // just to start the ints
read_adc(adc_start_only);
//
setup_timer1(tmr_internal | tmr_div_by_8); // Timer 0
enable_interrupts(INT_Timer1); // T0 int setup
//
printf(lcd_putc, "\f"); // clear lcd
lcd_gotoxy(2,1); // pos,line
printf(lcd_putc," #1 "); // display menu number
delay_ms(50);
lcd_gotoxy(12,1); // pos,line
printf(lcd_putc," #2 "); // display menu number
while (TRUE) // main routine
{
RESTART_WDT(); // reset watchdog
Output_High(Led);
delay_ms(100);
Output_Low(Led);
delay_ms(100);
if (tdone)
{
tdone=0;
}
//
for (rcl=0;rcl<10;rcl++) // display the 8 a-d hex values on lcd
{
rch=Vad[rcl];
if (rcl < 5)
{
lcd_gotoxy((rcl*3+1),1); // goto lcd pos,line
}
else
{
lcd_gotoxy(((rcl-5)*3+1),2); // goto lcd pos,line
}
delay_ms(10);
printf(lcd_putc,"%x",rch);
delay_ms(10);
}
}
} |
|
|
|
gpsmikey
Joined: 16 Nov 2010 Posts: 588 Location: Kirkland, WA
|
|
Posted: Sun Jan 16, 2011 1:53 pm |
|
|
The first thing I notice is with all the ones I am familiar with, there has to be a delay between the two calls below - there is a settling time after setting the channel before you can start a conversion. See the set_adc_channel( ) example in the CCS compiler manual.
set_adc_channel(adcnt);
---- need a delay here ---
read_adc(adc_start_only);
mikey _________________ mikey
-- you can't have too many gadgets or too much disk space !
old engineering saying: 1+1 = 3 for sufficiently large values of 1 or small values of 3 |
|
|
pieter
Joined: 16 Jan 2011 Posts: 27
|
|
Posted: Sun Jan 16, 2011 3:28 pm |
|
|
Thank you mikey but that is not the problem.
I put a delay in but it makes no difference.
The read happens then setup next channel and then start only.
Then it waits for the interrupt to occur again. |
|
|
SherpaDoug
Joined: 07 Sep 2003 Posts: 1640 Location: Cape Cod Mass USA
|
|
Posted: Sun Jan 16, 2011 3:37 pm |
|
|
pieter wrote: | Thank you mikey but that is not the problem.
I put a delay in but it makes no difference.
The read happens then setup next channel and then start only.
Then it waits for the interrupt to occur again. |
It may not be the ONLY problem, but it CERTAINLY is a problem. Put in a 30us delay or any reading you do get will be lousy. _________________ The search for better is endless. Instead simply find very good and get the job done. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Sun Jan 16, 2011 3:49 pm |
|
|
Seriously, you are trying to use the interrupts for the wrong thing.
Generally, it takes longer to get into, and out of an interrupt handler, than to simply wait for the ADC conversion to complete in the external code. Normally, the _only_ time the ADC interrupt should be used, is when you use a programmable timer to trigger the actual reading automatically.
What you are doing though, ought to work, with one big caveat (see the bottom of my post).
Two suggestions:
1) Use your timer, instead of using the ADC interrupt. On successive timer ticks, trigger a reading, then on the next tick, read the value, and advance to the next channel. Next tick, go back to taking the reading.
2) Perform your operation just by selecting, waiting for the capacitor to charge, and taking an ADC reading, in the external code.
I think the main problem, is you are configuring the ADC incorrectly. The division ratios, are not available with the internal RC oscillator. Check the diagram for your chip. You should be OK on the charging time, since on your chip this can be added to the acquisition 'automatically', and you are doing this, but it may not be working, because you are mixing 'invalid' values in the setup.
Best Wishes |
|
|
pieter
Joined: 16 Jan 2011 Posts: 27
|
|
Posted: Mon Jan 17, 2011 1:59 pm |
|
|
Ok, here is the correct code:
It reads the first 6 12-bit a-d's of the pic24hj64gp204 and displays the result in 16bit hex on a lcd. The a-d's are read in the a-d interrupt routine.
Add your own display routine (disp.c) and it should compile fine.
The problem was: (nothing of the advice given above....)
If I change the port settings from #use fast_io(port) to default, it seems that the compiler makes the pins i/o's, outputs, and thus pulls down the signals to ground. The a-d's then read 0's.
The working code:
Code: |
//
#list
#include <c:\mpc\devices\24HJ64GP204.h>
#device ADC=12
//////// Fuses: WRTB,NOWRTB,BSSH8K,BSSS8K,NOBSS,PROTECT,NOPROTECT,WRT,NOWRT
//////// Fuses: FRC,FRC_PLL,PR,PR_PLL,NOCKSFSM,CKSFSM,SOSC,LPRC,OSCIO
//////// Fuses: NOOSCIO,EC,HS,NOPR,WDT,NOWDT,WINDIS,NOWINDIS,WPRES128
//////// Fuses: WPRES32,WPOSTS1,WPOSTS2,WPOSTS3,WPOSTS4,WPOSTS5,WPOSTS6
//////// Fuses: WPOSTS7,WPOSTS8,WPOSTS9,WPOSTS10,WPOSTS11,WPOSTS12,WPOSTS13
//////// Fuses: WPOSTS14,WPOSTS15,WPOSTS16,NOPUT,PUT2,PUT4,PUT8,PUT16,PUT32
//////// Fuses: PUT64,PUT128,XT,FRC_PS,IESO,NOIESO,PROTECTH,NORSS,RSS256
//////// Fuses: RSS2048,RSS4096,NOSSS,SSSS32K,SSSH32K,WRTSS,NOWRTSS,NORBS
//////// Fuses: RBS128,RBS256,RBS1024,DEBUG,NODEBUG,JTAG,NOJTAG,ICSP1,ICSP2
//////// Fuses: ICSP3,CKSNOFSM,BSSH4K,BSSS4K,BSSH1K,BSSS1K,SSSH16K,SSSS16K
//////// Fuses: SSSH8K,SSSS8K,PROTECT_HIGH
//#FUSES WDT, NOPROTECT, NOJTAG, NOWRT, NODEBUG, NOIESO, FRC, NOOSCIO, NOPR //, NOIOL1WAY
#FUSES WDT //No Watch Dog Timer
#FUSES NOWRTB //Boot block not write protected
#FUSES NOBSS //No boot segment
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOWRT //Program memory not write protected
#FUSES FRC_PLL //Internal Fast RC Oscillator with PLL Enabled
//#FUSES NOCKSFSM //Clock Switching is disabled, fail Safe clock monitor is disabled
#FUSES NOOSCIO //OSC2 is general purpose output
#FUSES NOPR //Pimary oscillaotr disabled
//#FUSES NOWINDIS //Watch Dog Timer in Window mode
#FUSES WPRES128 //Watch Dog Timer PreScalar 1:128
#FUSES WPOSTS16 //Watch Dog Timer PostScalar 1:32768
#FUSES PUT128 //Power On Reset Timer value 128ms
//#FUSES IOL1WAY //Allows only one reconfiguration of peripheral pins
#FUSES NOIESO //Internal External Switch Over mode disabled
#FUSES NORSS //No secure segment RAM
#FUSES NOSSS //No secure segment
#FUSES NOWRTSS //Secure segment not write protected
#FUSES NORBS //No Boot RAM defined
#FUSES NODEBUG //No Debug mode for ICD
//#FUSES NOCOE //Device will reset into operational mode
#FUSES NOJTAG //JTAG disabled
//#FUSES ICSP3 //ICD uses PGC3/PGD3 pins
//#FUSES NOALTI2C //I2C mapped to alternate pins
#use delay(clock=40000000, RESTART_WDT)
#use rs232(baud=4800, xmit=PIN_b11, rcv=PIN_b10) // baud=38400
#list
#id 0x0001
#PRAGMA ZERO_RAM
#use fast_io(A)
#use fast_io(B)
#use fast_io(C)
#include <Disp.c>
//
// Software Versions:
//
//
// Pin definitions
#define Led Pin_B9
//
// ram
//
//**********************************************************************************
//
int Rch;
int Rcl;
int16 Rcx;
int Rdl;
long cursor; // cursor position: 0xXXdY xx=1 to 20 y=1 to 4 y=0 for < else > cursor
long lcdcfc; // lcd curser flash counter
int ledcnt;
int t1test;
int tdone;
int16 Vad[12];
int16 adval;
int adcnt;
//
//**********************************************************************************
//
#int_Timer1 // clock div 2, div bt 2^16, div set timer prescale
void Timer1_handler(void)
{
t1test++;
if (t1test==38)
{
t1test=0;
ledcnt++;
tdone=1;
}
}
#int_Adc1
void Adc_handler(void)
{
adval=read_adc(adc_read_only);
Vad[adcnt]=adval;
adcnt++;
if (adcnt > 5) adcnt=0;
set_adc_channel(adcnt);
read_adc(adc_start_only);
}
//
//**********************************************************************************
//
void printStart() // print strings
{
printf(lcd_putc, "\f"); // clear lcd
delay_ms(40); // 20
printf(lcd_putc, "\f Hello world ");
printf(lcd_putc, "\n A-D Test ");
}
//
//**********************************************************************************
main()
{
RESTART_WDT();
SET_TRIS_A(0xfb7f); // 1111 1011 0111 1111
SET_TRIS_B(0x0c1f); // 0000 1100 0001 1111
SET_TRIS_C(0xffc3); // 1111 1111 1100 0011
Output_A(0x0000);
Output_B(0x0000);
Output_C(0x0000);
Output_High(Led);
delay_ms(500);
//
lcd_init(); // init the LCD.
printf(lcd_putc, "\f"); // clear lcd
delay_ms(500);
printstart();
Cursor=0x0114; // pos=xxxx xxxx cursor=xxxx line=xxxx
delay_ms(100);
//
printf("Hello World");
//
setup_comparator(nc_nc_nc_nc);
//
setup_adc_ports(san0 | san1 | san2 | san3 | san4 | san5 | VSS_VDD);
setup_adc(adc_clock_internal | adc_clock_div_32); // | adc_tad_mul_16); //
enable_interrupts(int_adc1);
set_adc_channel(0);
read_adc(adc_start_only);
//
setup_timer1(tmr_internal | tmr_div_by_8); // Timer 1
enable_interrupts(INT_Timer1); // T1 int setup
//
printf(lcd_putc, "\f"); // clear lcd
lcd_gotoxy(2,1); // pos,line
printf(lcd_putc," #1 "); // display menu number
delay_ms(50);
lcd_gotoxy(12,1); // pos,line
printf(lcd_putc," #2 "); // display menu number
delay_ms(500);
printf(lcd_putc, "\f"); // clear lcd
while (TRUE) // main routine
{
RESTART_WDT(); // reset watchdog
Output_High(Led);
delay_ms(100);
Output_Low(Led);
delay_ms(100);
if (tdone)
{
tdone=0;
}
//
for (rcl=0;rcl<6;rcl++)
{
rcx=Vad[rcl];
if (rcl < 3)
{
lcd_gotoxy((rcl*5+1),1); // goto lcd pos,line
}
else
{
lcd_gotoxy(((rcl-3)*5+1),2); // goto lcd pos,line
}
printf(lcd_putc,"%LX",rcx);
delay_ms(2);
}
}
} |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Mon Jan 17, 2011 3:22 pm |
|
|
Seriously, do a simple test. Set a pin before you read all the channels. Then reset it when the routine finishes. Then replace the code with simple read_adc commands, without using the interrupt, and without the separate start/read operations. You may be quite appalled at how much _worse_ the interrupt driven code is.
The main point I was trying to make, was _not_ to use the ADC interrupt, unless_ you are triggering this from something else, and want the synchronous sampling this allows. Otherwise, all using the interrupt does, is cost you time.
Best Wishes |
|
|
|
|
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
|