summaryrefslogtreecommitdiff
path: root/pcr-controller
diff options
context:
space:
mode:
authorBernhard Tittelbach <xro@realraum.at>2013-10-15 00:53:11 +0000
committerBernhard Tittelbach <xro@realraum.at>2013-10-15 00:53:11 +0000
commit5eb5a1d895695f7821868b34732d0d6eca2fdb23 (patch)
tree8ffdbf16bbd76b5f91d846669ec72cd3d0c510d1 /pcr-controller
parentjson output experiment, etc (diff)
various bugfixes and improvements + documentation
git-svn-id: https://svn.spreadspace.org/avr/trunk@245 aa12f405-d877-488e-9caf-2d797e2a1cc7
Diffstat (limited to 'pcr-controller')
-rw-r--r--pcr-controller/Makefile2
-rw-r--r--pcr-controller/cmd_queue.c74
-rw-r--r--pcr-controller/cmd_queue.h7
-rw-r--r--pcr-controller/pcr-controller.c172
-rw-r--r--pcr-controller/pid_control.c6
-rw-r--r--pcr-controller/protocol_uc.txt166
-rw-r--r--pcr-controller/temp_curve.c40
-rw-r--r--pcr-controller/temp_curve.h2
8 files changed, 302 insertions, 167 deletions
diff --git a/pcr-controller/Makefile b/pcr-controller/Makefile
index 1ed2909..e5d923c 100644
--- a/pcr-controller/Makefile
+++ b/pcr-controller/Makefile
@@ -26,7 +26,7 @@ OBJ := $(NAME).o pwm.o pid_control.o temp_curve.o cmd_queue.o
LIBS := util led lufa-descriptor-usbserial anyio onewire ds1820
EXTERNAL_LIBS := lufa
RESET_FUNC := ../tools/reset_lufa_cdc
-RESET_PARAM := 'r'
+RESET_PARAM := 'R'
LUFA_PATH := ../contrib/LUFA-120219
LUFA_OPTS = -D USB_DEVICE_ONLY
diff --git a/pcr-controller/cmd_queue.c b/pcr-controller/cmd_queue.c
index 65cf001..6d12296 100644
--- a/pcr-controller/cmd_queue.c
+++ b/pcr-controller/cmd_queue.c
@@ -19,59 +19,61 @@
*/
#include <stdlib.h>
+#include <stdio.h>
#include "cmd_queue.h"
+//static assert:
+//~ static int SDFLKJ[sizeof(int) == sizeof(int16_t)] = { 0 };
+
+#define CMDQ_INPUT_LIST_LEN 2
typedef struct {
- uint8_t read_num_numbers;
+ uint8_t num_args;
void* function_ptr;
+ int16_t input_list[CMDQ_INPUT_LIST_LEN];
+ uint8_t num_args_read;
} cmd_queue_item;
#define CMQ_QUEUE_LENGTH 4
cmd_queue_item cmd_queue_[CMQ_QUEUE_LENGTH];
uint8_t cmd_queue_todo_pos_ = 0;
+uint8_t cmd_queue_fillargs_pos_ = 0;
uint8_t cmd_queue_next_here_ = 0;
-#define CMDQ_INPUT_LIST_LEN 2
-int16_t input_list_[CMDQ_INPUT_LIST_LEN];
-uint8_t num_args_read_ = 0;
+
#define CMDQ_READBUFFER_LEN 20
char cmdq_readbuffer_[CMDQ_READBUFFER_LEN];
-char *cmdq_readbuffer_pos_ = cmdq_readbuffer_;
-char *const cmdq_readbuffer_end_ = cmdq_readbuffer_ + (CMDQ_READBUFFER_LEN - 1);
+uint8_t cmdq_readbuffer_pos_ = 0;
inline void cmdq_finishReadingArgument(void)
{
- *cmdq_readbuffer_pos_ = '\0';
- cmdq_readbuffer_pos_ = cmdq_readbuffer_;
- input_list_[num_args_read_++] = atoi(cmdq_readbuffer_);
+ cmdq_readbuffer_[cmdq_readbuffer_pos_] = '\0';
+ cmdq_readbuffer_pos_ = 0;
+ cmd_queue_[cmd_queue_fillargs_pos_].input_list[cmd_queue_[cmd_queue_fillargs_pos_].num_args_read++] = atoi(cmdq_readbuffer_);
}
//call regularily if in state CQ_READING
uint8_t cmdq_addCharToArgumentBuffer(uint8_t c)
{
if ( cmd_queue_todo_pos_ == cmd_queue_next_here_ )
- return 1; //nothing to do with us
- if (num_args_read_ >= CMDQ_INPUT_LIST_LEN)
+ return 1; //nothing to do with us, since no cmd's queued
+ if (cmd_queue_[cmd_queue_fillargs_pos_].num_args_read >= CMDQ_INPUT_LIST_LEN)
return 1; //nothing to do with us
- if (num_args_read_ >= cmd_queue_[cmd_queue_todo_pos_].read_num_numbers )
+ if (cmd_queue_[cmd_queue_fillargs_pos_].num_args_read >= cmd_queue_[cmd_queue_fillargs_pos_].num_args )
return 1; //nothing to do with us
-
//if input terminated by \n or \r then addArgument
- if (c == '\n' || c == '\r')
+ if (c == '\n' || c == '\r' || c == ',' || c == 0x1B)
{
cmdq_finishReadingArgument();
return 0;
} else { //continue reading
- *cmdq_readbuffer_pos_ = (char) c;
- cmdq_readbuffer_pos_++;
+ cmdq_readbuffer_[cmdq_readbuffer_pos_++] = (char) c;
}
- //if numlen of readbuffer reached, addArgument as well
- if (cmdq_readbuffer_pos_ == cmdq_readbuffer_end_)
+ //if numlen +1 of readbuffer reached, addArgument as well (leave one char free to terminate with \0)
+ if (cmdq_readbuffer_pos_ +1 >= CMDQ_READBUFFER_LEN)
{
cmdq_finishReadingArgument();
- return 0;
}
return 0;
}
@@ -79,35 +81,47 @@ uint8_t cmdq_addCharToArgumentBuffer(uint8_t c)
void cmdq_queueCmdWithNumArgs(void* fptr, uint8_t num_args)
{
if (num_args > CMDQ_INPUT_LIST_LEN)
+ {
+ printf("{\"cmd_ok\":false,\"error\":\"max args == %d\"}\r\n", CMDQ_INPUT_LIST_LEN);
return; //can't do that Would hang cmdq
- cmd_queue_[cmd_queue_next_here_].read_num_numbers=num_args;
- cmd_queue_[cmd_queue_next_here_].function_ptr=fptr;
+ }
+ if ((cmd_queue_next_here_ +1) % CMQ_QUEUE_LENGTH == cmd_queue_todo_pos_) //for this check REQUIRED: CMQ_QUEUE_LENGTH > 2
+ cmdq_doWork(); //no more space in queue -> execute now !
+ cmd_queue_[cmd_queue_next_here_].num_args = num_args;
+ cmd_queue_[cmd_queue_next_here_].function_ptr = fptr;
+ cmd_queue_[cmd_queue_next_here_].num_args_read = 0;
+ cmd_queue_fillargs_pos_ = cmd_queue_next_here_;
cmd_queue_next_here_++;
cmd_queue_next_here_ %= CMQ_QUEUE_LENGTH;
}
void cmdq_doWork(void)
{
- if ( cmd_queue_todo_pos_ == cmd_queue_next_here_ )
- return;
-
- // is num_args_read_ now equal to num args we expect ?
- if (num_args_read_ == cmd_queue_[cmd_queue_todo_pos_].read_num_numbers )
+ while ( cmd_queue_todo_pos_ != cmd_queue_next_here_ )
{
- switch (num_args_read_)
+ // is num_args_read_ now equal to num args we expect ?
+ if (cmd_queue_[cmd_queue_todo_pos_].num_args_read != cmd_queue_[cmd_queue_todo_pos_].num_args )
+ break;
+ if (cmd_queue_[cmd_queue_todo_pos_].function_ptr == 0 )
+ break;
+
+ switch (cmd_queue_[cmd_queue_todo_pos_].num_args)
{
case 0:
((void(*)(void)) cmd_queue_[cmd_queue_todo_pos_].function_ptr)();
break;
case 1:
- ((void(*)(int16_t)) cmd_queue_[cmd_queue_todo_pos_].function_ptr)(input_list_[0]);
+ ((void(*)(int16_t)) cmd_queue_[cmd_queue_todo_pos_].function_ptr)(cmd_queue_[cmd_queue_todo_pos_].input_list[0]);
break;
case 2:
- ((void(*)(int16_t,int16_t)) cmd_queue_[cmd_queue_todo_pos_].function_ptr)(input_list_[0], input_list_[1]);
+ ((void(*)(int16_t,int16_t)) cmd_queue_[cmd_queue_todo_pos_].function_ptr)(cmd_queue_[cmd_queue_todo_pos_].input_list[0], cmd_queue_[cmd_queue_todo_pos_].input_list[1]);
break;
}
- num_args_read_ = 0;
+ cmd_queue_[cmd_queue_todo_pos_].num_args_read = 0;
+ cmd_queue_[cmd_queue_todo_pos_].num_args = 0;
+ cmd_queue_[cmd_queue_todo_pos_].function_ptr = 0;
cmd_queue_todo_pos_++;
cmd_queue_todo_pos_ %= CMQ_QUEUE_LENGTH;
+ printf("{\"cmd_ok\":true}\r\n");
}
} \ No newline at end of file
diff --git a/pcr-controller/cmd_queue.h b/pcr-controller/cmd_queue.h
index 84b8a01..d632f43 100644
--- a/pcr-controller/cmd_queue.h
+++ b/pcr-controller/cmd_queue.h
@@ -23,6 +23,13 @@
#include <avr/io.h>
+/* The only actual reason for this queue is to enable non-blocking reads.
+* I.e. we want to avoid blocking the main loop while waiting on a user-input terminating '\n', '\r' or ',' .
+* As we could (and DO if the queue is full) execute a command right away once all arguments have been read,
+* the queue really does not need to be 4 long and the whole handling could me much much simpler.
+* I.e. only ever remember ONE command and execute it as soon as all args are present!
+*/
+
uint8_t cmdq_addCharToArgumentBuffer(uint8_t c);
void cmdq_queueCmdWithNumArgs(void* fptr, uint8_t num_args);
void cmdq_doWork(void);
diff --git a/pcr-controller/pcr-controller.c b/pcr-controller/pcr-controller.c
index 95a3c19..1b8741b 100644
--- a/pcr-controller/pcr-controller.c
+++ b/pcr-controller/pcr-controller.c
@@ -53,23 +53,42 @@
#define HIGHv OP_SETBIT
#define LOWv OP_CLEARBIT
-#define PUMP_PIN PINB3
-#define PELTIER_INA PINF7
-#define PELTIER_INB PINB6
-#define PELETIER_PWM_EN PINB5
+#define PELTIER_INA_PIN PINF7
+#define PELTIER_INA_PORT PORTF
+#define PELTIER_INA_DDR DDRF
+
+#define PELTIER_INB_PIN PINB6
+#define PELTIER_INB_PORT PORTB
+#define PELTIER_INB_DDR DDRB
+
+#define PELETIER_PWM_EN_PIN PINB5
+#define PELETIER_PWM_EN_PORT PORTB
+#define PELETIER_PWM_EN_DDR DDRB
+
#define TOPHEAT_PIN PIND7
+#define TOPHEAT_PORT PORTD
+#define TOPHEAT_DDR DDRD
+
+#define PUMP_PIN PINC6
+#define PUMP_PORT PORTC
+#define PUMP_DDR DDRC
+
+#define ONEWIRE_PIN PINC7
+#define ONEWIRE_PINBASE PINC
uint8_t num_temp_sensors_ = 0;
int16_t raw_temp_ = 0;
+uint8_t temp_is_fresh_ = 0;
uint8_t debug_ = 0;
uint8_t monitor_temp_ = 0;
// at f_system_clk = 10Hz, system_clk_ will not overrun for at least 13 years. PCR won't run that long
-uint32_t system_clk_ = 0;
+volatile uint32_t system_clk_ = 0;
//with F_CPU = 16MHz and TIMER3 Prescaler set to /1024, TIMER3 increments with f = 16KHz. Thus if TIMER3 reaches 16, 1ms has passed.
#define T3_MS *16
//set TICK_TIME to 1/10 of a second
-#define TICK_TIME (100 T3_MS)
+#define SYSCLKTICK_DURATION_IN_MS 100
+#define TICK_TIME (SYSCLKTICK_DURATION_IN_MS T3_MS)
ISR(TIMER3_COMPA_vect)
{
@@ -77,6 +96,8 @@ ISR(TIMER3_COMPA_vect)
system_clk_++;
//set up "clock" comparator for next tick
OCR3A = (OCR3A + TICK_TIME) & 0xFFFF;
+ if (debug_)
+ led_toggle();
}
void initSysClkTimer3(void)
@@ -96,6 +117,7 @@ void initSysClkTimer3(void)
void queryAndSaveTemperature(uint8_t bit_resolution)
{
+ static uint32_t conversion_start_time = 0;
uint8_t sensor_index = 0;
if (num_temp_sensors_ == 0)
@@ -103,21 +125,31 @@ void queryAndSaveTemperature(uint8_t bit_resolution)
num_temp_sensors_ = ds1820_discover();
}
- for (sensor_index=0; sensor_index < num_temp_sensors_; sensor_index++)
+ if (conversion_start_time == 0)
{
- ds1820_set_resolution(sensor_index, bit_resolution);
- ds1820_start_measuring(sensor_index);
- }
-
- ds1820_wait_conversion_time(bit_resolution);
-
- for (sensor_index=0; sensor_index < num_temp_sensors_; sensor_index++)
+ // -- trigger temperatur conversion in sensor
+ for (sensor_index=0; sensor_index < num_temp_sensors_; sensor_index++)
+ {
+ ds1820_set_resolution(sensor_index, bit_resolution);
+ ds1820_start_measuring(sensor_index);
+ }
+ conversion_start_time = system_clk_;
+ // -- end trigger
+ } else
+ if ( (system_clk_ - conversion_start_time)*SYSCLKTICK_DURATION_IN_MS > ds1820_get_conversion_time_ms(bit_resolution))
{
- raw_temp_ = ds1820_read_temperature(sensor_index);
- if (raw_temp_ != DS1820_ERROR)
- {
- break; //we need only one successfully read value
- }
+ // -- receive temperatur after conversion time has passed
+ for (sensor_index=0; sensor_index < num_temp_sensors_; sensor_index++)
+ {
+ raw_temp_ = ds1820_read_temperature(sensor_index);
+ if (raw_temp_ != DS1820_ERROR)
+ {
+ temp_is_fresh_ = 1;
+ break; //we need only one successfully read value
+ }
+ }
+ conversion_start_time = 0;
+ // -- end receive
}
}
@@ -182,16 +214,16 @@ void setPeltierCoolingDirectionPower(int16_t value)
if (value >= 0)
{
- PIN_HIGH(PORTF, PELTIER_INA);
- PIN_LOW(PORTB, PELTIER_INB);
+ PIN_HIGH(PELTIER_INA_PORT, PELTIER_INA_PIN);
+ PIN_LOW(PELTIER_INB_PORT, PELTIER_INB_PIN);
pwm_set((uint8_t) value);
} else {
- PIN_LOW(PORTF, PELTIER_INA);
- PIN_HIGH(PORTB, PELTIER_INB);
+ PIN_LOW(PELTIER_INA_PORT, PELTIER_INA_PIN);
+ PIN_HIGH(PELTIER_INB_PORT, PELTIER_INB_PIN);
pwm_set((uint8_t) (-1 * value));
}
if (debug_)
- printf("Peltier value: %d, INA: %d, INB: %d\r\n", value, (PORTF & _BV(PELTIER_INA)) > 0, (PORTB & _BV(PELTIER_INB)) > 0);
+ printf("Peltier value: %d, INA: %d, INB: %d\r\n", value, (PELTIER_INA_PORT & _BV(PELTIER_INA_PIN)) > 0, (PELTIER_INB_PORT & _BV(PELTIER_INB_PIN)) > 0);
}
void handle_cmd(uint8_t cmd)
@@ -210,29 +242,31 @@ void handle_cmd(uint8_t cmd)
case 't':
case 's': printStatus(); return;
case 'L': led_toggle(); break;
- case 'l': cmdq_queueCmdWithNumArgs(led_toggle, 0); break;
+ case 'l': cmdq_queueCmdWithNumArgs((void*) led_toggle, 0); return;
case 'p':
case 'i':
case 'd':
pid_printVars();
return;
- case 'T': cmdq_queueCmdWithNumArgs(pid_setTargetValue, 1); break;
- case 'P': cmdq_queueCmdWithNumArgs(pid_setP, 1); break;
- case 'I': cmdq_queueCmdWithNumArgs(pid_setI, 1); break;
- case 'D': cmdq_queueCmdWithNumArgs(pid_setD, 1); break;
- case 'A': PIN_HIGH(PORTB, PUMP_PIN); break;
- case 'a': PIN_LOW(PORTB, PUMP_PIN); break;
- case 'B': PIN_HIGH(PORTD, TOPHEAT_PIN); break;
- case 'b': PIN_LOW(PORTD, TOPHEAT_PIN); break;
+ case 'T': cmdq_queueCmdWithNumArgs((void*) pid_setTargetValue, 1); return;
+ case 'P': cmdq_queueCmdWithNumArgs((void*) pid_setP, 1); return;
+ case 'I': cmdq_queueCmdWithNumArgs((void*) pid_setI, 1); return;
+ case 'D': cmdq_queueCmdWithNumArgs((void*) pid_setD, 1); return;
+ case 'A': PIN_HIGH(PUMP_PORT, PUMP_PIN); break;
+ case 'a': PIN_LOW(PUMP_PORT, PUMP_PIN); break;
+ case 'B': PIN_HIGH(TOPHEAT_PORT, TOPHEAT_PIN); break;
+ case 'b': PIN_LOW(TOPHEAT_PORT, TOPHEAT_PIN); break;
+ case '.': tcurve_printCurve(); return;
case '-': //reset temp curve
tcurve_reset();
break;
case '+': //add temp curve entry
//~ tcurve_add(readNumber(), readNumber());
- cmdq_queueCmdWithNumArgs(tcurve_add, 2);
- break;
- case 'Z': cmdq_queueCmdWithNumArgs(tcurve_setRepeats, 1); break;
- case 'E': cmdq_queueCmdWithNumArgs(tcurve_setPostCycleTargetTemp, 1); break;
+ cmdq_queueCmdWithNumArgs((void*) tcurve_add, 2);
+ return;
+ case '!': cmdq_queueCmdWithNumArgs((void*) tcurve_setRepeatStartPosToLatestEntry, 0); return;
+ case 'Z': cmdq_queueCmdWithNumArgs((void*) tcurve_setRepeats, 1); return;
+ case 'E': cmdq_queueCmdWithNumArgs((void*) tcurve_setPostCycleTargetTemp, 1); return;
default: printf("{\"cmd_ok\":false,\"error\":\"unknown cmd\"}\r\n"); return;
}
printf("{\"cmd_ok\":true}\r\n");
@@ -250,13 +284,13 @@ int main(void)
sei();
led_off();
- owi_init(PINC7, &PINC);
- PINMODE_OUTPUT(DDRB, PUMP_PIN);
- PIN_LOW(PORTB, PUMP_PIN);
- PINMODE_OUTPUT(DDRB, PELETIER_PWM_EN);
- PINMODE_OUTPUT(DDRB, PELTIER_INB);
- PINMODE_OUTPUT(DDRF, PELTIER_INA);
- PINMODE_OUTPUT(DDRD, TOPHEAT_PIN);
+ owi_init(ONEWIRE_PIN, &ONEWIRE_PINBASE);
+ PINMODE_OUTPUT(PUMP_DDR, PUMP_PIN);
+ PIN_LOW(PUMP_PORT, PUMP_PIN);
+ PINMODE_OUTPUT(PELETIER_PWM_EN_DDR, PELETIER_PWM_EN_PIN);
+ PINMODE_OUTPUT(PELTIER_INB_DDR, PELTIER_INB_PIN);
+ PINMODE_OUTPUT(PELTIER_INA_DDR, PELTIER_INA_PIN);
+ PINMODE_OUTPUT(TOPHEAT_DDR, TOPHEAT_PIN);
pwm_init();
pwm_set(0);
@@ -286,34 +320,40 @@ int main(void)
cmdq_doWork(); //may call queued functions
- queryAndSaveTemperature(11); //at 11bit resolution, this takes at least 390ms
-
- if (monitor_temp_)
- printStatus();
+ queryAndSaveTemperature(11); //at 11bit resolution
- if (tcurve_isSet())
+ if (temp_is_fresh_)
{
- uint16_t time_elapsed = (uint16_t) (system_clk_ - last_time);
- last_time = system_clk_;
- //PID_DISABLED == TCURVE_ERROR so this works out fine and we disable heating and PID in this case
- pid_setTargetValue(tcurve_getTempToSet(raw_temp_, time_elapsed));
- if (debug_)
+ temp_is_fresh_ = 0; //once used, temp is used up ;->
+
+ if (monitor_temp_)
+ printStatus();
+
+ if (tcurve_isSet())
{
- printf("t: %lu, elapsed: %u, target_temp: %d\r\n", system_clk_, time_elapsed, pid_getTargetValue());
+ uint16_t time_elapsed = (uint16_t) (system_clk_ - last_time);
+ last_time = system_clk_;
+ //PID_DISABLED == TCURVE_ERROR so this works out fine and we disable heating and PID in this case
+ pid_setTargetValue(tcurve_getTempToSet(raw_temp_, time_elapsed));
}
- }
- // PID control
- // make sure this is called at exact periodic intervals (i.e. make sure there are no large variable delays in for loop)
- // e.g. enable periodic temp monitoring 'm' rather than querying temp at some intervall 's'
- if (pid_isEnabled())
- {
- while (system_clk_ - last_time2 < 5 * TICK_TIME); //wait until at least 500ms have passed since last time. Should be enough time for everything else to finish. (after 13 years, code will hang here)
- last_time2 = system_clk_;
- setPeltierCoolingDirectionPower(pid_calc(raw_temp_));
+ // PID control
+ // make sure this is called at exact periodic intervals (i.e. make sure there are no large variable delays in for loop)
+ // e.g. enable periodic temp monitoring 'm' rather than querying temp at some intervall 's'
+ if (pid_isEnabled())
+ {
+ if (debug_)
+ printf("pid_calc..");
+ while (system_clk_ - last_time2 < 5); //wait until at least 500ms have passed since last time. Should be enough time for everything else to finish. (after 13 years, code will hang here)
+ if (debug_)
+ printf(" clk: %lu, elaps: %lu\r\n",system_clk_ , system_clk_ - last_time2);
+ last_time2 = system_clk_;
+ temp_is_fresh_ = 0;
+ setPeltierCoolingDirectionPower(pid_calc(raw_temp_));
+ }
+ else
+ setPeltierCoolingDirectionPower(0);
}
- else
- setPeltierCoolingDirectionPower(0);
anyio_task();
}
diff --git a/pcr-controller/pid_control.c b/pcr-controller/pid_control.c
index f1d7d3f..95d190e 100644
--- a/pcr-controller/pid_control.c
+++ b/pcr-controller/pid_control.c
@@ -85,12 +85,12 @@ int16_t pid_calc(int16_t current_value)
if (pid_target_value_ == PID_DISABLED)
return PID_DISABLED;
- int32_t error = pid_target_value_ - current_value;
+ int32_t error = (int32_t) pid_target_value_ - (int32_t) current_value;
// derivative
// instead of derivative of error we take derivative on measurement
// since dError/dt = - dInput/dt (note the - )
- int32_t d_measure = current_value - pid_last_input_;
- pid_last_input_ = current_value;
+ int32_t d_measure = (int32_t) current_value - pid_last_input_;
+ pid_last_input_ = (int32_t) current_value;
// integral (bring pid_i_ into integral, so we get smooth transfer if pid_i_ suddenly changes)
pid_i_integralsum_ += pid_i_ * error;
diff --git a/pcr-controller/protocol_uc.txt b/pcr-controller/protocol_uc.txt
index 68c4c90..18a2465 100644
--- a/pcr-controller/protocol_uc.txt
+++ b/pcr-controller/protocol_uc.txt
@@ -1,72 +1,110 @@
-Command bytes:
-'s' Temperatursensor lesen -> parse_float(string("%3.2f")) + \r\n
-'T' Temperatursoll setzen <- string (int(float(temp)*16))
-'t' Temperatursoll lesen -> parse_float(string("%3.2f")) + \r\n
-'P' P-Wert setzen <- string (uint16_t x * 1024)
-'p' Alle PID Werte ausgeben -> string (uint16_t) + \r\n
-'I' I-Wert setzen <- string (uint16_t x * 1024)
-'i' Alle PID Werte ausgeben -> string (uint16_t) + \r\n
-'D' D-Wert setzen <- string (uint16_t x * 1024)
-'d' Alle PID Werte ausgeben -> string (uint16_t p / 1024, i / 1024, d / 1024) + \r\n
-'A' Pumpe on
-'a' Pumpe off
-'B' Deckelheizung on
-'b' Deckelheizung off
-'L' Toggle LED (Debug)
-'l' Toggle LED by using queuing system (Debug)
-'R' Reset (Alle Register zurücksetzen und neu initialisieren)
-'=' Halte aktuelle Temperatur (PID Ziel gleich aktuelle Temp messen)
-'-' Lösche gesetzte Temperaturkurve
-'+' Füge einen Punkt zur Temperaturkurve hinzu. erwartet Zieltemperatur und zeit (in10tel sekunden) für wie lange die temperatur gehalten werden soll bevor zur nächsten gesprungen wird. <- string(int(float(temp)*16)) \n <- string(int(seconds*10)) \n
-'Z' setzte Anzahl Zyklen in denen die Temperaturkurve wiederholt wird (0 == default == keine Wiederholung == 1 Zyklus, 1 == 1 Wiederholung == 2 Zyklen) <- string(int(repeats))
-'E' Temperatursoll das nach Ende des Temperaturkurvenzyklus gesetzt werden soll <- string (int(float(temp)*16))
-'m' Schalte ständige Ausgabe der aktuellen Temperatur ein/aus
-
-Nach jedem Setz-Command: Bestätigung mit "OK\r\n" (oder so)
-
-
-
-Das folgende Beispiel
-fragt die Temperatur ab,
-löscht eine evtl gesetzte Temperaturkurve
-Hält für's Erste die aktuelle Temperatur
-Schaltet die Pumpe ein
-Programmiert eine Kurve von 95°C (15min) -> 65°C (1s) -> 60°C (30s) -> 70°C (30s)
-Wiederholt die Kurve 30 mal
-Kühlt die Proben nach dem Ende auf 5°C
-Gibt periodisch die aktuelle Temperatur aus.
-
-Example PCR:
+==== Command bytes ====
+'s' Temperatursensor lesen -> parse_float(string("%3.2f")) + \r\n
+'t' Same as above
+'T' Set PID target temperature. <-TempValue
+ (Only works if no temperature curve is set.)
+'P' Set PID value P <-PIDValue
+'I' Set PID value I <-PIDValue
+'D' Set PID value D <-PIDValue
+'p' Print all PID values as JSON string
+'i' Same as above
+'d' Same as above
+'A' Switch on pump.
+'a' Switch pump off.
+'B' Switch on top heater.
+'b' Switch top heater off.
+'L' Toggle LED (Debug)
+'l' Toggle LED by using queuing system (Debug)
+'R' Reset microcontroller
+'r' Same as above
+'=' Set PID target temperature to current temperature.
+'-' Clear temperature curve.
+'.' Print out currently programmed temperature curve as JSON string.
+'+' Add a temperature curve point. <-TempValue <-Duration
+ Excpects 2 arguments: Targettemperature and duration for which that temperature is to be held after it has been reached.
+'!' Set the last added (with '+') temperature curve point to be the cycle start point.
+ E.g. if >0 curve repetitions are set (with 'Z') the repetitions will start here, instead of at the first added curve point.
+'Z' Set number of cycle repetitions <-IntValue
+ E.g: 0 == default == no repetitions == 1 cycle
+ 1 == 1 repetitions == 2 cycles)
+ ....
+'E' Program a final hold temperature. PID will try to hold this value after all cycles have finished. <-TempValue
+'m' Toggle periodic status output as JSON string.
+'?' Toggle Debug Output.
+'#' Disable PID (i.e. set PID target temperature to -2048.00)
+ (Only works if no temperature curve is set. If needed use '-' first.)
+
+
+==== Command arguments ====
+If arguments are required they are to be given as numeric string.
+
+Temperature is given in degrees celcsius multiplied by 16, thus allowing us to set decimal degrees by storing and transmitting integer values.
+Negative temperatures are prepended by '-'.
+E.g. a temperature of -20 °C would be input as -320.
+
+PID parpameters are multiplied by 1024 (or whatever PID_SCALE is set to).
+E.g. an I value of 0.5 would be input as 512.
+
+Duration or time values are input as 100ms (1/10th second) integer values.
+E.g. a duration of 2 seconds would be input as 20.
+
+If multiple arguments are required, they are to be separated by the comma character ','.
+
+<-IntValue ...means: string(uint16_t x)
+<-TempValue ...means: string(int16_t(float temp * 16))
+<-PIDValue ...means: string(uint16_t x * 1024)
+<-Duration ...means: string(uint16_t s * 10)
+
+
+==== Command responses ====
+are formated as JSON values.
+PID Values are output just like they are expected to be input.
+Temperatures are output as formated float values in °C, expect when printing the current temperature curve when temperatures are printed as internal integer values (see TempValue)
+
+A value of -2048.00 or -32768 generally means something is DISABLED or inapplicable in the current state.
+
+
+==== Example uc Answers ====
+Responses to "t" or "s":
+{"t":503, "currtemp":20.34, "targettemp":-2048.00, "curve":false, "curve_t_elapsed":0, "cycles_left":0} //curve and pid disabled (pid disabel when targettemp == -2048.00
+{"t":97000, "currtemp":40.34, "targettemp":70.00, "curve":true, "curve_t_elapsed":14, "cycles_left":11}
+{"t":97200, "currtemp":69.72, "targettemp":70.00, "curve":true, "curve_t_elapsed":214, "cycles_left":11}
+{"t":110123, "currtemp":30.14, "targettemp":30.00, "curve":true, "curve_t_elapsed":10, "cycles_left":9}
+{"t":9999999, "currtemp":5.02, "targettemp":5.00, "curve":true, "curve_t_elapsed":65535, "cycles_left":0} //we know all is finished because targettemp is hold-temp
+
+Response to "."
+{"curve":[{"temp":1520,"duration":9000,"is_curr":1,"is_loop_start":1},{"temp":1040,"duration":10,"is_curr":0,"is_loop_start":0},{"temp":960,"duration":300,"is_curr":0,"is_loop_start":0},{"temp":1120,"duration":300,"is_curr":0,"is_loop_start":0},0],"end_temp:":80}
+
+Response to other commands:
+{"cmd_ok":false,"error": "No DS1820 sensors on 1wire bus, thus no temperature"}
+{"cmd_ok":false,"error":"talking to DS18b20, no valid temperature!"}
+{"cmd_ok":true}
+
+
+==== Example Program ====
s
-
=
A
b
-+
-1520
-9000
-+
-1040
-10
-+
-960
-300
-+
-1120
-300
-Z
-30
-E
-80
++1520,9000
++1040,10
+!
++960,300
++1120,300
+Z30
+E80
m
+The sequence of above commands
+- prints current temperature
+- deletes any currenlty set temperature curve
+- instructs the PID controller to hold the current temperature
+- enables the pump
+- programms the following temperature curve: 95°C (15min) -> [ -> 65°C (1s) -> 60°C (30s) -> 70°C (30s) ]
+- sets the curve to repeat the items in [] brackets 30 times
+- programms final holding temperature of 5°C (after temperature curve and all cylces have finished).
+- activates periodic status output.
-Example uc Answers:
-{"cmd_ok":false,"error": "No DS1820 sensors on 1wire bus, thus no temperature"}
-{"cmd_ok":false,"error":"talking to DS18b20, no valid temperature!"}
-{"cmd_ok":true}
-{"t":503, "currtemp":20.34, "targettemp":-2048.00, "curve":false, "curve_t_elapsed":0, "cycles_left":0} //curve and pid disabled (pid disabel when targettemp == -2048.00
-{"t":97000, "currtemp":40.34, "targettemp":70.00, "curve":true, "curve_t_elapsed":14, "cycles_left":11}
-{"t":97200, "currtemp":69.72, "targettemp":70.00, "curve":true, "curve_t_elapsed":214, "cycles_left":11}
-{"t":110123, "currtemp":30.14, "targettemp":30.00, "curve":true, "curve_t_elapsed":10, "cycles_left":9}
-{"t":9999999, "currtemp":5.02, "targettemp":5.00, "curve":true, "curve_t_elapsed":65535, "cycles_left":0} //we know all is finished because targettemp is hold-temp
+
+(c) Bernhard Tittelbach, 2013
diff --git a/pcr-controller/temp_curve.c b/pcr-controller/temp_curve.c
index 534ddfa..36ec55a 100644
--- a/pcr-controller/temp_curve.c
+++ b/pcr-controller/temp_curve.c
@@ -20,6 +20,9 @@
#include "temp_curve.h"
#include <stdlib.h>
+#include <stdio.h>
+
+extern uint8_t debug_;
const int16_t temp_margin_ = 8; // 0.5 °C
@@ -33,6 +36,7 @@ struct tc_entry {
tc_entry *temp_curve_ = 0;
tc_entry *temp_curve_end_ = 0;
tc_entry *temp_curve_current_ = 0;
+tc_entry *temp_curve_restart_pos_ = 0;
uint16_t temp_stable_time_ = 0;
@@ -45,15 +49,22 @@ void tcurve_reset(void)
tc_entry *curr = temp_curve_;
tc_entry *next = 0;
while (curr != 0) {
- next = temp_curve_->next;
+ next = curr->next;
+ if (debug_)
+ printf("tcreset: curr: 0x%x, next: 0x%x, end: 0x%x\r\n",(uint16_t)curr,(uint16_t)next,(uint16_t)temp_curve_end_);
free(curr);
+ if (curr == temp_curve_end_)
+ break; //just to be sure
curr = next;
}
temp_curve_ = 0;
temp_curve_end_ = 0;
temp_curve_current_ = 0;
curve_num_repeats_ = 0;
+ temp_curve_restart_pos_ = temp_curve_;
temp_curve_finished_ = 0;
+ if (debug_)
+ printf("tcreset: done\n\n");
}
uint8_t tcurve_hasFinished(void)
@@ -99,12 +110,35 @@ void tcurve_add(int16_t temp, uint16_t hold_for_ticks)
temp_curve_end_ = new_entry;
temp_curve_ = new_entry;
temp_curve_current_ = new_entry;
+ temp_curve_restart_pos_ = new_entry;
} else {
temp_curve_end_->next = new_entry;
temp_curve_end_ = new_entry;
}
}
+void tcurve_setRepeatStartPosToLatestEntry(void)
+{
+ temp_curve_restart_pos_= temp_curve_end_;
+}
+
+void tcurve_printCurve(void)
+{
+ if (temp_curve_ == 0)
+ {
+ printf("{\"cmd_ok\":false,\"error\":\"No curve set\"}\r\n");
+ return;
+ }
+ printf("{\"curve\":[");
+ for (tc_entry *ce = temp_curve_; ; ce=ce->next)
+ {
+ printf("{\"temp\":%d,\"duration\":%u,\"is_curr\":%d,\"is_loop_start\":%d},",ce->target_temp, ce->hold_for_timeticks, ce == temp_curve_current_,ce == temp_curve_restart_pos_);
+ if (ce == temp_curve_end_)
+ break;
+ }
+ printf("0],\"end_temp:\":%d}\r\n", post_cycle_target_temp_);
+}
+
int16_t tcurve_getTempToSet(int16_t current_temp, uint16_t ticks_elapsed)
{
if (temp_curve_current_ == 0)
@@ -129,8 +163,8 @@ int16_t tcurve_getTempToSet(int16_t current_temp, uint16_t ticks_elapsed)
temp_curve_current_ = temp_curve_current_->next;
} else if (curve_num_repeats_)
{
- //restart temp curve from the beginning
- temp_curve_current_ = temp_curve_;
+ //restart temp curve from the beginning (or the set position)
+ temp_curve_current_ = temp_curve_restart_pos_;
curve_num_repeats_--;
} else
temp_curve_finished_ = 1;
diff --git a/pcr-controller/temp_curve.h b/pcr-controller/temp_curve.h
index 86d5000..104ecb3 100644
--- a/pcr-controller/temp_curve.h
+++ b/pcr-controller/temp_curve.h
@@ -27,6 +27,7 @@
void tcurve_reset(void);
void tcurve_setRepeats(uint8_t r);
+void tcurve_setRepeatStartPosToLatestEntry(void);
uint8_t tcurve_isSet(void);
uint8_t tcurve_hasFinished(void);
uint16_t tcurve_getTimeElapsed(void);
@@ -34,5 +35,6 @@ uint8_t tcurve_getRepeatsLeft(void);
void tcurve_setPostCycleTargetTemp(int16_t v);
void tcurve_add(int16_t temp, uint16_t hold_for_s);
int16_t tcurve_getTempToSet(int16_t current_temp, uint16_t time_elapsed);
+void tcurve_printCurve(void);
#endif \ No newline at end of file