Fall 15 Team 2: Coding the switch

ThorCodeCompletedHammer

An interesting aspect of the project is that it is possible to use a switch to toggle the magnet. In order to use the A3BU board, we have a MOSFET switch that is triggered by a button on the board. In addition to this, we have the LCD display of the board display a shortened version of the famous line from the comic books: “Whosoever holds this hammer, if they be worthy shall have the power of Thor”.

Team 1.2 – Code

codeblockWhat you see above is how we went about getting user input from the keypad. We initially set a row high then wait 50ms to ensure the voltage has a chance to ramp up to solid logic levels. We then check to see which column goes high. This tells us which key is pressed by creating a coordinate pair (row, column). We then set the row back low and move on to the next row. This continues until all rows (total of 4) have been set high and then low again.

This could be easily improved by moving the input handler to an interrupt service routine that gets called when changes are detected on the input pins. However, this would also require more time and consideration to pull off without it having adverse effects on the sequential flow of our program.

Arduino code for team 4.1’s U-box

Team 4.1 Arduino controled armSince our 5v servo motor needed more juice to run than our A3BU could provide we opted to use an Arduino to power the motor for the arm. Below is the fairly simple code needed to flip the switch on our U-box. An initial position is set, then once the pin state is read high the arm position is moved to flip the switch and then return to its initial position.

#include <Servo.h>

Servo myservo;  // create servo object to control a servo

// twelve servo objects can be created on most boards

const int pin = 2;

int pos = 0;    // variable to store the servo position

int state = 0;

void setup()

{

myservo.attach(9);  // attaches the servo on pin 9 to the servo object

pinMode(pin, INPUT);

}   Continue reading Arduino code for team 4.1’s U-box

Smart House

A3BU code:

#include <asf.h>
#include <board.h>
#include “pwm.h”
#include “gpio.h”
#include “ioport.h”
#include “port_driver.h”
#include “avr\interrupt.h”
#include “gfx_mono.h”
#include <st7565r.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

int dutyCycle = 5;
struct pwm_config motorPwm;
#define lightLevel IOPORT_CREATE_PIN(PORTB,0)
#define alarmSense IOPORT_CREATE_PIN(PORTA,0)
int alarmOn = 0;

//Button motor toggle
ISR(PORTF_INT0_vect)
{
if (dutyCycle == 5)
{
dutyCycle = 10;
pwm_start(&motorPwm, dutyCycle);
}
else
{
dutyCycle = 5;
pwm_start(&motorPwm, dutyCycle);
}
}

//Alarm Flag
ISR(PORTA_INT0_vect)
{
int val = ioport_get_pin_level(alarmSense);

if(val == 1 && alarmOn == 0)
{
alarmOn = 1;
gpio_set_pin_low(LED0);
gpio_set_pin_low(LED1);
gfx_mono_draw_string(“\n\nALARM DETECTED!!!!”,0,0,&sysfont);
}
if (val == 0  && alarmOn == 1)
{
alarmOn = 0;
gpio_set_pin_high(LED0);
gpio_set_pin_high(LED1);
gfx_mono_draw_string(“\n\nNo alarm detected.”,0,0,&sysfont);
}
}

//Light flag
ISR(PORTB_INT0_vect)
{
if (ioport_get_pin_level(lightLevel) == 1)
{
gfx_mono_draw_string(“\nLights are on. “,0,0,&sysfont);
}
else if (ioport_get_pin_level(lightLevel) == 0)
{
gfx_mono_draw_string(“\nLights are off.”,0,0,&sysfont);
}
}

