Serial Musical Organ 1.0
Buzzer controller and musical organ
Loading...
Searching...
No Matches
Macros | Functions | Variables
main.c File Reference

Main program for serial-controlled musical organ. More...

#include "includes/CPU.h"
#include <avr/io.h>
#include <util/delay.h>
#include "includes/pinDefines.h"
#include "includes/scale16.h"
#include "includes/organ.h"
#include "includes/pre_defined_songs.h"
#include "includes/USART.h"
Include dependency graph for main.c:

Go to the source code of this file.

Macros

#define ARRAY_SIZE(x)   (sizeof(x) / sizeof((x)[0]))
 Calculate the number of elements in a static array at compile time.
 

Functions

int main (void)
 Main program entry point.
 

Variables

uint16_t currentNoteLength = Q
 Current note duration in milliseconds.
 
const uint16_t notes []
 Array of musical notes mapped to keyboard keys.
 

Detailed Description

Main program for serial-controlled musical organ.

Author
Roybel Carbonell Camejo
Date
2026-04-29
Version
1.1

This program implements a serial-controlled musical organ that plays notes received via USART on an ATmega168 microcontroller. It maps keyboard keys to musical notes and allows dynamic control of note duration through serial commands. The program also supports playing pre-programmed songs.

Hardware Requirements

Dependencies

Serial Commands

Key Action Mode
a, s, d, f, g, h, j, k, l, ;, ' White keys (natural notes) Musical
w, e, t, y, i, o, p Black keys (sharp notes) Musical
[ Set short note duration (250ms) Control
] Set long note duration (500ms) Control
1 Play "Twinkle Twinkle Little Star" Song
2 Play "Imperial March" (Star Wars) Song

Musical Note Mapping

The following keyboard keys correspond to musical notes:

White Keys (Natural Notes):

Key Note Frequency Octave
a G4 392 Hz 4th
s A4 440 Hz 4th
d B4 494 Hz 4th
f C5 523 Hz 5th
g D5 587 Hz 5th
h E5 659 Hz 5th
j F5 698 Hz 5th
k G5 784 Hz 5th
l A5 880 Hz 5th
; A#5 932 Hz 5th
' C6 1047 Hz 6th

Black Keys (Sharp Notes):

Key Note Frequency Octave
w G#4 415 Hz 4th
e A#4 466 Hz 4th
t C#5 554 Hz 5th
y D#5 622 Hz 5th
i F#5 740 Hz 5th
o G#5 831 Hz 5th
p B5 988 Hz 5th

Note Durations

Usage

  1. Hardware Setup:
    • Connect buzzer to BUZZER_PIN (see pinDefines.h)
    • Connect USB-to-Serial adapter to USART pins (PD0/RX, PD1/TX)
  2. Software Setup:
    • Compile and flash to ATmega168
    • Open serial terminal (9600 baud, 8N1)
  3. Operation:
    • Press letter keys (a, s, d, f, etc.) to play notes
    • Press '[' or ']' to change note duration
    • Press '1' to play Twinkle Twinkle Little Star
    • Press '2' to play Imperial March

Flow Control & Blocking Behavior

Memory Usage Analysis

Known Issues & Limitations

Future Improvements

License

This program is open source. Feel free to modify and distribute.

See also
pre_defined_songs.c Song implementations
organ.c Note generation implementation
USART.c Serial communication implementation

Definition in file main.c.

Macro Definition Documentation

◆ ARRAY_SIZE

#define ARRAY_SIZE (   x)    (sizeof(x) / sizeof((x)[0]))

Calculate the number of elements in a static array at compile time.

Parameters
xThe array to calculate size for
Returns
Number of elements in the array
Note
This macro only works with actual arrays, not pointers
Warning
Using on pointers will give incorrect results
Examples
/home/luka/WORK/Programming/ARDUINO/AVR-Square-Wave-Organ/src/main.c.

Definition at line 357 of file main.c.

Function Documentation

◆ main()

int main ( void  )

Main program entry point.

Returns
int Program exit status (never reached in embedded systems)

Initializes the buzzer pin and USART communication, then enters an infinite loop that processes incoming serial commands and plays corresponding musical notes or songs.

Initialization Steps

  1. Configure buzzer pin as output (BUZZER_DDR)
  2. Initialize USART communication (initUSART)
  3. Display control instructions via serial (printString)
  4. Enter main processing loop

Main Loop Operation

The main loop continuously:

  1. Receive: Waits for a character via receiveByte() (blocking call)
  2. Echo: Transmits the character back via transmitByte()
  3. Check Notes: Maps key to note using parallel arrays
  4. Process Commands: Handles special characters ([, ], 1, 2)
  5. Default: Plays a rest for unassigned keys (ignores CR/LF)
  6. Delay: Small delay (10ms) to prevent CPU saturation

Command Priority

  1. Musical notes (a-z keys) - Highest priority
  2. Song triggers ('1', '2')
  3. Mode controls ('[', ']')
  4. Rest (all other characters) - Lowest priority

