Temperature Controlled Box – Source Code


#include <asf.h>
#include <stdio.h>

static volatile int16_t last_temperature;
#define INPUT_PIN              ADCCH_POS_PIN1
#define OUTPUT_STR_SIZE        40
struct pwm_config mypwm[4];
int32_t destemp;
#define MY_LED0     IOPORT_CREATE_PIN(PORTA, 16)
#define MY_fan                  IOPORT_CREATE_PIN(PORTA,19)
#define MY_LED1     IOPORT_CREATE_PIN(PORTA, 17)
static void adc_handler(ADC_t *adc, uint8_t ch_mask, adc_result_t result)
{
#ifdef CONF_BOARD_OLED_UG_2832HSWEG04
gfx_mono_draw_filled_rect(0,0,128,32,GFX_PIXEL_CLR);
#endif
int32_t temperature;
char out_str[OUTPUT_STR_SIZE];

/* Compute current temperature in Celsius, based on linearization
* of the temperature sensor adc data.
*/
ioport_init();

ioport_set_pin_dir(MY_LED0, IOPORT_DIR_OUTPUT);
ioport_set_pin_dir(MY_LED1, IOPORT_DIR_OUTPUT);
if (result > 697) {
temperature = (int8_t)((-0.0295 * result) + 40.5);
} if (result > 420) {
temperature = (int8_t)((-0.0474 * result) + 53.3);
} else {
temperature = (int8_t)((-0.0777 * result) + 65.1);
}

last_temperature = temperature;

// Write temperature to display
last_temperature = last_temperature * 1.8 + 32;

if (last_temperature-2>destemp)
{

snprintf(out_str, OUTPUT_STR_SIZE, "Temperature:%1d F AC  ", last_temperature);
gpio_set_pin_low(LED0);
gpio_set_pin_high(LED1);
ioport_set_pin_level(MY_LED0, 3.3);
ioport_set_pin_level(MY_fan, 5);
ioport_set_pin_level(MY_LED1, 0);

}
else if (last_temperature+2<destemp)
{

snprintf(out_str, OUTPUT_STR_SIZE, "Temperature:%1d F Heat", last_temperature);
gpio_set_pin_low(LED1);
gpio_set_pin_high(LED0);
ioport_set_pin_level(MY_LED0, 0);
ioport_set_pin_level(MY_fan, 0);
ioport_set_pin_level(MY_LED1, 3.3);
}
else// if(last_temperature==destemp || (last_temperature-2>=destemp && last_temperature+2<=destemp))
{

snprintf(out_str, OUTPUT_STR_SIZE, "Temperature:%1d F off ", last_temperature);
gpio_set_pin_high(LED0);
gpio_set_pin_high(LED1);
ioport_set_pin_level(MY_LED0, 0);
ioport_set_pin_level(MY_fan, 0);
ioport_set_pin_level(MY_LED1, 0);

}
//            snprintf(out_str, OUTPUT_STR_SIZE, "Temperature: %2d F", last_temperature);
gfx_mono_draw_string(out_str, 0, 0, &sysfont);

// Start next conversion.
adc_start_conversion(adc, ch_mask);
}

static void adc_handler2(ADC_t *adc, uint8_t ch_mask, adc_result_t result)
{
#ifdef CONF_BOARD_OLED_UG_2832HSWEG04
gfx_mono_draw_filled_rect(0,0,128,32,GFX_PIXEL_CLR);
#endif
char out_str[OUTPUT_STR_SIZE];
if(result>= 65000){
result = 64;
}
result = (int)(result/22);
if(result < 64){
result = 64;
}
destemp=result;
snprintf(out_str, OUTPUT_STR_SIZE, "Desired Temp: %1d F   ", result);
//result = (int)result/1.2;
//gfx_mono_draw_filled_rect(0,17,result,7,GFX_PIXEL_SET);
//gfx_mono_draw_filled_rect(result,17,128-result,7,GFX_PIXEL_CLR);

gfx_mono_draw_string(out_str, 0, 20, &sysfont);
adc_start_conversion(adc, ch_mask);
}