int main (void)
{
// Insert system clock initialization code here (sysclk_init()).
sysclk_init();
board_init();
gfx_mono_init();
st7565r_init();

gpio_set_pin_high(LCD_BACKLIGHT_ENABLE_PIN);
gfx_mono_draw_string(“MONITOR ONLINE:”,0,0,&sysfont);
gfx_mono_draw_string(“\nLights are off.”,0,0,&sysfont);
gfx_mono_draw_string(“\n\nNo alarm detected.”,0,0,&sysfont);

pwm_init(&motorPwm, PWM_TCC0, PWM_CH_A, 50);//this is SDA on J1 on the A3BU Xplained
pwm_start(&motorPwm, dutyCycle);

/* Configure PF1 as input, triggered on rising edge. */
PORT_ConfigurePins( &PORTF, 0x02, false, false, PORT_OPC_TOTEM_gc, PORT_ISC_RISING_gc );
PORT_SetPinsAsInput( &PORTF, 0x02 );
/* Configure Interrupt0 to have medium interrupt level, triggered by pin 1. */
PORT_ConfigureInterrupt0( &PORTF, PORT_INT0LVL_MED_gc, 0x02);

//Alarm Flag PA0 J3
PORT_ConfigurePins( &PORTA, 0x01, false, false, PORT_OPC_TOTEM_gc, PORT_ISC_BOTHEDGES_gc );
PORT_SetPinsAsInput( &PORTA, 0x01 );
/* Configure Interrupt0 to have medium interrupt level, triggered by pin 1. */
PORT_ConfigureInterrupt0( &PORTA, PORT_INT0LVL_MED_gc, 0x01);

/* Enable medium level interrupts in the PMIC. */
PMIC.CTRL |= PMIC_MEDLVLEN_bm;
/* Enable the global interrupt flag. */
sei();
while (true)
{
}
}

Smart House

ARDUINO CODE:

/*
3.3V VCC Power
GND GND Ground
A4 SDA I2C Data
A5 SCL I2C Clock
3 INT Interrupt
8 – Speaker
*/

#include <Wire.h>
#include <SparkFun_APDS9960.h>

// Pins
#define APDS9960_INT 3 // Needs to be an interrupt pin
#define Speaker_PIN 8 // Speaker

// Constants
#define PROX_INT_HIGH 50 // Proximity level for interrupt
#define PROX_INT_LOW 0 // No far interrupt

// Global variables
SparkFun_APDS9960 apds = SparkFun_APDS9960();
uint8_t proximity_data = 0;
int isr_flag = 0;

void setup() {

// Set speaker and communication as output
pinMode(8, OUTPUT);
pinMode(APDS9960_INT, INPUT);
pinMode(7,OUTPUT);

// Initialize Serial port
Serial.begin(9600);
Serial.println(F(“Speaker is online!”));
// Initialize interrupt routine
attachInterrupt(0, interruptRoutine, FALLING);

// Initialize proximity sensor
if ( apds.init() ) {
Serial.println(F(“APDS-9960 initialization complete”));
} else {
Serial.println(F(“Something went wrong during APDS-9960 init!”));
}

// Adjust the Proximity sensor gain
if ( !apds.setProximityGain(PGAIN_2X) ) {
Serial.println(F(“Something went wrong trying to set PGAIN”));
}

// Set proximity interrupt thresholds
if ( !apds.setProximityIntLowThreshold(PROX_INT_LOW) ) {
Serial.println(F(“Error writing low threshold”));
}
if ( !apds.setProximityIntHighThreshold(PROX_INT_HIGH) ) {
Serial.println(F(“Error writing high threshold”));
}

// Start running the proximity sensor
if ( apds.enableProximitySensor(true) ) {
Serial.println(F(“Proximity sensor is now running”));
} else {
Serial.println(F(“Something went wrong during sensor init!”));
}
}

void loop() {

// If interrupt occurs, print out the proximity level
if ( isr_flag == 1 ) {

// Read proximity level and print it out
if ( !apds.readProximity(proximity_data) ) {
Serial.println(“Error reading proximity value”);
} else {
Serial.print(“Proximity detected! Level: “);
Serial.println(proximity_data);
}

// Turn on speaker play tone at 523 Hz for 300 ms

tone(8, 523, 300);
Serial.println(“HI”);

// Reset flag and clear APDS-9960 interrupt (IMPORTANT!)
isr_flag = 0;

digitalWrite(7,LOW);
if ( !apds.clearProximityInt() ) {
Serial.println(“Error clearing interrupt”);
}

}
}

