3
0

Checks now status of temperature controller relais

output
This commit is contained in:
Markus Rosenstihl 2017-05-31 16:33:42 +01:00
parent 0e43ea9758
commit 6ea36736ed

View File

@ -1,78 +1,101 @@
#include <limits.h> #include <limits.h>
// Needed for LiquidCrystal_I2C.h #include <SPI.h>
#include <Wire.h> #include <TFT.h>
// from https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads/ //#include <SD.h>
#include <LiquidCrystal_I2C.h> // display setup
#define CS 18
#define DC 19
#define RESET 17
// as per http://funduino.de/nr-06-zwei-i%C2%B2c-displays-gleichzeitig
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
boolean setup_ok=true; // false will stop loop() // create an instance of the library
TFT TFTscreen = TFT(CS, DC, RESET);
boolean setup_ok = true;
const int N = 16; // number of sample averages const int N = 16; // number of sample averages
volatile unsigned int deltas[N]; // array of time deltas between interrupt volatile unsigned int deltas[N]; // array of time deltas between interrupt
volatile unsigned int n = 0; // run variable volatile unsigned int n = 0; // run variable
unsigned long total; unsigned long total;
float flow; float flow;
int prescaler; struct rgb {
char buff[10]; // temp. buffer for string manipulation/formatting int red=0;
char serialbuff[16]; // temp. buffer for string manipulation/formatting int green=0;
int blue=0;
};
// begin user configuration parameters
/* /*
User configuration This is the prescaler setting for timer1:
==================
Flow meter
==========
The PFG flow meter can measure from 0.24 to 17 l/min at 4 pulses/s per l/min
max period about 1s, i.e. min flow of 0.24l/min
min period about 15 ms i.e. max flow of 17l/min
The time base of the timer counter TCNT1 The time base of the timer counter TCNT1
t_step or seconds/tick = prescaler/clock t_step or seconds/tick = prescaler/clock
Note: Maximum TCNT1 value is 65535, i.e. Note: Maximum TCNT1 value is 65535, i.e.
Maximum time lengths (and thus timeouts) per prescaler value are: Maximum time lengths (and thus timeouts) are:
8 0.0327675 s 8 0.0327675 s
64 0.26214 s 64 0.26214 s
256 1.04856 s 256 1.04856 s
1024 4.19424 s 1024 4.19424 s
*/
#define PRESCALER 256 // todo: make this dependent on timeout
For accuracy the prescaler is set automatically fitting to the TIMEOUT. /*
The flow meter can measure from 0.24 to 17 l/min at 4 pulses/s per l/min
max period about 1s, i.e. min flow of 0.24l/min
min period about 15 ms i.e. max flow of 17l/min
*/ */
#define TIMEOUT 1.0 // measurement timeout in Hz (needs to be less than timer1 limits above) #define TIMEOUT 1.0 // measurement timeout in Hz (needs to be less than timer1 limits above)
#define DISPLAY_INTERVAL 1.0 // display update interval (and serial send interval) #define DISPLAY_INTERVAL 1.0 // display update interval (and serial send interval)
const float conversion = 4.0; // conversion factor, pulses/s per l/min const float conversion = 4.0; // conversion factor, pulses/s per l/min
const float flow_threshold = 1.0; // alarm threshold for flow const float flow_threshold = 0.5; // alarm threshold for flow
// end user configuration parameters
/* // begin hardware configuration / wiring setup
Hardware configuration / wiring setup // Pin 13 has an LED connected on most Arduino boards.
===================================== // alarm LED pin
#define ALARM_LED_PIN 4
// interlock pin
#define INTERLOCK_PIN 5
#define OVERTEMP_PIN 14
Pin 13 has an LED connected on most Arduino boards. // end hardware configuration / wiring setup
This is the alarm LED pin
*/
#define ALARM_LED_PIN 13
// interlock output pin
#define INTERLOCK_PIN 12
/* // temp. buffer for string manipulation/formatting
Setup routine char buff[10];
============= char old_flow_string[32];
char new_flow_string[32];
char old_status_string[16] = "yyyyyyyyyyyyyyy";
char new_status_string[16];
boolean status_change = true;
boolean status_safety = false;
Run once upon startup
*/
void setup() void setup()
{ {
lcd.begin(16,2); // start LCD (16x2 characters) SPI.setClockDivider(SPI_CLOCK_DIV2);
lcd.home (); // go home TFTscreen.begin();
lcd.print("PFG security"); // string first line // clear the screen with a black background
lcd.setCursor ( 0, 1 ); // go to the next line struct rgb bg;
lcd.print (""); // string second line bg.red = 0;
bg.green = 0;
bg.blue = 0;
TFTscreen.background(bg.red, bg.green, bg.blue);
// write the static text to the screen
// set the font color to white
TFTscreen.stroke(255, 255, 255);
// set the font size
TFTscreen.setTextSize(2);
// write the text to the top left corner of the screen
TFTscreen.text("PFG Safety", 0, 0);
Serial.begin(19200); // serial line speed Serial.begin(19200); // serial line speed
/* Interrupt pins /* Interrupt pins
UNO: UNO:
@ -82,12 +105,10 @@ void setup()
attachInterrupt(0, get_time, FALLING); attachInterrupt(0, get_time, FALLING);
pinMode(ALARM_LED_PIN, OUTPUT); pinMode(ALARM_LED_PIN, OUTPUT);
pinMode(INTERLOCK_PIN, OUTPUT); pinMode(INTERLOCK_PIN, OUTPUT);
pinMode(OVERTEMP_PIN, INPUT);
/* // starting values for the deltas array
Set sensible default starting values for the deltas array, // otherwise the array values are maybe zero at the beginning and we get very high (wrong) flow values
otherwise the array values are maybe zero at the beginning
and we get very high (wrong) flow values.
*/
for (int k = 0; k < N; k++) { for (int k = 0; k < N; k++) {
deltas[k] = UINT_MAX; deltas[k] = UINT_MAX;
} }
@ -96,28 +117,13 @@ void setup()
timer1 setup timer1 setup
*/ */
// select prescaler according to TIMEOUT
if (TIMEOUT < 0.0327675)
prescaler = 8;
else if (TIMEOUT < 0.26214)
prescaler = 64;
else if (TIMEOUT < 1.04856)
prescaler = 256;
else if (TIMEOUT < 4.19424)
prescaler = 1024;
else {
lcd.setCursor (0,1); // char 0 on line 0 or 1
lcd.print ("ERR TIMEOUT BIG");
setup_ok=false;
return;
}
noInterrupts(); // disable all interrupts noInterrupts(); // disable all interrupts
// clear timer1 registers // clear timer1 registers
TCCR1A = 0; TCCR1A = 0;
TCCR1B = 0; TCCR1B = 0;
TCNT1 = 0; // timer1 counter, reset on every HW interrupt from the flow meter (see get_time function) TCNT1 = 0; // timer1 counter, reset on every HW interrupt pulse from the flow meter (see get_time function)
OCR1A = (int)(16e6/prescaler*TIMEOUT);// Clear timer on compare match value: 16MHz/PRESCALER*timeout(in s) OCR1A = (int)(16e6 / PRESCALER * TIMEOUT); // Clear timer on compare match 16MHz/PRESCALER*timeout(in s)
TCCR1B |= (1 << WGM12); // CTC mode (Clear Timer on Compare Match) TCCR1B |= (1 << WGM12); // CTC mode (Clear Timer on Compare Match)
/* /*
Prescaler settings x=0,1,2 (Timer0, Timer1, Timer2) Prescaler settings x=0,1,2 (Timer0, Timer1, Timer2)
@ -127,22 +133,60 @@ void setup()
1 0 0 Clk/256 (1 << CS12) 1 0 0 Clk/256 (1 << CS12)
1 0 1 Clk/1024 (1 << CS12)|(1 << CS10) 1 0 1 Clk/1024 (1 << CS12)|(1 << CS10)
*/ */
if (prescaler == 8) if (PRESCALER == 8) {
TCCR1B |= (1 << CS11); TCCR1B |= (1 << CS11);
else if (prescaler == 64) if (TIMEOUT > 0.0327675) {
interrupts();
//lcd.setCursor (0,1); // char 0 on line 0 or 1
//lcd.print ("CFGERR TIMEOUT");
setup_ok = false;
return;
}
}
else if (PRESCALER == 64) {
if (TIMEOUT > 0.26214) {
interrupts();
//lcd.setCursor (0,1); // char 0 on line 0 or 1
//lcd.print ("CFGERR TIMEOUT");
setup_ok = false;
return;
}
TCCR1B |= (1 << CS11) | (1 << CS10); TCCR1B |= (1 << CS11) | (1 << CS10);
else if (prescaler == 256) }
else if (PRESCALER == 256) {
if (TIMEOUT > 1.04856) {
interrupts();
//lcd.setCursor (0,1); // char 0 on line 0 or 1
//lcd.print ("CFGERR TIMEOUT");
setup_ok = false;
return;
}
TCCR1B |= (1 << CS12); TCCR1B |= (1 << CS12);
else if (prescaler == 1024) }
else if (PRESCALER == 1024) {
if (TIMEOUT > 4.19424) {
interrupts();
//lcd.setCursor (0,1); // char 0 on line 0 or 1
//lcd.print ("CFGERR TIMEOUT");
setup_ok = false;
return;
}
TCCR1B |= (1 << CS12) | (1 << CS10); TCCR1B |= (1 << CS12) | (1 << CS10);
}
else {
interrupts();
// lcd.setCursor (0,1); // char 0 on line 0 or 1
// lcd.print ("CFGERR prescaler");
setup_ok = false;
return;
}
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
interrupts(); // enable all interrupts interrupts(); // enable all interrupts
delay(500); delay(100);
} }
// if after OCR1A seconds no pulse from flow meter occured an interrupt will force a very high delta value // if after OCR1A seconds no pulse from flow meter occured an interrupt will force a very high delta value
ISR(TIMER1_COMPA_vect) { // interupt service routine which will be called when an interrupt occurs at timer1 ISR(TIMER1_COMPA_vect) { // function which will be called when an interrupt occurs at timer1
deltas[n] = UINT_MAX; // add maximum value in the current array position deltas[n] = UINT_MAX; // add maximum value in the current array position
n++; n++;
if (n == N) n = 0; // wrap around if (n == N) n = 0; // wrap around
@ -150,8 +194,9 @@ ISR(TIMER1_COMPA_vect) { // interupt service routine which will be called when a
void loop() void loop()
{ {
struct rgb bg;
if (!setup_ok) return; if (!setup_ok) return;
delay((int) (DISPLAY_INTERVAL*1000));
total = 0; total = 0;
// sum up all deltas in array // sum up all deltas in array
for (int k = 0; k < N; k++) { for (int k = 0; k < N; k++) {
@ -162,45 +207,109 @@ void loop()
} }
total += deltas[k]; total += deltas[k];
} }
// calculate average flow // and calculate average flow
flow = N/(float)total/conversion*16e6/prescaler; flow = N / (float)total / conversion * 16e6 / PRESCALER;
// flow // flow
//flow = total/N/conversion; //flow = total/N/conversion;
// format decimal value and save string in buff // format decimal value and save string in buff
dtostrf(flow, 5, 3, buff); dtostrf(flow, 5, 3, buff);
/* /* security logic
Security logic
==============
If flow is too small,i.e. flow < flow_threshold: if flow is too small,i.e. flow < flow_threshold:
a) alarm LED on a) alarm LED on
b) interlock LOW b) interlock LOW
*/ */
if (flow < flow_threshold) { strcpy(old_flow_string, new_flow_string);
digitalWrite(ALARM_LED_PIN, HIGH); strcpy(old_status_string, new_status_string);
digitalWrite(INTERLOCK_PIN, LOW);
snprintf(serialbuff, sizeof(serialbuff), "ERR %s l/min",buff ); snprintf(new_flow_string, sizeof(new_flow_string), "%s l/min", buff );
Serial.println(new_flow_string); // transmit flow
if ((flow < flow_threshold) ||digitalRead(OVERTEMP_PIN) ) { // flow too small, rise alarm
if (status_safety == true) {
status_change = true;
} }
else { else {
status_change = false;
}
status_safety = false;
digitalWrite(ALARM_LED_PIN, HIGH);
digitalWrite(INTERLOCK_PIN, LOW);
//if (status_change) {
bg.red=255;
bg.green=0;
bg.blue=0;
TFTscreen.background(bg.red, bg.green, bg.blue);
//}
if (digitalRead(OVERTEMP_PIN))
snprintf(new_status_string, sizeof(new_status_string), "Status: %s", "TEMP!" );
else
snprintf(new_status_string, sizeof(new_status_string), "Status: %s", "FLOW!" );
}
else {
if (status_safety == false) {
status_change = true;
}
else {
status_change = false;
}
status_safety = true;
digitalWrite(ALARM_LED_PIN, LOW); digitalWrite(ALARM_LED_PIN, LOW);
digitalWrite(INTERLOCK_PIN, HIGH); digitalWrite(INTERLOCK_PIN, HIGH);
snprintf(serialbuff, sizeof(serialbuff), "OK %s l/min",buff ); if (status_change) {
bg.red=0;
TFTscreen.background(bg.red, bg.green, bg.blue);
//TFTscreen.text("Status:", 0, 20);
//TFTscreen.text("l/min", 6 *((20+2)/2), 40);
} }
Serial.println(serialbuff); // transmit flow snprintf(new_status_string, sizeof(new_status_string), "Status: %s", "OK" );
lcd.home();
lcd.print (serialbuff); // display flow
lcd.setCursor (0,1); // char 0 on line 0 or 1
//delay(DISPLAY_INTERVAL*1000);
dtostrf(flow_threshold,5,3,buff);
snprintf(serialbuff, sizeof(serialbuff), "THR %s l/min",buff );
lcd.print(serialbuff); // display threshold
} }
//Serial.begin(19200); // serial line speed
//Serial.println(new_status_string); // transmit flow
//Serial.end();
writeText(new_status_string, old_status_string, 2, 8 * ((20 + 2) / 2) * 0, 20, bg);
writeText(new_flow_string, old_flow_string, 2, 0, 40, bg);
delay((int) (DISPLAY_INTERVAL * 1000));
}
void writeText(char* newtext, char* oldtext, int textWidth, int x, int y, struct rgb bg) {
TFTscreen.setTextSize(textWidth);
int n = 13; //max(strlen(newtext),strlen(oldtext));
int charWidth = textWidth * 10 / 2 + 2;
int curPos = x;
for (int i = 0; i < n; i++) {
if ((oldtext[i] != newtext[i]) && (i < strlen(oldtext))) { // only write changed characters
// delete old char
TFTscreen.stroke(0, 0, 0);
TFTscreen.text(&oldtext[i], curPos, y);
}
// write new char
TFTscreen.stroke(255, 255, 255);
TFTscreen.text(&newtext[i], curPos, y);
// draw a rectangle to the end of the screen
if (i >= strlen(newtext)) {
TFTscreen.stroke(bg.red, bg.green, bg.blue);
TFTscreen.rect(curPos, y, TFTscreen.width() - curPos, textWidth * 10);
break;
}
// advance position
curPos += charWidth;
}
}
void get_time() { void get_time() {
deltas[n] = TCNT1; // save current timer1 count deltas[n] = TCNT1; // save current timer1 count