산업 제조
산업용 사물 인터넷 | 산업자재 | 장비 유지 보수 및 수리 | 산업 프로그래밍 |
home  MfgRobots >> 산업 제조 >  >> Manufacturing Technology >> 제조공정

OLED 화면에서 실시간 ECG 얻기

구성품 및 소모품

Arduino UNO
× 1
uECG 장치
× 1
nRF24 모듈(일반)
× 1
ElectroPeak 0.96" OLED 64x128 디스플레이 모듈
× 1

이 프로젝트 정보


얼마 전에 uECG 장치에서 데이터를 가져오는 방법을 보여주는 몇 가지 프로젝트를 게시했습니다. 하지만 코드가 상당히 복잡했고 여전히 기본 데이터만 사용하고 있었습니다. 그래서 마지막으로 이 방법을 더 간단하고 훨씬 더 안정적으로 만드는 Arduino 라이브러리를 작성했습니다. https://github.com/ultimaterobotics/uECG_library(Library Manager에서 RF24 라이브러리도 설치해야 합니다. Adafruit의 SSD1306 라이브러리도 이 프로젝트에서와 같이 OLED에 데이터를 표시하고 싶습니다.

1. 회로도

회로도는 nRF24 모듈 및 OLED를 사용하는 다른 프로젝트와 동일합니다. nRF24는 Arduino의 SPI 버스(D13, D12, D11)와 모듈 CS 및 CE 라인용 두 개의 임의 핀에 연결됩니다. 편의를 위해 D10 및 D9를 선택했습니다. 유일한 중요한 점 :nRF24 모듈은 3.3V에 연결해야 합니다. 라인, 5V가 아닙니다! 또한 3.3V와 GND 사이에 1uF 또는 10uF 커패시터를 추가하는 데 많은 도움이 됩니다. 이러한 nRF24 모듈에는 Arduino가 항상 3.3V 라인에서 제공할 수 없는 안정적인 전압이 필요하므로 커패시터가 도움이 됩니다.

OLED는 I2C를 통해 연결됩니다. SDA는 A4, SCL은 A5이며 5V 라인에서 전원이 공급됩니다. 제 경우에는 OLED 모듈에 I2C 프로토콜용 저항이 내장되어 있었습니다. 모듈에 없는 경우 SDA에서 3.3V로, SCL에서 3.3V로 4.7k 저항을 추가해야 하지만 최근에 본 대부분의 모듈에는 이미 저항이 있습니다.

아래에 첨부된 회로도를 볼 수 있으며 조립된 프로젝트의 사진은 다음과 같습니다.

2. 코드

uECG 라이브러리는 적절한 작동을 위해 다음과 같이 몇 줄의 코드를 필요로 합니다.

setup()에서 uECG.begin(pin_cs, pin_ce)을 호출해야 합니다. nRF24 CS 및 CE 라인에 사용되는 핀 번호를 알려야 합니다. 그러면 모듈이 켜지고 내부적으로 올바른 모드가 됩니다.

loop()에서는 가능한 한 자주 uECG.run()을 호출해야 합니다. uECG 장치는 많은 데이터를 전송합니다(몇 밀리초마다 한 패킷). 그리고 다음 시간까지 uECG.run()을 호출하지 않을 경우 패킷이 도착하면 데이터가 손실됩니다. 즉, 루프 내에서 delay() 함수를 호출하지 않고 타이밍이 필요한 작업에는 millis()를 사용합니다(라이브러리 예제에 해당 예제를 추가했습니다).

이 프로젝트 코드는 라이브러리 내에서 예제로 사용할 수 있으며 아래에 첨부되어 있습니다(너무 복잡해 보이는 경우 - 여기에서 코드의 95%가 최적화된 디스플레이 도면 전용임을 명심하십시오. 직렬 모니터에 값을 간단하게 인쇄하려면 몇 줄만 필요):

#include 
#include
#include

#define SCREEN_WIDTH 128 // OLED 디스플레이 너비, 픽셀 단위
#define SCREEN_HEIGHT 64 // OLED 디스플레이 높이, 픽셀 단위

// I2C(SDA, SCL 핀)에 연결된 SSD1306 디스플레이에 대한 선언
# 정의 OLED_RESET -1 // 핀 번호 재설정(또는 Arduino 재설정 핀을 공유하는 경우 -1)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

int rf_cen =9; //nRF24 칩 활성화 핀
int rf_cs =10; //nRF24 CS 핀

