summaryrefslogtreecommitdiff
path: root/controller.c
blob: 6dee4da5145e9f8599a1b18db90dca0cd45fe244 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include <avr/io.h>
#include <avr/interrupt.h>
#include <math.h>
#include <stdio.h>
#include <string.h>

#include "controller.h"

#include "bridge.h"
#include "serial.h"

static void adc_init(void)
{
	/* Configure the ADC */
	ADMUX = (1 << REFS1) | (1 << REFS0);
	/* select channel x (0 for now) */
	ADMUX |= 0x0;
	ADCSRA = (1 << ADEN) | (1 << ADIE)
		| (1 << ADPS2) | (1 << ADPS1)
		| (1 << ADPS0);
}

/* Initializes TIMER1 */
static void timer_init(void)
{
	TCCR1B = (1 << WGM12) | (1 << CS12) | (1 << CS10);
	OCR1A = 7200;
	TIMSK|=(1<<OCIE1A);
}

static volatile char controller_in_init;
static volatile char controller_active;
static volatile long controller_target_temp;
static volatile char controller_num_iterations;
static volatile uint16_t controller_measured_temp;

void controller_init(void)
{
	controller_active = 0;
	controller_in_init = 1;

	bridge_init();
	adc_init();
	timer_init();
}

static long celsius_to_adc(double target_temp)
{
	long rv;

	rv = 1203.59290 * exp(-0.0686201496 * target_temp) + 413.59437;
	if (rv > 1017)
		return 1017;
	if (rv < 450)
		return 450;
	return rv;
}

static double adc_to_celsius(long adc)
{
	double rv;

	rv = adc - 413.59437;
	rv /= 1203.59290;
	rv = log(rv);
	rv /= -0.0686201496;
	return rv;
}

int controller_set(double target)
{
	if (target < 8.0 || target > 42.0)
		return 1;

	controller_target_temp = celsius_to_adc(target);
	controller_num_iterations = 1;
	controller_active = 1;
	return 0;
}

double controller_get(void)
{
	return adc_to_celsius(controller_measured_temp);
}

void controller_off(void)
{
	controller_active = 0;
	bridge_off();
}

ISR(TIMER1_COMPA_vect)
{
	/* Start adc measurement */
	ADCSRA |= (1<<ADSC);
}

ISR(ADC_vect) 
{
	if (controller_in_init) {
		controller_measured_temp = ADCW;
		controller_in_init = 0;
	} else {
		controller_measured_temp = (0.8 * controller_measured_temp)
			                 + (0.2 * ADCW);
	}

	if (! controller_active)
		return;

	controller_num_iterations--;
	if (controller_num_iterations) {
#if 0
		char buffer[128];
		snprintf(buffer, sizeof(buffer), "DEBUG adc==%ld adc_target=%ld\r\n",
				(long int)controller_measured_temp,
				controller_target_temp);
		serial_send(buffer, strlen(buffer), 0);
#endif
		return;
	}

	controller_num_iterations = 60;

	if ((long)controller_measured_temp < controller_target_temp - 5) {
		/* Cooling required */
		bridge_on_cool();
		return;
	}

	if ((long)controller_measured_temp > controller_target_temp + 20) {
		/* Heating required */
		bridge_on_heat();
		return;
	}

	/* Temperature is roughly okay, turn bridge off until next
	 * measurement. */
	bridge_off();
}