eel4746_avr_piano

For our Microprocessor's class final project, we chose to make a chiptune piano using AVR C on two Arduino UNOs.
Log | Files | Refs | README | LICENSE

notes.c (5097B)


      1 /*
      2  *  EEL4746C - AVR Piano - Speaker Section
      3  *  speaker is connected to PD2 and ground
      4  *  15 buttons are connected to PD3-7, PC0-4, PB0-4
      5  *  the LCD Arduino UNO is connected to TX/RX (PD0/1)
      6  */
      7 
      8 #include <avr/io.h>
      9 #include <avr/interrupt.h>
     10 
     11 #define F_CPU		16e6
     12 #include <util/delay.h>
     13 
     14 #define	T1_PRESCALAR	8
     15 #define FREQ(f)		(16e6 / f / T1_PRESCALAR / 2)
     16 
     17 #define HIGH(sn)	((sn >> 8) & 0xff)
     18 #define LOW(sn)		(sn & 0xff)
     19 
     20 #define P_RX		0
     21 #define P_TX		1
     22 #define P_SPKR		2
     23 
     24 #define MARIO		50
     25 
     26 unsigned short freqs[] = {
     27 	// PD3-7
     28 	100,
     29 	200,
     30 	250,
     31 	300,
     32 	350,
     33 	// PB0-4
     34 	400,
     35 	450,	// middle c
     36 	500,
     37 	600,
     38 	700,
     39 	// PC0-4
     40 	750,
     41 	800,
     42 	850,
     43 	900,
     44 	950,
     45 
     46 	// notes
     47 	[MARIO] = 131,	// C3
     48 	262,	// C4
     49 	110,	// A2
     50 	220,	// A3
     51 	117,	// Bb2
     52 	233,	// Bb3
     53 
     54 	87,
     55 	175,
     56 	73,
     57 	147,
     58 	78,
     59 	156,
     60 
     61 	156,
     62 	147,
     63 	139,
     64 	131,
     65 	156,
     66 	147,
     67 	104,
     68 	98,
     69 	139,
     70 
     71 	156,
     72 	185,
     73 	175,
     74 	165,
     75 	233,
     76 	220,
     77 	208,
     78 	156,
     79 	123,
     80 	123,
     81 	110,
     82 	104,
     83 
     84 	['"'] = 16000,
     85 
     86 	[255] = 0	// used as a 'silent' note
     87 };
     88 
     89 unsigned short t_freqs[] = {
     90 	// PD3-7
     91 	FREQ(100),
     92 	FREQ(200),
     93 	FREQ(250),
     94 	FREQ(300),
     95 	FREQ(350),
     96 	// PB0-4
     97 	FREQ(400),
     98 	FREQ(450),	// middle c
     99 	FREQ(500),
    100 	FREQ(600),
    101 	FREQ(700),
    102 	// PC0-4
    103 	FREQ(750),
    104 	FREQ(800),
    105 	FREQ(850),
    106 	FREQ(900),
    107 	FREQ(950),
    108 
    109 	// notes
    110 	[MARIO] = FREQ(131),	// C3
    111 	FREQ(262),	// C4
    112 	FREQ(110),	// A2
    113 	FREQ(220),	// A3
    114 	FREQ(117),	// Bb2
    115 	FREQ(233),	// Bb3
    116 
    117 	FREQ(87),
    118 	FREQ(175),
    119 	FREQ(73),
    120 	FREQ(147),
    121 	FREQ(78),
    122 	FREQ(156),
    123 
    124 	FREQ(156),
    125 	FREQ(147),
    126 	FREQ(139),
    127 	FREQ(131),
    128 	FREQ(156),
    129 	FREQ(147),
    130 	FREQ(104),
    131 	FREQ(98),
    132 	FREQ(139),
    133 
    134 	FREQ(156),
    135 	FREQ(185),
    136 	FREQ(175),
    137 	FREQ(165),
    138 	FREQ(233),
    139 	FREQ(220),
    140 	FREQ(208),
    141 	FREQ(156),
    142 	FREQ(123),
    143 	FREQ(123),
    144 	FREQ(110),
    145 	FREQ(104),
    146 
    147 	['"'] = FREQ(16000),
    148 
    149 	[255] = 0	// used as a 'silent' note
    150 };
    151 unsigned char note = 0;
    152 // 0 = normal/piano mode
    153 // 1 = recording mode
    154 // 2 = mario demo
    155 unsigned char mode = '0';
    156 
    157 ISR (PCINT0_vect)
    158 {
    159 	// check if any button in the whole port is pressed
    160 	for (unsigned char i = 0; i <= 5; i++) {
    161 		if (PINB & (1 << i)) {
    162 			note = i + 5;
    163 			break;
    164 		}
    165 	}
    166 }
    167 
    168 ISR (PCINT1_vect)
    169 {
    170 	// check if any button in the whole port is pressed
    171 	for (unsigned char i = 0; i <= 5; i++) {
    172 		if (PINC & (1 << i)) {
    173 			note = i + 10;
    174 			break;
    175 		}
    176 	}
    177 }
    178 
    179 ISR (PCINT2_vect)
    180 {
    181 	// check if any button in the whole port is pressed
    182 	for (unsigned char i = 3; i <= 7; i++) {
    183 		if (PIND & (1 << i)) {
    184 			note = i - 3;
    185 			break;
    186 		}
    187 	}
    188 }
    189 
    190 void
    191 usart_init(void)
    192 {
    193 	// 9600 bps, TX enabled
    194 	UBRR0 = 103;
    195 	UCSR0B = 1 << TXEN0;
    196 	UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
    197 }
    198 
    199 void
    200 usart_send(unsigned char c)
    201 {
    202 	while (!(UCSR0A & (1 << UDRE0)));
    203 	UDR0 = c;
    204 }
    205 
    206 void
    207 usart_send_str(const char *c)
    208 {
    209 	for (unsigned char i = 0; c[i] != '\0'; i++)
    210 		usart_send(c[i]);
    211 }
    212 
    213 unsigned char
    214 usart_read(void)
    215 {
    216 	while (!(UCSR0A & (1 << RXC0)));
    217 	return UDR0;
    218 }
    219 
    220 void
    221 playtone(void)
    222 {
    223 	// Prepare Timer/Counter
    224 	TCNT1 = 1;
    225 	OCR1A = t_freqs[note];
    226 	TCCR1B |= 1 << CS11;
    227 
    228 	// Monitor OutPut Compare Flag
    229 	while ((TIFR1 & (1 << OCF1A)) == 0);
    230 
    231 	// Toggles port For Speaker
    232 	PORTD ^= 1 << P_SPKR;
    233 	TIFR1 |= 1 << OCF1A;
    234 	TCCR1B &= ~(1 << CS11);
    235 }
    236 
    237 void
    238 play_note(unsigned char _note, unsigned short _cycles)
    239 {
    240 	note = _note;
    241 
    242 	usart_send(note);
    243 
    244 	for (unsigned short i = 0; i < _cycles; i++)
    245 		playtone();
    246 
    247 	_delay_ms(25);
    248 }
    249 
    250 int
    251 main(void) 
    252 {
    253 	// Data Direction for Buttons, UART, Speaker
    254 	DDRB = 0x00;
    255 	DDRC = 0x00;
    256 	DDRD = (1 << P_TX) | (1 << P_SPKR); 
    257 
    258 	// Enabling Pin Change Interrupt for All Buttons
    259 	PCMSK0 = 0b00011111;
    260 	PCMSK1 = 0b00011111;
    261 	PCMSK2 = 0b11111000;
    262 	PCICR = (1 << PCIE0) | (1 << PCIE1) | (1 << PCIE2);
    263 
    264 	TCCR1A = 0x00; // use timer1 CTC mode
    265 	TCCR1B = 1 << WGM12; // already prescaled by 8 in table
    266 
    267 	sei();
    268 
    269 	usart_init();
    270 
    271 	// Sends Square wave to the Speaker When a Button is Pressed
    272 	unsigned short cycles = 0;
    273 	unsigned char tmp = 0;
    274 	for (unsigned char n = 0;; n = (n + 1) % 2) {
    275 		if (PINC & _BV(5))
    276 			mode = '2';
    277 		else if (PINB & _BV(5))
    278 			mode = '3';
    279 		else
    280 			mode = '0';
    281 
    282 		// check if any buttons are pressed, otherwise don't play a note
    283 		if (mode == '0' && ((PINB & PCMSK0) | (PINC & PCMSK1) | (PIND & PCMSK2)) == 0) {
    284 			// if a button was released, then send note and cycles played
    285 			if (cycles > 0) {
    286 				usart_send(tmp);
    287 				cycles = 0;
    288 			}
    289 			continue;
    290 		}
    291 
    292 		if (mode == '0') {
    293 			tmp = note;
    294 
    295 			playtone();
    296 
    297 			cycles = (cycles + 1) % 0xffff;
    298 		} else if (mode == '1') {
    299 			
    300 		} else if (mode == '3') {
    301 			for (unsigned char i = 0; i < 2; i++) {
    302 				for (unsigned char j = 0; j <= 5; j++)
    303 					play_note(MARIO + j, freqs[MARIO + j] * 0.3);
    304 				_delay_ms(1800);
    305 			}
    306 
    307 			for (unsigned char i = 0; i < 2; i++) {
    308 				for (unsigned char j = 6; j <= 11; j++)
    309 					play_note(MARIO + j, freqs[MARIO + j] * 0.3);
    310 				_delay_ms(1800);
    311 			}
    312 
    313 			for (unsigned char i = 12; i <= 14; i++)
    314 				play_note(MARIO + i, freqs[MARIO + i] * 0.3);
    315 			for (unsigned char i = 15; i <= 20; i++)
    316 				play_note(MARIO + i, freqs[MARIO + i] * 0.6);
    317 
    318 			for (unsigned char i = 21; i <= 26; i++)
    319 				play_note(MARIO + i, freqs[MARIO + i] * 0.3);
    320 			for (unsigned char i = 27; i <= 32; i++)
    321 				play_note(MARIO + i, freqs[MARIO + i] * 0.6);
    322 		}
    323 	}
    324 }