/* * 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 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 unsigned short freqs[] = { // PD3-7 FREQ(100), FREQ(200), FREQ(250), FREQ(300), FREQ(350), // PB0-4 FREQ(400), FREQ(500), FREQ(600), FREQ(700), FREQ(750), // PC0-4 FREQ(1000), FREQ(1250), FREQ(1500), FREQ(1750), FREQ(2000), [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 = 8; UCSR0B = (1 << RXEN0) | (1 << TXEN0); UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); } void usart_send(unsigned char c) { while (!(UCSR0A & (1 << UDRE0))); UDR0 = c; } unsigned char usart_read(void) { while (!(UCSR0A & (1 << RXC0))); return UDR0; } 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 (;;) { // check if any buttons are pressed, otherwise don't play a note if (((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; } else { if (UCSR0A & (1 << RXC0)) { mode = UDR0; usart_send(mode); } } continue; } if (mode == 0) { // Prepare Timer/Counter TCNT1 = 1; tmp = note; 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); cycles = (cycles + 1) % 0xffff; } else if (mode == 0xb0) { note = usart_read(); tmp = usart_read(); cycles = tmp << 8; tmp = usart_read(); cycles |= tmp; (void)usart_read(); for (unsigned char i = 0; i < cycles; i++) { TCNT1 = 1; OCR1A = freqs[note]; TCCR1B |= 1 << CS11; while ((TIFR1 & (1 << OCF1A)) == 0); PORTD ^= 1 << P_SPKR; TIFR1 |= 1 << OCF1A; TCCR1B &= ~(1 << CS11); } } } }