void interruptRoutine() {
digitalWrite(7,HIGH);

isr_flag = 1;

}

Code Snippet for team 4.1’s U-box

Here I will explain how the code for our U-box works. In this section everyone usually says “The code was fairly simple…”. I will say, with knowledge learned prior labs it becomes significantly easier to understand what we are doing. We figured out we needed to use the Arduino to power the servo motor due to voltage issues so we then planned to use the A3BU to control the LCD user interface. The LCD logic is controlled by the ADCB channel, J2 header, ADC1 pin PB1. Similar to the temperature conversion code we used in lab 4. After initializing the board, sysclk, sleepmgr and ADC channel I used the below expressions.In the code snippet below the ASCII faces we use can be explicitly seen, as well as the progression of faces based on the input pin PB1 and a count variable. Once the switch is flipped the input signal is converted and the voltage to PB1 becomes greater than 50 and the led begins to blink with 100% duty cycle. This signal is used to activate the LCD screen.

int mcount = 0;

static void adc_handler(ADC_t *adc, uint8_t ch_mask, adc_result_t result)
{…

if ((result > 50) && (mcount < 5)){

blink = 1;

gfx_mono_draw_string(”                      “, 0, 0, &sysfont);
gfx_mono_draw_string(”                      “, 0, 8, &sysfont);
gfx_mono_draw_string(”                      “, 0, 16, &sysfont);
gfx_mono_draw_string(”                      “, 0, 24, &sysfont);

mcount = mcount + 1;

gfx_mono_draw_string(”                      “, 0, 0, &sysfont);
gfx_mono_draw_string(”      (-)   (-)      “, 0, 8, &sysfont);
gfx_mono_draw_string(”    ________     “, 0, 16, &sysfont);
gfx_mono_draw_string(”                        “, 0, 24, &sysfont);
delay_ms(500);

gfx_mono_draw_string(”       _     _      “, 0, 0, &sysfont);
gfx_mono_draw_string(”      / \\   / \\     “, 0, 8, &sysfont);
gfx_mono_draw_string(”                       “, 0, 16, &sysfont);
gfx_mono_draw_string(”    \\_______/    “, 0, 24, &sysfont);
delay_ms(500);
}
…}

Golden Monkeys The Code

With regards to the coding of the project it was done by our CECS Major Nicholas Morrison. When we got together to work on the coding we had issues with the timing of the decoders which caused some of the LEDS to pop up and light, however since the timing was wrong some of the LEDS just stayed on, but most stayed off. After messing with the code a little more we were able to obtain some blinking, but, again, most of the LEDS stayed off.

After more inspection we found that the connections to the A3BU were connected incorrectly, which made it difficult for our programmer to accurately troubleshoot the code. This basically caused an issue with determining which pin in the LED drivers were high and low. 2015042595183202When trying to further troubleshoot the A3BU we found that we are having issues with designating pins. We have 16 pins available, and we need 20 however that would mean that we would have to disable the 4 pins that are currently in use by the A3BU.

Unfortunately, even though we completed the hardware, and tried our very best with the programming, we were not able to troubleshoot the issues that surfaced when we tried to implement the A3BU with the LED cube. The LED cube is functional when you apply a power source to it, but we were not able to program the A3BU to properly work with the Decoders and the LED drivers to make the LED cube to work properly.

This is the Code that does not function as of yet:

/**
* \file
*
* \brief Empty user application template
*
*/

