fbpx

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.

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

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

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

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.

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!

Podobne artykuły

.

10 Komentarzy

Kamil · 07/09/2020 o 09:42

Błąd przy zmianie parametrów, to błąd kompilatora. Zauważyłem, że jest to najpewniej niewystarczająca pamięć, żeby obsłużyć nawet niewiele większą ilość próbek.

Co do wyniku -999, faktycznie czujnik jest średni jeśli chodzi o jakość sygnału. Poprawiłem to algorytmem, wycinając duże odchylenia i jest lepiej.

sara · 12/08/2020 o 20:40

hi,
I used this code in my system with 6 other sensors with all I2C4. But When I put this callback for MAX3010x the whole program goes to hanging and suddenly stops. Just by commenting the callback others seems OK. can you help me with this issue?

Kamil · 05/08/2020 o 19:37

Witam, spróbowałem zastosować udostępniony kod na Nucleo F103RB. Póki co napotkałem dwa problemy:
1) przy próbie zmiany wartości MAX30102_MEASUREMENT_SECONDS (na np.10) lub MAX30102_SAMPLES_PER_SECOND (na np. 200), program nie kompiluje się. Co może być tego przyczyną?
2) drugi problem to wynik SpO2 praktycznie zawsze pozostaje na -999. HR jest w miare poprawny. Nie ingerowałem w pliki algorithm.* oraz MAX30102.*
Pozdrawiam

    Mateusz Salamon · 06/08/2020 o 10:12

    Jaki błąd dostajesz przy zmianie tych parametrów?
    Ten wynik -999 spowodowany jest pewnie jakimiś śmieciami w pomiarach. Niestety ten czujnik nie jest jakiś porywający i musi mieć dosyć dobre warunki do pomiarów. W telefonie to widzę, bo gdy tylko ruszę lekko palec – pomiar wariuje.

saeideh · 07/06/2020 o 19:23

hello & THANK YOU FOR YOUR good explain but could you please tell me about wiring, I get confused about TEST and INT button and INT (MAX30102) and how to config them

    Mateusz Salamon · 07/06/2020 o 19:39

    Don’t care about TEST pin 🙂 It’s only for timing check purpose.

    INT is interrupt pin from MAX30102. Youi have to set EXTI interrupt pin on STM32, enable Interrupt for falling edge and write a callback for it.

Kursad · 16/04/2020 o 17:31

i tested your project with stm32f103cbu and stm32f411ce and
this module https://www.aliexpress.com/i/33019226882.html but it didnt work, pls help me about projrct , thanks for now

    Mateusz Salamon · 18/04/2020 o 15:48

    I don’t know what did you do in your project. You can send me a full description to mateusz@msalamon.pl. I will try to help you 🙂

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 *