#include //standard AVR header #define F_CPU 16000000UL // THE CPU FREQUENCY #include //delay header #include //interrupt header #include #define LCD_DPRT PORTD //LCD DATA PORT #define LCD_DDDR DDRD //LCD DATA DDR #define LCD_DPIN PIND //LCD DATA PIN #define LCD_CPRT PORTB //LCD COMMANDS PORT #define LCD_CDDR DDRB //LCD COMMANDS DDR #define LCD_CPIN PINB //LCD COMMANDS PIN #define LCD_RS 0 //LCD RS #define LCD_EN 1 //LCD EN // Define your buffer sizes #define SERIAL_BUFFER_SIZE 20 #define NOTES_BUFFER_SIZE 20 // Global variables char serialBuffer[SERIAL_BUFFER_SIZE]; char notesBuffer[NOTES_BUFFER_SIZE]; int serialIndex = 0; int notesIndex = 0; volatile int buttonState = 0; // Holds the state of all buttons void usart_init(void) { // 9600 bps, RX enabled UBRR0 = 103; UCSR0B = 1 << RXEN0; UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); } char getNote(void) { while (!(UCSR0A & (1 << RXC0))); unsigned char c = UDR0; // convert 0-9 to ascii character if (c <= 9) c += '0'; // convert to capital hex else if (c >= 0xa && c <= 0xf) c = c - 0xa + 'A'; // shift to rest of alphabet else if (c >= 0x10) c = c - 0x10 + 'G'; return c; } // void lcd_putValue(unsigned char val) { LCD_DPRT &= 0x0F; LCD_DPRT |= (val & 0xF0); //send cmnd to data port LCD_CPRT |= (1 << LCD_EN); //EN = 1 for H-to-L pulse _delay_us(1); //wait to make enable wide LCD_CPRT &= ~(1 << LCD_EN); //EN = 0 for H-to-L pulse _delay_us(100); //wait to make enable wide LCD_DPRT &= 0x0F; LCD_DPRT |= val << 4; //send cmnd to data port LCD_CPRT |= (1 << LCD_EN); //EN = 1 for H-to-L pulse _delay_us(1); //wait to make enable wide LCD_CPRT &= ~(1 << LCD_EN); //EN = 0 for H-to-L pulse _delay_us(100); //wait to make enable wide } //******************************************************* void lcdCommand(unsigned char cmnd) { LCD_CPRT &= ~(1 << LCD_RS); //RS = 0 for command lcd_putValue(cmnd); } //******************************************************* void lcdData(unsigned char data) { LCD_CPRT |= (1 << LCD_RS); //RS = 1 for data lcd_putValue(data); } void lcd_clear() { lcdCommand(0x01); _delay_us(1700); } void lcd_showCursor() { lcdCommand(0x0E); _delay_us(50); } void lcd_hideCursor() { lcdCommand(0x0C); _delay_us(50); } //******************************************************* void lcd_init() { LCD_DDDR |= 0xF0; LCD_CDDR |= (1 << LCD_RS) | (1 << LCD_EN); LCD_CPRT &= ~(1 << LCD_EN); //LCD_EN = 0 _delay_us(2000); //wait for init. lcdCommand(0x33); //send $33 for init. lcdCommand(0x32); //send $32 for init lcdCommand(0x28); //init. LCD 2 line,5*7 matrix lcdCommand(0x0e); //display on, cursor on lcdCommand(0x06); //shift cursor right lcd_clear(); } //******************************************************* void lcd_gotoxy(unsigned char x, unsigned char y) { unsigned char firstCharAdr[] = { 0x80, 0xC0, 0x94, 0xD4 }; //Table 12-4 lcdCommand(firstCharAdr[y - 1] + x - 1); _delay_us(100); } //******************************************************* void lcd_print(char *str) { unsigned char i = 0; while (str[i] != 0) //while it is not end of string { lcdData(str[i]); i++; } } char getSerialData() { // Read serial data and return it return ' '; } void setup() { // Initialize Serial communication // Initialize LCD // Initialize buttons as inputs // Set pins A4 and A5 as inputs with pull-up resistors enabled DDRC &= ~((1 << DDC4) | (1 << DDC5)); PORTC |= (1 << PORTC4) | (1 << PORTC5); // Enable Pin Change Interrupt on pins PC4 and PC5 PCMSK1 |= (1 << PCINT12) | (1 << PCINT13); // Enable PCINT for pins PC4 and PC5 PCICR |= (1 << PCIE1); // Enable Pin Change Interrupt 1 sei(); // Enable global interrupts } ISR(PCINT1_vect) { // Update button state when any pin changes state for (unsigned char i = 4; i <= 5; i++) { if (PINC & (1 << i)) { if(buttonState == 0) buttonState = i; else buttonState = 0; break; } } } void displayNotes() { char circularBuffer[16]; static int bufferIndex = 0; lcd_clear(); lcd_gotoxy(6, 2); lcd_print("PLAYING"); _delay_ms(1000); lcd_clear(); _delay_ms(1000); while (buttonState == 4) { char randomValue = getNote(); if (bufferIndex == 16) { // Remove the first value and shift other values down for (int i = 0; i < 16 - 1; i++) { circularBuffer[i] = circularBuffer[i + 1]; } // Add the new value at the end circularBuffer[16 - 1] = randomValue; } else { // Add the new value to the buffer circularBuffer[bufferIndex] = randomValue; bufferIndex++; } lcd_clear(); for (int i = 0; i <= bufferIndex - 1; i++) { char singleChar[2] = {circularBuffer[i], '\0'}; lcd_gotoxy(17-bufferIndex+i ,1); lcd_print(singleChar); // Print the single character lcd_gotoxy(6,2); lcd_print("PLAYING"); } _delay_ms(1000); } bufferIndex = 0; lcd_clear(); } void displaySerialData() { char circularBuffer[16]; static int bufferIndex = 0; lcd_clear(); lcd_gotoxy(3, 2); lcd_print("RECORDING"); _delay_ms(1000); lcd_clear(); _delay_ms(1000); while (buttonState == 5) { char randomValue = getNote(); if (bufferIndex == 16) { // Remove the first value and shift other values down for (int i = 0; i < 16 - 1; i++) { circularBuffer[i] = circularBuffer[i + 1]; } // Add the new value at the end circularBuffer[16 - 1] = randomValue; } else { // Add the new value to the buffer circularBuffer[bufferIndex] = randomValue; bufferIndex++; } lcd_clear(); lcd_gotoxy(1,1); for (int i = 0; i <= bufferIndex-1; i++) { char singleChar[2] = {circularBuffer[bufferIndex- 1 - i], '\0'}; lcd_gotoxy(i+1,1); lcd_print(singleChar); // Print the single character lcd_gotoxy(3,2); lcd_print("RECORDING"); } _delay_ms(1000); } bufferIndex = 0; lcd_clear(); } //******************************************************* int main(void) { lcd_init(); lcd_hideCursor(); setup(); lcd_clear(); while (1) { // Check button state and perform actions accordingly if (buttonState == 5) { displaySerialData(); } else if (buttonState == 4) { displayNotes(); } else { lcd_gotoxy(6,2); lcd_print("PIANO"); _delay_ms(1000); } } return 0; }