/**
* \mainpage User Application template doxygen documentation
*
* \par Empty user application template
*
* Bare minimum empty user application template
*
* \par Content
*
* -# Include the ASF header files (through asf.h)
* -# “Insert system clock initialization code here” comment
* -# Minimal main function that starts with a call to board_init()
* -# “Insert application code here” comment
*
*/

/*
* Include header files for all drivers that have been imported from
* Atmel Software Framework (ASF).
*/
#include <asf.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <string.h>
#include <stdio.h>
#define AXIS_X 1
#define AXIS_Y 2
#define AXIS_Z 3

// Delay loop.
// This is not calibrated to milliseconds,
// but we had allready made to many effects using this
// calibration when we figured it might be a good idea
// to calibrate it.
void delay_time(uint16_t x)
{
uint8_t y, z;
for ( ; x > 0 ; x–){
for ( y = 0 ; y < 90 ; y++){
for ( z = 0 ; z < 6 ; z++){
asm volatile (“nop”);
}
}
}
}

static void setup()
{
ioport_pin_t J1[8] = {J1_PIN0, J1_PIN1, J1_PIN2, J1_PIN3, J1_PIN4, J1_PIN5, J1_PIN6, J1_PIN7};
ioport_pin_t J2[4] = {J2_PIN0, J2_PIN1, J2_PIN2, J2_PIN3};
ioport_pin_t J4[8] = {J4_PIN0, J4_PIN1, J4_PIN2, J4_PIN3, J4_PIN4, J4_PIN5, J4_PIN6, J4_PIN7};
int i = 0;
for(i = 0; i <8; i++)
{
ioport_set_pin_dir(J1[i],IOPORT_DIR_OUTPUT);
ioport_set_pin_dir(J4[i],IOPORT_DIR_OUTPUT);
if(i<4)
{
ioport_set_pin_dir(J2[i],IOPORT_DIR_OUTPUT);
}
}
}

int main(void)

{
// Insert system clock initialization code here (sysclk_init()).
pmic_init();
ioport_init();
setup();
int j = 0;
// while(true)
// {
while(true)
{

int i = 2;
ioport_pin_t J4[8] = {J4_PIN0, J4_PIN1, J4_PIN2, J4_PIN3, J4_PIN4, J4_PIN5, J4_PIN6, J4_PIN7};
ioport_set_pin_high(J2_PIN0);
for (i=0; i<8; i++)
{
if(i != 7)
ioport_set_pin_low( J4[i]);
else
ioport_set_pin_high(J4[i]);
}
ioport_set_pin_high(J2_PIN1);
ioport_set_pin_high(J2_PIN2);
ioport_set_pin_high(J2_PIN3);
ioport_pin_t J1[8] = {J1_PIN0, J1_PIN1, J1_PIN2, J1_PIN3, J1_PIN4, J1_PIN5, J1_PIN6, J1_PIN7};
for (i=0; i<8; i++)
{
if(i != 7)
ioport_set_pin_low(J1[i]);
else
ioport_set_pin_high(J1[i]);
}

delay_time(10);
ioport_set_pin_low(J2_PIN0);

delay_time(10000);
}
}

Further inspection, and after many red bulls, we discovered that the issue with our project lied in the hardware and connections that were in the LED cube and the IC circuit board. We tested the pins of the A3BU with a multimeter and we were getting the voltages that we wanted, however when we connected the A3BU to the LED cube we received some malfunctions — none of which was really the programs fault.

This is the final code that was developed:

/**
* \file
*
* \brief Empty user application template
*
*/

/**
* \mainpage User Application template doxygen documentation
*
* \par Empty user application template
*
* Bare minimum empty user application template
*
* \par Content
*
* -# Include the ASF header files (through asf.h)
* -# “Insert system clock initialization code here” comment
* -# Minimal main function that starts with a call to board_init()
* -# “Insert application code here” comment
*
*/

/*
* Include header files for all drivers that have been imported from
* Atmel Software Framework (ASF).
*/
#include <asf.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <string.h>
#include <stdio.h>
#define AXIS_X 1
#define AXIS_Y 2
#define AXIS_Z 3

