BluePill:PB2 state change not detected when connecting to ground - is my core out of date?

Post here all questions related to LibMaple core if you can't find a relevant section!
Post Reply
Piter_de_Vries
Posts: 11
Joined: Sat Sep 17, 2022 4:12 pm

BluePill:PB2 state change not detected when connecting to ground - is my core out of date?

Post by Piter_de_Vries »

I'm trying to use PB2 for a button in my project and it isn't working for some reason. The entirety of my code is posted below. When I change the button pin to PB12, the program behaves as expected but for PB2, no change is detected when I connect the pin to ground. I have confirm that the voltage drops to 0 on this pin using a multimeter so I'm certain it's not my breadboarding.

The button pin is defined on line 41 while lines 281 onwards encode the response to button presses.

Is there something I need to do for button PB2 to be usable for GPIO?

I think I'm using Roger's core but at this location it has only a "maple" folder. C:\Users\piter\AppData\Local\Arduino15\packages\stm32duino\hardware\STM32F1\2021.2.27\cores
If I need to uninstall the old core and change to a new one do I just delete C:\Users\piter\AppData\Local\Arduino15\packages\stm32duino\ ?

Thanks.

Image

Code: Select all

/*
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 0  // value is 1 to enable debugging serial printing
#define DEBUG2 1  // 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 3000-4000)
#define BCOEFFICIENT 3950
// the value of the resistor used to make a potential divider with the thermistor
#define SERIESRESISTOR 10000

// an array is need to store the pins to which each bimetallic switch will be attached
unsigned char bimetallicSwitchMonitoringPins[30] = { /* 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 and also PB12 which I was using temporarily for the button

bool initialBimetallicSwitchState;

// an array to store the state of each bimetallic switch
bool bimetallicSwitchStates[30];

// 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 lastButtonState;
bool currentButtonState;
bool buttonIsBeingPressed;
bool shortButtonPressDetected;
bool longButtonPressDetected;
unsigned long buttonPressTimeStart;
unsigned long buttonPressTimeEnd;

void setup() {
  Serial.begin(9600);
  pinMode(BUTTONPIN, INPUT_PULLUP);
  // pinMode(13, OUTPUT); // what is this for?
  // 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 < 30; 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 < 30; 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();
  serialDataTransferTask();
}

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);
    return;
  }
}

// bimetallic switch state checking is blocked when the relevant flag is false: this function sets the flag to
// true every bimetallicSwitchStateCheckingInterval seconds ****** might as well set this flag to true after recording temperatures
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 < 30; i++) {
  DEBUG2((String)bimetallicSwitchMonitoringPins[i] + "=" + bimetallicSwitchStates[i] + ",");
  } */
  DEBUGLN2((String)currentButtonState +",");  
  return;
}

void bimetallicSwitchStateCheckingTask() {
  if (bimetallicSwitchStateCheckingFlag == false) {
    return;
  }
  for (unsigned char i = 0; i < 30; 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
      temperatureArray1[i + (30 * phaseOneCompleteFlag)] = temperature1;                // fill the relevant arrays with the last-recorded temperatures
      temperatureArray2[i + (30 * phaseOneCompleteFlag)] = temperature2;
      temperatureArray3[i + (30 * phaseOneCompleteFlag)] = temperature3;
    }
    if (bimetallicSwitchStates[0] != initialBimetallicSwitchState && bimetallicSwitchStates[0] == bimetallicSwitchStates[i] && phaseOneCompleteFlag == false) {  // check whether all of the bimetallic switches have changed from their states
      phaseOneCompleteFlag = true;
      return;
      if (bimetallicSwitchStates[0] != initialBimetallicSwitchState && bimetallicSwitchStates[0] == bimetallicSwitchStates[i] && 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 MOSFET switching 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 = 4095 / 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.print((String) "Switch,Temp1,Temp2,Temp3,Average123,Temp4,Temp5,Temp6,Average456");
    for (i = 0; i < 30; i++) {
      Serial.print((String)(i + 1) + temperatureArray1[i] + "," + temperatureArray2[i] + "," + temperatureArray3[i] + ",," + temperatureArray1[i + 30] + "," + temperatureArray2[i + 30] + "," + temperatureArray3[i + 30] + ",");
    }
  }
}

void buttonPressDetection(const unsigned char BUTTON_PIN, bool &lastButtonState, bool &currentButtonState, unsigned long &buttonPressTimeStart, unsigned long &buttonPressTimeEnd, bool &buttonIsBeingPressed, bool &shortButtonPressDetected, bool &longButtonPressDetected) {
  // 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) {
      Serial.println("A short press is detected");
      shortButtonPressDetected = true;
    }
    longButtonPressDetected = false;
  }

  if (buttonIsBeingPressed == true && longButtonPressDetected == false) {
    long pressDuration = millis() - buttonPressTimeStart;

    if (pressDuration > LONG_PRESS_TIME) {
      Serial.println("A long press is detected");
      longButtonPressDetected = true;
    }
  }

  // save the last state
  lastButtonState = currentButtonState;
}
hobbya
Posts: 43
Joined: Thu Dec 19, 2019 3:27 pm
Answers: 1

