NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Microcontroller Programming » Music with the MCU??

February 15, 2011
by missle3944
missle3944's Avatar

Hi, I recently modified the code to work on the ATMEGA 168 mcu that I have with my USB nerdkit. But I cannot get the music to play through the peizio buzzer. I am able to get the text to work on the screen but it wont play through PB1, the one i selected. I'm not sure if I messed up on the clock prescaling, but heres 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"

 // 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 / 50;
 uint16_t cycles = tmp / delaysm;

 while(cycles > 0) {
 PORTC |= ~(1<<PB1);
 delay_us(delay);
 PORTC &= ~(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 D5 851
 #define E5 758
 #define Fsh5 675
 #define G5 637
 #define A5 568
 #define B5 506
 #define C6 477
 #define D6 425
 #define DUR 40

 int main() {

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

// loop forever!
while(1) {

lcd_clear_and_home(); 
lcd_write_string(PSTR("  Happy ")); play_tone(D5, DUR);
lcd_write_string(PSTR("birth"));    play_tone(E5, DUR);
lcd_write_string(PSTR("day ")); play_tone(D5, DUR);
lcd_write_string(PSTR("to "));  play_tone(G5, DUR);
lcd_write_string(PSTR("you ")); play_tone(Fsh5, 2*DUR);

lcd_line_two();
lcd_write_string(PSTR("  Happy ")); play_tone(D5, DUR);
lcd_write_string(PSTR("birth"));    play_tone(E5, DUR);
lcd_write_string(PSTR("day ")); play_tone(D5, DUR);
lcd_write_string(PSTR("to "));  play_tone(A5, DUR);
lcd_write_string(PSTR("you ")); play_tone(G5, 2*DUR);

lcd_clear_and_home(); 
lcd_write_string(PSTR("Happy "));   play_tone(D5, DUR);
lcd_write_string(PSTR("birth"));    play_tone(D6, DUR);
lcd_write_string(PSTR("day ")); play_tone(B5, DUR);
lcd_write_string(PSTR("dear "));    play_tone(G5, DUR);
lcd_write_string(PSTR("__"));   play_tone(Fsh5, DUR);
lcd_write_string(PSTR("__"));   play_tone(E5, DUR);

lcd_line_two();
lcd_write_string(PSTR(" Happy "));  play_tone(C6, DUR);
lcd_write_string(PSTR("birth"));    play_tone(B5, DUR);
lcd_write_string(PSTR("day ")); play_tone(G5, DUR);
lcd_write_string(PSTR("to "));  play_tone(A5, DUR);
lcd_write_string(PSTR("you! "));    play_tone(G5, 2*DUR);
lcd_clear_and_home();

// delay a bit
delay_ms(500);
}

 return 0;
}
February 18, 2011
by hevans
(NerdKits Staff)

hevans's Avatar

Hi missile3944,

I think your issue is that you are trying to set the PB1 bit of the PORTC register, so what you are actually doing is setting PC1 to go and off.

Humberto

February 18, 2011
by missle3944
missle3944's Avatar

Hi hevans, thanks for your reply. I am confused how I would not have do that then. Because it was in the original code that was made for the old mcu. -missle3944

February 18, 2011
by missle3944
missle3944's Avatar

Hi Humberto, I just changed my code around so I took out the port c register. But I am confused because on the downloadable code it includes that. I also think I left out a very key part in the program to work and I put that in...

 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 / 50;
 uint16_t cycles = tmp / delaysm;

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

 }

// 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 D5 851
 #define E5 758
 #define Fsh5 675
 #define G5 637
 #define A5 568
 #define B5 506
 #define C6 477
 #define D6 425
 #define DUR 40

 int main() {

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

// loop forever!
while(1) {

 // enable the piezo as output
 PORTB |= ~(1<<PB1);
// fire up the LCD
lcd_init();
lcd_home();

lcd_clear_and_home();
February 19, 2011
by hevans
(NerdKits Staff)

hevans's Avatar

Hi missle3944,

The code above is not complete, did you intentionally leave out part of the code? I see you changed the code to use PB1, so now it really should work when you put the piezzo buzzer on PB1. Does it just not do anything?

Humberto

February 19, 2011
by missle3944
missle3944's Avatar

Hi Humberto,

I ran the code succesfully but it just stays stuck on the first note when playing through the piezio and it only displays "happy" on the LCD. Here is my code that I used.

/ 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"

 // 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 / 50;
 uint16_t cycles = tmp / delaysm;

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

 }

// 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 D5 851
 #define E5 758
 #define Fsh5 675
 #define G5 637
 #define A5 568
 #define B5 506
 #define C6 477
 #define D6 425
 #define DUR 40

 int main() {

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

// loop forever!
while(1) {

 // enable the piezo as output
 PORTB |= ~(1<<PB1);
// fire up the LCD
lcd_init();
lcd_home();

lcd_clear_and_home(); 
lcd_write_string(PSTR("  Happy ")); play_tone(D5, DUR);
lcd_write_string(PSTR("birth"));    play_tone(E5, DUR);
lcd_write_string(PSTR("day ")); play_tone(D5, DUR);
lcd_write_string(PSTR("to "));  play_tone(G5, DUR);
lcd_write_string(PSTR("you ")); play_tone(Fsh5, 2*DUR);

lcd_line_two();
lcd_write_string(PSTR("  Happy ")); play_tone(D5, DUR);
lcd_write_string(PSTR("birth"));    play_tone(E5, DUR);
lcd_write_string(PSTR("day ")); play_tone(D5, DUR);
lcd_write_string(PSTR("to "));  play_tone(A5, DUR);
lcd_write_string(PSTR("you ")); play_tone(G5, 2*DUR);

lcd_clear_and_home(); 
lcd_write_string(PSTR("Happy "));   play_tone(D5, DUR);
lcd_write_string(PSTR("birth"));    play_tone(D6, DUR);
lcd_write_string(PSTR("day ")); play_tone(B5, DUR);
lcd_write_string(PSTR("dear "));    play_tone(G5, DUR);
lcd_write_string(PSTR("__"));   play_tone(Fsh5, DUR);
lcd_write_string(PSTR("__"));   play_tone(E5, DUR);

lcd_line_two();
lcd_write_string(PSTR(" Happy "));  play_tone(C6, DUR);
lcd_write_string(PSTR("birth"));    play_tone(B5, DUR);
lcd_write_string(PSTR("day ")); play_tone(G5, DUR);
lcd_write_string(PSTR("to "));  play_tone(A5, DUR);
lcd_write_string(PSTR("you! "));    play_tone(G5, 2*DUR);
lcd_clear_and_home();

// delay a bit
delay_ms(500);
}

 return 0;
}
February 19, 2011
by missle3944
missle3944's Avatar

Hi Humberto,

Thank you, it works now!! Figured out that when I was comparing it to the original code I left out the (cycles--) part. Now it plays flawlessly. But it sounded funny to me with the piezo it came with so I salvaged a speaker from a old telephone.

-missle3944

December 04, 2011
by 2electrified
2electrified's Avatar

Hi Missle3944,

I was wondering could you list the modified happy birthday code for the ATmega168 controller chip that you got successfully running. I am looking to make this a birthday gift for my mom, also, could you put up a snapshot on your designed circuit as well. I am getting confused on how to setup the pushbutton switch, buzzer and so on. Not sure if I use both sides of the chip or just one side. Any visual would be greatly appreciated it. I am a beginner here, and I work better seeing visuals. Thank you Lisa

December 04, 2011
by missle3944
missle3944's Avatar

2electrified,

Have you checked out the tutorial, "making music with the microcontroller" yet?

-dan

December 04, 2011
by 2electrified
2electrified's Avatar

Hi Dan, Yes I have checked out the tutorial, but I am still having problems with my program. I am not getting sound output, I am only getting the words displayed on my the LCD panel. I have my buzzer wired to pin 15 on MCU chip - red wire of the buzzer on pin 15 MCU and white wire of the buzzer on GND on blue rail on breadboard.

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"

 // 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 lcd_blank_line() {
  lcd_write_string(PSTR("                        "));
}

void lcd_quick_clear_and_home() {
    lcd_home();
    lcd_blank_line();
    lcd_line_two();
    lcd_blank_line();
 //   lcd_home();

    lcd_line_three();
    lcd_blank_line();
    lcd_line_four();
    lcd_home();

}

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 / 50;
 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 D5 851
 #define E5 758
 #define Fsh5 675
 #define G5 637
 #define A5 568
 #define B5 506
 #define C6 477
 #define D6 425
 #define DUR 40

 int main() {

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

// PORTB |= (1<<PB1);

// fire up the LCD
lcd_init();
lcd_home();

// loop forever!
while(1) {

 // enable the piezo as output
 PORTB |= ~(1<<PB1);

// fire up the LCD
lcd_init();
lcd_home();

lcd_clear_and_home(); 
lcd_write_string(PSTR("  Happy ")); play_tone(D5, DUR);
lcd_write_string(PSTR("birth"));    play_tone(E5, DUR);
lcd_write_string(PSTR("day ")); play_tone(D5, DUR);

lcd_line_two();
lcd_write_string(PSTR("      to "));  play_tone(G5, DUR);
lcd_write_string(PSTR("you ")); play_tone(Fsh5, 2*DUR);

lcd_line_three();
lcd_write_string(PSTR("  Happy ")); play_tone(D5, DUR);
lcd_write_string(PSTR("birth"));    play_tone(E5, DUR);
lcd_write_string(PSTR("day ")); play_tone(D5, DUR);

lcd_line_four();
lcd_write_string(PSTR("      to "));  play_tone(A5, DUR);
lcd_write_string(PSTR("you ")); play_tone(G5, 2*DUR);

lcd_clear_and_home(); 
lcd_write_string(PSTR("  Happy "));   play_tone(D5, DUR);
lcd_write_string(PSTR("birth"));    play_tone(D6, DUR);
lcd_write_string(PSTR("day ")); play_tone(B5, DUR);

lcd_line_two();
lcd_write_string(PSTR("      dear "));    play_tone(G5, DUR);
lcd_write_string(PSTR("__"));   play_tone(Fsh5, DUR);
lcd_write_string(PSTR("__"));   play_tone(E5, DUR);

lcd_line_three();
lcd_write_string(PSTR("  Happy "));  play_tone(C6, DUR);
lcd_write_string(PSTR("birth"));    play_tone(B5, DUR);
lcd_write_string(PSTR("day ")); play_tone(G5, DUR);

lcd_line_four();
lcd_write_string(PSTR("      to "));  play_tone(A5, DUR);
lcd_write_string(PSTR("you! "));    play_tone(G5, 2*DUR);
lcd_clear_and_home();

// delay a bit
delay_ms(500);
}

 return 0;
}

Below is a snapshot of my wired breadboard Alt Text

I am not sure if you need to know the LCD wire configuration but here ya go. LCD pin 1 wired to GND on blue rail on breadboard; LCD pin 2 wired to positive on red rail on breadboard; LCD pin 3 wired to 1K resistor which is coming of GND from the voltage regulator; LCD pin 4 wired to pin 13 on MCU; LCD pin 5 wired to GND on the voltage regulator; LCD pin 6 wired to pin 12 MCU; LCD pin 11 wired to pin 4 on MCU; LCD pin 12 wired to pin 5 on MCU; LCD pin 13 wired to pin 6 on MCU; and LCD pin 14 wired to pin 11 on MCU.

If you could please look over what I have presented here and let me know what I need to change in order to get sound from my buzzer.

Thank you

Lisa

December 05, 2011
by missle3944
missle3944's Avatar

Lisa,

I think I had a similar problem when I set this up too. I recall it was something to do with me accidently leaving out the cpu cycles function.Anyway, Here you go, this code just plays when the nerdkit is turned on. Just try it first and then just copy and paste the changes for the button. Dont pay any attention to the comments because I didn't bother to change them. Hope this Helps

-Dan

// 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"

 // 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 / 50;
 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 Fsh5 675
 #define G5 637
 #define A5 568
 #define B5 506
 #define C6 477
 #define D6 425
 #define G1 10204
 #define DUR 40

 int main() {

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

// loop forever!
while(1) {

// fire up the LCD
lcd_init();
lcd_home();

lcd_clear_and_home(); 
lcd_write_string(PSTR("  HOT ")); play_tone(E6, DUR);
lcd_line_two();
lcd_write_string(PSTR("  CROSS")); play_tone(D6, DUR);
lcd_line_three();
lcd_write_string(PSTR("******BUNSS*****")); play_tone(C6, 2*DUR);

lcd_write_string(PSTR("  Happy ")); play_tone(D5, DUR);
lcd_write_string(PSTR("birth"));    play_tone(E5, DUR);
lcd_write_string(PSTR("day ")); play_tone(D5, DUR);
lcd_write_string(PSTR("to "));  play_tone(G5, DUR);
lcd_write_string(PSTR("you ")); play_tone(Fsh5, 2*DUR);

lcd_line_two();
lcd_write_string(PSTR("  Happy ")); play_tone(D5, DUR);
lcd_write_string(PSTR("birth"));    play_tone(E5, DUR);
lcd_write_string(PSTR("day ")); play_tone(D5, DUR);
lcd_write_string(PSTR("to "));  play_tone(A5, DUR);
lcd_write_string(PSTR("you ")); play_tone(G5, 2*DUR);

lcd_clear_and_home(); 
lcd_write_string(PSTR("Happy "));   play_tone(D5, DUR);
lcd_write_string(PSTR("birth"));    play_tone(D6, DUR);
lcd_write_string(PSTR("day ")); play_tone(B5, DUR);
lcd_write_string(PSTR("dear "));    play_tone(G5, DUR);
lcd_write_string(PSTR("__"));   play_tone(Fsh5, DUR);
lcd_write_string(PSTR("__"));   play_tone(E5, DUR);

lcd_line_two();
lcd_write_string(PSTR(" Happy "));  play_tone(C6, DUR);
lcd_write_string(PSTR("birth"));    play_tone(B5, DUR);
lcd_write_string(PSTR("day ")); play_tone(G5, DUR);
lcd_write_string(PSTR("to "));  play_tone(A5, DUR);
lcd_write_string(PSTR("you! "));    play_tone(G5, 2*DUR);
lcd_clear_and_home();

// delay a bit
delay_ms(500);
}

 return 0;
}
December 05, 2011
by 2electrified
2electrified's Avatar

Hi Dan, Thanks for your post. I saw what you uploaded and compared your program to mine, and I found in my line 59, I have a "~" symbol which shouldn't of been there, so I removed it, and also, I had two lines doing the same output thing - line 85 and line 97, so I just null line 97 recompiled my program and it worked perfectly. By looking at your program and comparing to mine, I had symbols errors. Thank you very much for your help. I am so happy I finally got this to run. My next step is to install a push button switch to this circuit. Thanks again. Lisa

Post a Reply

Please log in to post a reply.

Did you know that you can connect a computer keyboard to your microcontroller? Learn more...