Music Keypad – Schematic

First, we had to find a way to implement the keypad properly. After searching for the schematic on the internet, we realized that one pin was connected to all four buttons. The schematic is below. To understand the functionality of the keypad, we began the code by only using the first button. We connected one of the pins attached to all buttons to VCC on the J2 header. The other pin connected to button one is connected to ADC2 pin of the J2 header as well. We decided on using the J2 header because they are ADC/DAC pins on the microcontroller. Also, the J2 header pins were defined in the code as COL1, COL2, COL3, and COL4 for the column of each button. The code stated that the light on the microcontroller, LED0, will turn on when button one is pushed via an if statement. We also added a string of code to display on the LCD screen to show what button was pressed. At first, the LCD screen seemed to act a bit intermittent, and after speaking with the professor, a 10k resistor was added to eliminate floating values. By adding the resistor, we were able to have button one work successfully.  We started to implement button two.  After a bit of troubleshooting we were able to get button two working successfully, and from there it was just a matter of duplicating the code.

General schematic for our project
Wiring for the 4-input keypad
Schematic for 4 input keypad

U of L LED Sign Schematic

The schematic above is basic circuitry used in the implementation on the sign. It is powered by the A3BU, goes through a 110 ohm resistor before continuing to the LEDs where it daisy chains to each LED in that particular circuit. As mentioned above, there are 7 different circuits on the sign. One circuit for each of the LED colors(5) and two for the red and white LEDs on the letters “U” and “L”. This was done because we wanted to display U L without the rest of the sign being lighted. Although this is very basic circuitry, there were 114 LEDs on the sign, therefor soldering all the connections was very time consuming. But, it went together very well and we had no bad LEDs or bad connections to redo. The 5V power was coming from the J1 header on the A3BU. We used 7 J1 header pins, one for each circuit, and then grounded all LEDs to the A3BU via one ground.

Harry Potter Sorting Hat – Code Overview

Once all of the sensors were integrated into a single circuit, all of the separate test code for the sensors (among other things) needed to be written into a single cohesive program. The sensors and piezo buzzers were controlled by the Arduino microcontroller. As such, much of the code was written in the Arduino IDE.

Serial communication was first established between the Arduino and A3BU boards. The A3BU code would initialize and set itself up using the USART framework. The A3BU code had a continuous loop where it would wait to receive a byte (character) on its RxD pin on J1. If the Arduino sent a ‘G’, the A3BU would then write “Gryffindor” to its LCD screen using the GFX Monochrome library. If it received an ‘S’, it would write “Slytherin,” and etc. There were 4 characters for each of the 4 houses.

In the Arduino code, it first entered a while loop which would iterate until the IR distance sensor detected the hat was placed on a person’s head. Afterwards, the color sensor was triggered. It initialized itself and read in the RGB values (luminance was calculated based on these). It passes the calculated luminance value to a function, which returned a single character corresponding to the house (‘G’ = Gryffindor, ‘S’ = Slytherin, ‘R’ = Ravenclaw, ‘H’ = Hufflepuff). This character was sent to the A3BU board using the Serial.print() function. At this point, it would call a function to trigger the piezo buzzers for play the Harry Potter tune to indicate that the mighty hat had sorted the wearer into a house. The wearer would then take the hat off and read their house on the A3BU’s LCD screen (as well as enjoy that sweet tune played by the piezo buzzers).

A3BU Xplained Code: 

#include <asf.h>
#include <conf_usart_example.h>
#include <delay.h>
#include <gfx_mono.h>
#include <sysfont.h>

int main (void)
{
       board_init();
       sysclk_init();
       gfx_mono_init();

       // USART options.
       static usart_rs232_options_t USART_SERIAL_OPTIONS = {
              .baudrate = USART_SERIAL_EXAMPLE_BAUDRATE,
              .charlength = USART_SERIAL_CHAR_LENGTH,
              .paritytype = USART_SERIAL_PARITY,
              .stopbits = USART_SERIAL_STOP_BIT
       };

       // Initialize USART driver in RS232 mode
       usart_init_rs232(USART_SERIAL_EXAMPLE, &USART_SERIAL_OPTIONS);

       gpio_toggle_pin(NHD_C12832A1Z_BACKLIGHT);

     
       uint8_t received_byte;
       char character;

       while(true)
       {
              received_byte = usart_getchar(USART_SERIAL_EXAMPLE);
              character = (int)received_byte;

              gfx_mono_init();

              if(character == 'G')
              {
                     gfx_mono_draw_string("Gryffindor!", 0, 0, &sysfont);
              }else if(character == 'S')
              {
                     gfx_mono_draw_string("Slytherin!", 0, 0, &sysfont);
              }else if(character == 'H')
              {
                     gfx_mono_draw_string("Hufflepuff!", 0, 0, &sysfont);
              }else if(character == 'R')
              {
                     gfx_mono_draw_string("Ravenclaw!", 0, 0, &sysfont);
              }else
              {
                     gfx_mono_draw_string("Hat is confused...", 0, 0, &sysfont);
              }
       }
}