Error Handling

  • Unrecognized commands (except CR/LF) trigger a rest (silence)
  • No error messages are sent to avoid serial clutter
  • Invalid note keys are silently ignored (no error feedback)

@performance Performance Characteristics

  • Note latency: ~1-2ms (UART receive + processing)
  • Note jitter: Low (deterministic blocking delays)
  • CPU usage: 100% during note playback (busy-wait)
  • Memory footprint: ~150 bytes RAM, ~3KB flash
See also
playNote() Function that generates tones
play_twinkle_little_star() Song implementation
play_imperial_march() Song implementation
rest() Silence generation function

< Received character from USART

< Flag indicating if character was a valid note

< Loop counter for key mapping

Keyboard key mapping array

Maps physical keyboard keys to musical notes. Must maintain same order as notes[] array.

The array includes:

  • White keys: a, s, d, f, g, h, j, k, l, ;, '
  • Black keys: w, e, t, y, i, o, p

Total of 18 keys covering 2 octaves (G4 to C6)

Invariant
ARRAY_SIZE(keys) == ARRAY_SIZE(notes)
See also
notes Musical notes array (same order)

Step 1: Receive character from USART

Note
This function blocks until a character is received

Step 2: Echo character back to sender

Useful for debugging and providing visual feedback

Note
Can be disabled to reduce serial traffic

Step 3: Check if character is a valid musical note

Iterates through keys array and plays corresponding note if a match is found.

Step 4: Process non-note commands

Handles control characters, song triggers, and ignores unwanted characters.

Handle all other characters

Ignore carriage return and line feed (common from terminal) For all other characters, play a rest (silence) to indicate the key was received but invalid.

Step 5: Small delay to prevent CPU saturation

Allows other tasks (if any) to run and prevents the main loop from consuming 100% CPU when idle. A value of 10ms is sufficient for smooth operation.

Examples
/home/luka/WORK/Programming/ARDUINO/AVR-Square-Wave-Organ/src/main.c.

Definition at line 455 of file main.c.

References ARRAY_SIZE, BUZZER_DDR, BUZZER_PIN, currentNoteLength, H, initUSART(), notes, play_imperial_march(), play_twinkle_little_star(), playNote(), printString(), Q, receiveByte(), rest(), and transmitByte().

Here is the call graph for this function:

Variable Documentation

◆ currentNoteLength

uint16_t currentNoteLength = Q

Current note duration in milliseconds.

Global variable that stores the currently selected note duration. Initialized to Q (quarter note, typically 250ms) for shorter notes. Modified by '[' (short mode) and ']' (long mode) commands.

Note
Changing this variable affects ALL subsequent notes played
Warning
Does NOT affect songs that use hardcoded durations
See also
Q Short note duration (250ms)
H Long note duration (500ms)
Examples
/home/luka/WORK/Programming/ARDUINO/AVR-Square-Wave-Organ/src/main.c.

Definition at line 371 of file main.c.

Referenced by main().

◆ notes

const uint16_t notes[]
Initial value:
= {G4, Gx4, A4, Ax4, B4, C5, Cx5,
D5, Dx5, E5, F5, Fx5, G5, Gx5,
A5, Ax5, B5, C6}
#define Gx5
Definition scale16.h:84
#define Cx5
Definition scale16.h:77
#define B4
Definition scale16.h:61
#define G5
Definition scale16.h:83
#define D5
Definition scale16.h:78
#define F5
Definition scale16.h:81
#define C5
Definition scale16.h:76
#define C6
Definition scale16.h:87
#define Gx4
Definition scale16.h:70
#define A5
Definition scale16.h:73
#define G4
Definition scale16.h:69
#define Ax5
Definition scale16.h:74
#define A4
Definition scale16.h:59
#define Dx5
Definition scale16.h:79
#define Fx5
Definition scale16.h:82
#define E5
Definition scale16.h:80
#define B5
Definition scale16.h:75
#define Ax4
Definition scale16.h:60

Array of musical notes mapped to keyboard keys.

This array contains frequency values (timer compare values) for notes corresponding to keys in the same position in the keys array.

Index Mapping:

Index Key Note Frequency
0 a G4 392 Hz
1 w G#4 415 Hz
2 s A4 440 Hz
3 e A#4 466 Hz
4 d B4 494 Hz
5 f C5 523 Hz
6 t C#5 554 Hz
7 g D5 587 Hz
8 y D#5 622 Hz
9 h E5 659 Hz
10 j F5 698 Hz
11 i F#5 740 Hz
12 k G5 784 Hz
13 o G#5 831 Hz
14 l A5 880 Hz
15 p B5 988 Hz
16 ; A#5 932 Hz
17 ' C6 1047 Hz
Note
The order MUST match the keys array in main() function
Warning
Changing this array requires updating keys array to match
See also
keys Keyboard key mapping array
scale16.h Note definitions
Examples
/home/luka/WORK/Programming/ARDUINO/AVR-Square-Wave-Organ/src/main.c, and /home/luka/WORK/Programming/ARDUINO/AVR-Square-Wave-Organ/src/pre_defined_songs.c.

Definition at line 406 of file main.c.

Referenced by main().