Jump to content
43oh

[ ENDED ] June 2011 - 43oh Project of the Month Contest


The May-June 2011 - 43oh Project of the Month Contest  

27 members have voted

You do not have permission to vote in this poll, or see the poll results. Please sign in or register to vote in this poll.

Recommended Posts

  • Replies 66
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

Popular Posts

To measure the CIR carrier frequency, each individual pulse of IR must be detected. Common IR demodulator modules can not do this - they respond to a burst of IR, not each pulse.   There are parts m

As this was suggested to me last month, I will try and submit my color matching game. As it is a beginner's first project, I am not sure if it is really worthy to be featured in a contest but you neve

Here's my project, don't have any pics or videos of it in action yet, will post some ASAP. I am using some of RobG's LCD code:http://www.43oh.com/forum/viewtopic.php?f=9&t=540 I found a 35-bit l

Posted Images

I'll open the competition (and set the bar low enough to encourage others) with my latest creation - Persistence of vision on a diet. Essentially just a proof of concept for me to waste a few hours on, but the results were good enough to put a satisfied smile on my face. It uses 8 LEDs and 1 resistor in conjunction with an MSP430G2211, and the code just switches columns after a pre-set delay. The keen eyed out there might spot the lack of a resistor in series with the LEDs - I'm relying on the current limited outputs of the uC to prevent any excess current/heat/smoke/fire and it seems to work.

 

EDIT: I'm "getting away with it" but the outputs aren't current limited, and should have a resistor in series.

 

Enough babble, the circuit in all it's glory.

 

TheCircuit.jpg

 

The code.

#include       //This is the header file for your chip.

void delay(unsigned int delayTime);


void main(void) {         

  WDTCTL = WDTPW + WDTHOLD;    //Hold the WDT (WatchDog Timer)

  P1DIR = 0xff;            //Set Port 1 (P1) to output.

  unsigned int i=250;         //This is the delay value between each column (found by trial and error)

  while(1){   

     P1OUT = 0x00;            
     delay(i);               
     P1OUT = 0x7C;            //Mr GreenFace's first column.
     delay(i);               //The delay
     P1OUT = 0x82;            
     delay(i);
     P1OUT = 0xA9;
     delay(i);
     P1OUT = 0xA1;
     delay(i);
     P1OUT = 0xA9;
     delay(i);
     P1OUT = 0x82;
     delay(i);
     P1OUT = 0x7C;            //Mr GreenFace's last column.
     delay(i);
     P1OUT = 0x00;
     delay(i);

  }

}

void delay(unsigned int delayTime){
  int x;
  for (x=0;x      x=x*1;
  }
} 

 

The (very dodgy) schematic is attached.

 

Video of the project in action.

 

 

The circuit on stripboard.

 

circuit.jpg

 

First text effort.

 

Mike.jpg

 

An attempt at mixing inverse and regular text...Not great

 

inverse.jpg

 

About the best picture I managed to get...

 

43oh.jpg

post-2193-135135500297_thumb.jpg

Link to post
Share on other sites

As this was suggested to me last month, I will try and submit my color matching game. As it is a beginner's first project, I am not sure if it is really worthy to be featured in a contest but you never know... Plus, the prizes look extremely attractive.

 

This is an improved version which now features sound feedback to help the player.

The goal is to match a target color by adjusting separately red, green and blue components of an RGB LED. The length of the beeps and their pitch also help you into finding the proper combination.

The required parts are very few and the game is driven by a MSP430G2233. You can find some more details in the original post along with references to the websites I learnt/got inspiration from.

 

Here is a video of the resulting game :

 

 

Here is also the circuit

 

post-1281-13513550031_thumb.jpg

 

Finally, here is the code :

 

/*
******
Color matching game. By Fabrice C.
******
This is my first program with a microcontroller so 
everything is probably not as pretty as it should...

Original inspiration came from :
http://www.fangletronics.com/2010/02/amazing-dr-boardmans-colour-conundrum.html

A lot of code was inspired by the tutorials/examples from :
http://mspsci.blogspot.com/ 
and 
http://www.msp430launchpad.com/2010/09/simple-adc-example-on-launchpad.html
and
http://blog.hodgepig.org/2010/09/30/jam-jar-lamp/
*/