Sample Arduino Uno Code:

void setup() //setup is called automatically
{
    Serial.begin(9600); //Initialize baud rate to 9600
    pinMode(1, OUTPUT); //set TxD pin to output for A3BU communication
}

void loop() //Arduino calls this function automatically continuously (main function)
{
    //Until IR sensor detects the hat is put on, do not go further
    distanceReading = analogRead(2);
    while( distanceReading < 350 ) //350 is the distance from IR sensor to base of boxhat
    {
         distanceReading = analogRead(2); //read value form analog pin 2
    };
    Serial.println("Hat is put on...distance: " + distanceReading);

    
    Serial.println("Activating color sensor...");
    uint16_t luxValue = readColorSensor();    

    char houseCode = determineHouse(luxValue); 
    Serial.print(houseCode); //send the house code to the A3BU

    if(houseCode == 'G' || houseCode == 'S' || houseCode == 'H' || houseCode =='R')
    {
        playHPTune();
    }

    delay(5000);
}
uint16_t readColorSensor()
{
    if (tcs.begin()) 
    {
      Serial.println("Found sensor");
    } else 
    {
      Serial.println("No TCS34725 found ... check your connections");
      while (1);
    }     
    // Now we're ready to get readings!
    delay(1000);

    uint16_t r, g, b, c, colorTemp, lux;

    
    tcs.getRawData(&r, &g, &b, &c);
    colorTemp = tcs.calculateColorTemperature(r, g, b);
    lux = tcs.calculateLux(r, g, b);

    return lux;
}
 

Harry Potter Sorting Hat – Schematics/Hardware

The IR sensor’s function in our project was to detect when the hat is worn. Initially, it was implemented alone on a breadboard for testing. This particular sensor had a supply voltage of 4.5V-5.5V, so it could take power directly from the Arduino board. The sensor test program and serial monitor in the Arduino IDE showed the output values ranging from 0-1023, which indicated the detected distance.

Initially, we had the color sensor connected directly to the 5V port of the Arduino board. Once we realized that the color sensor has a max voltage setting of 3.8V, a voltage divider was implemented within the circuit to step down the 5V from the Arduino. The two resistors in voltage divider in series were a 220 Ohm resistor and a 330 Ohm resistor.

The 5V from the Arduino was inputted into the power line of the breadboard. From there, the voltage divider stepped it down for the devices that required it. The last item we needed to implement was a piezo buzzer, which was very simple in nature (when pin is high, buzz; when pin is low, stop buzzing). Delays and duty cycles are cleverly used to trick the piezo buzzer in playing decipherable simple music. A short tune of the Harry Potter theme music was found and implemented into our code.

Below are some of the pictures of to give a overview of how everything was wired up:

Defect Detector – Schematic

Here you can see the servo motor to the left that was connected to our A3BU which is being controlled by PWM. The duty cycles ranged from 15 (middle), 10 (left), and 20 (right)

Wiring:

In order to connect the servo motor and pressure sensor to the A3BU, first we had to look up what colors were used for the power, ground, and signal for the servo and then pins that were used for the pressure sensor. The servo motor is wired up to an external 5V DC power supply with an orange cable connected to the PWM pin on the A3BU. The pressure sensor was connected to a 3.3V power supply from the board and was connected to the ADC pin of the A3BU. The A3BU received power from a laptop.

Music Keypad – Code Snippet

One of the most difficult parts of our projects was figuring out how to initialize our keypad and retrieve inputs to the A3BU.  In the code below, we initialize the 4 ADC pins to receive inputs from the 4 buttons on the keypad.  Then we have to set each of the inputs to -1 initially.  The code stated that the light on the microcontroller, LED0, will turn on when button one is pushed via an if statement. We also added a string of code to display on the LCD screen to show what button was pressed. At first, the LCD screen seemed to act a bit intermittent, and after speaking with the professor, a 10k resistor was added. By adding the resistor, we were able to have button one work successfully.  We started to implement button two. We had the issue of something not working properly. Both buttons were wired exactly the same and the code was also identical. After a bit of troubleshooting, the code was changed from  “if (ioport_get_pin_level(COL1) > 0)” to “if (ioport_get_pin_level(COL1) == 1)”. By setting a more definite condition, we were able to clear that issue up. We were able to get button one and two to work successfully. We, then, added button three and four. They were tested and passed with no errors.  When not pressed, the keypad button in question is set to 0: off. When pressed, it is set to 1: on.

