Hi everyone, I'm still quite new to micros, and am doing a project on the PIC18F452. I am experiencing some troubles with ADC conversion, and think that it is a simple solution, but I'm not sure what it is. I tried to provide all the pertienent info, and explain my problem. If someone can please take a look at it, and let me know what I'm doing wrong I would really appreciate it. ============================================== ========= H/W and S/W setup ========= - PIC18f452 running on a 4MhZ oscillator - using PICDEM 2 Board and PCB I created - MCC18 C compiler - MPLAB 6.4 I am doing three A/D conversions on PORT A. In all three cases, I take the hex value returned from the A/D conversion and, using thresholds, assign a discrete "digital" value for use in my main program. I am experiencing some troubles with accuracy of the ADC. ============================================== ========= What I have done so far ========= - double checked my sample time (ADC_FOSC / Ta/d ) value. From the 18F452 datasheet (page 188) I selected a healthy buffer time, using TOSC32 (my PIC is running off a 4Mhz oscillator), so in the code I used ADC_FOSC_32 for my configuration bit (page 16 in the MCC18 libraries pdf file). - Right before doing the conversion, I am using setChanADC to specificy which pin on PORTA I want to do the conversion for - although there are other operations between the conversions, I created a no-op delay loop that cycles through 180 operations after my setChanAdc() function call. I am assuming 1 instruction per 2.5e-7 second, at 4Mhz. I read in the datasheet (page 187) that there is a A/D changing time, and recall reading somewhere else in the datasheet that it is typically 20us. Therefore the no-op loop alone exceeds this 20us requirement. - calculated my desired hex value for Vx [ ( V / Vdd) * 1023 ] ---- convert answer to hex ---> Hex value wanted from A/D conversion - have finally gotten so frustrated/baffled, that I hooked up my 18f452 onto the PICDEM 2 board in debug mode, and am looking at the result of my A/D conversion in the software window with breakpoints. ============================================== ========= Explanation of Trouble ========= I am NOT having trouble with this conversion. It is on pin2, which is ADC_CHAN0 / PORTAbits.RA0. The first conversion is the voltage off a POT directly to pin2. Values can range from ~0v to ~5v. When using the PICDEM 2 board in debug mode, I watch the window for my ADC value, and it increases and decreases in a manner that corresponds with the voltage changed by the pot. The second conversion is one I am having trouble with (the 3rd is the same nature as the second, and have excluded it from my question). I am now running my 18F452 on the PICDEM board with MPLAB 6.4, looking at the value returned from the A/D conversion (in my code, it is the last function call and the variable is 'a2dResult'). This takes place in the function call checkLight(). When I start up my code in debug mode, I begin simple testing and put 5v (my Vdd) onto pin 3 / ADC_CHAN1. With breakpoints and the MPLAB Watch window I see that the returned value is an expected 0x3FF. I then try the same, by applying 0v on pin 3. Then the A/D conversion returns an expected 0x000 value. However, I placed a voltage divider on my PICDEM board, and tried to measure the voltage, and I get a hex value returned to the variable 'a2dResult'. After that, if I reapply 5v or 0v to pin 3 (ADC_CHAN1) I no longer get the expected 0x3FF or 0x000 value, or anything remotely close to it. The readings for ADC_CHAN1 become very unpredictable, however the A/D conversions for ADC_CHAN0 (pin 2 w/ the POT) remain stable and continue to be accurate. I read in the datasheet that the maximum impedance for analog sources is 2.5Kohm, but I am not sure if this. What I would like to do is to be able to accurately read off ADC_CHAN1 and ADC_CHAN2 in my program. I am not sure if I am doing something wrong with my code, hardware setup, or what. I have a suspicion it is software, as my hardware circuits are quite simple. If anyone can help, please let me know. Thanks, Greg ============================================== ========= Code ========= (some of the formatting might get lost when I click submit - sorry!) /* Include Libraries */ #include <p18f452.h> /* for TRISB and PORTB declarations */ #include <adc.h> /* A/D library */ #include <stdlib.h> /* Standard Library */ /**********************************************/ /* Function Prototypes */ int checkSpeed( void ); void delay(int, int); void checkLight( void ); int checkAdc( int ); /***********************************************/ /* Variable Declaration */ /* */ /* main() */ int test = 0; // test variable used in main to determine if Ra1 is detecting high load (temp) int dipVal = 0; // value returned from checkDip() function call int speedVal = 0; // speed setting returned from checkSpeed() function call int onTime = 0; // max amount of time a particular channel/light can be turned on int offTime = 0; // amount of time a channel/light will be turned off int delayCounter = 0; // counter variable, useed in output display engine for on and off time int speedCounter = 1; // used in nested loop to get around max numeric value -- full explanation in dev notes int curOutput = 1; // current chanel being output /* checkSpeed() */ int a2dSpeed = 0 ; // value obtained from a2d conversion int userInputSpeed = 0; // speed setting, inferred from a2dSpeed value, returned to main // 1 = slow, 2 = medium, 3 = fast /* delay() */ int i = 0; // counter, used for delay loop int j = 1; // counter, used for number of loops -- speed control /* checkLight() */ //macros int bright = 1; // alias used for code readability, and quick changes int nightTime = 0; // macro definition --> for code readability --> digital value of a2dLightResult value int dayTime = 2; // macro definition --> for code readability --> digital value of a2dLightResult value //counters in state tests int brightTestCount = 0; int darkTestCount = 0; //current light value in state tests int a2dLightResult; // Hex value obtained from ADC reading on channel 1 (pin 3) int currentLight = 0; // digital value (night/day) of a2dLightResult which is the current light reading //threshold settings int lightThreshold = 0x01F; // light threshold. 346+ = nighttime, 346- = daytime int maxLightCount = 15; // maximum number of consecutive light/dark test results allowed /* checkAdc */ int temp = 0; // counter used for ADC delay loop int adcDelay = 180; // delay required for adc reading // 20uS wait time + generious safety margin of 50% int a2dResult = 0; // result obtained from A/D conversion void main( void ) { /* Initialize Configuration */ TRISA = 0b00000111; // configs first 3 ports of PORTA for INPUT -- used for checkSpeed() TRISC = 0xFF; // configs PORTC for INPUT -- used for checkDip() TRISD = 0x00; // configs PORTD for OUTPUT -- used for light output TRISB = 0x00; // configs PORTB to all output pins /* configure A/D convertors */ /* detailled explanation is located at: p 16-18 in MPLAB-C18-Libraries.pdf */ /* ADC_FOSC_32 -> a/d clock source uses FOSC/32 ADC_RIGHT_JUST -> result in least significant bits ADC_8ANA_0REF -> VREF+ = Vdd and VREF- = Vss (both analog) / in my case Vdd = ~5v and Vss = ~0v ADC_CH# -> the channel being used ADC_INT_OFF -> disable interrupts */ /* ADC_CH0 -> speed */ OpenADC( ADC_FOSC_32 & ADC_RIGHT_JUST & ADC_8ANA_0REF,ADC_CH0 & ADC_CH1 & ADC_CH2 & ADC_INT_OFF ); /* checkSpeed() */ /* main program */ while(1) { /* (re)initialize values */ speedVal = 0; dipVal = 0; /* obtain user input */ checkLight(); // detects amount of ambient light speedVal = checkSpeed(); // check speed setting } /* end while(1) */ } /* end main() */ /*************************************************** Function: checkSpeed() Arguments: none Return: int userInputSpeed -> digitized value of user's speed selection (1 = slow, 2 = medium, 3 = fast) I/O Pins Used: PORTA -> RA0 Description: checkSpeed() checks PORTA.RA0 and through a series of if statements, converts the voltage into one of 3 values and returns this value ****************************************************/ int checkSpeed ( void) { a2dSpeed = checkAdc(ADC_CH0); // check ADC on channel A0, which is pin 2 /* Interpret a2d value into slow/medium/fast speed */ if( a2dSpeed <= 341) // slow setting userInputSpeed = 1; else if( (a2dSpeed <= 682) && (a2dSpeed >= 342) ) // medium setting userInputSpeed = 2; else if ( (a2dSpeed <= 1023) && (a2dSpeed >= 683) ) // fast setting userInputSpeed = 3; else userInputSpeed = -1; // signifies error w/ a2d conversion return userInputSpeed; /* return obtained value */ } /* end checkSpeed() */ void checkLight( void ) { /* (re)init values */ a2dLightResult = -1; currentLight = -1; /* read ADC value */ a2dLightResult = checkAdc( ADC_CH1 ); // obtain ADC reading from channel 1 (pin 3) /* give a2dLightResults a finite, digital value of 'night' or 'day' */ if(a2dLightResult >= 0x1F0) // nighttime PORTB = 1; if(a2dLightResult < 0x1F0) // daytime PORTB = 15; } int checkAdc( int portaChan ) { // (re)init variables a2dResult = -1; // result of adc read temp = 0; // counter used in adc delay loop /* AtoD Conversion */ /* CloseADC() is not used, as nowhere in the MCC18 libraries documentation, or PIC18F452 datasheet does it suggest leaving an A/D converter on is harmful or discouraged. Opening the A/D converter once (in main()'s init period, and leaving it open saves some computational time */ SetChanADC( portaChan ); // Open ADC channel specified by user /* research timing constraings when using SetChanADC function call */ /* p187 - 188 in pic18f452 datasheet */ while(temp < adcDelay) // temporary solution temp++; ConvertADC(); // Start conversion while( BusyADC() ); // Wait for completion a2dResult = ReadADC(); // Read result return a2dResult; } |
|
A/D conversion problems on ADC_CHAN1 and ADC_CHAN2
This is an update to my earlier posted problem. I have now changed my openADC() function call to only use 1 channel, and rely on the setADCChannel() function. It looks like this: OpenADC( ADC_FOSC_32 & ADC_RIGHT_JUST & ADC_8ANA_0REF,ADC_CH0 & ADC_INT_OFF ); I have not experienced any success yet. When putting a 5v signal on pin 3 (ADC_CHAN1) and receive values of 377 to 3FF. This, itself is strange, as I can verify with a multimeter that the 5v signal is almost identical to the 5v powering the chip ( +/- 0.01V). However, when I apply a ground signal to pin 3, I receive an ADC value of 0x2AF, which is far too high. I have verified that it is indeed a ~0V signal going into pin 3. Any help is appreciated. I also have increased my delay loop in the checkAdc() function to cycle 1800 times, from 180 times. Thanks, Greg ----------------------- Hi everyone, I'm still quite new to micros, and am doing a project on the PIC18F452. I am experiencing some troubles with ADC conversion, and think that it is a simple solution, but I'm not sure what it is. I tried to provide all the pertienent info, and explain my problem. If someone can please take a look at it, and let me know what I'm doing wrong I would really appreciate it. ============================================== ========= H/W and S/W setup ========= - PIC18f452 running on a 4MhZ oscillator - using PICDEM 2 Board and PCB I created - MCC18 C compiler - MPLAB 6.4 I am doing three A/D conversions on PORT A. In all three cases, I take the hex value returned from the A/D conversion and, using thresholds, assign a discrete "digital" value for use in my main program. I am experiencing some troubles with accuracy of the ADC. ============================================== ========= What I have done so far ========= - double checked my sample time (ADC_FOSC / Ta/d ) value. From the 18F452 datasheet (page 188) I selected a healthy buffer time, using TOSC32 (my PIC is running off a 4Mhz oscillator), so in the code I used ADC_FOSC_32 for my configuration bit (page 16 in the MCC18 libraries pdf file). - Right before doing the conversion, I am using setChanADC to specificy which pin on PORTA I want to do the conversion for - although there are other operations between the conversions, I created a no-op delay loop that cycles through 180 operations after my setChanAdc() function call. I am assuming 1 instruction per 2.5e-7 second, at 4Mhz. I read in the datasheet (page 187) that there is a A/D changing time, and recall reading somewhere else in the datasheet that it is typically 20us. Therefore the no-op loop alone exceeds this 20us requirement. - calculated my desired hex value for Vx [ ( V / Vdd) * 1023 ] ---- convert answer to hex ---> Hex value wanted from A/D conversion - have finally gotten so frustrated/baffled, that I hooked up my 18f452 onto the PICDEM 2 board in debug mode, and am looking at the result of my A/D conversion in the software window with breakpoints. ============================================== ========= Explanation of Trouble ========= I am NOT having trouble with this conversion. It is on pin2, which is ADC_CHAN0 / PORTAbits.RA0. The first conversion is the voltage off a POT directly to pin2. Values can range from ~0v to ~5v. When using the PICDEM 2 board in debug mode, I watch the window for my ADC value, and it increases and decreases in a manner that corresponds with the voltage changed by the pot. The second conversion is one I am having trouble with (the 3rd is the same nature as the second, and have excluded it from my question). I am now running my 18F452 on the PICDEM board with MPLAB 6.4, looking at the value returned from the A/D conversion (in my code, it is the last function call and the variable is 'a2dResult'). This takes place in the function call checkLight(). When I start up my code in debug mode, I begin simple testing and put 5v (my Vdd) onto pin 3 / ADC_CHAN1. With breakpoints and the MPLAB Watch window I see that the returned value is an expected 0x3FF. I then try the same, by applying 0v on pin 3. Then the A/D conversion returns an expected 0x000 value. However, I placed a voltage divider on my PICDEM board, and tried to measure the voltage, and I get a hex value returned to the variable 'a2dResult'. After that, if I reapply 5v or 0v to pin 3 (ADC_CHAN1) I no longer get the expected 0x3FF or 0x000 value, or anything remotely close to it. The readings for ADC_CHAN1 become very unpredictable, however the A/D conversions for ADC_CHAN0 (pin 2 w/ the POT) remain stable and continue to be accurate. I read in the datasheet that the maximum impedance for analog sources is 2.5Kohm, but I am not sure if this. What I would like to do is to be able to accurately read off ADC_CHAN1 and ADC_CHAN2 in my program. I am not sure if I am doing something wrong with my code, hardware setup, or what. I have a suspicion it is software, as my hardware circuits are quite simple. If anyone can help, please let me know. Thanks, Greg ============================================== ========= Code ========= (some of the formatting might get lost when I click submit - sorry!) /* Include Libraries */ #include <p18f452.h> /* for TRISB and PORTB declarations */ #include <adc.h> /* A/D library */ #include <stdlib.h> /* Standard Library */ /**********************************************/ /* Function Prototypes */ int checkSpeed( void ); void delay(int, int); void checkLight( void ); int checkAdc( int ); /***********************************************/ /* Variable Declaration */ /* */ /* main() */ int test = 0; // test variable used in main to determine if Ra1 is detecting high load (temp) int dipVal = 0; // value returned from checkDip() function call int speedVal = 0; // speed setting returned from checkSpeed() function call int onTime = 0; // max amount of time a particular channel/light can be turned on int offTime = 0; // amount of time a channel/light will be turned off int delayCounter = 0; // counter variable, useed in output display engine for on and off time int speedCounter = 1; // used in nested loop to get around max numeric value -- full explanation in dev notes int curOutput = 1; // current chanel being output /* checkSpeed() */ int a2dSpeed = 0 ; // value obtained from a2d conversion int userInputSpeed = 0; // speed setting, inferred from a2dSpeed value, returned to main // 1 = slow, 2 = medium, 3 = fast /* delay() */ int i = 0; // counter, used for delay loop int j = 1; // counter, used for number of loops -- speed control /* checkLight() */ //macros int bright = 1; // alias used for code readability, and quick changes int nightTime = 0; // macro definition --> for code readability --> digital value of a2dLightResult value int dayTime = 2; // macro definition --> for code readability --> digital value of a2dLightResult value //counters in state tests int brightTestCount = 0; int darkTestCount = 0; //current light value in state tests int a2dLightResult; // Hex value obtained from ADC reading on channel 1 (pin 3) int currentLight = 0; // digital value (night/day) of a2dLightResult which is the current light reading //threshold settings int lightThreshold = 0x01F; // light threshold. 346+ = nighttime, 346- = daytime int maxLightCount = 15; // maximum number of consecutive light/dark test results allowed /* checkAdc */ int temp = 0; // counter used for ADC delay loop int adcDelay = 180; // delay required for adc reading // 20uS wait time + generious safety margin of 50% int a2dResult = 0; // result obtained from A/D conversion void main( void ) { /* Initialize Configuration */ TRISA = 0b00000111; // configs first 3 ports of PORTA for INPUT -- used for checkSpeed() TRISC = 0xFF; // configs PORTC for INPUT -- used for checkDip() TRISD = 0x00; // configs PORTD for OUTPUT -- used for light output TRISB = 0x00; // configs PORTB to all output pins /* configure A/D convertors */ /* detailled explanation is located at: p 16-18 in MPLAB-C18-Libraries.pdf */ /* ADC_FOSC_32 -> a/d clock source uses FOSC/32 ADC_RIGHT_JUST -> result in least significant bits ADC_8ANA_0REF -> VREF+ = Vdd and VREF- = Vss (both analog) / in my case Vdd = ~5v and Vss = ~0v ADC_CH# -> the channel being used ADC_INT_OFF -> disable interrupts */ /* ADC_CH0 -> speed */ OpenADC( ADC_FOSC_32 & ADC_RIGHT_JUST & ADC_8ANA_0REF,ADC_CH0 & ADC_CH1 & ADC_CH2 & ADC_INT_OFF ); /* checkSpeed() */ /* main program */ while(1) { /* (re)initialize values */ speedVal = 0; dipVal = 0; /* obtain user input */ checkLight(); // detects amount of ambient light speedVal = checkSpeed(); // check speed setting } /* end while(1) */ } /* end main() */ /*************************************************** Function: checkSpeed() Arguments: none Return: int userInputSpeed -> digitized value of user's speed selection (1 = slow, 2 = medium, 3 = fast) I/O Pins Used: PORTA -> RA0 Description: checkSpeed() checks PORTA.RA0 and through a series of if statements, converts the voltage into one of 3 values and returns this value ****************************************************/ int checkSpeed ( void) { a2dSpeed = checkAdc(ADC_CH0); // check ADC on channel A0, which is pin 2 /* Interpret a2d value into slow/medium/fast speed */ if( a2dSpeed <= 341) // slow setting userInputSpeed = 1; else if( (a2dSpeed <= 682) && (a2dSpeed >= 342) ) // medium setting userInputSpeed = 2; else if ( (a2dSpeed <= 1023) && (a2dSpeed >= 683) ) // fast setting userInputSpeed = 3; else userInputSpeed = -1; // signifies error w/ a2d conversion return userInputSpeed; /* return obtained value */ } /* end checkSpeed() */ void checkLight( void ) { /* (re)init values */ a2dLightResult = -1; currentLight = -1; /* read ADC value */ a2dLightResult = checkAdc( ADC_CH1 ); // obtain ADC reading from channel 1 (pin 3) /* give a2dLightResults a finite, digital value of 'night' or 'day' */ if(a2dLightResult >= 0x1F0) // nighttime PORTB = 1; if(a2dLightResult < 0x1F0) // daytime PORTB = 15; } int checkAdc( int portaChan ) { // (re)init variables a2dResult = -1; // result of adc read temp = 0; // counter used in adc delay loop /* AtoD Conversion */ /* CloseADC() is not used, as nowhere in the MCC18 libraries documentation, or PIC18F452 datasheet does it suggest leaving an A/D converter on is harmful or discouraged. Opening the A/D converter once (in main()'s init period, and leaving it open saves some computational time */ SetChanADC( portaChan ); // Open ADC channel specified by user /* research timing constraings when using SetChanADC function call */ /* p187 - 188 in pic18f452 datasheet */ while(temp < adcDelay) // temporary solution temp++; ConvertADC(); // Start conversion while( BusyADC() ); // Wait for completion a2dResult = ReadADC(); // Read result return a2dResult; } |
|
I am not going to be able to make suggestions re: your problem as I have never used the version of C that you are using. However, I would suggest that you cut your code down to the essence of the problem. You have dozens of variables, dozens of lines of code, all unrelated to the problem at hand. I would think it would be easier to do the troubleshooting with just a few lines of code specific to getting the A/D value and displaying it. Perhaps someone else around here can help once the code is down to a manageable size. Also, I was wondering why you set speedVal to 0, then grabbed an A/D value, stuffed in speedVal and turned around and set it back to 0. It's probably not important to this problem but it raised an eyebrow. --- In , scubagreg7777777 <no_reply@y...> wrote: > > This is an update to my earlier posted problem. I have now changed my > openADC() function call to only use 1 channel, and rely on the > setADCChannel() function. It looks like this: > OpenADC( ADC_FOSC_32 & ADC_RIGHT_JUST & ADC_8ANA_0REF,ADC_CH0 & > ADC_INT_OFF ); > I have not experienced any success yet. When putting a 5v signal on > pin 3 (ADC_CHAN1) and receive values of 377 to 3FF. This, itself is > strange, as I can verify with a multimeter that the 5v signal is > almost identical to the 5v powering the chip ( +/- 0.01V). > > However, when I apply a ground signal to pin 3, I receive an ADC value > of 0x2AF, which is far too high. I have verified that it is indeed a > ~0V signal going into pin 3. > > Any help is appreciated. I also have increased my delay loop in the > checkAdc() function to cycle 1800 times, from 180 times. > > Thanks, > Greg > ----------------------- > > Hi everyone, > > I'm still quite new to micros, and am doing a project on the > PIC18F452. I am experiencing some troubles with ADC conversion, and > think that it is a simple solution, but I'm not sure what it is. I > tried to provide all the pertienent info, and explain my problem. If > someone can please take a look at it, and let me know what I'm doing > wrong I would really appreciate it. > ============================================== > ========= H/W and S/W setup ========= > - PIC18f452 running on a 4MhZ oscillator > - using PICDEM 2 Board and PCB I created > - MCC18 C compiler > - MPLAB 6.4 > > I am doing three A/D conversions on PORT A. In all three cases, I > take the hex value returned from the A/D conversion and, using > thresholds, assign a discrete "digital" value for use in my main program. > > I am experiencing some troubles with accuracy of the ADC. > ============================================== > ========= What I have done so far ========= > > - double checked my sample time (ADC_FOSC / Ta/d ) value. From the > 18F452 datasheet (page 188) I selected a healthy buffer time, using > TOSC32 (my PIC is running off a 4Mhz oscillator), so in the code I > used ADC_FOSC_32 for my configuration bit (page 16 in the MCC18 > libraries pdf file). > > - Right before doing the conversion, I am using setChanADC to > specificy which pin on PORTA I want to do the conversion for > > - although there are other operations between the conversions, I > created a no-op delay loop that cycles through 180 operations after my > setChanAdc() function call. I am assuming 1 instruction per 2.5e-7 > second, at 4Mhz. I read in the datasheet (page 187) that there is a > A/D changing time, and recall reading somewhere else in the datasheet > that it is typically 20us. Therefore the no-op loop alone exceeds > this 20us requirement. > > - calculated my desired hex value for Vx [ ( V / Vdd) * 1023 ] > ---- convert answer to hex ---> Hex value wanted from A/D conversion > > - have finally gotten so frustrated/baffled, that I hooked up my > 18f452 onto the PICDEM 2 board in debug mode, and am looking at the > result of my A/D conversion in the software window with breakpoints. > > > ============================================== > ========= Explanation of Trouble ========= > > I am NOT having trouble with this conversion. It is on pin2, which is > ADC_CHAN0 / PORTAbits.RA0. The first conversion is the voltage off a > POT directly to pin2. Values can range from ~0v to ~5v. When using > the PICDEM 2 board in debug mode, I watch the window for my ADC value, > and it increases and decreases in a manner that corresponds with the > voltage changed by the pot. > > The second conversion is one I am having trouble with (the 3rd is the > same nature as the second, and have excluded it from my question). I > am now running my 18F452 on the PICDEM board with MPLAB 6.4, looking > at the value returned from the A/D conversion (in my code, it is the > last function call and the variable is 'a2dResult'). This takes place > in the function call checkLight(). When I start up my code in debug > mode, I begin simple testing and put 5v (my Vdd) onto pin 3 / > ADC_CHAN1. With breakpoints and the MPLAB Watch window I see that the > returned value is an expected 0x3FF. I then try the same, by applying > 0v on pin 3. Then the A/D conversion returns an expected 0x000 value. > > However, I placed a voltage divider on my PICDEM board, and tried to > measure the voltage, and I get a hex value returned to the variable > 'a2dResult'. After that, if I reapply 5v or 0v to pin 3 (ADC_CHAN1) I > no longer get the expected 0x3FF or 0x000 value, or anything remotely > close to it. The readings for ADC_CHAN1 become very unpredictable, > however the A/D conversions for ADC_CHAN0 (pin 2 w/ the POT) remain > stable and continue to be accurate. > > I read in the datasheet that the maximum impedance for analog sources > is 2.5Kohm, but I am not sure if this. What I would like to do is to > be able to accurately read off ADC_CHAN1 and ADC_CHAN2 in my program. > I am not sure if I am doing something wrong with my code, hardware > setup, or what. I have a suspicion it is software, as my hardware > circuits are quite simple. If anyone can help, please let me know. > > Thanks, > Greg > > ============================================== > ========= Code ========= > (some of the formatting might get lost when I click submit - sorry!) > > > /* Include Libraries */ > #include <p18f452.h> /* for TRISB and PORTB declarations */ > #include <adc.h> /* A/D library */ > #include <stdlib.h> /* Standard Library */ > /**********************************************/ > /* Function Prototypes */ > > int checkSpeed( void ); > void delay(int, int); > void checkLight( void ); > int checkAdc( int ); > /***********************************************/ > /* Variable Declaration */ > /* */ > > /* main() */ > int test = 0; // test variable used in main to determine if Ra1 is > detecting high load (temp) > > int dipVal = 0; // value returned from checkDip() function call > int speedVal = 0; // speed setting returned from > checkSpeed() function call > int onTime = 0; // max amount of time a particular channel/light > can be turned on > int offTime = 0; // amount of time a channel/light will be turned off > int delayCounter = 0; // counter variable, useed in output > display engine for on and off time > int speedCounter = 1; // used in nested loop to get around max > numeric value -- full explanation in dev notes > int curOutput = 1; // current chanel being output > /* checkSpeed() */ > int a2dSpeed = 0 ; // value obtained from a2d conversion > int userInputSpeed = 0; // speed setting, inferred from a2dSpeed > value, returned to main > // 1 = slow, 2 = medium, 3 = fast > > /* delay() */ > int i = 0; // counter, used for delay loop > int j = 1; // counter, used for number of loops -- speed control > /* checkLight() */ > //macros > int bright = 1; // alias used for code readability, and > quick changes > int nightTime = 0; // macro definition --> for code > readability --> digital value of a2dLightResult value > int dayTime = 2; // macro definition --> for code > readability --> digital value of a2dLightResult value > //counters in state tests > int brightTestCount = 0; > int darkTestCount = 0; > //current light value in state tests > int a2dLightResult; // Hex value obtained from ADC reading on > channel 1 (pin 3) > int currentLight = 0; // digital value (night/day) of > a2dLightResult which is the current light reading > //threshold settings > int lightThreshold = 0x01F; // light threshold. 346+ = nighttime, > 346- = daytime > int maxLightCount = 15; // maximum number of consecutive > light/dark test results allowed > > /* checkAdc */ > int temp = 0; // counter used for ADC delay loop > int adcDelay = 180; // delay required for adc reading > // 20uS wait time + generious safety margin of 50% > int a2dResult = 0; // result obtained from A/D conversion > void main( void ) > { > > /* Initialize Configuration */ > TRISA = 0b00000111; // configs first 3 ports of PORTA for INPUT -- > used for checkSpeed() > TRISC = 0xFF; // configs PORTC for INPUT -- used for checkDip() > TRISD = 0x00; // configs PORTD for OUTPUT -- used for light > output > TRISB = 0x00; // configs PORTB to all output pins > > > /* configure A/D convertors */ > /* detailled explanation is located at: p 16-18 in > MPLAB-C18-Libraries.pdf */ > /* ADC_FOSC_32 -> a/d clock source uses FOSC/32 > ADC_RIGHT_JUST -> result in least significant bits > ADC_8ANA_0REF -> VREF+ = Vdd and VREF- = Vss (both analog) / in my > case Vdd = ~5v and Vss = ~0v > ADC_CH# -> the channel being used > ADC_INT_OFF -> disable interrupts */ > > /* ADC_CH0 -> speed */ > OpenADC( ADC_FOSC_32 & ADC_RIGHT_JUST & ADC_8ANA_0REF,ADC_CH0 & > ADC_CH1 & ADC_CH2 & ADC_INT_OFF ); /* checkSpeed() */ > /* main program */ > while(1) > { > > /* (re)initialize values */ > speedVal = 0; > dipVal = 0; > /* obtain user input */ > checkLight(); // detects amount of ambient light > speedVal = checkSpeed(); // check speed setting > } /* end while(1) */ > } /* end main() */ > > > /*************************************************** > Function: checkSpeed() > Arguments: none > Return: int userInputSpeed -> digitized value of user's speed selection > (1 = slow, 2 = medium, 3 = fast) > I/O Pins Used: PORTA -> RA0 > > Description: checkSpeed() checks PORTA.RA0 and through a series of if > statements, > converts the voltage into one of 3 values and returns this > value > ****************************************************/ > int checkSpeed ( void) > { > a2dSpeed = checkAdc(ADC_CH0); // check ADC on channel A0, > which is pin 2 > /* Interpret a2d value into slow/medium/fast speed */ > if( a2dSpeed <= 341) // slow setting > userInputSpeed = 1; > else if( (a2dSpeed <= 682) && (a2dSpeed >= 342) ) // medium setting > userInputSpeed = 2; > else if ( (a2dSpeed <= 1023) && (a2dSpeed >= 683) ) // fast setting > userInputSpeed = 3; > else > userInputSpeed = -1; // signifies error w/ a2d conversion > return userInputSpeed; /* return obtained value */ > > } /* end checkSpeed() */ > > > void checkLight( void ) > { > /* (re)init values */ > a2dLightResult = -1; > currentLight = -1; > /* read ADC value */ > a2dLightResult = checkAdc( ADC_CH1 ); // obtain ADC reading > from channel 1 (pin 3) > > /* give a2dLightResults a finite, digital value of 'night' or 'day' */ > if(a2dLightResult >= 0x1F0) // nighttime > PORTB = 1; > > if(a2dLightResult < 0x1F0) // daytime > PORTB = 15; > > } > > > int checkAdc( int portaChan ) > { > // (re)init variables > a2dResult = -1; // result of adc read > temp = 0; // counter used in adc delay loop > > /* AtoD Conversion */ > /* CloseADC() is not used, as nowhere in the MCC18 libraries > documentation, or PIC18F452 datasheet > does it suggest leaving an A/D converter on is harmful or > discouraged. Opening the A/D converter > once (in main()'s init period, and leaving it open saves some > computational time > */ > SetChanADC( portaChan ); // Open ADC channel specified by user > > /* research timing constraings when using SetChanADC function call */ > /* p187 - 188 in pic18f452 datasheet */ > while(temp < adcDelay) // temporary solution > temp++; > > ConvertADC(); // Start conversion > while( BusyADC() ); // Wait for completion > a2dResult = ReadADC(); // Read result > return a2dResult; > } |
I don’t know if this will help, but I wrote the following program to study and demonstrate the two (I think its two) wait periods needed in the A to D part in the PIC18F family. Hope this helps.
George
;****************************************************************************** ; Copy and distribute freely. ; ; The author of this program clames no liability from its use ; ; and makes no clames as to its reliability. ; ; ; ; If you include your e-mail address I’ll send you updates and other ; ; programs as I complete them. ; ; George Dorian ; ; PO Box 233 ; ; Kentfield CA, 94914 ; ; ; ; This program clears the first 0x3FF bytes of RAM then reads the A to D ; ; converter MAX_COUNT times. The RAM byte corresponding to the A to D value ; ; is incremented each time. For example: Set a DC voltage on an A to D ; ; channel, (I’m using ch 0.) If an A to D reading was 0x13F then that RAM ; ; address will be incremented. ; ; ; ; Let this program run through an emulator or the ICD 2 debugger (I used the ; ; ICD 2 with this code, and it works fine.) for a few seconds, then pause the ; ; run, then examine RAM locations 0x000 through 0x3FF If you have a good ; ; anti-aliasing filter and you have a proper acquisition and conversion time ; ; set up with the A to D converter then you should see one RAM location with ; ; the same value of MAX_COUNT. If you don’t have this set up right then ; ; you’ll see some other RAM locations with numbers. ; ; ; ; This allows you to see if there is any aliasing and if you’re allowing for ; ; proper acquisition and conversion time with the A to D. ; ; ; ; As an experiment, try reducing ACQ_SET to a very low number, like 1 or 3 or ; ; something. You should see a few RAM locations below the intended location ; ; being incremented. This is because you’r not allowing enough acquisition ; ; time for the A to D converter. ; ; ; ; This code was written with a PIC18F452. Be sure to use a PIC18F chip with ; ; at lest 5 RAM banks. Four banks for the RAM incrementing and one bank for ; ; “count” and “acq_count”. I was using an 8 Meg clock oscillator. Your MPU ; ; speed will make a big difference too if you use a different frequency. ; ; ; ; ;******************************************************************************
LIST PF452 ;directive to define processor #include <P18F452.INC> ;processor specific variable definitions
;****************************************************************************** ;Configuration bits
__CONFIG _CONFIG1H, _OSCS_OFF_1H & _HS_OSC_1H __CONFIG _CONFIG2L, _BOR_OFF_2L & _PWRT_ON_2L __CONFIG _CONFIG2H, _WDT_OFF_2H __CONFIG _CONFIG3H, _CCP2MX_OFF_3H __CONFIG _CONFIG4L, _STVR_OFF_4L & _LVP_OFF_4L & _DEBUG_ON_4L __CONFIG _CONFIG5L, _CP0_OFF_5L & _CP1_OFF_5L & _CP2_OFF_5L & _CP3_OFF_5L __CONFIG _CONFIG5H, _CPB_OFF_5H & _CPD_OFF_5H __CONFIG _CONFIG6L, _WRT0_OFF_6L & _WRT1_OFF_6L & _WRT2_OFF_6L & _WRT3_OFF_6L __CONFIG _CONFIG6H, _WRTC_OFF_6H & _WRTB_OFF_6H & _WRTD_OFF_6H __CONFIG _CONFIG7L, _EBTR0_OFF_7L & _EBTR1_OFF_7L & _EBTR2_OFF_7L & _EBTR3_OFF_7L __CONFIG _CONFIG7H, _EBTRB_OFF_7H
;****************************************************************************** MAX_COUNT equ 0xff ;Do this many A to D conversions. ACQ_SET equ .20 ;Timer for acquistion time.
A2D_0 equ b'00000000' A2D_1 equ b'00001000' A2D_2 equ b'00010000' A2D_3 equ b'00011000' A2D_4 equ b'00100000' A2D_5 equ b'00101000' A2D_6 equ b'00110000' A2D_7 equ b'00111000'
;****************************************************************************** ;Variable definitions
CBLOCK 0x400 count acq_count
ENDC
;****************************************************************************** ;Vectors ORG 0x0000 goto Main ;Reset vector.
ORG 0x0008 ; goto High_ISR ;High priority interrupt vector
ORG 0x0018 ; goto Low_ISR ;Low priority interrupt vector and routine
;****************************************************************************** ;Start of main program Main: movlw 0x04 ;Set BSR to Bank 4. (Only used for 'count' and 'aqu_count') movwf BSR, ACCESS clrf count clrf acq_count
lfsr FSR0, 0x00 ;Clear RAM. Clear_RAM_Loop clrf POSTINC0, ACCESS ;Clear RAM pointed to by INDF register and inc. movlw 0x00 cpfseq FSR0L, ACCESS bra Clear_RAM_Loop movlw 0x04 cpfseq FSR0H, ACCESS bra Clear_RAM_Loop
movlw b'11001110' ;setup A/D converter. movwf ADCON1, ACCESS Loop movlw b'10000001' | A2D_0 ;Select A/D channel 0. movwf ADCON0, ACCESS
movlw ACQ_SET ;Wait for aquisition time, then... movwf acq_count Acq_Loop decfsz acq_count, F bra Acq_Loop
bsf ADCON0, GO_DONE, ACCESS ; start conversion. AD_Wait btfsc ADCON0, GO_DONE, ACCESS ;Did A/D conversion compleat? bra AD_Wait ; No, loop back.
movff ADRESL, FSR0L ;Load A/D output to FSR0, then... movff ADRESH, FSR0H incf INDF0, F, ACCESS ; incroment the RAM byte corisponding to A/D reading.
incf count, F ;Have we compleated n A/D conversions? movlw MAX_COUNT cpfseq count bra Loop ; No, continue.
End_Loop bra End_Loop
END
-----Original
Message-----
|