commit 1d123f3ff2c3ce5089f92dc0913110dcfb83e4ec Author: Emanuele Trabattoni Date: Sat Jun 22 10:44:55 2024 +0200 First Commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..89cc49c --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.pio +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..080e70d --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,10 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide" + ], + "unwantedRecommendations": [ + "ms-vscode.cpptools-extension-pack" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..f81fa6e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "files.associations": { + "*.h": "cpp", + "cstdio": "cpp" + } +} \ No newline at end of file diff --git a/include/README b/include/README new file mode 100644 index 0000000..194dcd4 --- /dev/null +++ b/include/README @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/lib/DHT/DHT.cpp b/lib/DHT/DHT.cpp new file mode 100644 index 0000000..46208bb --- /dev/null +++ b/lib/DHT/DHT.cpp @@ -0,0 +1,229 @@ +/* + * DHT Library for Digital-output Humidity and Temperature sensors + * + * Works with DHT11, DHT22 + * SEN11301P, Grove - Temperature&Humidity Sensor (Seeed Studio) + * SEN51035P, Grove - Temperature&Humidity Sensor Pro (Seeed Studio) + * AM2302 , temperature-humidity sensor + * HM2303 , Digital-output humidity and temperature sensor + * + * Copyright (C) Wim De Roeve + * based on DHT22 sensor library by HO WING KIT + * Arduino DHT11 library + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documnetation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "DHT.h" + +#define DHT_DATA_BIT_COUNT 40 + +DHT::DHT(PinName pin, eType DHTtype) +{ + _pin = pin; + _DHTtype = DHTtype; + _firsttime = true; +} + +DHT::~DHT() +{ + +} + +eError DHT::stall(DigitalInOut &io, int const level, int const max_time) +{ + int cnt = 0; + while (level == io) { + if (cnt > max_time) { + + return ERROR_NO_PATIENCE; + } + cnt++; + wait_us(1); + } + return ERROR_NONE; +} + +eError DHT::readData() +{ + uint8_t i = 0, j = 0, b = 0, data_valid = 0; + uint32_t bit_value[DHT_DATA_BIT_COUNT] = {0}; + + eError err = ERROR_NONE; + time_t currentTime = time(NULL); + + DigitalInOut DHT_io(_pin); + + // IO must be in hi state to start + if (ERROR_NONE != stall(DHT_io, 0, 250)) { + return BUS_BUSY; + } + + // start the transfer + DHT_io.output(); + DHT_io = 0; + // only 500uS for DHT22 but 18ms for DHT11 + (_DHTtype == 11) ? wait_us(18000) : wait_us(500); + DHT_io = 1; + wait_us(30); + DHT_io.input(); + + // wait till the sensor grabs the bus + if (ERROR_NONE != stall(DHT_io, 1, 40)) { + return ERROR_NOT_PRESENT; + } + // sensor should signal low 80us and then hi 80us + if (ERROR_NONE != stall(DHT_io, 0, 100)) { + return ERROR_SYNC_TIMEOUT; + } + if (ERROR_NONE != stall(DHT_io, 1, 100)) { + return ERROR_NO_PATIENCE; + } + // capture the data + for (i = 0; i < 5; i++) { + for (j = 0; j < 8; j++) { + if (ERROR_NONE != stall(DHT_io, 0, 75)) { + return ERROR_DATA_TIMEOUT; + } + // logic 0 is 28us max, 1 is 70us + wait_us(40); + bit_value[i*8+j] = DHT_io; + if (ERROR_NONE != stall(DHT_io, 1, 50)) { + return ERROR_DATA_TIMEOUT; + } + } + } + // store the data + for (i = 0; i < 5; i++) { + b=0; + for (j=0; j<8; j++) { + if (bit_value[i*8+j] == 1) { + b |= (1 << (7-j)); + } + } + DHT_data[i]=b; + } + + // uncomment to see the checksum error if it exists + //printf(" 0x%02x + 0x%02x + 0x%02x + 0x%02x = 0x%02x \n", DHT_data[0], DHT_data[1], DHT_data[2], DHT_data[3], DHT_data[4]); + data_valid = DHT_data[0] + DHT_data[1] + DHT_data[2] + DHT_data[3]; + if (DHT_data[4] == data_valid) { + _lastReadTime = currentTime; + _lastTemperature = CalcTemperature(); + _lastHumidity = CalcHumidity(); + + } else { + err = ERROR_CHECKSUM; + } + + return err; + +} + +float DHT::CalcTemperature() +{ + int v; + + switch (_DHTtype) { + case DHT11: + v = DHT_data[2]; + return float(v); + case DHT22: + v = DHT_data[2] & 0x7F; + v *= 256; + v += DHT_data[3]; + v /= 10; + if (DHT_data[2] & 0x80) + v *= -1; + return float(v); + } + return 0; +} + +float DHT::ReadHumidity() +{ + return _lastHumidity; +} + +float DHT::ConvertCelciustoFarenheit(float const celsius) +{ + return celsius * 9 / 5 + 32; +} + +float DHT::ConvertCelciustoKelvin(float const celsius) +{ + return celsius + 273.15; +} + +// dewPoint function NOAA +// reference: http://wahiduddin.net/calc/density_algorithms.htm +float DHT::CalcdewPoint(float const celsius, float const humidity) +{ + float A0= 373.15/(273.15 + celsius); + float SUM = -7.90298 * (A0-1); + SUM += 5.02808 * log10(A0); + SUM += -1.3816e-7 * (pow(10, (11.344*(1-1/A0)))-1) ; + SUM += 8.1328e-3 * (pow(10,(-3.49149*(A0-1)))-1) ; + SUM += log10(1013.246); + float VP = pow(10, SUM-3) * humidity; + float T = log(VP/0.61078); // temp var + return (241.88 * T) / (17.558-T); +} + +// delta max = 0.6544 wrt dewPoint() +// 5x faster than dewPoint() +// reference: http://en.wikipedia.org/wiki/Dew_point +float DHT::CalcdewPointFast(float const celsius, float const humidity) +{ + float a = 17.271; + float b = 237.7; + float temp = (a * celsius) / (b + celsius) + log(humidity/100); + float Td = (b * temp) / (a - temp); + return Td; +} + +float DHT::ReadTemperature(eScale Scale) +{ + if (Scale == FARENHEIT) + return ConvertCelciustoFarenheit(_lastTemperature); + else if (Scale == KELVIN) + return ConvertCelciustoKelvin(_lastTemperature); + else + return _lastTemperature; +} + +float DHT::CalcHumidity() +{ + int v; + + switch (_DHTtype) { + case DHT11: + v = DHT_data[0]; + return float(v); + case DHT22: + v = DHT_data[0]; + v *= 256; + v += DHT_data[1]; + v /= 10; + return float(v); + } + return 0; +} + + diff --git a/lib/DHT/DHT.h b/lib/DHT/DHT.h new file mode 100644 index 0000000..d571438 --- /dev/null +++ b/lib/DHT/DHT.h @@ -0,0 +1,99 @@ +/* + * DHT Library for Digital-output Humidity and Temperature sensors + * + * Works with DHT11, DHT21, DHT22 + * SEN11301P, Grove - Temperature&Humidity Sensor (Seeed Studio) + * SEN51035P, Grove - Temperature&Humidity Sensor Pro (Seeed Studio) + * AM2302 , temperature-humidity sensor + * RHT01,RHT02, RHT03 , Humidity and Temperature Sensor (Sparkfun) + * + * Copyright (C) Wim De Roeve + * based on DHT22 sensor library by HO WING KIT + * Arduino DHT11 library + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documnetation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MBED_DHT_H +#define MBED_DHT_H + +#include "mbed.h" + +//typedef enum eType eType; +enum eType { + DHT11 = 11, + SEN11301P = 11, + RHT01 = 11, + DHT22 = 22, + AM2302 = 22, + SEN51035P = 22, + RHT02 = 22, + RHT03 = 22 +}; + +//typedef enum eError eError; +enum eError { + ERROR_NONE = 0, + BUS_BUSY, + ERROR_NOT_PRESENT, + ERROR_ACK_TOO_LONG, + ERROR_SYNC_TIMEOUT, + ERROR_DATA_TIMEOUT, + ERROR_CHECKSUM, + ERROR_NO_PATIENCE +}; + +//typedef enum eScale eScale; +enum eScale { + CELCIUS = 0, + FARENHEIT, + KELVIN +}; + + +class DHT +{ + +public: + + DHT(PinName pin, eType DHTtype); + ~DHT(); + eError readData(void); + float ReadHumidity(void); + float ReadTemperature(eScale const Scale); + float CalcdewPoint(float const celsius, float const humidity); + float CalcdewPointFast(float const celsius, float const humidity); + +private: + time_t _lastReadTime; + float _lastTemperature; + float _lastHumidity; + PinName _pin; + bool _firsttime; + eType _DHTtype; + uint8_t DHT_data[5]; + float CalcTemperature(); + float CalcHumidity(); + float ConvertCelciustoFarenheit(float const); + float ConvertCelciustoKelvin(float const); + eError stall(DigitalInOut &io, int const level, int const max_time); + +}; + +#endif diff --git a/lib/PID/pid.cpp b/lib/PID/pid.cpp new file mode 100644 index 0000000..9d85064 --- /dev/null +++ b/lib/PID/pid.cpp @@ -0,0 +1,324 @@ +/** + * @author Aaron Berk + * + * @section LICENSE + * + * Copyright (c) 2010 ARM Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @section DESCRIPTION + * + * A PID controller is a widely used feedback controller commonly found in + * industry. + * + * This library is a port of Brett Beauregard's Arduino PID library: + * + * http://www.arduino.cc/playground/Code/PIDLibrary + * + * The wikipedia article on PID controllers is a good place to start on + * understanding how they work: + * + * http://en.wikipedia.org/wiki/PID_controller + * + * For a clear and elegant explanation of how to implement and tune a + * controller, the controlguru website by Douglas J. Cooper (who also happened + * to be Brett's controls professor) is an excellent reference: + * + * http://www.controlguru.com/ + */ + +/** + * Includes + */ +#include "PID.h" + +PID::PID(float Kc, float tauI, float tauD, float interval) { + + usingFeedForward = false; + inAuto = false; + + //Default the limits to the full range of I/O: 3.3V + //Make sure to set these to more appropriate limits for + //your application. + setInputLimits(0.0, 3.3); + setOutputLimits(0.0, 3.3); + + tSample_ = interval; + + setTunings(Kc, tauI, tauD); + + setPoint_ = 0.0; + processVariable_ = 0.0; + prevProcessVariable_ = 0.0; + controllerOutput_ = 0.0; + prevControllerOutput_ = 0.0; + + accError_ = 0.0; + bias_ = 0.0; + + realOutput_ = 0.0; + +} + +void PID::setInputLimits(float inMin, float inMax) { + + //Make sure we haven't been given impossible values. + if (inMin >= inMax) { + return; + } + + //Rescale the working variables to reflect the changes. + prevProcessVariable_ *= (inMax - inMin) / inSpan_; + accError_ *= (inMax - inMin) / inSpan_; + + //Make sure the working variables are within the new limits. + if (prevProcessVariable_ > 1) { + prevProcessVariable_ = 1; + } else if (prevProcessVariable_ < 0) { + prevProcessVariable_ = 0; + } + + inMin_ = inMin; + inMax_ = inMax; + inSpan_ = inMax - inMin; + +} + +void PID::setOutputLimits(float outMin, float outMax) { + + //Make sure we haven't been given impossible values. + if (outMin >= outMax) { + return; + } + + //Rescale the working variables to reflect the changes. + prevControllerOutput_ *= (outMax - outMin) / outSpan_; + + //Make sure the working variables are within the new limits. + if (prevControllerOutput_ > 1) { + prevControllerOutput_ = 1; + } else if (prevControllerOutput_ < 0) { + prevControllerOutput_ = 0; + } + + outMin_ = outMin; + outMax_ = outMax; + outSpan_ = outMax - outMin; + +} + +void PID::setTunings(float Kc, float tauI, float tauD) { + + //Verify that the tunings make sense. + if (Kc == 0.0 || tauI < 0.0 || tauD < 0.0) { + return; + } + + //Store raw values to hand back to user on request. + pParam_ = Kc; + iParam_ = tauI; + dParam_ = tauD; + + float tempTauR; + + if (tauI == 0.0) { + tempTauR = 0.0; + } else { + tempTauR = (1.0 / tauI) * tSample_; + } + + //For "bumpless transfer" we need to rescale the accumulated error. + if (inAuto) { + if (tempTauR == 0.0) { + accError_ = 0.0; + } else { + accError_ *= (Kc_ * tauR_) / (Kc * tempTauR); + } + } + + Kc_ = Kc; + tauR_ = tempTauR; + tauD_ = tauD / tSample_; + +} + +void PID::reset(void) { + + float scaledBias = 0.0; + + if (usingFeedForward) { + scaledBias = (bias_ - outMin_) / outSpan_; + } else { + scaledBias = (realOutput_ - outMin_) / outSpan_; + } + + prevControllerOutput_ = scaledBias; + prevProcessVariable_ = (processVariable_ - inMin_) / inSpan_; + + //Clear any error in the integral. + accError_ = 0; + +} + +void PID::setMode(int mode) { + + //We were in manual, and we just got set to auto. + //Reset the controller internals. + if (mode != 0 && !inAuto) { + reset(); + } + + inAuto = (mode != 0); + +} + +void PID::setInterval(float interval) { + + if (interval > 0) { + //Convert the time-based tunings to reflect this change. + tauR_ *= (interval / tSample_); + accError_ *= (tSample_ / interval); + tauD_ *= (interval / tSample_); + tSample_ = interval; + } + +} + +void PID::setSetPoint(float sp) { + + setPoint_ = sp; + +} + +void PID::setProcessValue(float pv) { + + processVariable_ = pv; + +} + +void PID::setBias(float bias){ + + bias_ = bias; + usingFeedForward = 1; + +} + +float PID::compute() { + + //Pull in the input and setpoint, and scale them into percent span. + float scaledPV = (processVariable_ - inMin_) / inSpan_; + + if (scaledPV > 1.0) { + scaledPV = 1.0; + } else if (scaledPV < 0.0) { + scaledPV = 0.0; + } + + float scaledSP = (setPoint_ - inMin_) / inSpan_; + if (scaledSP > 1.0) { + scaledSP = 1; + } else if (scaledSP < 0.0) { + scaledSP = 0; + } + + float error = scaledSP - scaledPV; + + //Check and see if the output is pegged at a limit and only + //integrate if it is not. This is to prevent reset-windup. + if (!(prevControllerOutput_ >= 1 && error > 0) && !(prevControllerOutput_ <= 0 && error < 0)) { + accError_ += error; + } + + //Compute the current slope of the input signal. + float dMeas = (scaledPV - prevProcessVariable_) / tSample_; + + float scaledBias = 0.0; + + if (usingFeedForward) { + scaledBias = (bias_ - outMin_) / outSpan_; + } + + //Perform the PID calculation. + controllerOutput_ = scaledBias + Kc_ * (error + (tauR_ * accError_) - (tauD_ * dMeas)); + + //Make sure the computed output is within output constraints. + if (controllerOutput_ < 0.0) { + controllerOutput_ = 0.0; + } else if (controllerOutput_ > 1.0) { + controllerOutput_ = 1.0; + } + + //Remember this output for the windup check next time. + prevControllerOutput_ = controllerOutput_; + //Remember the input for the derivative calculation next time. + prevProcessVariable_ = scaledPV; + + //Scale the output from percent span back out to a real world number. + return ((controllerOutput_ * outSpan_) + outMin_); + +} + +float PID::getInMin() { + + return inMin_; + +} + +float PID::getInMax() { + + return inMax_; + +} + +float PID::getOutMin() { + + return outMin_; + +} + +float PID::getOutMax() { + + return outMax_; + +} + +float PID::getInterval() { + + return tSample_; + +} + +float PID::getPParam() { + + return pParam_; + +} + +float PID::getIParam() { + + return iParam_; + +} + +float PID::getDParam() { + + return dParam_; + +} diff --git a/lib/PID/pid.h b/lib/PID/pid.h new file mode 100644 index 0000000..1923262 --- /dev/null +++ b/lib/PID/pid.h @@ -0,0 +1,213 @@ +/** + * @author Aaron Berk + * + * @section LICENSE + * + * Copyright (c) 2010 ARM Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @section DESCRIPTION + * + * A PID controller is a widely used feedback controller commonly found in + * industry. + * + * This library is a port of Brett Beauregard's Arduino PID library: + * + * http://www.arduino.cc/playground/Code/PIDLibrary + * + * The wikipedia article on PID controllers is a good place to start on + * understanding how they work: + * + * http://en.wikipedia.org/wiki/PID_controller + * + * For a clear and elegant explanation of how to implement and tune a + * controller, the controlguru website by Douglas J. Cooper (who also happened + * to be Brett's controls professor) is an excellent reference: + * + * http://www.controlguru.com/ + */ + +#ifndef PID_H +#define PID_H + +/** + * Includes + */ +#include + +/** + * Defines + */ +#define MANUAL_MODE 0 +#define AUTO_MODE 1 + +/** + * Proportional-integral-derivative controller. + */ +class PID { + +public: + + /** + * Constructor. + * + * Sets default limits [0-3.3V], calculates tuning parameters, and sets + * manual mode with no bias. + * + * @param Kc - Tuning parameter + * @param tauI - Tuning parameter + * @param tauD - Tuning parameter + * @param interval PID calculation performed every interval seconds. + */ + PID(float Kc, float tauI, float tauD, float interval); + + /** + * Scale from inputs to 0-100%. + * + * @param InMin The real world value corresponding to 0%. + * @param InMax The real world value corresponding to 100%. + */ + void setInputLimits(float inMin , float inMax); + + /** + * Scale from outputs to 0-100%. + * + * @param outMin The real world value corresponding to 0%. + * @param outMax The real world value corresponding to 100%. + */ + void setOutputLimits(float outMin, float outMax); + + /** + * Calculate PID constants. + * + * Allows parameters to be changed on the fly without ruining calculations. + * + * @param Kc - Tuning parameter + * @param tauI - Tuning parameter + * @param tauD - Tuning parameter + */ + void setTunings(float Kc, float tauI, float tauD); + + /** + * Reinitializes controller internals. Automatically + * called on a manual to auto transition. + */ + void reset(void); + + /** + * Set PID to manual or auto mode. + * + * @param mode 0 -> Manual + * Non-zero -> Auto + */ + void setMode(int mode); + + /** + * Set how fast the PID loop is run. + * + * @param interval PID calculation peformed every interval seconds. + */ + void setInterval(float interval); + + /** + * Set the set point. + * + * @param sp The set point as a real world value. + */ + void setSetPoint(float sp); + + /** + * Set the process value. + * + * @param pv The process value as a real world value. + */ + void setProcessValue(float pv); + + /** + * Set the bias. + * + * @param bias The bias for the controller output. + */ + void setBias(float bias); + + /** + * PID calculation. + * + * @return The controller output as a float between outMin and outMax. + */ + float compute(void); + + //Getters. + float getInMin(); + float getInMax(); + float getOutMin(); + float getOutMax(); + float getInterval(); + float getPParam(); + float getIParam(); + float getDParam(); + +private: + + bool usingFeedForward; + bool inAuto; + + //Actual tuning parameters used in PID calculation. + float Kc_; + float tauR_; + float tauD_; + + //Raw tuning parameters. + float pParam_; + float iParam_; + float dParam_; + + //The point we want to reach. + float setPoint_; + //The thing we measure. + float processVariable_; + float prevProcessVariable_; + //The output that affects the process variable. + float controllerOutput_; + float prevControllerOutput_; + + //We work in % for calculations so these will scale from + //real world values to 0-100% and back again. + float inMin_; + float inMax_; + float inSpan_; + float outMin_; + float outMax_; + float outSpan_; + + //The accumulated error, i.e. integral. + float accError_; + //The controller output bias. + float bias_; + + //The interval between samples. + float tSample_; + + //Controller output as a real world value. + volatile float realOutput_; + +}; + +#endif /* PID_H */ diff --git a/lib/README b/lib/README new file mode 100644 index 0000000..2593a33 --- /dev/null +++ b/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into executable file. + +The source code of each library should be placed in an own separate directory +("lib/your_library_name/[here are source files]"). + +For example, see a structure of the following two libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +and a contents of `src/main.c`: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +PlatformIO Library Dependency Finder will find automatically dependent +libraries scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/mbed_app.json b/mbed_app.json new file mode 100644 index 0000000..a0e000b --- /dev/null +++ b/mbed_app.json @@ -0,0 +1,10 @@ +{ + "target_overrides": { + "*": { + "mbed-trace.enable": false, + "mbed-trace.max-level": "TRACE_LEVEL_DEBUG", + "rtos.main-thread-stack-size": 8192, + "target.printf_lib": "std" + } + } +} \ No newline at end of file diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..6364985 --- /dev/null +++ b/platformio.ini @@ -0,0 +1,14 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:nucleo_f401re] +platform = ststm32 +board = nucleo_f401re +framework = mbed diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..76b56ac --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,29 @@ +#include +#include +#include + +auto t_controller = PID(1, 1, 0, 2); +auto t_sensor = DHT(PC_10, AM2302); +auto led = DigitalOut(PA_5); + +int main() +{ + printf("Start\n"); + t_controller.setInputLimits(10,30); + t_controller.setOutputLimits(0,100); + t_controller.setSetPoint(29); + while (true) + { + if (eError::ERROR_NONE != t_sensor.readData()){ + printf("Error\n"); + continue; + } + auto t = t_sensor.ReadTemperature(CELCIUS); + auto h = t_sensor.ReadHumidity(); + t_controller.setProcessValue(t); + auto c = t_controller.compute(); + printf("T:%3.1f\tH:%3.1f\tCV:%3.1f\n",t,h,c); + led = !led; + ThisThread::sleep_for(2s); + } +} \ No newline at end of file diff --git a/test/README b/test/README new file mode 100644 index 0000000..9b1e87b --- /dev/null +++ b/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Test Runner and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html