Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <Arduino.h>
- #include <STM32RTC.h>
- #include <rtc.h>
- #include <STM32LowPower.h>
- #include <low_power.h>
- /*
- rationale
- 30 bimetallic switches and three thermistors will be connected to a BluePill to record the temperature at which each bimetallic switch changes state (the project will be placed in a hot or cold place to trigger the switches)
- plan
- check and store switch states in an array on setup
- every second, check each switch state in turn and if different from the value in the array, change the value in the array and record the temperature for each thermistor in separate arrays
- when all thermistors have changed state, start speaker
- when button is pressed, stop speaker and store temperatures in new array positions for the next stage
- every second, check each switch state in turn and if different from the value in the array, change the value in the array and record the temperature for each thermistor in separate arrays
- when all thermistors have changed state, start speaker
- when button is pressed, stop speaker and begin serial data transfer
- */
- #define DEBUG 1 // value is 1 to enable debugging serial printing
- #define DEBUG2 0 // value is 1 to enable debugging serial printing
- #if DEBUG == 1
- #define DEBUG(x) Serial.print(x)
- #define DEBUGLN(x) Serial.println(x)
- #else
- #define DEBUG(x)
- #define DEBUGLN(x)
- #endif
- #if DEBUG2 == 1
- #define DEBUG2(x) Serial.print(x)
- #define DEBUGLN2(x) Serial.println(x)
- #else
- #define DEBUG2(x)
- #define DEBUGLN2(x)
- #endif
- // how many bimetallic switches to monitor simultaneously - might not use this, actually
- #define NUMBEROFBIMETALLICSWITCHES 30
- // which analog pins to use with thermistors
- #define THERMISTORPIN1 PA7 //
- #define THERMISTORPIN2 PB0 //
- #define THERMISTORPIN3 PB1 //
- // which digital pins to use for BUTTONPIN to trigger sending contents of matrix to serial
- #define BUTTONPIN PB2 //
- // buzzer pin
- #define PIEZOPIN PA6 //
- // resistance at 25 degrees C
- #define THERMISTORNOMINAL 10000
- // temp. for nominal resistance (almost always 25 C)
- #define TEMPERATURENOMINAL 25
- // how many samples to take and average, more takes longer
- // but is more 'smooth'
- #define NUMSAMPLES 5
- // The beta coefficient of the thermistor (usually 1000-4000)
- #define BCOEFFICIENT 3950
- // the value of the resistor used to make a potential divider with the thermistor
- #define SERIESRESISTOR 9940
- // an array is need to store the pins to which each bimetallic switch will be attached
- unsigned char bimetallicSwitchMonitoringPins[NUMBEROFBIMETALLICSWITCHES] = { PB12, PB13, PB14, PB15, PA8, PA9, PA10, PA11, PA12, PA15, PB3, PB4, PB5, PB6, PB7, PB8, PB9, PA13, PA14, PC13, PC14, PC15, PA0, PA1, PA2, PA3, PA4, PA5, PB10, PB11 }; // commented out the pins needed for serial and swd programming
- bool initialBimetallicSwitchState;
- // an array to store the state of each bimetallic switch
- bool bimetallicSwitchStates[NUMBEROFBIMETALLICSWITCHES];
- // places to store temperatures temporarily
- int temperature1;
- int temperature2;
- int temperature3;
- // places to store temperatures after detecting change in switch state
- int temperatureArray1[60];
- int temperatureArray2[60];
- int temperatureArray3[60];
- // arrays to store thermistor readings prior to conversion to an average temperature
- int samples1[NUMSAMPLES];
- int samples2[NUMSAMPLES];
- int samples3[NUMSAMPLES];
- // how frequently to check the bimetallic switch states and act on readings
- const unsigned long temperatureMeasurementInterval = 1000;
- const unsigned long thermistorReadShortInterval = 10;
- // how long button should be pressed
- const int SHORT_PRESS_TIME = 1000; // 1000 milliseconds
- const int LONG_PRESS_TIME = 1000; // 1000 milliseconds
- bool bimetallicSwitchStateCheckingFlag = false;
- bool thermistorSamplingFlag = false;
- bool userInterventionRequiredFlag = false;
- bool thermistorSamplingCompleteFlag = false;
- bool phaseOneCompleteFlag = false;
- bool phaseTwoCompleteFlag = false;
- bool readyToUploadFlag = false;
- bool lastButtonState;
- bool currentButtonState;
- bool buttonIsBeingPressed;
- bool shortButtonPressDetected;
- bool longButtonPressDetected;
- unsigned long buttonPressTimeStart;
- unsigned long buttonPressTimeEnd;
- int loopcounter = 0;
- //I have to declare functions before they're called because apparently that's how C++ works? What a waste of time
- void buttonPressDetection(const unsigned char BUTTON_PIN, bool &lastButtonState, bool ¤tButtonState, unsigned long &buttonPressTimeStart, unsigned long &buttonPressTimeEnd, bool &buttonIsBeingPressed, bool &shortButtonPressDetected, bool &longButtonPressDetected);
- void userInterventionAttractionTask();
- void thermistorSamplingTimerTask();
- void thermistorSamplingTask();
- void thermistorSampleAveragingTask();
- void bimetallicSwitchStateCheckingTask();
- void phaseFlagSettingTask();
- void powerSavingTask();
- void serialDataTransferTask();
- unsigned char samplesToTemp(int samplesSensor[]);
- void setup() {
- // Configure low power
- LowPower.begin();
- Serial.begin(9600);
- pinMode(BUTTONPIN, INPUT); // have to use INPUT with an external pullup resistor, not INPUT_PULLUP because PB2 on the BluePill devboard has a 100K resistor between it and the header pins
- pinMode(PIEZOPIN, OUTPUT);
- tone(PIEZOPIN, 800, 1); // makes a blip noise with the piezo at power-up
- // set each pin in bimetallicSwitch monitoring array to INPUT_PULLUP, then fill each position in the array with the initial state of each pin
- for (unsigned char i = 0; i < NUMBEROFBIMETALLICSWITCHES; i++) {
- pinMode(bimetallicSwitchMonitoringPins[i], INPUT_PULLUP);
- bimetallicSwitchStates[i] = digitalRead(bimetallicSwitchMonitoringPins[i]);
- }
- // check that all of the bimetallic switches are in the same state and if they are not, attract user intervention
- for (unsigned char i = 1; i < NUMBEROFBIMETALLICSWITCHES; i++) {
- if (bimetallicSwitchStates[0] != bimetallicSwitchStates[i]) {
- userInterventionRequiredFlag = true;
- return;
- }
- initialBimetallicSwitchState = bimetallicSwitchStates[0];
- }
- }
- void loop() {
- buttonPressDetection(BUTTONPIN, lastButtonState, currentButtonState, buttonPressTimeStart, buttonPressTimeEnd, buttonIsBeingPressed, shortButtonPressDetected, longButtonPressDetected);
- userInterventionAttractionTask();
- thermistorSamplingTimerTask();
- thermistorSamplingTask();
- thermistorSampleAveragingTask();
- bimetallicSwitchStateCheckingTask();
- phaseFlagSettingTask();
- powerSavingTask();
- serialDataTransferTask();
- loopcounter++;
- }
- void powerSavingTask() {
- if (userInterventionRequiredFlag == true || readyToUploadFlag == true) {
- return;
- }
- LowPower.sleep(200);
- }
- void userInterventionAttractionTask() {
- if (userInterventionRequiredFlag == false) {
- return;
- }
- static unsigned long previousMillis = 0;
- unsigned long currentMillis = millis();
- if (currentMillis - previousMillis > 1200) {
- previousMillis = currentMillis;
- tone(PIEZOPIN, 800, 600);
- }
- if (shortButtonPressDetected == true) {
- noTone(PIEZOPIN);
- userInterventionRequiredFlag = false;
- }
- if (shortButtonPressDetected == true && phaseTwoCompleteFlag == true) {
- readyToUploadFlag = true;
- }
- }
- void thermistorSamplingTimerTask() {
- static unsigned long previousMillis = 0;
- unsigned long currentMillis = millis();
- if (currentMillis - previousMillis < temperatureMeasurementInterval) {
- return;
- }
- previousMillis = currentMillis;
- thermistorSamplingFlag = true;
- for (unsigned char i = 0; i < NUMBEROFBIMETALLICSWITCHES; i++) {
- DEBUG2((String)bimetallicSwitchMonitoringPins[i] + "=" + bimetallicSwitchStates[i] + ",");
- }
- DEBUGLN2((String) "initialState:" + initialBimetallicSwitchState + ", phaseOne:" + phaseOneCompleteFlag + ", phaseTwo:" + phaseTwoCompleteFlag + ", intervention:" + userInterventionRequiredFlag + ", buttonState:" + currentButtonState + ", shortButton:" + shortButtonPressDetected);
- return;
- }
- void bimetallicSwitchStateCheckingTask() {
- if (bimetallicSwitchStateCheckingFlag == false || userInterventionRequiredFlag == true || phaseTwoCompleteFlag == true) {
- return;
- }
- for (unsigned char i = 0; i < NUMBEROFBIMETALLICSWITCHES; i++) {
- if (digitalRead(bimetallicSwitchMonitoringPins[i]) != bimetallicSwitchStates[i]) { // check whether the current state of each bitmetallic switch is different from its corresponding state stored in the array
- bimetallicSwitchStates[i] = !bimetallicSwitchStates[i]; // set the bimetallic switch state to its new state
- tone(PIEZOPIN, 800, 1); // makes a blip noise with the piezo every time a bimetallic switch changes state
- temperatureArray1[i + (NUMBEROFBIMETALLICSWITCHES * phaseOneCompleteFlag)] = temperature1; // fill the relevant arrays with the last-recorded temperatures
- temperatureArray2[i + (NUMBEROFBIMETALLICSWITCHES * phaseOneCompleteFlag)] = temperature2;
- temperatureArray3[i + (NUMBEROFBIMETALLICSWITCHES * phaseOneCompleteFlag)] = temperature3;
- }
- }
- }
- void phaseFlagSettingTask() {
- if (readyToUploadFlag == true) {
- return;
- }
- unsigned char i = 0;
- while (i++ < NUMBEROFBIMETALLICSWITCHES - 1 && bimetallicSwitchStates[i] == bimetallicSwitchStates[0] && bimetallicSwitchStates[0] != initialBimetallicSwitchState)
- ;
- if (i == NUMBEROFBIMETALLICSWITCHES && phaseOneCompleteFlag == false) {
- phaseOneCompleteFlag = true;
- userInterventionRequiredFlag = true;
- initialBimetallicSwitchState = bimetallicSwitchStates[0];
- } else if (i == NUMBEROFBIMETALLICSWITCHES && phaseOneCompleteFlag == true) {
- phaseTwoCompleteFlag = true;
- userInterventionRequiredFlag = true;
- }
- }
- void thermistorSamplingTask() {
- static unsigned long previousMillis = 0;
- static unsigned char index = 0;
- if (thermistorSamplingFlag == false) {
- return;
- }
- unsigned long currentMillis = millis();
- // at the "thermistorReadInterval
- if (millis() - previousMillis < thermistorReadShortInterval) {
- return;
- }
- previousMillis = millis();
- // take NUMSAMPLES samples
- samples1[index] = analogRead(THERMISTORPIN1);
- samples2[index] = analogRead(THERMISTORPIN2);
- samples3[index] = analogRead(THERMISTORPIN3);
- index = (index + 1) % NUMSAMPLES; // this resets index to 0 when array contains NUMSAMPLES values
- if (index == 0) { // when index is reset to 0, it's because the array is full and complete
- thermistorSamplingFlag = false; // sampling can now stop for a while
- thermistorSamplingCompleteFlag = true; // this lets the next stage of the main loop begin
- return;
- }
- }
- void thermistorSampleAveragingTask() {
- // check whether array is full - this flag is set to true when the array is full
- if (thermistorSamplingCompleteFlag == false) {
- return;
- }
- // do the averaging here
- temperature1 = samplesToTemp(samples1);
- DEBUG(", 1: ");
- DEBUG(temperature1);
- DEBUGLN("°C");
- temperature2 = samplesToTemp(samples2);
- DEBUG(", 2: ");
- DEBUG(temperature2);
- DEBUGLN("°C");
- temperature3 = samplesToTemp(samples3);
- DEBUG(", 3: ");
- DEBUG(temperature3);
- DEBUGLN("°C");
- thermistorSamplingCompleteFlag = false; // reset this flag so sampling can begin again
- bimetallicSwitchStateCheckingFlag = true; // this flag lets the bimetallic switch checking start
- }
- // function for turning list of resistance measurements into temperature reading
- unsigned char samplesToTemp(int samplesSensor[]) {
- float average = 0;
- // average all the samples out
- for (unsigned char index = 0; index < NUMSAMPLES; index++) {
- average += samplesSensor[index];
- }
- average /= NUMSAMPLES;
- DEBUG("Average analog reading ");
- DEBUG(average);
- // convert the value to resistance
- average = 1023 / average - 1; // value 4095 is for 12-bit ADC; 1023 for a 8-bit ADC
- average = SERIESRESISTOR / average;
- DEBUG(", Thermistor resistance ");
- DEBUG(average);
- float steinhart;
- steinhart = average / THERMISTORNOMINAL; // (R/Ro)
- steinhart = log(steinhart); // ln(R/Ro)
- steinhart /= BCOEFFICIENT; // 1/B * ln(R/Ro)
- steinhart += 1.0 / (TEMPERATURENOMINAL + 273.15); // + (1/To)
- steinhart = 1.0 / steinhart; // Invert
- steinhart -= 273.15; // convert absolute temp to C
- DEBUG(", Temperature ");
- DEBUG(steinhart);
- DEBUG(" °C");
- return steinhart + 0.5; // adding 0.5 prevents it always rounding down when turning float to int
- }
- void serialDataTransferTask() {
- static unsigned char i;
- if (phaseTwoCompleteFlag == true && userInterventionRequiredFlag == false && longButtonPressDetected == true) {
- Serial.println((String) "Switch\tTemp1\tTemp2\tTemp3\tAverage123\tTemp4\tTemp5\tTemp6\tAverage456");
- for (i = 0; i < NUMBEROFBIMETALLICSWITCHES; i++) {
- Serial.println((String)(i + 1) + "\t" + temperatureArray1[i] + "\t" + temperatureArray2[i] + "\t" + temperatureArray3[i] + "\t=AVERAGE(B" + (i + 2) + ":D" + (i + 2) + ")\t" + temperatureArray1[i + NUMBEROFBIMETALLICSWITCHES] + "\t" + temperatureArray2[i + NUMBEROFBIMETALLICSWITCHES] + "\t" + temperatureArray3[i + NUMBEROFBIMETALLICSWITCHES] + "\t=AVERAGE(F" + (i + 2) + ":H" + (i + 2) + ")");
- }
- delay(3000);
- }
- }
- void buttonPressDetection(const unsigned char BUTTON_PIN, bool &lastButtonState, bool ¤tButtonState, unsigned long &buttonPressTimeStart, unsigned long &buttonPressTimeEnd, bool &buttonIsBeingPressed, bool &shortButtonPressDetected, bool &longButtonPressDetected) {
- shortButtonPressDetected = false; // there might be a better place to put this but it seems to work here
- // read the state of the switch/button:
- currentButtonState = digitalRead(BUTTON_PIN);
- if (lastButtonState == HIGH && currentButtonState == LOW) { // button is pressed
- buttonPressTimeStart = millis();
- buttonIsBeingPressed = true;
- longButtonPressDetected = false;
- } else if (lastButtonState == LOW && currentButtonState == HIGH) { // button is released
- buttonIsBeingPressed = false;
- buttonPressTimeEnd = millis();
- long pressDuration = buttonPressTimeEnd - buttonPressTimeStart;
- if (10 < pressDuration && pressDuration < SHORT_PRESS_TIME) {
- DEBUG("A short press is detected");
- shortButtonPressDetected = true;
- }
- longButtonPressDetected = false;
- }
- if (buttonIsBeingPressed == true && longButtonPressDetected == false) {
- long pressDuration = millis() - buttonPressTimeStart;
- if (pressDuration > LONG_PRESS_TIME) {
- DEBUG("A long press is detected");
- longButtonPressDetected = true;
- }
- }
- // save the last state
- lastButtonState = currentButtonState;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement