Rowerowy miernik kadencji - miniaturyzacja i zmiana koncepcji (2/2)


Tomasz Bartuś



2018-10-18
Miernik kadencji

Wstęp

W poprzednim odcinku zaprezentowałem prosty obrotomierz bazujący na pomiarze napięcia efektu Halla. Pomimo swojej użyteczności, układ był jednak zbyt duży i nieporęczny aby móc go bezpośrednio zastosować w rowerze. W tym odcinku dokonamy jego miniaturzacji (Fig. 1) oraz zmienimy koncepcję szkicu obsługującego urządzenie. W szkicu z projektu 35 wartości kadencji były wyświetlane w kilkusekundowych przedziałach czasowych definiowanych zmienną sampleTime. W nowym szkicu, wartości kadencji będą wyświetlane na bieżąco, w czasie rzeczywistym.

Układ obrotomierza
Fig. 1. Układ miernika kadencji

Układ

W związku z tym, że hallotron AH49E znajdując się poza oddziaływaniem pola magnetycznego podaje na swoje wyjście napięcie około 2,5V, które czasami może być interpretowane przez mikrokontroler jako stan wysoki, zdecydowano się na zmianę konstrukcji układu. Wykorzystano komparator napięć LM393 (Fig. 2) - układ porównujący ze sobą dwa napięcia wejściowe i w zależności od ich stosunku do siebie, zwierający pin wyjściowy do masy. Krótką charakterystykę tego układu przedstawiono w projekcie 37.

Rowerowy miernik kadencji
Fig. 2. Schemat układu miernika kadencji z wyświetlaczem OLED

Komparator LM393 będzie zasilany z układu Arduino napięciem 5V. Napięcie wyjściowe hallotronu w warunkach występowania silnego pola magnetycznego wynosi 4-5V. W nocie katalogowej układu LM393 przeczytamy, że napięcie zasilania komparatora powinno być o ok. 1,5V wyższe niż porównywane napięcia wejściowe. Komparator będzie porównywał napięcie z detektora pola magnetycznego (pin 2) z napięciem pochodzącym z regulowanego dzielnika napięcia utworzonego na potencjometrze R3 (pin 3). Regulacja tego napięcia umożliwi kalibrację układu do warunków pracy konkretnego rozwiązania aplikacyjnego.

Jeżeli nie ma pola magnetycznego, napięcie na wejściu nieodwracającym komparatora UIn1(+) dostarczane z potencjometru R3 na pin 3 komparatora jest większe od napięcia wyjściowego hallotronu podawanego na wejście odwracające komparatora UIn1(-) (pin 2).

UIn1(+) > UIn1(-)

Wyjście układu LM393 jest wtedy rozłączone od masy. Prąd nie płynie także przez rezystor R4 i diodę LED1. Przez krótką chwilę prąd płynący od zacisku +5V przez R5 ładuje okładki kondensatora C1. Prąd ładowania kondensatora wraz z ilością zgromadzonego ładunku, z czasem zanika. Na wejściu D2 układu Arduino cały czas występuje wtedy stan wysoki.

W chwili kiedy hallotron dostanie się w strefę oddziaływania pola magnetycznego, napięcie na jego wyjściu wzrasta do ok. 4-5V. Napięcie na wejściu odwracającym komparatora UIn1(-) (pin 2) jest teraz wyższe niż na wejściu nieodwracającycm UIn1(+) (pin 3).

UIn1(-) > UIn1(+)

Wyjście komparatora zostaje zwarte do masy. Przez R4 oraz LED1 zaczyna płynąć prąd, co powoduje zaświecenie diody LED. Jednocześnie dochodzi do rozładowania kondensatora C1. Na wejściu D2 układu Arduino pojawia się stan niski. Sygnały te będą zliczane przez układ mikrokontrolera. Dodatkowo do układu dodano kondensator filtrujący C2. Wyświetlaczo OLED podłączono do pinów SDA (A4) i SCL (A5) układu Arduino Nano.

Schemat montażowy

Zmontujmy układ z Fig. 3.

Rowerowy miernik kadencji
Fig. 3. Schemat układu miernika kadencji z wyświetlaczem OLED

Lista części

  1. platforma Arduino Nano,
  2. płytka prototypowa,
  3. hallotron AH49E,
  4. moduł wyświetlacza OLED 0,91" 128 × 32,
  5. układ scalony LM393,
  6. rezystor 150Ω,
  7. rezystor 1kΩ,
  8. rezystor 10kΩ,
  9. rezystor 100kΩ,
  10. potencjometr podkówkowy (dowolna wartość, tu 10kΩ),
  11. kondensatory 100nF 2 szt.,
  12. dioda LED,
  13. przewody/mostki.

W szkicu obsługującym urządzenie, na wstępie zostanie utworzona jednowymiarowa i numReadings-elementowa tablica. Gdy na wyjściu OUT czujnika Halla pojawi się stan wysoki, do tablicy zostanie zapisany czas wykrycia pola magnetycznego. Gdy liczba pomiarów przekroczy liczbę elementów tablicy, najstarszy pomiar zostanie podmieniony najmłodszym. Na podstawie wyników zapisanych w tablicy będzie obliczany przedział czasu jaki upłynął pomiędzy najstarszym pomiarem a najmłodszym. Jeżeli w obliczanym przedziale czasu wystąpiło numReadings impulsów, to z proporcji zostanie obliczona liczba impulsów na minutę (RPM). Wartość ta będzie się zmieniała co impuls i na bieżąco będzie wyświetlana na wyświetlaczu OLED.