int main(void)
{
struct adc_config         adc_conf;
struct adc_config adc_conf2;
struct adc_channel_config adcch_conf;
struct adc_channel_config adcch_conf2;

board_init();
sysclk_init();
sleepmgr_init();
irq_initialize_vectors();
cpu_irq_enable();
gfx_mono_init();

// Enable backlight if display type is not OLED
#ifndef CONF_BOARD_OLED_UG_2832HSWEG04
ioport_set_pin_high(LCD_BACKLIGHT_ENABLE_PIN);
#endif

// Initialize configuration structures.
adc_read_configuration(&ADCA, &adc_conf);
adcch_read_configuration(&ADCA, ADC_CH0, &adcch_conf);

adc_read_configuration(&ADCB, &adc_conf2);
adcch_read_configuration(&ADCB, ADC_CH1, &adcch_conf2);

/* Configure the ADC module:
* - unsigned, 12-bit results
* - VCC voltage reference
* - 200 kHz maximum clock rate
* - manual conversion triggering
* - temperature sensor enabled
* - callback function
*/
adc_set_conversion_parameters(&adc_conf, ADC_SIGN_ON, ADC_RES_12,
ADC_REF_VCC);
adc_set_clock_rate(&adc_conf, 200000UL);
adc_set_conversion_trigger(&adc_conf, ADC_TRIG_MANUAL, 1, 0);
adc_enable_internal_input(&adc_conf, ADC_INT_TEMPSENSE);

adc_set_conversion_parameters(&adc_conf2, ADC_SIGN_ON, ADC_RES_12,
ADC_REF_VCC);
adc_set_clock_rate(&adc_conf2, 200000UL);
adc_set_conversion_trigger(&adc_conf2, ADC_TRIG_MANUAL, 1, 0);
adc_enable_internal_input(&adc_conf2, ADC_INT_TEMPSENSE);

adc_write_configuration(&ADCA, &adc_conf);
adc_set_callback(&ADCA, &adc_handler);

adc_write_configuration(&ADCB, &adc_conf2);
adc_set_callback(&ADCB, &adc_handler2);

/* Configure ADC channel 0:
* - single-ended measurement from temperature sensor
* - interrupt flag set on completed conversion
* - interrupts disabled
*/
adcch_set_input(&adcch_conf, ADCCH_POS_PIN1, ADCCH_NEG_NONE,
1);
adcch_set_interrupt_mode(&adcch_conf, ADCCH_MODE_COMPLETE);
adcch_enable_interrupt(&adcch_conf);

adcch_write_configuration(&ADCA, ADC_CH0, &adcch_conf);

// Enable the ADC and start the first conversion.
adc_enable(&ADCA);
adc_start_conversion(&ADCA, ADC_CH0);

adcch_set_input(&adcch_conf2, ADCCH_POS_PIN1, ADCCH_NEG_NONE,
1);
adcch_set_interrupt_mode(&adcch_conf2, ADCCH_MODE_COMPLETE);
adcch_enable_interrupt(&adcch_conf2);

adcch_write_configuration(&ADCB, ADC_CH1, &adcch_conf);

// Enable the ADC and start the first conversion.
adc_enable(&ADCB);
adc_start_conversion(&ADCB, ADC_CH1);

do {
// Sleep until ADC interrupt triggers.
sleepmgr_enter_sleep();
} while (1);
}

Temperature Controlled Box – Final Build

The final build of our project was successful in creating a +7 degrees Fahrenheit change in less than 1 minute, and a -7 degrees Fahrenheit change in less than 3 minutes. We could have pushed our system further, although we found this temperature range to be fitting of realistic temperature settings in traditional HVAC systems. In any case, the project fulfilled its designed purpose.

 

Despite the project being a success, there were a few issues and design changes which we did not implement but would have improved the overall functionality of the system. Once obtaining a desired temperature, the system would not rerun a heat or cold mode until the actual temperature dropped below or rose above 2 degrees of the ideal (assuming the ideal temperature had remained constant). This was so the fan or hair dryer would not be turning rapidly off and on. When the room reached a sub 72 temperature, the fan would not reactivate for some time, however the hair dryer would never last more than 10 seconds. This is likely due to the moderate insulation of the control room, which could have been improved by sealing off gaps more tightly and adding a layer or two of higher insulating material.

 

