This project is about making a toy which will make some musical notes using a buzzer. Connected with a power bank, you can start and stop the playing of musical notes using a button. Based on the degree of tilt on the X-, Y- and Z-axis, a simple note is mapped and the corresponding sound will be played. There is also a LED light which will turn on/off based on the note being played.
This device was originally named Pokemon Musical Ball. But I could not find a sphere container to house the Freedom board and the external power bank. Hence I use a recycled mineral water plastic bottle to house the board and power bank.
Please note some of the terms used in the images below still refer to the old name 'poke_ball'.
This is the getting started video.
Freedom board Online Training.
Using Kinetis Design Studio v3.x with Kinetis SDK v2.0To setup the development environment, follow the instructions explained in this FAQ link and go to the section "Using Kinetis Design Studio v3.x with Kinetis SDK v2.0".
Connect all the componentsAttach the Grove base shield to the K82F board and follow these steps:
- Connect the Grove Button to socket D2
- Connect the Grove Buzzer to socket D3
- Connect the Grove LED Socket with LED to socket D4
This project requires connecting the FLEXIO pins with the I2C pins of accelerometer. The connection should be set as following:
- J12-3, J12-15 connected
- J12-4, J12-16 connected
The following few images show the steps how the Freedom Maraca is built.
In pin_mux.c
void BOARD_InitPins(void)
{
/* Initialize LPUART4 pins below */
/* Ungate the port clock */
CLOCK_EnableClock(kCLOCK_PortC);
/* Affects PORTC_PCR14 register */
PORT_SetPinMux(PORTC, 14U, kPORT_MuxAlt3);
/* Affects PORTC_PCR15 register */
PORT_SetPinMux(PORTC, 15U, kPORT_MuxAlt3);
}
In main.c
Define for LED, buzzer, button and clock speed constants
#define GROVE_BUZZER_GPIO GPIOD
#define GROVE_BUZZER_GPIO_PIN 0U
#define GROVE_LED_GPIO GPIOC
#define GROVE_LED_GPIO_PIN 11U
#define GROVE_BUTTON_GPIO GPIOC
#define GROVE_BUTTON_GPIO_PIN 12U
null
#define CLK_SPEED 150000000 //Put your board's clock speed here in Hz, FRDM-K82F = 150000000
Define the init structure for the output LED pin and the input button pin.
gpio_pin_config_t led_config = {
kGPIO_DigitalOutput, 0,
};
gpio_pin_config_t button_config = {
kGPIO_DigitalInput, 0,
};
Init output LED, buzzer and input button GPIOs.
GPIO_PinInit(GROVE_BUTTON_GPIO, GROVE_BUTTON_GPIO_PIN, &button_config);
GPIO_PinInit(GROVE_LED_GPIO, GROVE_LED_GPIO_PIN, &led_config);
Init various clocks and SetPinMuxs.
CLOCK_EnableClock(kCLOCK_PortD);
PORT_SetPinMux(PORTD, 0U, kPORT_MuxAsGpio);
PORT_SetPinMux(PORTC, 12U, kPORT_MuxAsGpio);
PORT_SetPinMux(PORTC, 11U, kPORT_MuxAsGpio);
...
CLOCK_EnableClock(kCLOCK_PortB);
/* FlexIO-I2C SDA pin */
/* Affects PORTB_PCR10 register */
PORT_SetPinMux(PORTB, 10U, kPORT_MuxAlt7);
/* FlexIO-I2C SCL pin */
/* Affects PORTB_PCR11 register */
PORT_SetPinMux(PORTB, 11U, kPORT_MuxAlt7);
Buzzer sound settings and play sound functions.
// mapping of distance value of X-, Y- and Z-axis to buzzer notes
const char noteMaps[] = { 'C', 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'C', 'c', ' ' };
const int tempo = 30;
void playTone(int tone, int duration) {
for (long i = 0; i < duration * 1000L; i += tone * 2) {
GPIO_SetPinsOutput(GROVE_BUZZER_GPIO, 1u << GROVE_BUZZER_GPIO_PIN);
delayMicroSeconds(tone);
GPIO_ClearPinsOutput(GROVE_BUZZER_GPIO, 1u << GROVE_BUZZER_GPIO_PIN);
delayMicroSeconds(tone);
}
}
null
void playNote(char note, int duration) {
char names[] = { 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'C' };
int tones[] = { 191, 170, 151, 143, 127, 113, 101, 95 };
// play the tone corresponding to the note name
for (int i = 0; i < 8; i++) {
if (names[i] == note) {
playTone(tones[i], duration);
}
}
}
This code reads button state and controls the state of playing.
buttonState = GPIO_ReadPinInput(GROVE_BUTTON_GPIO, GROVE_BUTTON_GPIO_PIN);
if (buttonState == 0U && lastButtonState == 1U && playing == false) {
playing = true;
lastButtonState = buttonState;
} else if (buttonState == 0U && lastButtonState == 1U && playing == true) {
playing = false;
lastButtonState = buttonState;
} else {
lastButtonState = buttonState;
}
if (playing == true) {
...
}
Turn the LED on/off based on the note played.
if (note == 'c' || note == 'e' || note == 'g' || note == 'b') {
GPIO_WritePinOutput(GROVE_LED_GPIO, GROVE_LED_GPIO_PIN, 1U);
} else {
GPIO_WritePinOutput(GROVE_LED_GPIO, GROVE_LED_GPIO_PIN, 0U);
}
Read the acceleration values and compute the distance value of (x*x + y*y + z*z)/1000. In the current implementation, the mapping of distance values to sound notes is still very primitive.
status0_value = 0;
/* wait for new data are ready. */
while (status0_value != 0xff)
{
I2C_read_accel_regs(&i2cDev, g_accel_addr_found, ACCEL_STATUS, &status0_value, 1);
}
/* Multiple-byte Read from STATUS (0x00) register */
I2C_read_accel_regs(&i2cDev, g_accel_addr_found, ACCEL_STATUS, readBuff, 7);
status0_value = readBuff[0];
x = ((int16_t)(((readBuff[1] * 256U) | readBuff[2]))) / 4U;
y = ((int16_t)(((readBuff[3] * 256U) | readBuff[4]))) / 4U;
z = ((int16_t)(((readBuff[5] * 256U) | readBuff[6]))) / 4U;
distance = (x*x + y*y + z*z) / 1000;
note = mapNote(distance);
mapNote() function maps a distance value to a sound note.
char mapNote(int distance) {
int i = distance / 1000;
if (i >= 10) i = 10;
return noteMaps[i];
}
Build and run the Freedom Maraca app
Comments