kenemon 29 Posted September 10, 2011 Share Posted September 10, 2011 Hi All, trying to make a photo sensor, I came across this nice example. Simple, and it works well! http://gushh.net/blog/msp430-launchpad-led-as-photodiode/ When I improvise with his code a little, I am running into some strange problems. Can anyone see any obvious errors I have made, my exp with the ADC is surely lacking. You input is welcome :thumbup: #include "msp430g2452.h" // #define LED_SENSEL INCH_0 // LED sensor L #define LED_SENSER INCH_1 //LED sensor R unsigned int adcvalL = 0; unsigned int adcvalR = 0; unsigned int analogRead(unsigned int pin) { ADC10CTL0 = ADC10ON + ADC10SHT_2 + SREF_1 + REFON + REF2_5V; ADC10CTL1 = ADC10SSEL_0 + pin; ADC10CTL0 |= ENC + ADC10SC; while (1) { if ((ADC10CTL1 ^ ADC10BUSY) & ((ADC10CTL0 & ADC10IFG)==ADC10IFG)) { ADC10CTL0 &= ~(ADC10IFG +ENC); break; } } return ADC10MEM; } void main(void) { unsigned int i, delay; WDTCTL = WDTPW + WDTHOLD; // Hold the watchdog. P1DIR = BIT6; // L LED indicator P1DIR = BIT7; // R LED indicator while (1){ // Multi-sampling (8 samples with delay for stability). adcvalL = 0; for ( i=0; i < 8; i++ ) { adcvalL += analogRead( LED_SENSEL ); // Read the analog input. adcvalR += analogRead( LED_SENSER ); // Read the analog input. delay = 1000; while (--delay); } adcvalL >>= 3; // division by 8 adcvalR >>= 3; // division by 8 // Interpret the result if ( adcvalL < 500 ){ P1OUT |= BIT6; // Turn on L LED indicator if ( adcvalR < 500 ){ P1OUT |= BIT7; // Turn on R LED indicator }else{ P1OUT = 0x00; // Turn off the entire Port 1, thus turning off the LED as well. } } } Quote Link to post Share on other sites
bluehash 1,581 Posted September 10, 2011 Share Posted September 10, 2011 What are your problems. Quote Link to post Share on other sites
kenemon 29 Posted September 10, 2011 Author Share Posted September 10, 2011 thanks for the reply blue. I want to compare the L & R sensors ultimately. Here I am trying to use INCH_0 and INCH_1 simultaneously so that I can compare adcvalL and adcvalR. I cant get both inputs to register, one at time is fine. I think it is an issue with my ADC configuration. Thanks. KB Quote Link to post Share on other sites
jsolarski 94 Posted September 17, 2011 Share Posted September 17, 2011 you can only measure one ADC at a time. Quote Link to post Share on other sites
gwdeveloper 275 Posted September 17, 2011 Share Posted September 17, 2011 If you configure your ADC to use the DTC, it will happen so fast it will appear simultaneous. Since you're using INCH_0 and INCH_1, you can set the ADC to sample those sequentially and continuously. See this post http://www.43oh.com/forum/viewtopic.php?f=8&t=1418 for a tip on making the DTC data easy to read. kenemon 1 Quote Link to post Share on other sites
kenemon 29 Posted October 28, 2011 Author Share Posted October 28, 2011 Hi GW, i had a moment to get back to this ADC issue. I tried putting those items you mentioned in my code but it hasnt seemed to help. I am still getting erratic readings from the ADC without any basis. Can you find any issues with this code? /* LED as Photo-Sensor2 / KB, interpreted from others who know what the hell they are doing / Sept 15, 2011 */ #include "msp430g2452.h" // Change the header to "msp430x20x2.h" if you're using the default MCU bundled with the LaunchPad. #define LED_SENSEL INCH_0 // Left sensor #define LED_SENSER INCH_1 // Right sensor #define LED_INDL BIT6 //Left indicator #define LED_INDR BIT7 //Right indicator unsigned int adcvalL = 0; // Left value register unsigned int adcvalR = 0; //Right value register volatile int ADCdata[32]; unsigned int analogRead(unsigned char pin) { ADC10CTL0 &= ~ENC; // Disable ADC10 if (pin == LED_SENSER) { // IF Right scan then ADC10CTL1 &= ~INCH_0; // Deselect ADC Channel 5 (Left) ADC10CTL1 |= INCH_1; // Select ADC Channel 2 , Right LDR } else { // Scanning Left ADC10CTL1 &= ~INCH_1; // Deselect ADC Channel 2 ADC10CTL1 |= INCH_0; // Select ADC Channel 5, Left LDR } ADC10CTL0 |= ENC + ADC10SC; // Enable ADC10 and Conversion start while (ADC10CTL1 & ADC10BUSY); // Wait for ADC Conversion return(ADC10MEM); // Return ADC Value } void DelayMs(unsigned int ms) { while(ms--) { __delay_cycles(1000); // 1 ms delay for 1 MHz Internal Clock } } void main(void) { unsigned int i; WDTCTL = WDTPW + WDTHOLD; // Stop WDT // P1.6 and P1.7 output, Other as Input P1DIR = (LED_INDL | LED_INDR); // Enable the pull-down resistor on the unused input ports //P1REN = BIT4 + BIT5; P1REN = BIT2 + BIT4 + BIT3; // Start the ADC10 Peripheral // Vref = Vcc, 16 ADC Clock, Enable ADC10 ADC10CTL0 = SREF_0 + ADC10SHT_1 + ADC10ON; // Sample-and-hold ADC10SC bit, ADC10 Clock /1, ADC10 Source Clock, Single Channel Conversion ADC10SA = (unsigned int)ADCdata; ADC10DTC1 = 32; ADC10CTL1 = SHS_0 + ADC10DIV_0 + ADC10SSEL_0 + CONSEQ_0; ADC10AE0 = LED_SENSEL + LED_SENSER; // Enable A4 and A5 as ADC Input DelayMs(100); // Wait for ADC Ref to settle for(; { for ( i=0; i < 64; i++ ) { adcvalR += analogRead( LED_SENSER ); // Read the analog input. adcvalL += analogRead( LED_SENSEL ); // Read the analog input. } adcvalL >>= 4; // division by 8 to get avg adcvalR >>= 4; // division by 8 to get avg // Interpret the result P1OUT = 0x00; if ( (adcvalL > (adcvalR))) { P1OUT |= LED_INDL; // Turn on the left Green LED. P1OUT &= ~LED_INDR; DelayMs(300); } else if ( (adcvalR > (adcvalL))) { P1OUT |= LED_INDR; // Turn on the right LED. P1OUT &= ~LED_INDL; DelayMs(300);} else {P1OUT = 0x00; DelayMs(300); } } } Quote Link to post Share on other sites
gwdeveloper 275 Posted October 28, 2011 Share Posted October 28, 2011 Hello Kenemon, there a few things you could change to better use the ADC's DTC. The ADC should be enabled inside of the main loop and left running. Using the DTC, you can enable continuous repeated conversions and turn the cpu off. You can enter low power modes this way and not have the cpu turning the peripheral on and off. Try looking at the code I posted here http://www.43oh.com/forum/viewtopic.php?f=9&t=1701#p11692. In particular, the ADC_init function, and block below from the main loop. I'm using the continuous mode and repeating conversions. This does collect data from ADC channels, 5-0 and then filter out the 2 channels I am actually using. (Which are the same channels you are using.) // sample ADC10 and use DTC ADC10CTL0 &= ~ENC; while (ADC10CTL1 & BUSY); // Wait if ADC10 core is active ADC10SA = (unsigned int)ADCdata; // Data buffer start ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start // get float of left channel P1.4 left = 0; for (l=LEFT; l < MAXADC; l+=6) { left += ADCdata[l]; } left /= SAMPLES; // get float of right channel P1.5 right = 0; for (r=RIGHT; r < MAXADC; r+=6) { right += ADCdata[r]; } right /= SAMPLES; Let me know if you can't sort out the code on that link. kenemon 1 Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.