/* * EEL4746C - AVR Piano - Speaker Section * speaker is connected to PD2 and ground * 15 buttons are connected to PD3-7, PC0-4, PB0-4 * the LCD Arduino UNO is connected to TX/RX (PD0/1) */ #include #include #define F_CPU 16e6 #include #define T1_PRESCALAR 8 #define FREQ(f) (16e6 / f / T1_PRESCALAR / 2) #define HIGH(sn) ((sn >> 8) & 0xff) #define LOW(sn) (sn & 0xff) #define P_RX 0 #define P_TX 1 #define P_SPKR 2 #define MARIO 50 unsigned short freqs[] = { // PD3-7 #if 0 FREQ(100), FREQ(200), FREQ(250), FREQ(300), FREQ(350), // PB0-4 FREQ(400), #else FREQ(131), // middle c FREQ(262), FREQ(110), FREQ(220), FREQ(117), FREQ(233), #endif FREQ(500), FREQ(6000), FREQ(5000), FREQ(5500), // PC0-4 FREQ(4000), FREQ(7250), FREQ(6500), FREQ(5750), FREQ(5000), FREQ(5000), FREQ(6000), FREQ(7000), FREQ(8000), FREQ(8000), FREQ(8000), FREQ(8000), FREQ(8000), // notes [MARIO] = FREQ(131), // C3 FREQ(262), // C4 FREQ(110), // A2 FREQ(220), // A3 FREQ(117), // Bb2 FREQ(233), // Bb3 FREQ(87), FREQ(175), FREQ(73), FREQ(147), FREQ(78), FREQ(156), FREQ(156), FREQ(147), FREQ(139), FREQ(131), FREQ(156), FREQ(147), FREQ(104), FREQ(98), FREQ(139), FREQ(156), FREQ(185), FREQ(175), FREQ(165), FREQ(233), FREQ(220), FREQ(208), FREQ(156), FREQ(123), FREQ(123), FREQ(110), FREQ(104), ['"'] = FREQ(16000), [255] = 0 // used as a 'silent' note }; unsigned char note = 0; // 0 = buttons write note+cycles+\xff to UART // 1 = buttons don't do anything, speaker reads note+cycles+\xff from UART unsigned char mode = '0'; ISR (PCINT0_vect) { // check if any button in the whole port is pressed for (unsigned char i = 0; i <= 5; i++) { if (PINB & (1 << i)) { note = i + 5; break; } } } ISR (PCINT1_vect) { // check if any button in the whole port is pressed for (unsigned char i = 0; i <= 5; i++) { if (PINC & (1 << i)) { note = i + 10; break; } } } ISR (PCINT2_vect) { // check if any button in the whole port is pressed for (unsigned char i = 3; i <= 7; i++) { if (PIND & (1 << i)) { note = i - 3; break; } } } void usart_init(void) { // 115200 bps, RX/TX enabled UBRR0 = 103; UCSR0B = (1 << RXEN0) | (1 << TXEN0); UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); } void usart_send(unsigned char c) { while (!(UCSR0A & (1 << UDRE0))); UDR0 = c; } void usart_send_str(const char *c) { for (unsigned char i = 0; c[i] != '\0'; i++) usart_send(c[i]); } unsigned char usart_read(void) { while (!(UCSR0A & (1 << RXC0))); return UDR0; } void playtone(void) { // Prepare Timer/Counter TCNT1 = 1; OCR1A = freqs[note]; TCCR1B |= 1 << CS11; // Monitor OutPut Compare Flag while ((TIFR1 & (1 << OCF1A)) == 0); // Toggles port For Speaker PORTD ^= 1 << P_SPKR; TIFR1 |= 1 << OCF1A; TCCR1B &= ~(1 << CS11); } void play_note(unsigned char _note, unsigned short _cycles) { note = _note; if (note != 255) { for (unsigned short i = 0; i < _cycles; i++) playtone(); } else { // when note is 255, don't play anything for _cycles ms // Prepare Timer/Counter TCNT1 = 1; OCR1A = 16e3 * _cycles / T1_PRESCALAR; TCCR1B |= 1 << CS11; // Monitor OutPut Compare Flag while ((TIFR1 & (1 << OCF1A)) == 0); // Toggles port For Speaker PORTD ^= 1 << P_SPKR; TIFR1 |= 1 << OCF1A; TCCR1B &= ~(1 << CS11); } } int main(void) { // Data Direction for Buttons, UART, Speaker DDRB = 0x00; DDRC = 0x00; DDRD = (1 << P_TX) | (1 << P_SPKR); // Enabling Pin Change Interrupt for All Buttons PCMSK0 = 0b00011111; PCMSK1 = 0b00011111; PCMSK2 = 0b11111000; PCICR = (1 << PCIE0) | (1 << PCIE1) | (1 << PCIE2); TCCR1A = 0x00; // use timer1 CTC mode TCCR1B = 1 << WGM12; // already prescaled by 8 in table sei(); usart_init(); // Sends Square wave to the Speaker When a Button is Pressed unsigned short cycles = 0; unsigned char tmp = 0; for (unsigned char n = 0;; n = (n + 1) % 2) { if (UCSR0A & (1 << RXC0)) { mode = UDR0; PORTD &= ~(1 << P_SPKR); usart_send(mode); } // check if any buttons are pressed, otherwise don't play a note if (mode == '0' && ((PINB & PCMSK0) | (PINC & PCMSK1) | (PIND & PCMSK2)) == 0) { // if a button was released, then send note and cycles played if (cycles > 0) { usart_send(tmp); usart_send(HIGH(cycles)); usart_send(LOW(cycles)); usart_send(0xff); cycles = 0; } continue; } if (mode == '0') { tmp = note; playtone(); cycles = (cycles + 1) % 0xffff; } else if (mode == '1') { note = usart_read(); if (note >= 'Z') note -= '0'; tmp = usart_read(); cycles = tmp << 8; tmp = usart_read(); cycles |= tmp; tmp = usart_read(); // reset to default mode when an invalid note is read if (tmp != 'z' || note >= '|') { mode = '0'; continue; } for (unsigned short i = 0; i < cycles; i++) playtone(); } else if (mode == '2') { play_note(MARIO + 0, 131 * 0.3); play_note(MARIO + 1, 262 * 0.3); play_note(MARIO + 2, 110 * 0.3); play_note(MARIO + 3, 220 * 0.3); play_note(MARIO + 4, 117 * 0.3); play_note(MARIO + 5, 233 * 0.3); play_note(255, 1800); play_note(MARIO + 0, 131 * 0.3); play_note(MARIO + 1, 262 * 0.3); play_note(MARIO + 2, 110 * 0.3); play_note(MARIO + 3, 220 * 0.3); play_note(MARIO + 4, 117 * 0.3); play_note(MARIO + 5, 233 * 0.3); play_note(255, 1800); play_note(MARIO + 6, 87 * 0.3); play_note(MARIO + 7, 175 * 0.3); play_note(MARIO + 8, 73 * 0.3); play_note(MARIO + 9, 147 * 0.3); play_note(MARIO + 10, 78 * 0.3); play_note(MARIO + 11, 156 * 0.3); play_note(255, 1800); play_note(MARIO + 6, 87 * 0.3); play_note(MARIO + 7, 175 * 0.3); play_note(MARIO + 8, 73 * 0.3); play_note(MARIO + 9, 147 * 0.3); play_note(MARIO + 10, 78 * 0.3); play_note(MARIO + 11, 156 * 0.3); play_note(255, 1800); play_note(MARIO + 12, 156 * 0.3); play_note(255, 25); play_note(MARIO + 13, 147 * 0.3); play_note(255, 25); play_note(MARIO + 14, 139 * 0.3); play_note(255, 25); play_note(MARIO + 15, 131 * 0.6); play_note(255, 25); play_note(MARIO + 16, 156 * 0.3); play_note(255, 25); play_note(MARIO + 17, 147 * 0.6); play_note(255, 25); play_note(MARIO + 18, 104 * 0.6); play_note(255, 25); play_note(MARIO + 19, 98 * 0.6); play_note(255, 25); play_note(MARIO + 20, 139 * 0.6); play_note(MARIO + 21, 156 * 0.3); play_note(255, 25); play_note(MARIO + 22, 185 * 0.3); play_note(255, 25); play_note(MARIO + 23, 175 * 0.3); play_note(255, 25); play_note(MARIO + 24, 165 * 0.3); play_note(255, 25); play_note(MARIO + 25, 233 * 0.3); play_note(255, 25); play_note(MARIO + 26, 220 * 0.3); play_note(255, 25); play_note(MARIO + 27, 208 * 0.6); play_note(255, 25); play_note(MARIO + 28, 156 * 0.6); play_note(255, 25); play_note(MARIO + 29, 123 * 0.6); play_note(255, 25); play_note(MARIO + 30, 123 * 0.6); play_note(255, 25); play_note(MARIO + 31, 110 * 0.6); play_note(255, 25); play_note(MARIO + 32, 104 * 0.6); play_note(255, 25); play_note(255, 3600); } } }