Big picture: Team 4.1’s U-box

11173644_10204267139946834_797817752_n

For our final project our goal was to do something fun that would be entertaining to anyone who used our project. Thus we came up with the idea of the U-box. Our slightly more useful box does everything your typical useless box would do except it also has a cool LCD user interface thanks to the A3BU micro controller.

For those unfamiliar with what a useless box does we can explain. Basically you flip a switch, and then an arm comes out of the box and flips the switch back. This continues until either you give up or the box runs out of power. To this our group added a user interface that shows the attitude of the U-box. The first few times you flip the switch the box is disturbed. Keep flipping and the box will become angry. Finally the box will become so angry he gives up and you win. After this the “game” starts over again.

To accomplish the task of the U-box we needed to use PWM to control the servo motor and LED, input pins to determine if the switch was flipped, and additional software to tell the LCD display what to display to the user. Below is a link to download the video!

Team 4.1 U-Box video

The Graphing Calculator – Explained

This is Team 5.2 explaining how our graphing calculator works. Our design is an USART based, interrupt driven device that generates mathematical input into a graphical output on the A3BU’s LCD screen.

In simple terms, it’s a calculator. That graphs. (Our team had a lot of trouble coming up with a name. Graphulator, The Graph Master, and Graphtastic Graphing Machine were all considered.)

Various interrupt methods were incorporated into the design through user character input and push buttons on the A3BU board. The input from the PC is parsed using our own developed parsing code, which gathers all possible outputs for a given range of inputs. The software then plots those on the LCD screen. The push buttons include various scaling and scrolling methods that allow the user to interrupt the program in order to horizontally and vertically scroll and/or scale, along with re-centering capabilities.

The hardware design is very similar to that of Lab 3, using a MAX232 chip to bridge communication between the PC and the LCD on the A3BU’s on-board USART. This is done in conjunction with a serial connection via RS-232 signals.

 

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

Traffic Light- Big Picture

For our final project, we have chosen to create a stoplight using the ATxmega256A3BU microcontroller. This project idea is based off of a similar project done by a team member in Arduino. The circuit includes two stoplights (with a red, yellow, and green LED each), as well as two sets of lights for a crosswalk. The user can initiate the crosswalk sequence by clicking a small button within the circuit. This will interrupt the stoplight cycle and, theoretically, give a pedestrian a walk sign. We found this to be an interesting, and challenging project; however, it is very practical.

Below is a link to a YouTube video showing a complete cycle of the stoplight circuit.

 

 

Team In Progress: Color Sensing Motor Control – Schematics

Driving a DC Motor

Capture

Our team implemented a DC motor into our project using the circuit shown above. We used the SDA pin on the J1 header of the A3BU Xplained board to provide the signal, and we used 4 AA batteries as our power supply. The diode, wired in parallel with the motor, protects the transistor and the A3BU from possible reverse current. (Reverse current occurs when power is removed from the motor.) The diode does not affect the circuit when the power supply is on because, in this case, the diode is reverse-biased (meaning that it blocks current) and all the current flows through the motor. The transistor is used as an amplifier. The transistor has three pins (Collector, Emitter, and Base). The motor is connected to the Collector and the A3BU is connected to the Base. The Emitter is connected to ground. The A3BU cannot supply enough current for the motor to start turning, so the A3BU is connected to the transistor’s base, supplying the base current. The base current is multiplied by the gain of the transistor, and this current (the collector current) is supplied to the motor. The resistor is added to the circuit to create this base current. The high value (2.2 kΩ) of the resistor is used to limit the current going into the base since base currents are typically very small.