mirror of
https://codeberg.org/eel4746_piano/avr_piano.git
synced 2024-11-22 09:10:30 -05:00
312 lines
7.6 KiB
C
312 lines
7.6 KiB
C
#include <avr/io.h> //standard AVR header
|
|
#define F_CPU 16000000UL // THE CPU FREQUENCY
|
|
#include <util/delay.h> //delay header
|
|
#include <avr/interrupt.h> //interrupt header
|
|
#include <stdlib.h>
|
|
|
|
#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';
|
|
|
|
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();
|
|
}
|
|
|
|
void displayPiano() {
|
|
char circularBuffer[16];
|
|
static int bufferIndex = 0;
|
|
lcd_clear();
|
|
lcd_gotoxy(6, 2);
|
|
lcd_print("PIANO");
|
|
_delay_ms(1000);
|
|
lcd_clear();
|
|
_delay_ms(1000);
|
|
while (buttonState == 0) {
|
|
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(6, 2);
|
|
lcd_print("PIANO");
|
|
}
|
|
|
|
_delay_ms(1000);
|
|
}
|
|
bufferIndex = 0;
|
|
lcd_clear();
|
|
}
|
|
|
|
//*******************************************************
|
|
int main(void) {
|
|
lcd_init();
|
|
lcd_hideCursor();
|
|
usart_init();
|
|
setup();
|
|
lcd_clear();
|
|
while (1) {
|
|
// Check button state and perform actions accordingly
|
|
if (buttonState == 5) {
|
|
displaySerialData();
|
|
|
|
} else if (buttonState == 4) {
|
|
displayNotes();
|
|
}
|
|
else {
|
|
displayPiano();
|
|
}
|
|
}
|
|
return 0;
|
|
}
|