AD8232와 ESP8266을 이용해
ECG 로거를 제작함
초기 버전 완료하여 기록을 남김 ...
심전도를 SD카드에 저장
SPIFFS에 저장하기는 속도도 느리고
용량제한도 있어 사용하지 않음
SD카드에 저장하는데 매 ADC 읽기 이벤트 마다
SD카드에 저장하면 전체적인 속도가 매우 느려짐
따라서 해결책을 구글검색에서 조언받음
약512바이트 크기의 버퍼 2개를 교대로 사용해서 저장하고
하나의 버퍼가 다 차면 그때 SD카드에 저장
그동안은 다른 버퍼에 저장...
프로토타입 - 케이스에 조립
프로토 타입 - 테스트 중
케이스 : TINKERCAD -- 수정할 곳이 있음 (배터리 홀더, 충전잭, 커버의 LED 구멍위치)
프로그램 소스
// ============================================================================================
// ESP8266 보드 설치하기
// https://learn.sparkfun.com/tutorials/esp8266-thing-hookup-guide/installing-the-esp8266-arduino-addon
// To begin, we’ll need to update the board manager with a custom URL. Open up Arduino,
// then go to the Preferences (File > Preferences). Then, towards the bottom of the window,
// copy this URL into the “Additional Board Manager URLs” text box:
// ==> http://arduino.esp8266.com/stable/package_esp8266com_index.json
// Hit OK. Then navigate to the Board Manager by going to Tools > Boards > Boards Manager.
// There should be a couple new entries in addition to the standard Arduino boards.
// Look for esp8266. Click on that entry, then select Install.
//
// 'LIB' should be copied into under 'C:\Users\XXXXXXXXXXX\Documents\Arduino\libraries'
//
// SSD1306 Lib for ESP8266
// https://randomnerdtutorials.com/esp8266-0-96-inch-oled-display-with-arduino-ide/
// https://github.com/ThingPulse/esp8266-oled-ssd1306 (below is same LIB)
// https://github.com/squix78/esp8266-oled-ssd1306/archive/master.zip
// unzip to : C:\Users\XXXXXXXXXXX\Documents\Arduino\libraries
// other lib not tested
//
// Note : esp8266 board generic unknown error
// https://arduino-esp8266.readthedocs.io/en/latest/faq/a04-board-generic-is-unknown.html#how-to-fix-it
// 아래 폴더 아래에 있는 오래된 것 삭제 후 재시작
// => C:\Users\XXXXXXXXXXX\AppData\Local\Arduino15\packages\esp8266\hardware
// The blue LED on the ESP-01 - GPIO1 : BLUE = TxD --> GPIO 1, RxD = GPIO 3
// The blue LED on the Wemos D1 mini ESP-12F - GPIO2
// 10-bit analog ADC. The ADC range is from 0V to 1.0V (0 ... 1023)
// Timer & Ticker Exam :
// https://circuits4you.com/2018/01/02/esp8266-timer-ticker-example/
// 'timer 0' is for WiFi, only 'timer 1' can be used
// However 'Ticker' is prefered due to 'crash'
// Internal SD LIB is used no need to install
// SD exam only : https://www.instructables.com/id/SD-Card-Module-With-ESP8266/
// https://github.com/G6EJD/ESP8266-SD-Card-Reading-Writing/blob/master/ESP8266_D1_MicroSD_Test.ino
// ============================================================================================
// 2020.01.27 : 최초버전
// OLED 연결 : 0x3C address of the OLED, SDA=GPIO 0, SCL=GPIO 2
// SD카드 연결 : SCK,MOSI,MISO,SS 연결 (GPIO15 = SS)
// 2020.02.17 : micro SD 카드 연결 및 시간 + 삼각파 + AD값 저장
// 2020.02.18 : SD카드 저장시 속도 느려 그래프 디스플레이 잘 안됨 (SD 끄면 그래프 정상)
// 2020.02.21 : SPIFFS 사용 - 속도 느림 ....
// 2020.02.21 : SPIFFS 삭제 .. SD 저장가능하고 ECG는 판독할 수준임
// 2020.02.22 : SD 쓰기버퍼 시험
// 크기 500바이트 버퍼 2개 사용 후 교차 저장 - 작동속도 UP! (1sample/2-3ms)
// 10ms 마다 저장하도록 변경, OLED 그래프는 900-300 범위로 설정
// ============================================================================================
=
프로그램 변수 및 셋업과 타임 이벤트 핸들러
매 10ms 마다 이벤트 핸들러를 호출함 --> 5ms 마다 저장으로 수정중
clockTick.attach_ms(10, ClockHandler); // Use 'attach_ms' for ms
void ClockHandler(){ // Not much task here / no function call or RESET
ms++;
yaxis = yaxis + ydirection;
if(yaxis>300) ydirection = -1; // ECG의 시간기준 톱니파 생성
if(yaxis<0) ydirection = 1;
if(ms>=100) {ms = 0; sec++;}
if(sec>=60) {sec = 0; m++;}
if(m>=60) {m = 0; h++;}
if(h>=24) h = 0;
}
// -------------------------------------------------------------------------------------
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
//pinMode(A0, INPUT_ANALOG);
digitalWrite(LED_BUILTIN, LOW);
Serial.begin(115200); // Arduino monitor
display.init(); // OLED stuff : Initialise the display.
//display.flipScreenVertically(); // flipping
display.setFont(ArialMT_Plain_10);
display.drawString(0, 0, "ESP Clock");
display.drawString(70, 0, "Clock Init ...");
display.display(); // write the buffer to the display
//clockTick.attach(1, ClockHandler); // Use 'attach' for sec
clockTick.attach_ms(10, ClockHandler); // Use 'attach_ms' for ms
if (!SD.begin(CS_PIN)) {
Serial.println("Fail to open SD");
display.drawString(0, 0, "SD Fail");
display.display();
return;
}
File root;
root = SD.open("/");
root.rewindDirectory();
printDirectory(root, 0); // Display the card contents
root.close();
for(int ndx=0; ndx<100; ndx++){ // Log 화일명 설정 Log0 - Log99
logName = "Log" + String(ndx);
logFileName = logName + ".txt"; // SD card 화일 조사
if (!SD.exists(logFileName)) break; // 지난번에 기록한 로그
Serial.print(logFileName);
Serial.println(" is exsist on SD");
}
dataFile = SD.open(logFileName, FILE_WRITE); // 이번에 기록할 화일명
if(dataFile){
Serial.print(logFileName);
Serial.println(" is open to save log");
}
dataFile.close();
}
ADC 포트 읽고 이벤트 처리부분
SD카드 버퍼를 사용하면 데이터 저장을 2-3ms 마다 한번씩 할 수 있음
데이터의 저장 용량이 너무 커져 10ms 마다 한번씩 저장하도록 함
void loop() {
if(secOld != sec){
//detectBPM();
display.setColor(BLACK);
display.fillRect(0, 0, 127, 10);
display.display();
display.setColor(WHITE);
display.drawString(0, 0, logName); // 현재 로그화일 이름 표시
display.drawString(35, 0, " BPM ");
display.drawString(60, 0, BPM + " " + dispTime);
display.display(); // write the buffer to the display
//Serial.print(curTime);
//Serial.print(" | ");
//Serial.print(yaxis);
//Serial.print(" | ");
//Serial.println(adcValue);
secOld = sec;
}
if(msOld != ms){ // ----------------- do every 10 ms ---------------------
msOld = ms;
dispTime = String(h) + ":" + String(m) + ":" + String(sec);
curTime = dispTime + ":" + String(ms*10);
if ((digitalRead(LOM) == 0) && (digitalRead(LOM) == 0)) {
adcValue = analogRead(A0); // ADC=10 bits, 1V
adcLowN = alpha*adcValue + (1-alpha)*adcLowN1; // Low pass filter
adcLowN1 = adcLowN;
}
y = 60 - ((adcLowN - 300) / 10); // OLED : 128x64, OLED 그래프는 900-300 범위로 설정
display.drawLine(lastx, lasty, x, y); // ECG 그래프
display.drawLine(lastx, yaxisOld/5, x, yaxis/5); // 참고 타임라인
display.display();
// 먼저 버퍼에 기록 (512Byte 블럭) 시간정보 참고 타임라인 ECG 신호
char cTime[14] = {0};
char tempF[5] = {0};
curTime.toCharArray(cTime,13);
dtostrf(adcLowN, 4,0,tempF);
snprintf(strBuff,sizeof(strBuff),"%12s,%03d,%4s\n", cTime, yaxis, tempF);
if(buffIndex < 22) sdCardBuffA = sdCardBuffA + strBuff;
else sdCardBuffB = sdCardBuffB + strBuff;
buffIndex++;
if(buffIndex == 22){ // SD에 기록
dataFile = SD.open(logFileName, FILE_WRITE); // 파일존재하면 - APEEND모드
if(dataFile){
dataFile.println(sdCardBuffA); dataFile.close();
}
sdCardBuffA = "";
}
if(buffIndex == 44){ // SD에 기록
dataFile = SD.open(logFileName, FILE_WRITE); // 파일존재하면 - APEEND모드
if(dataFile){
dataFile.println(sdCardBuffB); dataFile.close();
}
sdCardBuffB = "";
buffIndex = 0;
}
Serial.println(adcLowN);
lasty = y;
lastx = x;
yaxisOld = yaxis;
x++;
if(x >= 128){ // x > 128, then RESET & clear screen
x = 0;
lastx = 0; // x가 128이면 0초기화 (라인이 끝까지 생성됨방지)
display.setColor(BLACK);
display.fillRect(0,10, 127, 63);
display.display();
display.setColor(WHITE);
}
} // ----------------- do every 10 ms ---------------------
}
기타 .. 처리
void detectBPM() { // calc bpm
if (adcValue > UpperThreshold) {
if (BeatComplete) {
BPM = ThisTime - LastTime;
BPM = int(60 / (float(BPM) / 1000));
BPMTiming = false;
BeatComplete = false;
}
if (BPMTiming == false) {
LastTime = millis();
BPMTiming = true;
}
}
if ((adcValue < LowerThreshold) & (BPMTiming))
BeatComplete = true;
}
// -------------------------------------------------------------------------------------
// 초기에 한번 사용 : SD 카드내의 화일 및 폴더 목록을 보여줌
// -------------------------------------------------------------------------------------
void printDirectory(File dir, int numTabs) {
int colcnt = 0;
while(true) {
File entry = dir.openNextFile();
if (! entry) {
break; // no more files
}
if (numTabs > 0) {
for (uint8_t i=0; i<=numTabs; i++) {
Serial.print('\t');
}
}
Serial.print(entry.name());
if (entry.isDirectory()) {
Serial.println("/");
printDirectory(entry, numTabs+1);
} else {
// files have sizes, directories do not
Serial.print("\t");
Serial.println(entry.size(), DEC);
}
entry.close();
}
}
로그데이터 샘플 (10ms 저장인데 실제론 20ms 정도임)
ESG 로그 데이터 검토 프로그램
'IoT_ESP8266' 카테고리의 다른 글
ESP8266 Modbus - qModMaster (0) | 2022.07.02 |
---|---|
ESP-12 D1 mini OLED SD card (0) | 2020.01.22 |
ESp-01 : 두개의 다이얼 제어 (0) | 2019.01.16 |
ESP-01 : 서버와 데이터 주고 받기 정리 (0) | 2019.01.14 |
jQuery 사용하기 (0) | 2019.01.13 |