// Delay loop.
// This is not calibrated to milliseconds,
// but we had already made to many effects using this
// calibration when we figured it might be a good idea
// to calibrate it.
static void delay_time(uint16_t x)
{
uint8_t y, z;
for ( ; x > 0 ; x–){
for ( y = 0 ; y < 90 ; y++){
for ( z = 0 ; z < 6 ; z++){
asm volatile (“nop”);
}
}
}
}

static void setup(void)
{
//J1: Cathode Control; J2: Pin 0 : Output Control, 1-3: Addressing; J4: Data bus
ioport_pin_t J1[8] = {J1_PIN0, J1_PIN1, J1_PIN2, J1_PIN3, J1_PIN4, J1_PIN5, J1_PIN6, J1_PIN7};
ioport_pin_t J2[4] = {J2_PIN0, J2_PIN1, J2_PIN2, J2_PIN3};
ioport_pin_t J4[8] = {J4_PIN0, J4_PIN1, J4_PIN2, J4_PIN3, J4_PIN4, J4_PIN5, J4_PIN6, J4_PIN7};
int i = 0;
for(i = 0; i <8; i++)
{
ioport_set_pin_dir(J1[i],IOPORT_DIR_OUTPUT);
ioport_set_pin_dir(J4[i],IOPORT_DIR_OUTPUT);
if(i<4)
{
ioport_set_pin_dir(J2[i],IOPORT_DIR_OUTPUT);
}
}
}

int main(void)
{
// Insert system clock initialization code here (sysclk_init()).
pmic_init();
ioport_init();
setup();
int i = 0;
int j = 0;
int k = 0;
int l = 0;
// while(true)
// {
while(true)
{

ioport_pin_t J4[8] = {J4_PIN0, J4_PIN1, J4_PIN2, J4_PIN3, J4_PIN4, J4_PIN5, J4_PIN6, J4_PIN7};
ioport_set_pin_high(J2_PIN0);
for (i=0; i<8; i++)
{
if(i != j)
ioport_set_pin_low( J4[i]);
else
ioport_set_pin_high(J4[i]);
}
switch (k)
{
case 0:
ioport_set_pin_low(J2_PIN1);
ioport_set_pin_low(J2_PIN2);
ioport_set_pin_low(J2_PIN3);
break;
case 1:
ioport_set_pin_high(J2_PIN1);
ioport_set_pin_low(J2_PIN2);
ioport_set_pin_low(J2_PIN3);
break;
case 2:
ioport_set_pin_low(J2_PIN1);
ioport_set_pin_high(J2_PIN2);
ioport_set_pin_low(J2_PIN3);
break;
case 3:
ioport_set_pin_high(J2_PIN1);
ioport_set_pin_high(J2_PIN2);
ioport_set_pin_low(J2_PIN3);
break;
case 4:
ioport_set_pin_low(J2_PIN1);
ioport_set_pin_low(J2_PIN2);
ioport_set_pin_high(J2_PIN3);
break;
case 5:
ioport_set_pin_high(J2_PIN1);
ioport_set_pin_low(J2_PIN2);
ioport_set_pin_high(J2_PIN3);
break;
case 6:
ioport_set_pin_low(J2_PIN1);
ioport_set_pin_high(J2_PIN2);
ioport_set_pin_high(J2_PIN3);
break;
case 7:
ioport_set_pin_high(J2_PIN1);
ioport_set_pin_high(J2_PIN2);
ioport_set_pin_high(J2_PIN3);
break;
default:
k = 0;
break;
}
ioport_pin_t J1[8] = {J1_PIN0, J1_PIN1, J1_PIN2, J1_PIN3, J1_PIN4, J1_PIN5, J1_PIN6, J1_PIN7};
for (i=0; i<8; i++)
{
if(i != l)
ioport_set_pin_low(J1[i]);
else
ioport_set_pin_high(J1[i]);
}
ioport_set_pin_low(J2_PIN0);
j++;
if(j >= 8)
{
j = 0;
k++;
if(k >= 8)
{
k = 0;
l++;
if(l >= 8)
{
l = 0;
}
}
}
delay_time(1000);
}
}

