Prawdopodobnie każdy mój czytelnik miał do czynienia z jakimś urządzeniem ubieralnym tzw. wearables. Nawet najprostsze opaski fitnesowe mają wbudowany czujnik tętna, który dokonuje pomiaru najczęściej na nadgarstku osoby użytkującej taki gadżet. Okazuje się, że nie jest to tajemnicza technologia, która jest dostępna jedynie dla zamkniętego grona producentów elektroniki użytkowej. Również na naszych biurkach możemy dokonać prostego pomiaru własnego tętna. Wystarczy do tego odpowiedni układ.

MAX30102 w służbie zdrowiu

Firma Maxim wypuściła kilka sensorów służących pomiarom tętna. Jednym z nich jest omawiany dzisiaj MAX30102 ( MAX30102 Datasheet). Jest to w zasadzie urządzenie 2 w 1 bowiem oprócz pulsu można nim mierzyć również saturację, czyli natlenienie krwi. Czujnik ten jest chętnie wykorzystywany w smartfonach , na przykład w Samsungach.

Sam czujnik do zasilania logiki wymaga napięcia 1,8 V. Opróćz tego wymagane jest również drugie napięcie do zasilenia diod. Może to być 3,3 V, ale diody spokojnie wytrzymują też 5 V. Moduł posiada wbudowane zasilanie diod właśnie na poziomie 5V, więc nie trzeba się nim niepotrzebnie martwić.

Czujnik ten posiada wbudowane dwie diody LED oświetlające badaną tkankę – czerwoną oraz podczerwoną. Do zbierania sygnału służy natomiast fotodetektor.

Układ cechuje się bardzo niskim poborem prądu wynoszącym w trybie Shutdown jedyne 0,7 µA. Całościowy prąd pobierany przez czujnik w stanie aktywnym w głównej mierze uzależniony jest od prądu pobieranego przez diody, który jest regulowany programowo. Nie licząc diod sam czujnik do pracy potrzebuje około 600 µA. Prąd każdej z LEDek natomiast regulowany jest programowo w zakresie 0÷51 mA. Huh! 51 mA na diodę wydaje się cakiem sporo. Nie odważyłem się puścić aż tak dużego prądu…

Czujnik posiada wyjście przerwania INT. Może ono służyć do sygnalizacji kilku zdarzeń. Najprzydatniejsze z nich moim zdaniem to sygnalizacja nowej próbki oraz zbliżającego się przepełnienie FIFO.

Odbiciowy pomiar tętna i saturacji

Wykorzystywany przez naszego Maxa pomiar nazywa się odbiciowym dlatego, że diody oraz fotodetektor znajdują się po tej samej stronie palca. Światło emitowane przez diody odbija się od palca(a dokładniej hemoglobiny) i wraca na detektor.

Pomiar saturacji krwi odbywa się dzięki zjawisku pochłaniania światła przez hemoglobinę. Hemoglobina natleniona w niskim stopniu pochłania światło o długości fali około 660 nm, natomiast hemoglobina mocno natleniona pochłonie więcej światła o długości fali 940 nm. Diody wbudowane w układ MAX30102 posiadają długości fal 660 nm oraz 880 nm. Mimo, że nie trafiają idealnie w długość fali podczerwonej, to działa poprawnie. Poziom natlenienia wyznacza się za pomocą stosunku transmitancji światła dla obu tych długości.

Przebieg wartości odbitego światła jako główną składową zawiera falę tętna z której łatwo jest odczytać puls. Poniżej zamieściłem wykres dla diody czerwonej, który ściągnąłem z mojego palca omawianym czujnikiem.

Schemat i CubeMX

Dzisiaj wykorzystam Nucleo z układem STM32F401RE. Schemat połączenia czujnika jest prosty za sprawą kompletnego modułu jaki kupujemy. Niestety pullupy na module są podłączone do 1,8 V co nie do końca chce współpracować z STM32 pędzącym na 3,3 V a przynajmniej z moim egzemplarzem. Dlatego dodałem zewnętrzene pullupy do napięcia zasilania modułu, a piny I2C oraz INT w mikrokontrolerze skonfigurowałem jako No pull-up and no pull-down.

I2C ustaw od razu na 400 kHz.

Do działania potrzebujesz jeszcze wejścia przerwania reagującego na zbocze opadające. Upewnij się, że Cube aktywował to przerwanie podczas inicjalizacji. Czasem bywają z tym jaja. Uprzedzając komentarze – tak, tak HAL jest najgorszy na świecie przez to 🙂

Biblioteka

Przechodzimy do najciekawszego czyli do tego, jak korzystać z naszego czujnika. Maxim na swojej stronie udostępnia przykładowy kod dla środowiska Arduino oraz mbed. O ile sam algorytm wyszukiwania szczytów w sygnale, przeliczania ich na tętno oraz algorytm liczący natlenienie krwi są ok, tak przykład zbierania próbek jest beznadziejny.