Another minor issue we had was the npn transistor eating a small about of voltage when passing VCC, which decreased the overall speed of the fan. We considered using a different transistor to see if it consumed less voltage, but the cooling process operated in a reasonable amount of time so we decided to leave it. This would be an ideal fix, however, if a smaller cooling time is desired. It is also important to note there may have been some current loss due to the potentiometer also being connected to VCC in parallel, so it may have been a good idea to throw on a resistor in series and recalibrate the potentiometer values to fit the new, probably smaller, voltage range.

 

Despite these minor setbacks, the project turned out almost better than expected. The enclosures were well constructed, everything fit together nicely, and we even had a laser engraved decal [done at First Build] on the front and top of the control room, with our names and the project logo. Overall, we were able to successfully build our designed project, and every team member did their share of work towards the final completion.

Temperature Controlled Box – Software

For the code portion of this project, we used Atmel Studio 7 on Windows 10 OS and, per usual, did not experience any interface issues.

 

Using the ADC handler we were able to monitor the current temperature. Inside this handler we output the current temperature and used if statements to decide whether we needed to turn on the fan or the hair dryer. Inside the second handler we monitored readings of the potentiometer. Before we did this, however, we manipulated the result so that we had the correct desired temp. We divided the result by 1.2, yielding a Fahrenheit scale of +/- 12 degrees from 72, and made sure that any undesirable values we got from the potentiometer when it was turned all the way to either side were removed. The desired temperature was a global variable that was compared in the first ADC handler. IOPORT_CREATE_PIN was used to create and output pin My_LED0, My_LED1, and My_FAN. Pins 17, 16, and 19 were then used to toggle the desired pin the command ioport_set_pin_level (which would be the desired pin; an INT with desired value). Since the enclosure leaked temperature we had to add an offset to the desired temperature so that we could show off the off functionality. To toggle the on-board LEDS we used the commands gpio_set_pin_low() and gpio_set_pin_high() as necessary. For outputting current temperature and the desired temperature on the LCD, we used a char array out_str and snprintf(out_str, OUTPUT_STR_SIZE, “Temperature: %2d F”, last_temperature) so that we could have the string on the screen update with every read of the temperature. Finally, we used gfx_mono_draw_string to actually generate the output on the LCD. The complete program can be found in the source code.

Temperature Controlled Box – Hardware

During the design phase of this project, we experimented with several ideas about most aspects of the project. Once we agreed about designing a temperature regulator, we knew fairly early on that we were going to use a hair dryer as our heat source, as the magnitude of hot air would be extremely effective for such a small enclosure. This proved to be the case once the project entered the testing phase.

 

The cold source, however, took a bit more planning. Our first design consisted of a small thermos filled with an ice bath with tubing placed directly over the water, with the other end inserted in the control room, with a fan somewhere in the middle. This design was abandoned fairly early due to multiple issues, primarily the moisture concern and building complexity of the model. Additionally, we were concerned that the effective cooling of this system would be insufficient. Our final design was much simpler to construct and proved to be effective enough for our purposes. We would house several ice packs in a wooden box that would sit directly next to the control room, with the fan directly between the two. The input/output holes were placed near the top and bottom of the reservoir on opposite sides, as to allow maximum air exposure to the ice packs.

 

Moving on the circuitry of the system, we utilized the temperature sensor and LCD screen of the A3BU, as well as the following pins, whose functions are summarized:

 

J1_VCC – Cold Reservoir Fan Power / Potentiometer Power

J1_TxD – NPN Transistor Base

J1_SDA – Blue LED

J1_SCL – Red LED/Relay Switch

J2_ADC1 – Potentiometer Sensor

J2_GND – Ground

 

The circuit runs in three different modes – off, heat, and cold. In all modes, VCC and ADC1 are constantly active, in order to figure out the desired temperature based off the resistance of the potentiometer. Off occurs when no other pins are active, and the actual temperature equals the desired temperature. The desired temperature is changed by rotating the potentiometer dial, which signals to ADC1. When the desired temperature is greater, SCL activates which both switches the relay outlets (turning on the hair dryer), and the red LED is powered on, indicating that the system is in heat mode. When the desired temperature is less, both TxD and SDA come on. TxD enables flow through the transistor, allowing VCC to power the fan, and SDA powers the blue LED, indicating cold mode. Once obtaining a desired temperature, the system will not rerun a heat or cold mode until the actual temperature drops below or rises above 2 degrees of the ideal (assuming the ideal temperature had remained constant).This circuit can be viewed in full in the schematic.