Team In Progress: Color Sensing Motor Control – Code

The code behind the project is fairly simple.

To establish communication between the Arduino and the color sensor, we sent register address and the byte value we want to write the magnetometer and loads the destination register with the value that was sent. To receive raw values, we send a register value address to a function and it will return the byte values for the magnetometer register’s content. Once the raw RGB values are read from their respective registers, they were converted into integers.

CaptureCapture

To determine the color being sensed, we compared the RGB values and found the color with the highest color value, then made that color the sensed color.

CaptureCapture

Once the color has been sensed, the Arduino sends out a character to the A3BU through UART.

The A3BU then takes the received character and adjusts the motor speed accordingly using Pulse Width Modulation.

Capture

Team 4.2 – Code Talk (The Hit new Talk Show starring Team 4.2)

First, the code driving it is fairly simple. The main initializes the board, the delays, and the IO ports. Then each pin that is being utilized in the project is set as either an input or output, depending on its functionality, with J1’s pins 0-2 being the input pins, J3 pins 0-2 and J2 pins 3-7 being the output pins for the LEDs. All the pins are then set to low, and the game starts. When the game starts, the input pins are enabled, and a while loop is entered:

while(player2selection==0)
{
//Waits until the player selects his option
if(gpio_pin_is_high(J1_PIN0)==true&&gpio_pin_is_high(J1_PIN1)==true&&gpio_pin_is_high(J1_PIN2))
{
player2selection=0;
}
if(gpio_pin_is_high(J1_PIN0)==true&&GPIO_PUSH_BUTTON_0)
{
player2selection=1;
}
else if(gpio_pin_is_high(J1_PIN2)==true)
{
player2selection=3;
}
else if(gpio_pin_is_high(J1_PIN1)==true)
{
player2selection=2;
}
else
{
player2selection=0;
}
}

As stated before, the pins that are referenced are the three input pins, corresponding to Rock, Paper, and Scissors respectively. This while loop stays active until one of the IO Pins are seen as being at a high logic value, and the corresponding selection is made for player 2, AKA the human player. (The first line of it where every pin is checked for being high was to combat some of the anomalies we had reached, and it was found that this did help filter some of them out.)

After the user inputs a value the pins for inputs are disabled, and the computer randomly selects a number between 1 and 3 for its selection.

 

comp=rand()%3+1;

After this a function is entered that lights up the selection LEDs by setting the corresponding pins as high for both the player and the computer for one second. Those pins are then set to low again, turning off the LEDs.

else if(player1selection==3 && player2selection==2)
{
//Set P1 P and C S
ioport_set_pin_high(J2_PIN6);
ioport_set_pin_high(J2_PIN7);
delay_ms(1000);
ioport_set_pin_low(J2_PIN7);
ioport_set_pin_low(J2_PIN6);
}

Next the code compares the computer and user selections to determine a winner, and the correct winner LED is lit up (if it is a tie then both of the red LEDs light up) for 3 seconds before turning off.

if(player1selection==player2selection)
{
ioport_set_pin_high(J3_PIN0);
ioport_set_pin_high(J3_PIN1);
delay_ms(3000);
ioport_set_pin_low(J3_PIN0);
ioport_set_pin_low(J3_PIN1);
}
else if((player2selection==1&&player1selection==2)||(player2selection==2&&player1selection==3)||(player2selection==3&&player1selection==1))
{
ioport_set_pin_high(J3_PIN0);
delay_ms(3000);
ioport_set_pin_low(J3_PIN0);
}

