Jump to content

lpdc

Members
  • Content Count

    12
  • Joined

  • Last visited

  • Days Won

    3
  1. I have just received the booster pack. Thank you very much. Now I just need to think of an interesting project to put it to good use. I will probably first try with the booster + servos project posted here a while ago. Thank you to everyone who voted for me and thank you to 43Oh ! Fabrice
  2. 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)
  3. 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 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
  4. Hello everyone, I found the time to try and implement some sound for my game. On the hardware side, it was just a matter of plugging an old PC buzzer to pin 2.6 (you will also see a variable resistor in the pictures as I wanted to be able to dim the sound while testing) Now the beginning of the game greets you with a short "tune" (I am no musician). While you play, you get sound guidance to help you find the right color. The beeps shorten as the color difference decreases, and the pitch of the beeps also changes when you manage to find the proper setting for a given channel. Finally, another tune is played when you win. Here is a video of the new version : Here is an updated schematic : 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; } } } } As this is a beginner's project, I would appreciate any comments/suggestions/criticism that would help me and my coding improve. Cheers, Fabrice
  5. Thanks a lot. Actually, I picked up the "volatile" habit in the source code from http://blog.hodgepig.org/2010/09/30/jam-jar-lamp/ I did not really know what it was so I assumed exactly the contrary : that it was an optimization and helped the code to run better on the microcontroller. I'll take them away from the source file right away. lpdc
  6. OK well maybe next time, I see the votes are already open and according to the post it says : In the mean time I would really appreciate any comments and ways to improve my code. LPDC.
  7. Thanks Bluehash but I'd feel bad entering any kind of contest with such a beginner's project. Maybe one day if I can add in some sound and package it better than on a breadboard...
  8. NOTE : A NEW IMPROVED VERSION CAN BE VIEWED ON PAGE 2 Hello everyone, 2 or 3 months ago, I announced here that, as a first project, I would like to program a color matching game inspired by the Amazing Dr. Boardman's Conundrum. I want to thank everyone who answered the post and gave me pointers. This is what I have achieved so far : Schematics of the circuit : The code is pasted below, largely inspired from the tutorials and examples at http://mspsci.blogspot.com/ and http://www.msp430launchpad.com/2010/09/ ... chpad.html and http://blog.hodgepig.org/2010/09/30/jam-jar-lamp/ As I said, this is my first try ever at programming micro controllers, so the code is probably rather ugly and not as efficient as it should. I am looking forward to any comments and suggestions as my goal is to learn and improve this program. As a next step, I would like to add a piezzo buzzer on the last available pin (2.6) in order to give some feedback during the game (modulating the sound according to the color difference). I have no clue yet how I will implement this. Any ideas/pointers welcome. Thanks again for the help, I would not have gone this far without it. /* ****** 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 volatile 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 volatile uint32_t sys_ticks = 0; // Used to keep track of PWM static volatile bool ADCDone = false; // Flag to check that the ADC sampling is done static volatile uint16_t ADCValue; // Result of ADC (converted value) static volatile int sampled_channel; // Channel being sampled by ADC static volatile int seed; // seed for random number generation /****************************************************/ 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(volatile int delta) // function returning true if the 2 RGB values are within // a distance "delta" (euclidian distance) { volatile int Dr; volatile int Dg; volatile int Db; Dr = led_brightness[0]-led_brightness[3]; Dg = led_brightness[1]-led_brightness[4]; Db = led_brightness[2]-led_brightness[5]; volatile unsigned int D;//no sqrt so no need for double D = (unsigned int)((Dr*Dr)+(Dg*Dg)+(Db*Db)); // 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 win (void) // Procedure to show the player he won. Right now it is only blinking the LEDs // To do : add some music there { volatile int R; volatile int G; volatile 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; unsigned int n; unsigned int i; for (i=0; i<10; i++) // blinks the 2 RGB leds 10 times { for (n=0; n<3000; 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<3000; 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; //To be fixed : may want the BIT6 on this port to also stay on. // Especially if we want to put a buzzer on BIT6 if (led_brightness[5] & led_ticks) bcm2 |= BIT7; 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++; // Following was meant to work with other BCM function but did does 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 { 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 white if (500 > T < 200) break ; } } 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 = 110; // 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 { 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; } } // 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(); } } }
  9. As I said, it is not my original idea. But I understand you, I also fell in love with the concept imediately. This looks so much like the experiments, carried out at the beginning of the 20th century, that led to the empiric creation of all the colour spaces and metrics on which are based today's colour management (CIE RGB, standard observers, CIE L*a*b* etc..). If I manage to carry out this project to its end, I will definitely post the code and pictures on this forum. LPDC
  10. Wow, thanks a lot everyone for you input. I do not often use forums in general but I am really impressed with how helpful everyone is here. I see now. I did not know that the 2 crystal pins could be used as regular input/output pins, I guess that I should have read the specs better instead of just reading the silkscreen print on the Launchpad board. This is very good news indeed, as a beginner's project it is good that I need only to worry about PWM and ADC without being required to throw some kind of multiplexing in there too. With a total of 10 pins, I will have enough leeway now to drive each LED independently, get the 3 potentiometer inputs and that will even leave me 1 last pin if I want to add in a piezzo buzzer to notify that a player won. Once again, thanks a lot everyone. LPDC
  11. Thanks a lot Mike. this is good news, even if it take 4 pins instead of 3 to drive the common cathode LEDs, this means that it is still doable with the 8 port microcontroller that came with the launchpad kit. Now that you mention it, I understand how a common annode/cathode could make the charlieplexing matrix more complex. Now I guess that I just need to do my homework : first try to use simply PWM and ADC to drive a single RGB LED with 3 potentiometers, then try to drive the 2 LEDs without PWM through a charlieplexing matrix and finally try to merge the 2 parts together. This is really a great forum, LPDC
  12. Hello everyone, I am a complete beginner with micro controllers and I chose to get started with a Launchpad as its small price made it pretty much risk-free even if I failed. As a first project, I have set myself the goal to duplicate the following circuit : http://www.fangletronics.com/2010/02/am ... ndrum.html The author of this project used a different microcontroller so I thought it would be a nice exercise to try and obtain the same behaviour with a MSP430 included in the Launchpad kit. Basically, the micro controller drives 2 RBG LEDs and gets imput from 3 potentiometers. A random color is displayed on one of the 2 LEDs and the goal is to match that color on the second LED by adjusting the potentiometers for R, G and B values. My first though was to use the MSPG2231 as it features the ADC required to read values from the potentiometers. Then I started to count the pins and fell off short 1 pin. I need 6 pins to drive the 2 RGB LEDs and 3 pins for the potentiometers. This amounts to 9 pins but as far as I can understand, I have only 8 pins available to use on the MSPG2231. I stumbled accross a website that describes "charlieplexing", according to this website, I could then use only 3 pins to drive my 6 LEDs. After such a long introduction, my question is : do you think it is possible to achieve my goal by doing both software PWM and charlieplexing at the same time ? I don't really know where to start from and I don't even know if PWM and charlieplexing can even mix together. I was considering to base the PWM part on the following post : http://blog.hodgepig.org/2010/09/30/jam-jar-lamp/ The other 2 options I considered are : *Waiting until a launchpad compatible chip with more pins becomes available (the MSP430G2252 for instance) *Using another IC that could talk to the MSP430 with only a few pins and that would maybe have hardware PWM ports to drive the LEDs directly (does such a component even exist ?) Thank you in advance to anyone who may give me advices/comments and thank you simply to all of you who read this far. LPDC
×
×
  • Create New...