PFG security firmware initila realease
This commit is contained in:
commit
dfe0c803bb
210
pfg_security.ino
Normal file
210
pfg_security.ino
Normal file
@ -0,0 +1,210 @@
|
||||
#include <limits.h>
|
||||
// Needed for LiquidCrystal_I2C.h
|
||||
#include <Wire.h>
|
||||
// from https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads/
|
||||
#include <LiquidCrystal_I2C.h>
|
||||
|
||||
|
||||
// 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()
|
||||
const int N=16; // number of sample averages
|
||||
volatile unsigned int deltas[N]; // array of time deltas between interrupt
|
||||
volatile unsigned int n = 0; // run variable
|
||||
unsigned long total;
|
||||
float flow;
|
||||
int prescaler;
|
||||
char buff[10]; // temp. buffer for string manipulation/formatting
|
||||
char serialbuff[16]; // temp. buffer for string manipulation/formatting
|
||||
|
||||
/*
|
||||
User configuration
|
||||
==================
|
||||
|
||||
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
|
||||
t_step or seconds/tick = prescaler/clock
|
||||
|
||||
Note: Maximum TCNT1 value is 65535, i.e.
|
||||
Maximum time lengths (and thus timeouts) per prescaler value are:
|
||||
8 0.0327675 s
|
||||
64 0.26214 s
|
||||
256 1.04856 s
|
||||
1024 4.19424 s
|
||||
|
||||
For accuracy the prescaler is set automatically fitting to the TIMEOUT.
|
||||
*/
|
||||
#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)
|
||||
|
||||
const float conversion = 4.0; // conversion factor, pulses/s per l/min
|
||||
const float flow_threshold = 1.0; // alarm threshold for flow
|
||||
|
||||
|
||||
/*
|
||||
Hardware configuration / wiring setup
|
||||
=====================================
|
||||
|
||||
Pin 13 has an LED connected on most Arduino boards.
|
||||
This is the alarm LED pin
|
||||
*/
|
||||
#define ALARM_LED_PIN 13
|
||||
// interlock output pin
|
||||
#define INTERLOCK_PIN 12
|
||||
|
||||
|
||||
/*
|
||||
Setup routine
|
||||
=============
|
||||
|
||||
Run once upon startup
|
||||
*/
|
||||
void setup()
|
||||
{
|
||||
lcd.begin(16,2); // start LCD (16x2 characters)
|
||||
lcd.home (); // go home
|
||||
lcd.print("PFG security"); // string first line
|
||||
lcd.setCursor ( 0, 1 ); // go to the next line
|
||||
lcd.print (""); // string second line
|
||||
Serial.begin(19200); // serial line speed
|
||||
/* Interrupt pins
|
||||
UNO:
|
||||
interrupt 1 is pin 3
|
||||
interrupt 0 is pin 2
|
||||
*/
|
||||
attachInterrupt(0, get_time, FALLING);
|
||||
pinMode(ALARM_LED_PIN, OUTPUT);
|
||||
pinMode(INTERLOCK_PIN, OUTPUT);
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
for (int k=0; k<N; k++){
|
||||
deltas[k]=UINT_MAX;
|
||||
}
|
||||
|
||||
/*
|
||||
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
|
||||
// clear timer1 registers
|
||||
TCCR1A = 0;
|
||||
TCCR1B = 0;
|
||||
TCNT1 = 0; // timer1 counter, reset on every HW interrupt from the flow meter (see get_time function)
|
||||
OCR1A = (int)(16e6/prescaler*TIMEOUT);// Clear timer on compare match value: 16MHz/PRESCALER*timeout(in s)
|
||||
TCCR1B |= (1 << WGM12); // CTC mode (Clear Timer on Compare Match)
|
||||
/*
|
||||
Prescaler settings x=0,1,2 (Timer0, Timer1, Timer2)
|
||||
CSx2 CSx1 CSx0 Beschreibung
|
||||
0 1 0 Clk/8 (1 << CS11)
|
||||
0 1 1 Clk/64 (1 << CS11)|(1 << CS10)
|
||||
1 0 0 Clk/256 (1 << CS12)
|
||||
1 0 1 Clk/1024 (1 << CS12)|(1 << CS10)
|
||||
*/
|
||||
if (prescaler == 8)
|
||||
TCCR1B |= (1 << CS11);
|
||||
else if (prescaler == 64)
|
||||
TCCR1B |= (1 << CS11)|(1 << CS10);
|
||||
else if (prescaler == 256)
|
||||
TCCR1B |= (1 << CS12);
|
||||
else if (prescaler == 1024)
|
||||
TCCR1B |= (1 << CS12)|(1 << CS10);
|
||||
|
||||
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
|
||||
interrupts(); // enable all interrupts
|
||||
delay(500);
|
||||
}
|
||||
|
||||
// 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
|
||||
deltas[n] = UINT_MAX; // add maximum value in the current array position
|
||||
n++;
|
||||
if (n==N) n=0; // wrap around
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (!setup_ok) return;
|
||||
delay((int) (DISPLAY_INTERVAL*1000));
|
||||
total = 0;
|
||||
// sum up all deltas in array
|
||||
for (int k=0; k<N; k++){
|
||||
// timeout occured, break out of loop
|
||||
if (deltas[k] == UINT_MAX) {
|
||||
total = ULONG_MAX; // and set total to highest possible value
|
||||
break;
|
||||
}
|
||||
total += deltas[k];
|
||||
}
|
||||
// calculate average flow
|
||||
flow = N/(float)total/conversion*16e6/prescaler;
|
||||
|
||||
// flow
|
||||
//flow = total/N/conversion;
|
||||
// format decimal value and save string in buff
|
||||
dtostrf(flow,5,3,buff);
|
||||
|
||||
/*
|
||||
Security logic
|
||||
==============
|
||||
|
||||
If flow is too small,i.e. flow < flow_threshold:
|
||||
a) alarm LED on
|
||||
b) interlock LOW
|
||||
|
||||
*/
|
||||
|
||||
if (flow < flow_threshold) {
|
||||
digitalWrite(ALARM_LED_PIN, HIGH);
|
||||
digitalWrite(INTERLOCK_PIN, LOW);
|
||||
snprintf(serialbuff, sizeof(serialbuff), "ERR %s l/min",buff );
|
||||
}
|
||||
else {
|
||||
digitalWrite(ALARM_LED_PIN, LOW);
|
||||
digitalWrite(INTERLOCK_PIN, HIGH);
|
||||
snprintf(serialbuff, sizeof(serialbuff), "OK %s l/min",buff );
|
||||
}
|
||||
Serial.println(serialbuff); // transmit flow
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
void get_time() {
|
||||
deltas[n] = TCNT1; // save current timer1 count
|
||||
n++;
|
||||
if (n==N) n=0; // wrap around
|
||||
TCNT1 = 0; // reset timer1 counter
|
||||
}
|
Loading…
Reference in New Issue
Block a user