Kod

/*
  The Bicycle Cadence Sensor
  Cadence Sensor measures the number of pedal revolutions per minute.
  Tomasz Bartuś
  bartus@agh.edu.pl
  2018-10-18
*/
#include <Arduino.h>
#include <SPI.h>
#include <U8g2lib.h>

U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ SCL, /* data=*/ SDA);   // pin remapping with ESP8266 HW I2C

#define numReadings 4               // number of the hall efect readings

int hall_din = 2;
int pomiar = 0;                     // total measurement number (from 0 to infinity)
long readings[numReadings];         // readings table initialization
int i = 0;                          // no of measurements counted from 0 to numReadings
int j = 0;
int index_min;
int cadence_limit = 90;             // cadence limit on which depends the direction of the displayed arrows 
int mean_cadence = 0;

long currentTime; //unsigned

void setup() {
  pinMode(hall_din, INPUT);
  Serial.begin(9600);
  u8g2.begin();

  u8g2.firstPage();
  do {
    u8g2.clearBuffer();
    u8g2.setFont(u8g2_font_ncenB14_tr);
    u8g2.drawStr(40, 15, "Cadence");
    u8g2.drawStr(40, 32, "Sensor");
    u8g2.drawLine(30, 0, 30, 32);
    u8g2.setFont(u8g2_font_ncenR10_tf);
    u8g2.setDisplayRotation(U8G2_R3);
    u8g2.drawStr(0, 25, "Bike");
  } while ( u8g2.nextPage() );
  delay(3000);
}

long minimum() {                            // the function that calculates a time of the oldest measurement
  long currentMinimum = 2147483647;         // we start really high, so that any element in the array will be lower that this
  for (int i = 0; i < numReadings; i++) {
    if ( readings[i] < currentMinimum ) {
      currentMinimum = readings[i];
    }
  }
  return currentMinimum;
}

long maximum() {                            // the function that calculates a time of the youngest measurement
  long currentMaximum = 0;                  // we start really low, so that any element in the array will be higher that this
  for (int i = 0; i < numReadings; i++) {
    if ( readings[i] > currentMaximum ) {
      currentMaximum = readings[i];
    }
  }
  return currentMaximum;
}

void loop() {
  if (digitalRead(hall_din) == LOW) {        // if the hall sensor detected a magnetic field:
    currentTime = millis();                  // save the current time to the currentTime variable

    if (pomiar < numReadings) {              // if the total measurement number is < numReadings
      readings[j] = currentTime;             // save the currentTime variable to the readings[j] table element

      long min = minimum();                  // calculate the minimum time value from the readings[numReadings] table
      long max = maximum();                  // calculate the maximum time value from the readings[numReadings] table

      for (int i = 0; i < numReadings; i++) {         // print the array
        Serial.print("readings[");
        Serial.print(i);
        Serial.print("] ma wartosc: ");
        Serial.println(readings[i]);
      }
      j = j + 1;

    } else {                                  // if the total measurement number is > numReadings
      long min = minimum();                   // calculate the minimum time value from the readings[numReadings] table
      long max = maximum();                   // calculate the maximum time value from the readings[numReadings] table
      for (int i = 0; i < numReadings; i++) { //
        if ( readings[i] == min ) {           // check the index of the minimum value from the array
          index_min = i;
          readings[index_min] = currentTime;

          for (int i = 0; i < numReadings; i++) {          // print the array
            Serial.print("readings[");
            Serial.print(i);
            Serial.print("] ma wartosc: ");
            Serial.println(readings[i]);
          }
          long deltaT = max - min;

          long count2rpm = (60000 * numReadings) / deltaT; // count the RPM value
          Serial.println(count2rpm);

          u8g2.firstPage();
          do {
            u8g2.clearBuffer();
            u8g2.setDisplayRotation(U8G2_R0);
            u8g2.setFont(u8g2_font_fub30_tf);
            char buf[50];
            sprintf (buf, "%d", count2rpm);
            u8g2.drawStr(45, 32, buf);
            u8g2.setFont(u8g2_font_ncenR10_tf);
            u8g2.drawLine(30, 0, 30, 32);
            if (count2rpm <= cadence_limit) {
              u8g2.drawTriangle(8,0, 11,16, 5,16);
              u8g2.drawTriangle(5,17, 11,17, 8,29);
              u8g2.drawTriangle(0,32, 7,29, 5,17);
              u8g2.drawTriangle(9,29, 16,32, 11,17);
            } else {
              u8g2.drawTriangle(0,0, 7,3, 5,15);
              u8g2.drawTriangle(5,15, 11,15, 8,3);
              u8g2.drawTriangle(5,16, 11,16, 8,32);
              u8g2.drawTriangle(16,0, 12,15, 9,3);
            }

          } while ( u8g2.nextPage() );
        }
      }
    }
    pomiar = pomiar + 1;
  
  } else {
    //      Serial.println("Far field");
  }

}

Film




Wykorzystane materiały

Nota katalogowa LM393
LM393: Komparator napiecia
Schemat modułu czujnika Halla
 
 

Doktorat

Spis treści
Rozdzialy
Abstrakt [pl]
Abstract [eng]