NerdKits - electronics education for a digital generation

You are not logged in. [log in]

Microcontroller Programming » How to play user entered sound?

February 20, 2011
by missle3944
missle3944's Avatar

I all, I am confused on how I would have my microcontroller playback notes that the user entered. For my question to sound simpler you can watch my video I already have the printf and scanf working and I can type a key on my keyboard and have the micro controller play it. But what I am asking if the user entered 3 diffrent notes and if it could be stored in the program memory? Towards the end of the video I ask if I can store user entered variables and play them back into sound notes.

February 21, 2011
by hevans
(NerdKits Staff)

hevans's Avatar

Hi missle3944,

That is a pretty neat project you have going. There are definitely ways to store values in variables, you can just modify your user interface to temporarily store the notes in a variable or in an array. If you want to store them permanently that is a little a bit more difficult. You will need to look into using either the EEPROM or an outside storage element.

Humberto

February 21, 2011
by missle3944
missle3944's Avatar

Hi humberto I only need to store them temporarily but I am a little confused on how I would do this. I started modifying my code but I am stuck on how I would have the user enter a vairable and then have the MCU play it. Here is my code

// musicbox1.c // for NerdKits with ATtiny26L // mrobbins@mit.edu

// F_CPU defined for delay.c

define F_CPU 14745600 // 8MHz

include <avr/io.h>

include <avr/interrupt.h>

include <avr/pgmspace.h>

include <util/delay.h>

include <inttypes.h>

include <stdlib.h>

include "../libnerdkits/delay.h"

include "../libnerdkits/lcd.h"

include "../libnerdkits/delay.h"

include "../libnerdkits/lcd.h"

include "../libnerdkits/uart.h"

// PIN DEFINITIONS: // // PA0 -- temperature sensor analog input // PB1 -- piezo buzzer // PD2 -- LCD RS (pin 4) // PA5 -- LCD E (pin 6) // PA7 -- button (pullup high) // PB3-6 -- LCD DB4-7 (pins 11-14)

void play_tone(uint16_t delay, uint8_t duration) { // delay is half-period in microseconds // duration is in 10ms increments

// example: 440Hz --> delay=1136

// duration = 2*delay * cycles (all in same units) // cycles = 10000 * duration / delay / 2 // cycles = 100 * duration / (delay/50) uint16_t tmp = 100 * duration; uint16_t delaysm = delay / 20; uint16_t cycles = tmp / delaysm;

while (cycles > 0) { PORTB |= (1<<PB1); delay_us(delay); PORTB &= ~(1<<PB1); delay_us(delay); cycles--; }

}

// define some notes // Frequencies from http://www.phy.mtu.edu/~suits/notefreqs.html // converted to half-periods (us) by calculating // 1000000/2/frequency // where frequency is in Hz #define C1 166 #define D6 425 #define D5 851 #define E5 758 #define E6 379 #define F5 675 #define G5 637 #define A5 568 #define B5 506 #define C6 477 #define D6 425 #define G1 10204 #define DUR 20

int main() {

// start up the LCD lcd_init(); FILE lcd_stream = FDEV_SETUP_STREAM(lcd_putchar, 0, _FDEV_SETUP_WRITE); lcd_write_string(PSTR("PIANO"));

// init serial port uart_init(); FILE uart_stream = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW); stdin = stdout = &uart_stream;

char tc; int x;

// enable the piezo as output DDRB |= (1<<PB1); // fire up the LCD

// loop forever! while(1) {

// fire up the LCD

tc = uart_read();

if(tc=='f') {play_tone(D5, DUR);

lcd_write_string(PSTR("D5")); } if(tc=='d'){ play_tone(C6, DUR);

lcd_write_string(PSTR("c6")); } if(tc=='a'){ play_tone(A5, DUR);

lcd_write_string(PSTR("A5")); } if(tc=='s') play_tone(B5, DUR);

if(tc=='g') play_tone(E5, DUR); if(tc=='h') play_tone(F5, DUR); if(tc=='j'){

lcd_line_two();
lcd_write_string(PSTR("PLAY WHAT YOU WANT"));
scanf_P(PSTR("%d"), &x);
printf_P(PSTR("You want %d"), &x);

lcd_clear_and_home();
lcd_write_string(PSTR("My Coolio Piano"));
}

// delay a bit delay_ms(500); }

return 0; }

February 21, 2011
by missle3944
missle3944's Avatar
// musicbox1.c
// for NerdKits with ATtiny26L
// mrobbins@mit.edu

// F_CPU defined for delay.c
#define F_CPU 14745600    // 8MHz

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include <inttypes.h>
#include <stdlib.h>

#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h"
#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h"
#include "../libnerdkits/uart.h"

 // PIN DEFINITIONS:
//
// PA0 -- temperature sensor analog input
// PB1 -- piezo buzzer
// PD2 -- LCD RS (pin 4)
// PA5 -- LCD E (pin 6)
// PA7 -- button (pullup high)
// PB3-6 -- LCD DB4-7 (pins 11-14)

void play_tone(uint16_t delay, uint8_t duration) {
// delay is half-period in microseconds
// duration is in 10ms increments

// example: 440Hz --> delay=1136

 // duration = 2*delay * cycles (all in same units)
 // cycles = 10000 * duration / delay / 2
 // cycles = 100 * duration / (delay/50)
 uint16_t tmp = 100 * duration;
 uint16_t delaysm = delay / 20;
 uint16_t cycles = tmp / delaysm;

 while (cycles > 0) {
 PORTB |= (1<<PB1);
 delay_us(delay);
 PORTB &= ~(1<<PB1);
 delay_us(delay);
 cycles--;
    }

 }

// define some notes
// Frequencies from http://www.phy.mtu.edu/~suits/notefreqs.html
// converted to half-periods (us) by calculating
//  1000000/2/frequency
// where frequency is in Hz
 #define C1 166
 #define D6 425
 #define D5 851
 #define E5 758
 #define E6 379
 #define F5 675
 #define G5 637
 #define A5 568
 #define B5 506
 #define C6 477
 #define D6 425
 #define G1 10204
 #define DUR 20

 int main() {

 // start up the LCD
  lcd_init();
  FILE lcd_stream = FDEV_SETUP_STREAM(lcd_putchar, 0, _FDEV_SETUP_WRITE);
  lcd_write_string(PSTR("PIANO"));

  // init serial port
  uart_init();
  FILE uart_stream = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);
  stdin = stdout = &uart_stream;

char tc;
int x;

 // enable the piezo as output
 DDRB |= (1<<PB1);
// fire up the LCD

// loop forever!
while(1) {

// fire up the LCD

tc = uart_read();

if(tc=='f') {play_tone(D5, DUR);

lcd_write_string(PSTR("D5"));
    }
if(tc=='d'){ play_tone(C6, DUR);

lcd_write_string(PSTR("c6"));
        }
if(tc=='a'){ play_tone(A5, DUR);

lcd_write_string(PSTR("A5"));
        }
if(tc=='s') play_tone(B5, DUR);

if(tc=='g') play_tone(E5, DUR);
if(tc=='h') play_tone(F5, DUR);
if(tc=='j'){

    lcd_line_two();
    lcd_write_string(PSTR("PLAY WHAT YOU WANT"));
    scanf_P(PSTR("%d"), &x);
    printf_P(PSTR("You want %d"), &x);

    lcd_clear_and_home();
    lcd_write_string(PSTR("My Coolio Piano"));
    }

// delay a bit
delay_ms(500);
}

 return 0;
 }
February 21, 2011
by 6ofhalfdozen
6ofhalfdozen's Avatar

Hi missle3944, Since it sounds like you are just trying to temporarily store a couple notes that the user inputs, you will want to use either several variables or an array. I am not 100% sure, but from what I have seen so far of how the compiler works they would need to be marked "volatile" to prevent the compiler from making them fixed values.

Here is what I would do. (using the code line numbers from your code only post above) on line 95, put in some code to start saving the uart_read values to either an array or your variables to hold the notes. Once you have saved the uart values to variables you can create a loop holding the code in lines 98-127 and runs that code for each note input.
for example.. lets say you want to play 5 notes. here is my pseudocode, I stink at C coding so you will need to "translate" this into real C for the NK.

uint qq =0   (qq = integer counter variable, array() is array to hold user input )

While qq <5 {
   array(qq) = uart_read
   delay 500ms
   qq = qq +1 }

(once this completes the array SHOULD be loaded, assuming the user entered notes,    
 you might want to add a delay here between user input and music playing)

 qq = 0    (reset the counter)

while qq < 5{
    here is your code lines 97-127 that plays the notes
 }

hopefully that gives you an idea of where to start.

February 21, 2011
by missle3944
missle3944's Avatar

Hi 6ofhalfdozen, what sort of code would I use to have the user enter the values? I am sorta confused with it. I get the array part but I am just lost when it comes to having the user enter the variables into the array

February 21, 2011
by missle3944
missle3944's Avatar