#include 
#include 
#include 
#include 


/****************************************************/

#define     P1_LED_BIT               (BIT0|BIT1|BIT2|BIT6|BIT7)
#define     P2_LED_BIT               (BIT6)

/****************************************************/



static  uint8_t led_brightness[6] = {0x00,0x00,0x00,0x00,0x00,0x00};
// This variable stores the brightness of the 2 RGB leds : {R1,G1,B1,R2,G2,B2}

static  uint32_t sys_ticks = 0;
// Used to keep track of PWM

static bool ADCDone = false;
// Flag to check that the ADC sampling is done

static uint16_t ADCValue;
// Result of ADC (converted value)

static int sampled_channel;
// Channel being sampled by ADC

static int seed;
// seed for random number generation

static long color_dif = 3000;
// Color_dif represents how close the player is from the target 

static uint32_t beep_tick =0;
// timer-linked counter for the beeper 

static bool beep_on = false;
// flag to determine if the beeper is supposed to be on or not.

static int beep_frequency = 40;
//The frequency of the beeping


/****************************************************/

static void cpu_init(void)
// Initialisation of the micro controller
{
   WDTCTL = WDTPW + WDTHOLD; // Stop Watch dog timer

   // configure system clock to about 16MHz
   BCSCTL1 &= ~(BIT0 + BIT1);  // set bits 0 and 1 to 0
BCSCTL1 |= BIT2 + BIT3;     // set bits 2 and 3 to 1
DCOCTL &= ~(BIT5 + BIT7);   // set bits 5 and 7 to 0
DCOCTL |= BIT6;             // set bit 6 to 1
   // seems like overkill but lower frequencies generated
   // quite a lot of flickering. PWM algo/usage may need improvement

   _enable_interrupt(); // to be able to use interrupts
   // Without this the timer and ADC callback functions would never be called.
}