The computer’s and player’s selections are then reset to 0, all the pins being used set to low again, and finally the function that runs the game is run again, repeating the process until the power is cut to the board. (There is currently no end state for the game. Ideally we would have wanted to implement another couple selection buttons to indicate if a person wanted to stop playing, but we did not have time to implement it. So for now, you’re stuck playing. FOREVER. Or until you walk away. Or cut the power. Or unwire something. Or punch it.)

 

Team ACM can see the Matrix. (or at least the tick count)

So here’s our codes detailing how we did things. This ticks the clock, checks if it needs to play a sound, and manages the sound it plays.

So one of the more… complicated things we ran into while programming this thing was being able to play the chime while keeping the clock ticking. The board didn’t have any multi-process support (unless we fancied writing our own scheduler), so we couldn’t just have it run both functions simultaneously. Instead, we got a bit more creative (desperate?) and made it so that while the clock is ticking, it is also checking to see if it should be playing a sound. See lines 30 and on for how we did this. We used ticks to count how long a note should play for (and for extending the DAAAAAAAAH at the end) The extension of the last note in particular was incredibly trying. We found that depending on the amount of ticks we told it to wait, the sound we continue (or not). However, the compiler did not like this solution. Any tick count below 55000 resulted in a short length, and any above 55000 resulted in a just too long length. BUT! adjusting the tick count for the length of the first three notes (which all play for the same amount of  time) would in fact actually basically adjust the play time accordingly! We stuck with the long one in the end, but still have no idea why the compiler couldn’t count correctly. Maybe, just maybe, it’s bad :p

  1.         //Run the clock
  2.         LED_Toggle(LED0);
  3.         struct pwm_config mypwm; //For PWM for speaker
  4.         uint16_t counter = 0; //Keep track of how long chime note has been playing
  5.         uint8_t playing = 0; //Keep track if our chime is playing
  6.         uint8_t chimeIndex = 0; //Keep track of position in Chime
  7.         uint16_t chime[4] = {440, 466, 493, 523};
  8.         while (true) {
  9.                 rtc_timestamp = rtc_get_time();
  10.                 // Update printed time if the time has changed
  11.                 if(rtc_timestamp != past_timestamp) {
  12.                         calendar_add_second_to_date(&date);
  13.                         LED_Toggle(LED0);
  14.                         LED_Toggle(LED1);
  15.                         drawNumber(secMSBColumn, date.second/10);
  16.                         drawNumber(secLSBColumn, date.second%10);
  17.                         drawNumber(minMSBColumn, date.minute/10);
  18.                         drawNumber(minLSBColumn, date.minute%10);
  19.                         drawNumber(hourMSBColumn, date.hour/10);
  20.                         drawNumber(hourLSBColumn, date.hour%10);
  21.                         //Make noises on quarter minutes
  22.                         if(date.second%15 == 0) {
  23.                                 playing = 1;
  24.                                 chimeIndex = 0;
  25.                                 pwm_init(&mypwm, PWM_TCC0, PWM_CH_A, chime[chimeIndex]);
  26.                                 pwm_start(&mypwm, 75);
  27.                         }
  28.                         past_timestamp = rtc_timestamp;
  29.                 }
  30.                 if(playing) {
  31.                         counter++;
  32.                         if(chimeIndex < (uint8_t) 3) {
  33.                                 if(counter%50000 == 0) {
  34.                                         chimeIndex++;
  35.                                         counter = (uint16_t)0;
  36.                                         pwm_set_frequency(&mypwm, chime[chimeIndex]);
  37.                                         pwm_start(&mypwm, 75);
  38.                                 }
  39.                         } else {
  40.                                 if(counter%70000 == 0) {
  41.                                         playing = (uint8_t) 0;
  42.                                         counter = (uint16_t) 0;
  43.                                         pwm_stop(&mypwm);
  44.                                 }
  45.                         }
  46.                 }
  47.         }