void setup() {
Serial.begin(115200); // 직렬 출력 - 디버깅에 매우 유용합니다.
while(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // 주소 0x3D for 128x64
Serial.println(F("SSD1306 할당 실패"));
}
display.display();
지연(100);
uECG.begin(rf_cs, rf_cen);
지연(100);

// 버퍼 지우기
display.clearDisplay();
display.setTextSize(1); // 일반 1:1 픽셀 스케일
display.setTextColor(WHITE); // 흰색 텍스트 그리기
display.cp437(true); // 전체 256자 '코드 페이지 437' 글꼴 사용
display.display();
delay(100);
Serial.println("표시 후");
}

uint32_t prev_data_count =0;
uint32_t prev_displ =0;

uint8_t ecg_screen[128];
int ecg_screen_len =128;
float ecg_avg =0;
float ecg_max =1;
float ecg_min =-1;
int ecg_size =40;

int displ_phase =0;

무효 루프()
{
uECG.run();
uint32_t data_count =uECG.getDataCount();
int new_data =data_count - prev_data_count;
prev_data_count =data_count;
if(new_data> 0)
{
uint32_t ms =millis();
int16_t ecg_data[8];
uECG.getECG(ecg_data, new_data);
for(int x =0; x Serial.println(ecg_data[x]);

for(int x =new_data; x ecg_screen[x-new_data] =ecg_screen[x];
for(int x =0; x {
ecg_avg *=0.99;
ecg_avg +=0.01*ecg_data[x];
ecg_max =ecg_max*0.995 + ecg_avg*0.005;
ecg_min =ecg_min*0.995 + ecg_avg*0.005;
if(ecg_data[x]> __max) ecg_data[x];ecg if(ecg_data[x] int ecg_y =63-ecg_size*(ecg_data[x] - ecg_min) / (ecg_max - ecg_min + 1);
ecg_screen[ ecg_screen_len-1-new_data+x] =ecg_y;
}

if(ms - prev_displ> 30)
{
prev_displ =ms;
if (displ_phase ==0)
{
display.clearDisplay();
display.setCursor(0, 0);
display.print("BPM:");
display.println(uECG.getBPM());
display.print(" RR:");
display.println(uECG.getLastRR());
display.print( "단계:");
display.print(uECG.getSteps());
int batt_mv =uECG.getBattery();
int batt_perc =(batt_mv - 3300)/8;
if(batt_perc <0) batt_perc =0;
if(batt_perc> 100) batt_perc =100;
display.drawLine(110, 0, 127, 0, 흰색);
display.drawLine(110, 10, 127, 10, 흰색);
display.drawLine( 110, 0, 110, 10, 흰색);
display.drawLine(127, 0, 127, 10, 흰색);
int bat_len =batt_perc / 6;
for(int x =1; x <10; x++)
display.drawLine(110, x, 110+bat_len, x, WHITE);
}
if(displ_phase ==1)
{
for( int x =1; x display.drawLine(x-1, ecg_screen[x-1], x, ecg_screen[x], WHITE);
}
if(displ_phase ==2)
{
for(int x =ecg_screen_len/2; x display.drawLine(x-1, ecg_screen[x- 1], x, ecg_screen[x], WHITE);
}
if(displ_phase ==3)
display.display();
displ_phase++;
if (displ_phase> 3) displ_phase =0;
}
}
}

3. 데이터 처리

많은 처리가 온보드에서 수행되며 장치에서 계산된 다양한 통계를 얻을 수 있습니다. BPM, GSR, 마지막 RR 간격, HRV 매개변수 및 16개 HRV 빈(첫 번째 빈은 변동이 <1%인 비트의 양을 나타내고, 두 번째 빈 - 1~2% 사이의 변동), 걸은 걸음 수, 가속도계 판독값(새로고침 빈도가 낮아서 포즈 추정에만 적합).

그러나 원시 ECG 판독값도 얻을 수 있습니다. 데이터 스트림이 완벽하지 않고 때때로 일부 패킷이 손실되지만 여전히 사용할 수 있는 것을 얻을 수 있습니다.

자, 그럼 끝입니다 - 이 장치가 구석에 먼지를 모으는 것이 있었다면 이제 실제로 큰 문제 없이 작동합니다 :)

<섹션 클래스="섹션 컨테이너 섹션 축소 가능" id="코드">

코드

uECG 아두이노 라이브러리
https://github.com/ultimaterobotics/uECG_library
내부에 OLED 및 간단한 직렬 예제가 있습니다.

회로도


제조공정

  1. Maxim:모바일 장치용 통합 PPG 및 ECG 바이오센서 모듈
  2. RPi가 있는 환경 센서 API
  3. TJBot 시작하기
  4. Verilog 모듈
  5. Verilog 매개변수
  6. 자바 9 - 모듈 시스템
  7. Arduino Pong 게임 - OLED 디스플레이
  8. Arduino 및 OLED 기반 Cellular Automata
  9. Dedge The Defs!
  10. Arduino 튜토리얼 01:시작하기