Niestety główna przykładowa pętla main zdominowana jest czekaniem na pojawienie się przerwania od czujnika. Wtedy pobierane i przeliczane są próbki. Po zebraniu najpierw 500, a później co każde 100 próbek uruchamiany jest algorytm. Próbki moim zdaniem niepotrzebnie są przesuwane w lewo po obliczeniach. Nie może być tak, że mikrokontroler specjalnie czeka na przerwanie! W dodatku cały czas diody świecą pełną mocą, nie ważne czy palec jest przyłożony do czujnika czy nie. Co za marnotrawienie prądu…

Przykład również nie będzie działał z inną konfiguracją czujnika niż 100 sampli na sekundę. Poprawiłem to.

Działanie mojej biblioteki oparłem na prostej maszynie stanowej z czterema stanami, gdzie w międzyczasie cały czas w przerwaniu zbierane są próbki. Próbki trafiają do bufora cyklicznego dzięki czemu nie trzeba ich przesuwać po każdym puszczeniu algorytmu. Co się dzieje w tych dzikich stanach maszynowych?

  1. MAX30102_STATE_BEGIN. Palec nie jest przyłożony do czujnika. Dioda czerwona jest wyłączona, IR na minimum. Dioda IR ma za zadanie wykryć palec położony na czujniku. Zawsze kiedy palec zostanie ściągnięty z czujnika, program wraca do tego stanu wygaszając diody.
  2. MAX30102_STATE_CALIBRATE. Po przyłożeniu palca należy zapełnić bufor ‘poprawnymi danymi’. Standardowo obliczenia wykonywane są na próbkach z ostatnich 5 sekund. Kalibracja, czyli zapełnienie bufora więc będzie tyle trwało.
  3. MAX30102_STATE_CALCULATE_HR. Po zebraniu odpowiedniej liczby próbek, dokonywane są obliczenia według algorytmu Maxima. W tym kroku przesunięty zostaje bufor cykliczny o ilości sampli odpowiadającej jednej sekundzie.
  4. MAX30102_STATE_COLLECT_NEXT_PORTION. W tym stanie obsługa czujnika znajduje się do czasu, kiedy zostanie zebrana kolejna porcja próbek, czyli z kolejnej sekundy. Po tym trafia do stanu numer 3 i cykl powtarza się aż do ściągnięcia palca z czujnika.

Używanie biblioteki

Bibliotekę pisałem tak, aby jej użycie było jak najprostsze. Całość opiera się na kilku krokach. Po pierwsze należy zainicjalizować bibliotekę i czujnik podając który intefejs I2C został użyty.

1
<br>MAX30102_STATUS Max30102_Init(I2C_HandleTypeDef *i2c);<br>

Kolejnym ważnym punktem jest obsługa przerwania. Należy przedefiniować wbudowaną w HALa funkcję weak.

1
<br>/* USER CODE BEGIN 4 */<br>void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {<br>if (GPIO_Pin == INT_Pin) {<br>Max30102_InterruptCallback();<br>}<br>}<br>/* USER CODE END 4 */<br>

Ostatnim warunkiem jest wrzucenie do pętli głównej funkcji odpowiadającej za obsługę maszyny stanów.

1
<br>void Max30102_Task(void);<br>

Teraz możesz czytać z biblioteki bieżące wartości tętna oraz saturacji za pomocą dwóch funkcji.

1
<br>int32_t Max30102_GetHeartRate(void);<br>int32_t Max30102_GetSpO2Value(void);<br>

Dodatkowa konfiguracja

Biblioteka oraz czujnik standardowo skonfigurowane są na 5-sekundowy pomiar oraz 100 próbek na sekundę. Możesz to dowolnie modyfikować. Biblioteka automatycznie dobierze wielkości buforów na sample oraz będzie w stanie dostosować obliczenia.

Dodatkowo jest takie ustawienie jak ilość sampli dla wywołania przerwania FIFO Almost Full. Jeżeli z jakiegoś powodu próbki nie będą odbierane na czas, będą one kolejkowane w czujniku. Zkolejkowanie ustawionej liczby próbek wywoła przerwanie od tego zdarzenia. Biblioteka wykrywając te przerwanie, odczyta wszystkie dostępne próbki jakie znajdują się w buforze, czyszcząc go jednocześnie. Bufor maksymalnie pomieści 32 próbki. Domyślna wartość 17 jest wartością minimalną która wywołuje przerwanie. Jak dla mnie jest to wystarczające ustawienie lecz nie sprawdzałem czujnika w prawdziwym boju. Być może w rozbudowanej aplikacji czujnik będzie się lepiej spisywał przy wyższej wartości.

1
<br>#define MAX30102_MEASUREMENT_SECONDS 5<br>#define MAX30102_SAMPLES_PER_SECOND 100 // 50, 100, 200, 400, 800, 100, 1600, 3200 sample rating<br>#define MAX30102_FIFO_ALMOST_FULL_SAMPLES 17<br>

Prezentacja działania

Mój przykładowy kod printuje na terminal obliczane wartości.

Całkiem niskie tętno jak na siedzenie i klepanie kodu. A myślałem, że to stresujące zajęcie 🙂 Zobacz jeszcze jak działa automatyczne załączanie i wyłączanie diod w zależności czy do czujnika jest przyłożony palec.

