![]() |
rims-arduino-library
v3.1.1
Recirculation infusion mash system library for Arduino
|
Recirculation infusion mash system (RIMS) library for Arduino. More...
#include <Rims.h>
Public Member Functions | |
Rims (UIRims *uiRims, byte analogPinPV, byte ssrPin, double *currentTemp, double *ssrControl, double *settedTemp) | |
Constructor. More... | |
void | setTempProbe (byte probeType, float probeCoefs[], float res1) |
Set temperature probe (RTD, thermistor or custom) parameters. More... | |
void | setPinLED (byte pinLED) |
Set pin for heater LED indicator. More... | |
void | setFlowSensor (byte pinFlow, float flowFactor, float lowBound=DEFAULTFLOWLOWBOUND, float upBound=DEFAULTFLOWUPBOUND, float criticalFlow=DEFAULTFLOWLOWBOUND) |
Set pin for flow sensor and parameters. More... | |
void | setHeaterPowerDetect (char pinHeaterVolt) |
Set pin to detect if there is voltage applied on heater. More... | |
void | setTuningPID (float Kp, float Ki, float Kd, float tauFilter, int mashWaterQty=-1) |
Set tuning for PID object. More... | |
void | setMemCSPin (byte csPin) |
Set pin for flash memory chip select. More... | |
void | checkMemAccessMode () |
Check if enterring in USB memory access mode. More... | |
void | run () |
Start and run Rims instance. More... | |
float | getTempPV () |
Get temperature from temperature probe (RTD, thermistor or custom). More... | |
float | getFlow () |
Get flow from hall-effect flow sensor. More... | |
bool | getHeaterVoltage () |
Check if heater is powered or not. More... | |
void | stopHeating (bool state) |
Stop heater no matter what PID output. More... | |
Protected Member Functions | |
virtual void | _initialize () |
Initialize a Rims instance before starting temperature regulation. More... | |
void | _initSession () |
Init all attributes and I/O for starting a brew session. | |
void | _endSession () |
Attributes treatments for ending a brew session. | |
virtual void | _iterate () |
Main method called for temperature regulation and other actions at each iteration. More... | |
void | _refreshTimer () |
Refresh time related values. More... | |
void | _refreshDisplay () |
Refresh display used by UIRims instance. | |
void | _refreshSSR () |
Refresh solid state relay. SSR will be refreshed in function of _controlValPtr (duty-cycle in percentage) and SSRWINDOWSIZE (mSec) values. | |
void | _serialPrintBrewData () |
Print current data points values to the Serial logger. Serial port (UART) need to be initialized in the main sketch with Serial.begin() | |
unsigned int | _memCountSessions () |
Count how many brew sessions were saved in flash mem. More... | |
unsigned long | _memCountSessionData () |
Count how many data point were taken. More... | |
void | _memInitSP () |
Initialize flash memory. More... | |
void | _memAddBrewData () |
Add data point to the flash memory. More... | |
void | _memDumpBrewData () |
Dump brew session data on USB serial port. | |
void | _memFreeSpace () |
Show free memory on flash mem via USB serial port. | |
void | _memClearAll () |
Clear all memory via USB serial port. | |
Friends | |
class | RimsIdent |
class | RimsTuner |
Recirculation infusion mash system (RIMS) library for Arduino.
Rims::Rims | ( | UIRims * | uiRims, |
byte | analogPinPV, | ||
byte | ssrPin, | ||
double * | currentTemp, | ||
double * | ssrControl, | ||
double * | settedTemp | ||
) |
Constructor.
uiRims | : UIRims*. Pointer to UIRims instance |
analogPinPV | : byte. Analog pin to temperature probe |
ssrPin | : byte. Pin to control heater's solid state relay. |
currentTemp | : double*. Pointer to a double that will be used for current temperature |
ssrControl | : double*. Pointer to a double that will use to control SSR duty-cycle |
settedTemp | : double*. Pointer to a double that will be use to store setted temperature |
|
protectedvirtual |
|
protectedvirtual |
Main method called for temperature regulation and other actions at each iteration.
At each PID calculation (at each SAMPLETIME mSec), datas is sent over Serial communication (and flash mem, if applicable) for logging purpose.
|
protected |
Add data point to the flash memory.
Five values is added at _memNextAddr, 20 bytes in total. Temperature setpoint (float : 4 bytes) is saved only once, at the beginning of the brew sessions in Rims::_memInitSP(). For exemple, for the first data (starting at ADDRBREWDATA or 0x002000) of the first brew session, the memory map would be :
Address | Data | Size |
---|---|---|
0x002000 | sp | 4 bytes |
0x002004 | time | 4 bytes |
0x002008 | cv | 4 bytes |
0x00200C | pv | 4 bytes |
0x002010 | flow | 4 bytes |
0x002014 | timerRemaining | 4 bytes |
|
protected |
Count how many data point were taken.
When brew data is added in the memory, a sector is filled with "0" to remember how many data were taken. This sector is at the address ADDRDATACOUNT or 0x001000 (second sector).
If 12 brew data were taken since de beginning (or 12 seconds were ellapsed), the memory map would be like this :
Address | Data |
---|---|
0x001000 | b00000000 |
0x001001 | b11110000 |
0x001002 | b11111111 |
0x001003 | b11111111 |
... | ... |
0x001FFF | b11111111 |
I used this method because of a limitation of the flash memory. I could not use normal counting because freshly erased bits can be cleared (set to "0") but cannot be set to "1" without full sector erase.
|
protected |
Count how many brew sessions were saved in flash mem.
Max is 4096 brew sessions. When a new brew session is started, the starting address of the datablock is saved in the brew sessions table, starting at ADDRSESSIONTABLE or 0x000000. For exemple, if 2 brew sessions were done of 2 seconds each (so 4+20+20=44 bytes each), the memory map of the brew sessions table would be :
Address | Data | Size |
---|---|---|
0x000000 | 0x00002000 | 4 bytes |
0x000004 | 0x0000202C | 4 bytes |
0x000008 | 0xFFFFFFFF | 4 bytes |
0x00000C | 0xFFFFFFFF | 4 bytes |
... | ... | ... |
0x000FFF | 0xFFFFFFFF | 4 bytes |
|
protected |
Initialize flash memory.
Verify where to store the new datas and add current temperature setpoint at the beginning of the datablock.
|
protected |
Refresh time related values.
If error on temperature >= MAXTEMPVAR, timer will not count down. Error on current temperature should not be greater than MAXTEMPVAR to count down. If current temperature setpoint is NAN
, current temperature is ignored in the countdown. If timer setted time is >= NOTIMELIMIT, timer will never elapsed and the remaining time will be equal to the running time.
void Rims::checkMemAccessMode | ( | ) |
Check if enterring in USB memory access mode.
Must be called at the end of the setup() function of the main sketch. If KEYSELECT is pressed, entering in USB memory access mode. In this mode, you can dump brew session data on the serial port and erase the entire memory. A basic menu interface is implemanted via serial communication.
The menu is :
Serial port (UART) need to be initialized in the main sketch with Serial.begin() to used memory access mode.
float Rims::getFlow | ( | ) |
Get flow from hall-effect flow sensor.
bool Rims::getHeaterVoltage | ( | ) |
Check if heater is powered or not.
If pinHeaterVolt is -1 (default value), always return true.
float Rims::getTempPV | ( | ) |
Get temperature from temperature probe (RTD, thermistor or custom).
First, probe is read and connection checkup is performed. Then, the measured sensor value is pre-filtered with a 1st order low-pass filter. Finally, the filtered value is converted to a temperature. If the probe is not connected, heating is stopped until reconnection.
void Rims::run | ( | ) |
Start and run Rims instance.
Should be called in the loop() function of your sketchbook
void Rims::setFlowSensor | ( | byte | pinFlow, |
float | flowFactor, | ||
float | lowBound = DEFAULTFLOWLOWBOUND , |
||
float | upBound = DEFAULTFLOWUPBOUND , |
||
float | criticalFlow = DEFAULTFLOWLOWBOUND |
||
) |
Set pin for flow sensor and parameters.
Make sure that the pin used for the flow sensor supports interrupts. For exemple, on an Arduino UNO, pin 3 is associated to interrupt #1. For more info : http://tinyurl.com/jwy4zgu.
Pull-up resistor is automatically enabled on the selected pin since it's needed for most hall-effect sensor.
pinFlow | : byte. Pin number (supporting interrupts) connected to the flow sensor. |
flowFactor | : float. Factor used to calculate flow from the input frequency, i.e. : \[ freq[Hz] = flowFactor * flow[L/min] \] |
lowBound | : float. Lower bound used for accepted flow rate. |
upBound | : float. Upper bound used for accepted flow rate |
criticalFlow | : float. If flow < criticalFlow , heater is turn off. Set at -1 to ignore flow mesurement on heater actions. |
void Rims::setHeaterPowerDetect | ( | char | pinHeaterVolt | ) |
Set pin to detect if there is voltage applied on heater.
If no voltage is detect on the heater, a speaker alarm is trigerred.
It can be easily and cheaply made with a +5V DC power supply in parallel with the SSR and heater. It is recommended to add a 10Kohm or so resistor in series with the power supply.
I use it to detect if my breaker is tripped or if I shut it off manually with an external switch. If the PID is informed that the heater is shut off, it will run smoother when the heater will be re-powered. This feature is really not mandatory.
pinHeaterVolt | : byte. 5V power supply pin. |
void Rims::setMemCSPin | ( | byte | csPin | ) |
Set pin for flash memory chip select.
WITH_W25QFLASH must be defined in Rims.h to used flash memory functions. Code was built on Windbond W25Q80BV SPI flash memory. (possible alternative : W25Q80DV)
MOSI, MISO and CLK are fixed pins on all Arduino. For ex, it's 11, 12, 13 for MOSI, MISO and CLK respectivly on Arduino UNO. For more information : http://tinyurl.com/6byntug.
If you have to convert 5V signal to 3.3V signal, here's a simple and cheap circuit that works well.
csPin | : byte. pin used for flash memory chip select. |
void Rims::setPinLED | ( | byte | pinLED | ) |
Set pin for heater LED indicator.
pinLED | : byte |
void Rims::setTempProbe | ( | byte | probeType, |
float | probeCoefs[], | ||
float | res1 | ||
) |
Set temperature probe (RTD, thermistor or custom) parameters.
If custom temperature probe is desired, insert your code in Rims::getTempPV
probeType | : byte. Either PROBE_RTD, PROBE_THERM or PROBE_CUSTOM |
probeCoefs | : float[4].
|
res1 | : float. Res1 [ohm] value in circuits above. |
void Rims::setTuningPID | ( | float | Kp, |
float | Ki, | ||
float | Kd, | ||
float | tauFilter, | ||
int | mashWaterQty = -1 |
||
) |
Set tuning for PID object.
Algorithm is in parallel form, i.e. :
\[ G_{c}(s) = K_{p}+\frac{K_{i}}{s}+\frac{K_{d}s}{\tau s+1} \]
where \(\tau=\mathrm{tauFilter[sec]}\). It can be set to the same value as a PID output filter. In practice, a good value of derivative filter is :
\[ \tau = \frac{K_{d}}{10} \]
For more information about PID the algorithm : http://tinyurl.com/nrvavus
For anti-windup, integration static saturation was replaced by integration clamping. Basically, it stop integration at a smarter time than "if limit is reached at the output of the integrator". More precisely, it stop integration if limit is reached at the ouput of the PID AND if the temperature error and and the PID output have the same sign.
Kp | : float. Propotionnal gain |
Ki | : float. Integral gain. |
Kd | : float. Derivative gain. |
tauFilter | : float. Derivative filter time constant in sec. |
mashWaterQty | : int (default=-1). If multiple regulators is needed, set this parameter to mash water volume in liter. This mash water volume will be associated to this PID. Total of 4 regulators is allowed (with different mash water volume). |
void Rims::stopHeating | ( | bool | state | ) |
Stop heater no matter what PID output.
state | : boolean. If true, heater is shut off. Else, heater is turned on. |