bool match(int delta)
// function returning true if the 2 RGB values are within 
// a distance "delta" (euclidian distance)
{
int Dr; 
int Dg;
int Db;
Dr = (int)led_brightness[0]-led_brightness[3];
Dg = (int)led_brightness[1]-led_brightness[4];
Db = (int)led_brightness[2]-led_brightness[5];

unsigned int D;//no sqrt so no need for double
D = (unsigned int)((Dr*Dr)+(Dg*Dg)+(Db*Db));

color_dif = (long)D; //updating the color_dif value for the sound feedback (this is the lenght of the beeps)

// we now check channel by channel if the target is close or not.
if ((-8		Dr = 1;
else 
	Dr = 0;
if ((-8		Dg = 1;
else 
	Dg = 0;	
if ((-8		Db = 1;
else 
	Db = 0;

// Now we will modulate the frequency of the beep depending on the number of channels which are on target
// (None : low tone, all of them : high tone)	
 switch(Dr+Dg+Db)
   {
       case 0:
       	beep_frequency = 30;
       	break;
       case 1:
       	beep_frequency = 120;
       	break;
       case 2:
       	beep_frequency = 210;
       	break;	
       case 3:
       	beep_frequency = 250;
   }


// cannot manage to do a sqrt without getting a compiling error
// so I am comparing the 2 squared values instead.	
if ( D <= (delta*delta))
	return true;
else
	return false; 
}

void play_tune (int freq, int duration)
// Function that detracts sound modulation interrupts to play a given sound for a given duration
{
beep_frequency = freq;
color_dif = duration;
beep_tick = 0; //starts ticking 
beep_on=true; //makes sure the buzzer is on
while (1) 
{
	if (!beep_on)
	break; //stops when the end of the duration is reached
}


} 

void win (void)
// Procedure to show the player he won. LEDs blink and a short "tune" is played
{ 
int R;
int G;
int B;
R= led_brightness[3];
G= led_brightness[4];
B= led_brightness[5];
// saves current RGB values of the target color

//LEDs off
led_brightness[0] = 0;
led_brightness[1] = 0;
led_brightness[2] = 0;
led_brightness[3] = 0;
led_brightness[4] = 0;
led_brightness[5] = 0;

// plays the short "tune"
play_tune(0,3000);
play_tune(67,6000);
play_tune(75,6000);
play_tune(84,6000); 
play_tune(200,15000);
play_tune(40,1800);
play_tune(200,25000);
play_tune(0,1000);

	int n;
int i;
for (i=0; i<10; i++)
// blinks the 2 RGB leds 10 times
{
	for (n=0; n<1500; n++); // delay
	// LEDs on
	led_brightness[0] = R;
	led_brightness[1] = G;
	led_brightness[2] = B;
	led_brightness[3] = R;
	led_brightness[4] = G;
	led_brightness[5] = B;

	for (n=0; n<1500; n++); //delay

	//LEDs off
	led_brightness[0] = 0;
	led_brightness[1] = 0;
	led_brightness[2] = 0;
	led_brightness[3] = 0;
	led_brightness[4] = 0;
	led_brightness[5] = 0;
}

}


// Binary Code Modulation
static void bcm_tick(uint8_t led_ticks)
{
   uint8_t bcm1 = 0x00;
   uint8_t bcm2 = 0x00;

//  This commented code does not work so I used the code from
//  http://www.msp430launchpad.com/2010/09/simple-adc-example-on-launchpad.html
//  instead
//     if (led_brightness[0] <= led_ticks)
//                bcm1 |= BIT0;
//     if (led_brightness[1] <= led_ticks)
//                bcm1 |= BIT1;
//     if (led_brightness[2] <= led_ticks)
//                bcm1 |= BIT2;
//                
//     if (led_brightness[3] <= led_ticks)
//                bcm1 |= BIT6;
//     if (led_brightness[4] <= led_ticks)
//                bcm1 |= BIT7; //To be fixed : may want the BIT6 on this port to also stay on.
//     if (led_brightness[5] <= led_ticks)
//                bcm2 |= BIT7;  
//
//     P1OUT = bcm1;
//     P2OUT = bcm2;
//    
   switch(led_ticks)
   {
       case 0x1:
       case 0x2:
       case 0x4:
       case 0x8:
       case 0x10:
       case 0x20:
       case 0x40:
       case 0x80:
           // led_ticks is a power of 2
           if (led_brightness[0] & led_ticks)
               bcm1 |= BIT0;
           if (led_brightness[1] & led_ticks)
               bcm1 |= BIT1;
           if (led_brightness[2] & led_ticks)
               bcm1 |= BIT2;

           if (led_brightness[3] & led_ticks)
               bcm1 |= BIT6;
           if (led_brightness[4] & led_ticks)
               bcm1 |= BIT7; 

           if (led_brightness[5] & led_ticks)
               bcm2 |= BIT7;  


           if  (beep_frequency & led_ticks)
           	if (beep_on) //beeps if necessary
           		bcm2 |= BIT6;   


           P1OUT = bcm1;
           P2OUT = bcm2;
   }
}

// Timer0 ISR
#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A (void)
//Call back function when the timer ticks

{
   bcm_tick(sys_ticks);
   sys_ticks++;
   beep_tick++;
   if (beep_tick > color_dif)
   {
   	beep_tick = 0;
    	beep_on = !beep_on;
   } 

// Following was meant to work with other BCM function but did not work.
//    if (sys_ticks > 255 )
//    	sys_ticks = 0;
// This was meant to enter low power mode but interrups stopped for some reason
   //__bis_SR_register(CPUOFF + GIE);
   //__bic_SR_register_on_exit(CPUOFF);
}

void Single_Measure(unsigned int chan)
// Frunction starting the ADC sampling
{
    ADC10CTL0 &= ~ENC; // Disable ADC
ADC10CTL0 = ADC10SHT_3 + ADC10ON + ADC10IE; // 16 clock ticks, ADC On, enable ADC interrupt
ADC10CTL1 = ADC10SSEL_3 + chan; // Set 'chan', SMCLK
ADC10CTL0 |= ENC + ADC10SC; // Enable and start conversion

}
#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR (void)
// Call back function for when the ADC sampling is done
{
   ADCValue = ADC10MEM; //saves measured value from register into ADCValue variable
   ADCDone = true; // sets the flag acknowledging that the ADC is done
   //__bic_SR_register_on_exit(CPUOFF);
}


void Generate_New_Target(void)
// Generates a random color for the target of the game and plays a short tune
{
   uint32_t T = 0;

   while (1)
   {
      led_brightness[3] = rand();
   led_brightness[4] = rand();
   led_brightness[5] = rand();
   T = led_brightness[3] + led_brightness[4] + led_brightness[5];
   // We check the total brightness of the 3 components as we don't want a 
   // color to be too dark or too bright
   if (500 > T < 200)
   break ;
   }
   // plays a little tune to notify the start of the game
   play_tune(20,6000);
play_tune(80,6000);
play_tune(140,6000); 
play_tune(200,6000);
play_tune(250,9000);
play_tune(0,9000);

}


int main(void)
// Main Program
{
   cpu_init();

   // setup LED pins
   P1DIR |= P1_LED_BIT;   // All LED pins as outputs
   //select i/o function of pins
P2SEL &= ~(BIT6|BIT7); // Acitvates the 2 ports on pins 12 and 13
//set them as outputs
P2DIR = BIT6 | BIT7;
P2OUT &= ~(BIT6|BIT7);
   P1OUT &= ~P1_LED_BIT;  // Turn off LED

   // TimerA SMCLK in UP mode
   TACTL = TASSEL_2 | MC_1;
   // Enable interrupt for TACCR0 match
   TACCTL0 = CCIE;
   // Set TACCR0, starts timer. 
   TACCR0 = 130;  // This must be short enough to look good and long enough for TIMER0_ISR to complete
                  // but I don't really understand the magic number


//Measures the value of Channel 3 (R potentiometer)
Single_Measure(INCH_3);
while (1) // waits until the measurement is finished
{
	if (ADCDone)
	break;
}

ADCDone = false;
seed = ((uint32_t)ADCValue*255)/990; 
// uses the measured value as the seed for random number generation
// if a constant seed is used, the order in which the target colors 
// are asked will always be the same when the micro controller is reset.
// This way, provided the R potentiometer was changed since last time, 
// a new color will be asked first. (crude but it works most of the time)
srand(seed);
// Sets the R, G, and B brightness of the target color to a random value
Generate_New_Target();

   Single_Measure(INCH_3);
   sampled_channel = 1; // Keeps track of the channel being measured

   while(1) // Endless loop
   {

       // tests if the dialed in values are close enough to the target
       if (match(5) == true)
       {
       	win(); // display winning animation

       	// Sets a new color as target
       	Generate_New_Target();
       }


       if (ADCDone) // if we have a measurement result available
       {
           ADCDone = false;
           // my potentiometers are not the best ones, I never
           // manage to get the sampled value up to 1023 
           // so I clip everything to 990 in order to make
           // sure that the player can dial in a maximum
           // brightness value of FF
           if (ADCValue > 990) 
           	ADCValue = 990;
           switch(sampled_channel)
	    {
	    	// adjust the brightness of a LED to the value 
	    	// measured on the corresponding potentimeter
	    	// and makes ready to sample the next channel
	        case 1:
	            led_brightness[0] = ((uint32_t)ADCValue*255)/990;
	            Single_Measure(INCH_4);
	            sampled_channel = 2;
	        break;
	        case 2:
	        	led_brightness[1] = ((uint32_t)ADCValue*255)/990;
	            Single_Measure(INCH_5);
	            sampled_channel = 3;
	        break;
	        case 3:
	        	led_brightness[2] = ((uint32_t)ADCValue*255)/990;
	            Single_Measure(INCH_3);
	            sampled_channel = 1;
	        break;
	    }


       }



   }
}



 

Wish me luck for the contest and if you like this project, please don't hesitate to vote for me.

 

Cheers,

 

Fabrice

Link to post
Share on other sites

I have my contest idea working, so I will describe what is is. There is still some work to be done, so code and schematic will be posted later.

 

EDIT:

 

Created a thread for this project here

 

This thread will be updated after the whole project has been presented.

Link to post
Share on other sites

Hi NatureTM, Paulbo mentioned on his blog that there was some sound feedback to help the player but I think he turned it off in his video so I don't know how it would compare.

What I did here is to have the beep duration and intervals to get smaller as the color difference decreased. In addition to this, the pitch of the beep gets higher with the number of channels that match their individual targets.

This really helps the player as the game is really not that easy without the sound feedback. (while testing, I have been known to pause the program and use the debugger and cheat to find an elusive color)

Link to post
Share on other sites

I like the sound of your project oPossum.. I recently did something along similar lines but MUCH simpler. I had a broken Digi Photo frame I cannibalised and discovered an IR receiver on it. No part number but it worked along the lines of the usual ones (normally Hi, low when carrier freq detected etc).. I did the detective work manually that your project does automatically.

 

I measured the duration of the various pulses (encoded pulses) and sent the info via the USB UART to the PC. My problem was that I could only measure a max of about 20 pulses with the memory of the G2231. The next project/code program deciphered the pulses and wrote out the info of the bits (Toggle, Address, command etc) to the serial port.

 

My plan was to create a programmable/Learning IR transmitter for if (when) we lose the remote for the TV at home. However as my wife is expecting our 2nd child in about 2 weeks (any day now though she says) the transmitter project is still a bunch of schematics in my head.

 

So congrats and Im very interested in seeing your thinking and solution, I get the feeling Im going to learn a lot.

 

Dan

Link to post
Share on other sites

To measure the CIR carrier frequency, each individual pulse of IR must be detected. Common IR demodulator modules can not do this - they respond to a burst of IR, not each pulse.

 

There are parts made for this specific application such as the Vishay TSOP98200 and TSOP98260. Unfortunately these parts are difficult to obtain.

 

There are general purpose IR detectors like the Fairchild QSE159 and Osram SFH5140, but they require 5 volts.

 

A photodiode and a transimpedance amplifier works well, but requires careful construction (not a breadboard) to work well.

 

I used an ordinary IR LED as a detector. Here is a video showing how it works...

 

 

Here is the code...

 

#include "msp430g2211.h"

main(void)
{
volatile unsigned d;
unsigned n, p;

P1DIR = 0xDA;				// Setup I/O
P1REN = 0x25;				// Pullup on P1.0 - counter input
P1OUT = 0x07;				// Ground on P1.3 - IR LED ground
P1SEL = 0x11;				// Enable external counter input
TACTL = 0x0024;				// Continuous count up, no prescale

p = 0;						// Reset previous count

for(; {
	n = TAR;				// Get current count

	if(n != p) {			// Compare to previous
		P1OUT |= 0x40;		// Turn on green LED if count has changed
	} else {
		P1OUT &= ~0x40;		// Turn off green LED if count is the same
	}

	p = n;					// Set previous count to current count

	d = 10;					// Wait a while
	do { --d; } while(d);	//
}
}

 

Measuring the carrier frequency requires counting pulses in a specific time period. Next post will show how that is done.

Link to post
Share on other sites

I apologize. I shouldn't have put it that way.

Since the voting starts 7 days prior to a month's end, this month's(May) deadline has already passed. Since there are less than five projects, the POTM rolls over to June.

 

Once we have five projects, the contest closes.

I'll take that back.

 

The Contest will close on the 23rd of June, 2011, as long as there are greater than five projects.

Thanks, and goodluck!

Link to post
Share on other sites
Guest
This topic is now closed to further replies.

×
×
  • Create New...