Podsumowanie

Pulsometr od Maxim’a jest bardo ciekawym urządzeniem. Działa poprawnie lecz niestety czasem zdarzy mu się potnąć skacząc z wyliczonym tętnem. Nie jestem dobry z obróbki sygnałów – miałem 3 z laborek 🙁 Jakby znalazł się ktoś, kto zerknie w kod algoytmu i go poprawi to będę niesamowicie wdzięczny! Z drugiej strony w moim smartfonie wygląda to podobnie, więc być może nie jest to wina kulawego algorytmu oraz mojego programu.

Obecnie urządzenia ubieralne potrafią mierzyć tętno z nadgarstka. Niestety ten czujnik słabo sobie radzi w tym miejscu. Zaczerpnąłem trochę teorii i do pomiaru nadgarstkowego zalecana jest jeszcze jedna, zielona dioda. Widać to np. we wspomnianych na samym początku opaskach fitnesowych lub zegarkach biegowych. Myślę, że można potraktować ten czujnik – tak samo jak w telefonie – bardziej jako ciekawostkę niż precyzyjny przyrząd pomiarowy. Ciągły pomiar z palca przydatny może być jedynie w szpitalu. Sam dla siebie nie widzę większego zastosowania. Może masz jakieś? Podziel się tym w komentarzu!

Pełny projekt wraz z biblioteką znajdziesz jak zwykle na moim GitHubie: link

Jeśli zauważyłeś jakiś błąd, nie zgadzasz się z czymś, chciałbyś coś dodać istotnego lub po prostu uważasz, że chciałbyś podystkutować w tym temacie, napisz komentarz. Pamiętaj, że dyskusja ma być kulturalna i zgodna z zasadami języka polskiego.

Jeżeli czujnik Ci się spodobał, możesz nabyć go w moim sklepie.

Wyniki konkursu z poprzedniego wpisu

Ostatnio zrecenzowałem książkę “Mikrokontrolery STM32 dla początkujących”, która opiera się na używanych przeze mnie bibliotekach HAL. Z tej okazji zorganizowałem konkurs w którym do wygrania łącznie były 4 komplety książka + płytka ewaluacyjna KA-NUCLEO-F411CEv2. Nie przedłużając już oto wybrani przeze mnie zwycięzcy:

1. Szymon Fronc z komentarzem:

Recenzja taka jak powinna być treściwa i rzeczowa budująca głód i chęci do podjęcia przygody z czymś co dla kogoś takiego jak ja jest dalszą drogą zabawy z mikrokontrolerami.Myśle ze STM’y mogą poszerzyć horyzonty(coś nowego niż dotychczasowe arduino), czego chętnie bym spróbował jeśli udałoby mi się zgarnąć taki zestaw dla siebie. Pora wziąć udział w konkursie 😀 Pozdrawiam i czekam na kolejne ciekawe recenzje!

2.  Mateusz z komentarzem:

Dobra, rzeczowa recenzja, która przede wszystkim zachęca “gang świeżaków” do rozpoczęcia przygody z mikrokontrolerami STM i szczerze odradza książkę bardziej doświadczonym programistom. Ja sam od dłuższego czasu siedzę w mikrokontrolerach z rodziny AVR i muszę przyznać, że do STM zabierałem się jak pies do jeża! Fajnie, że znajdują się osoby, które zarażają swoją pasją innych. Dziękuję i pozdrawiam!

3. Franek z komentarzem:

Dobra recenzja, widać że autor faktycznie jest doświadczony w temacie oraz jest zainteresowany książką. Na duży plus również to, iż jest to recenzja szczera pokazująca książkę również od strony jej wad i wprost mówiąca dla jakich odbiorców jest ona przeznaczona

4. Norbert z komentarzem:

Recenzja z pewnością zachęciła mnie do wzięcia udziału w konkursie, być może przełoży się to na podejście do tego “potwora” jakim są ogromne możliwości mikrokontrolerów STM32. Jeśli przedstawisz przekrój począwszy od początkujących propozycji po te bardziej zaawansowane – jestem w pełni za takimi publikacjami.

Gratuluję! W celu sfinalizowania konkursu odezwę się do Was mailowo. Pozdro!

4.6
05


Raz na jakiś czas wyślę Ci też e-mail z ciekawymi rzeczami które znalazłem


2 Komentarze

Michsł · 10/04/2019 o 13:42

Świetny wpis, jak zawsze zresztą. Może czas na komunikację LoRa ;)?

    Mateusz Salamon · 11/04/2019 o 20:42

    Dzięki! Moduły LoRa leżą w szafie w szufladce “do zrobienia” więc pewnie w końcu się pojawią. Nie mam tylko cos do nich weny 🙁

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *

Serwis wykorzystuje pliki cookies. Korzystając ze strony wyrażasz zgodę na wykorzystywanie plików cookies. Więcej informacji znajdziesz na stronie Polityka Prywatności

The cookie settings on this website are set to "allow cookies" to give you the best browsing experience possible. If you continue to use this website without changing your cookie settings or you click "Accept" below then you are consenting to this.

Close