Re: BluePill:PB2 state change not detected when connecting to ground - is my core out of date?

Post by hobbya »

PB2 is Boot1 of the bluepill and generally a jumper is fitted. The Boot1 jumper is usually tied to LOW. You should either tie the jumper to HIGH or remove this jumper before running your code.
Piter_de_Vries
Posts: 11
Joined: Sat Sep 17, 2022 4:12 pm

Re: BluePill:PB2 state change not detected when connecting to ground - is my core out of date?

Post by Piter_de_Vries »

hobbya wrote: Sun Sep 25, 2022 11:15 am PB2 is Boot1 of the bluepill and generally a jumper is fitted. The Boot1 jumper is usually tied to LOW. You should either tie the jumper to HIGH or remove this jumper before running your code.

I removed the jumper already and added a DuPont wire that goes to my tactile momentary switch.
Piter_de_Vries
Posts: 11
Joined: Sat Sep 17, 2022 4:12 pm

Re: BluePill:PB2 state change not detected when connecting to ground - is my core out of date?

Post by Piter_de_Vries »

I installed the offical STM32 core (I didn't until now realise you could have both installed simultaneously) and the problem persists when my sketch is compiled with that core (works with button set to PB12 but not PB2).

I tried the Blink sketch using PB2 and the LED is extremely dim. Could that be a clue? It's definitely flashing but is only visible if I look into the top of the LED; it appears off from the side.

Edit: I've done more experimenting with this pin and have more pertinent information. In the following sketch, setting PB2 to INPUT vs INPUT_PULLUP makes a difference. If I use INPUT, instead of INPUT_PULLUP, then the pin detects correctly when I move the jumper wire directly to GND or 3.3V. If I set the pin up with INPUT_PULLUP, it cannot detect when I move the jumper directly to GND. I read somewhere that the internal pull-up resistor is meant to be over 20K so I don't know what is happening. I guess a work around is to use INPUT and then an external pull-up resistor to stop the state from floating.

Edit: I'm not sure, but I think my chips are not genuine. They have 64 KB of flash but the BluePill Diagnostics v1.640 program crashes when I try to check for the extra hidden 64 KB. The other tests pass.

Code: Select all

int pushButton = PB2;

// the setup routine runs once when you press reset:
void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
  // make the pushbutton's pin an input:
  pinMode(pushButton, INPUT_PULLUP);
}

// the loop routine runs over and over again forever:
void loop() {
  // read the input pin:
  int buttonState = digitalRead(pushButton);
  // print out the state of the button:
  Serial.println(buttonState);
  delay(1);        // delay in between reads for stability
}
ozcar
Posts: 102
Joined: Wed Apr 29, 2020 9:07 pm
Answers: 4

Re: BluePill:PB2 state change not detected when connecting to ground - is my core out of date?

Post by ozcar »

Where are you getting access to PB2?

From the symptoms you describe, I would guess at the at the boot jumper pin. There is a 100k resistor between that and the pin on the processor.
Piter_de_Vries
Posts: 11
Joined: Sat Sep 17, 2022 4:12 pm

Re: BluePill:PB2 state change not detected when connecting to ground - is my core out of date?

Post by Piter_de_Vries »

ozcar wrote: Sun Sep 25, 2022 11:16 pm Where are you getting access to PB2?

From the symptoms you describe, I would guess at the at the boot jumper pin. There is a 100k resistor between that and the pin on the processor.
Yes, that's where I am connecting to PB2. Is the alternative to try to solder directly to the chip? or maybe on the chip's side of that resistor?

Thanks for letting me know anyway. I searched multiple times for issues surrounding using PB2 as a regular GPIO and didn't find this.
ozcar
Posts: 102
Joined: Wed Apr 29, 2020 9:07 pm
Answers: 4

Re: BluePill:PB2 state change not detected when connecting to ground - is my core out of date?

Post by ozcar »

Maybe leave your connection on the boot jumper pin, and just short the resistor out, either leaving it there or not. I'm not sure how useful the resistor is in the first place when there is no easy way to connect directly to the processor PB2 pin.

Edit:
For use as a button input (but not if you did want to drive a LED), I guess another possibility you could try would be to remove the INPUT_PULLUP from the pinMode and use an external pullup (so that the pullup is on the other side of the resistor).
Post Reply

Return to “General discussion”