Jump to content
43oh

differential photo sensor


Recommended Posts

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.
	}

}
}

Link to post
Share on other sites

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

Link to post
Share on other sites
  • 1 month later...

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);
	}
}
}

Link to post
Share on other sites

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.

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...