here is my modded code that has your array in it.

    // musicbox1.c
    // for NerdKits with ATtiny26L
    // mrobbins@mit.edu

    // F_CPU defined for delay.c
    #define F_CPU 14745600    // 8MHz

    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <avr/pgmspace.h>
    #include <util/delay.h>
    #include <inttypes.h>
    #include <stdlib.h>

    #include "../libnerdkits/delay.h"
    #include "../libnerdkits/lcd.h"
    #include "../libnerdkits/delay.h"
    #include "../libnerdkits/lcd.h"
    #include "../libnerdkits/uart.h"

     // PIN DEFINITIONS:
    //
    // PA0 -- temperature sensor analog input
    // PB1 -- piezo buzzer
    // PD2 -- LCD RS (pin 4)
    // PA5 -- LCD E (pin 6)
    // PA7 -- button (pullup high)
    // PB3-6 -- LCD DB4-7 (pins 11-14)

    void play_tone(uint16_t delay, uint8_t duration) {
    // delay is half-period in microseconds
    // duration is in 10ms increments

    // example: 440Hz --> delay=1136

     // duration = 2*delay * cycles (all in same units)
     // cycles = 10000 * duration / delay / 2
     // cycles = 100 * duration / (delay/50)
     uint16_t tmp = 100 * duration;
     uint16_t delaysm = delay / 20;
     uint16_t cycles = tmp / delaysm;

     while (cycles > 0) {
     PORTB |= (1<<PB1);
     delay_us(delay);
     PORTB &= ~(1<<PB1);
     delay_us(delay);
     cycles--;
        }

     }

    // define some notes
    // Frequencies from http://www.phy.mtu.edu/~suits/notefreqs.html
    // converted to half-periods (us) by calculating
    //  1000000/2/frequency
    // where frequency is in Hz
     #define C1 166
     #define D6 425
     #define D5 851
     #define E5 758
     #define E6 379
     #define F5 675
     #define G5 637
     #define A5 568
     #define B5 506
     #define C6 477
     #define D6 425
     #define G1 10204
     #define DUR 20

     int main() {

     // start up the LCD
      lcd_init();
      FILE lcd_stream = FDEV_SETUP_STREAM(lcd_putchar, 0, _FDEV_SETUP_WRITE);
      lcd_write_string(PSTR("PIANO"));

      // init serial port
      uart_init();
      FILE uart_stream = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);
      stdin = stdout = &uart_stream;

    char tc;
    int x;

     // enable the piezo as output
     DDRB |= (1<<PB1);
    // fire up the LCD

    // loop forever!
    uint qq =0

    While qq <5 {
       array(qq) = uart_read
       delay 500ms
       qq = qq +1 }

     qq = 0    (reset the counter)

    while qq < 5{

    // fire up the LCD

    tc = uart_read();

    if(tc=='f') {play_tone(D5, DUR);

    lcd_write_string(PSTR("D5"));
        }
    if(tc=='d'){ play_tone(C6, DUR);

    lcd_write_string(PSTR("c6"));
        }
if(tc=='a'){ play_tone(A5, DUR);

lcd_write_string(PSTR("A5"));
        }
if(tc=='s') play_tone(B5, DUR);

if(tc=='g') play_tone(E5, DUR);
if(tc=='h') play_tone(F5, DUR);
if(tc=='j'){

    lcd_line_two();
    lcd_write_string(PSTR("PLAY WHAT YOU WANT"));
    scanf_P(PSTR("%d"), &x);
    printf_P(PSTR("You want %d"), &x);

    lcd_clear_and_home();
    lcd_write_string(PSTR("My Coolio Piano"));
    }

// delay a bit
delay_ms(500);
}

 return 0;
 }
February 21, 2011
by 6ofhalfdozen
6ofhalfdozen's Avatar

Missle3944,

first off, I forgot to add a "qq= qq + 1" inside of the brackets on line 15 of my pseudocode. Otherwise, it will play those 5 notes forever without looking for new input from the user.

secondly, i highly doubt my pseudocode will compile as you plugged it into your code. array() might be a restricted name in C and you will most likely have to rename it something else. It also is not declared or initialized for size anywhere, which will cause big errors at compile time. you will need to properly code out my pseudocode for it to work.

As for your question, I am not exactly sure what you are asking. the "tc =uart_read()" is all the code you need to read a character from the uart and put it into the variable tc. The code in lines 3-6 of my pseudocode, uses a loop to read from the uart and put the value directly into the array a total of 5 times. this loads the array ready for usage with no extra effort needed. If you are asking about the actual user input getting to the mcu, the user will need to type 5 characters in close succession into putty (or whichever terminal program you care to use) to be sent to the NK. The way you have the code setup, the mcu continually looks for input and loads 5 values, plays 5 notes, over and over again. I belive the code is setup so that if you don't type anything the mcu will not play any notes. But if you send it 5 keys and nothing for a while it might recycle and keep playing the 5 notes or totally freak out due to invalid /no input.. not sure, you would need to ask some of the C code gurus about that one.. so if you type 35 keys into putty for sending, the mcu "should" load and play 7 blocks of five notes. Obviously there will be some timing considerations and such. I don't know if that helps or just makes things muddier.

February 21, 2011
by missle3944
missle3944's Avatar

6ofhalfdozen, you have just cleared my confusion up about user inputs. I'll have to look into the declaration of an array in c and I'll get back to you.

Thanks -missle3944

Post a Reply

Please log in to post a reply.

Did you know that you can connect to certain car computers via the OBD-II port with a microcontroller? Learn more...