Code to initialize our inputs from the numeric keypad. COL1 is for button 1, COL2 for button 2, COL3 for button 3, and COL4 for button 4.
Code to get the input from the keypad back to the board

Once we programmed our A3BU to receive inputs from the keypad, we had to create the desired output.  To create our short jingles, we used pulse width modulation to vary the frequencies and duty cycles.  The desired notes corresponded with a specific frequency, and we chose 85 as the optimum duty cycle to get the clearest tone.  By adding in delays, we were able to control the length of the note and the length of the pauses between the notes.

Code snippet from part of the song “Jingle Bells”

“Jingle Bells”

Defect Detector – Code

The most interesting part of the code for our project was, without a doubt, the code used to filter out false positives read by the ADC. There were two main methods we utilized to do this:

  • Get a good threshold value
// in main

int baseline_reading[25];
for (int i = 0; i < 25; i++) {
    _delay_ms(100);
    baseline_reading[i] = last_result;
}
THRESHOLD = get_threshold(baseline_reading, 25);

CUTOFF = THRESHOLD + OFFSET;

/* … */

int get_threshold(int readings[], int read_count)
{
    float xbar = 0.0, s = 0.0;
    for (int i = 0; i < read_count; i++) {
        xbar += readings[i];
    }
    xbar /= read_count;
    for (int i = 0; i < read_count; i++) {
        s += squared(readings[i] - xbar);
    }
    s /= read_count - 1;
    s = sqrt(s);
    return (int) (xbar + 0.75 * s);
}

The first method employed is simply setting a good threshold that the readings must surpass in order for the program to act upon them. To obtain this threshold a number of readings are taken at the start of the program. These preliminary readings are then used to get a good baseline for the threshold by finding the arithmetic mean of them and adding a fraction of a standard deviation. The precise number of standard deviations we added was arrived at through trial and error.

  • Ensure that the reading is consistent
do {
     // busy loops 200 ms at a time until a sufficiently large weight is placed on the sensor
     int streak = 0;
     do {
         _delay_ms(100);
         if (last_result < THRESHOLD)
             streak = 0;
         else
             streak++;
     } while (streak < STREAK_THRESHOLD);
     streak = 0;
     // sorts the object appropriately
     sort_object(&mypwm, last_result, CUTOFF);
} while (1);

The other method employed is to ensure that the readings we get from the ADC are consistently significant. To do this, instead of calling the sort routine whenever a result is significant, we only call the sort routine when each of the last N results have been significant. This helps to filter out fleeting spikes of voltage read by the ADC whether they are from simple noise or from the spike that results when an object is dropped onto the sensor rather than placed on top of it.

Defect Detector – Big Picture

The purpose of our final project was to build a device where a user could place an object into a box to be sorted. The pressure sensor embedded between two plates is designed to give an analog voltage output. The raw voltage obtained from the pressure sensor is converted by an analog to digital converter (ADC) on our A3BU board, and given a digital value between 0 and 127. The plate was controlled by a servo motor which could rotate to three positions; left, center, and right.

Audio Visualizer — Code (Fourier Transform)

Having previously used Fourier Series and Transforms in our signals and systems, and differential equations courses, we knew that we could find frequency data from a time domain signal. The challenge really came in trying to determine the best way to implement our understanding. On paper and by hand, Fourier Series and Transforms can be pretty time and calculation intensive. Also, because we’d be performing our calculations on a microcontroller, we had to shift our focus to Discrete Fourier Transforms, and then because of our near real time goal and limited processing power, we had to consider the algorithmic Fast Fourier Transform (FFT). With all this in mind, we knew that someone else had probably already solved this problem. After some research about implementation of FFT on Arduino (https://www.norwegiancreations.com/2017/08/what-is-fft-and-how-can-you-implement-it-on-an-arduino/) and some quick Google searches for AVR FFT, we stumbled upon an efficient, flexible, and open-source FFT written in Assembly (http://elm-chan.org/works/akilcd/report_e.html). Fortunately, the open-source code by ©ChaN was easily integrated into our project with Atmel Studio. Furthermore, the source files were well commented and were added to our project with great ease. Using the guidance of the comments in the Assembly FFT and the basic outline of the Arduino implementation, we were able to successfully sample and transform a signal into the frequency domain in near realtime.