본문 바로가기

활동/설계 수업

[1학년 2학기 설계] 교통카드 체크인 체온계

반응형

목적

코로나19로 QR체크인이나 안심콜체크인을 많이 시행한다. 이번 설계프로젝트는 매장 방문시 매번 시행하는 체크인과 발열체크 과정을 하나의 기계로 가능하도록 하는 것을 만드는 것에 목적을 두었다.

우선 교통카드를 이용하기로 했다. 어딘가 방문할때 대부분 교통카드를 소지하고 있을 가능성이 가장 높으며 신용카드 자체에 후불교통기능이 포함된 경우가 많기 때문이다. 그리고 교통카드 번호를 이용하면 충분히 역학조사 시 개인을 특정할 수 있을 것이라고 생각했다.

 

내용 및 결과

사용한 재료

RFID 센서 모듈, 0.96인치 OLED 4핀 I2C 모듈, 비접촉식 적외선 온도 센서모듈, mini, USB 5P to TTL, 아두이노 프로 미니 보드, 배터리 1A 충전모듈, 3.7V 리튬 폴리머 배터리

 

구동원리

1. RFID 센서에 카드를 인식한다.

2. 적외선 온도센서에 손을 댄 후 온도를 측정한다.

3. OLED디스플레이 화면에 뜬 체온을 확인한다.

4. 교통카드 번호를 통해 방문자가 체온과 함께 교통카드 번호를 저장시킨다.

 

회로도

 

소스코드

그냥 열심히 찾아보고 작성한 코드라 아주아주 더럽다... 이번학기에 게다가 겁도없이 21학점씩이나 신청해놔서 시간을 쪼개고 쪼개서 겨우 기능만 작동하도록 했다.

#include <Wire.h> // wire 통신을 위한 라이브러리
#include <Adafruit_MLX90614.h> // 온도센서 라이브러리
#include "U8glib.h" //oled 화면 구현 라이브러리
#include <SPI.h> // spi 통신을 위한 라이브러리
#include <MFRC522.h> // rfid 라이브러리
#include <EEPROM.h> // EEPROM 라이브러리 
#include <SoftwareSerial.h> //BT 통신 라이브러리 
Adafruit_MLX90614 mlx = Adafruit_MLX90614();
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE|U8G_I2C_OPT_DEV_0);  // OLED type 설정 > I2C / TWI

//rfid 기본 설정 
#define SS_PIN 10
#define RST_PIN 9
MFRC522 rfid(SS_PIN, RST_PIN);

//BT 기본 설정
SoftwareSerial mySerial(1, 0); //시리얼통신 (Tx 보내는핀, Rx받는핀) 설정 
String myString = ""; //받는 문자열 변수 

byte nuidPICC[4]; // 새로운 카드 정보 저장 변수
int MyTemp = 0; // 사용자 체온 저장 변수 
int address = 0; //EEPROM 저장 주소 변수 
byte CardNum1 = 0; // 교통카드 저장 변수 1/4
byte CardNum2 = 0; // 교통카드 저장 변수 2/4
byte CardNum3 = 0; // 교통카드 저장 변수 3/4
byte CardNum4 = 0; // 교통카드 저장 변수 4/4
int k = 0; //EEPROM 출력 for문 증감 변수
byte TempValue = 0; //EEPROM 출력 체온 데이터 변수 
byte CardValue1 = 0; //EEPROM 출력 카드 데이터 변수 1/4
byte CardValue2 = 0; //EEPROM 출력 카드 데이터 변수 2/4
byte CardValue3 = 0; //EEPROM 출력 카드 데이터 변수 3/4
byte CardValue4 = 0; //EEPROM 출력 카드 데이터 변수 4/4
MFRC522::MIFARE_Key key;

 


void setup() {
  Serial.begin(9600); //시리얼모니터 open
  mySerial.begin(9600); //BT Serial open
  SPI.begin(); // Init SPI bus
  rfid.PCD_Init(); // Init MFRC522

for (byte i = 0; i < 6; i++) {
    key.keyByte[i] = 0xFF;for (byte i = 0; i < 6; i++) {
    key.keyByte[i] = 0xFF;
  }
}
  
}

void loop() {
  u8g.firstPage(); //oled 화면 구현
  do {
    //첫화면 글자
    u8g.setFont(u8g_font_courB10);
    u8g.drawStr(5, 12, "Tag to Start");
  } while( u8g.nextPage() );


///교통카드 호환 여부 check  
  if ( ! rfid.PICC_IsNewCardPresent() )
    return;

    // Verify if the NUID has been readed
  if ( ! rfid.PICC_ReadCardSerial())
    return;
  
Serial.print(F("PICC type: "));
  MFRC522::PICC_Type piccType = rfid.PICC_GetType(rfid.uid.sak);
  Serial.println(rfid.PICC_GetTypeName(piccType));

  // Check is the PICC of Classic MIFARE type
  if (piccType != MFRC522::PICC_TYPE_MIFARE_MINI &&  
    piccType != MFRC522::PICC_TYPE_MIFARE_1K &&
    piccType != MFRC522::PICC_TYPE_MIFARE_4K) {
    Serial.println(F("Your tag is not of type MIFARE Classic."));
    
    u8g.firstPage();
     do {
      u8g.setFont(u8g_font_courB10);
      u8g.drawStr(5, 12, "Sorry:(");
      u8g.drawStr(5, 32, "ERROR CODE");
      u8g.drawStr(5, 52, "E01");
    }
    while( u8g.nextPage() );
    delay(1500);
    loop();
    
  }
  else {
    card();


    u8g.firstPage(); //oled 화면 구현
  do {
    //첫화면 글자
    u8g.setFont(u8g_font_courB10);
    u8g.drawStr(5, 12, "Checking");
    u8g.drawStr(5, 32, "Temperature");
  } while( u8g.nextPage() );
  delay(1500);

CheckTemperature();
  }
  
  
}



/**
 * Helper routine to dump a byte array as hex values to Serial. 
 */
void printHex(byte *buffer, byte bufferSize) {
  for (byte i = 0; i < bufferSize; i++) {
    Serial.print(buffer[i] < 0x10 ? " 0" : " ");
    Serial.print(buffer[i], HEX);
  }
}

/**
 * Helper routine to dump a byte array as dec values to Serial.
 */
void printDec(byte *buffer, byte bufferSize) {
//카드번호 저장 기능 추가
byte i = 0;
    CardNum1 = buffer[i];
    CardNum2 = buffer[i+1];
    CardNum3 = buffer[i+2];
    CardNum4 = buffer[i+3];

  
  for (byte i = 0; i < bufferSize; i++) {
    Serial.print(buffer[i] < 0x10 ? " 0" : " ");
    Serial.print(buffer[i], DEC);
    
  }
}



void card() {

/*  호환 교통카드 걸러내기 위해 check하는 부분 card함수에서 빼고 loop안에 넣음 
 *   // Verify if the NUID has been readed
  if ( ! rfid.PICC_ReadCardSerial())
    return;
  
Serial.print(F("PICC type: "));
  MFRC522::PICC_Type piccType = rfid.PICC_GetType(rfid.uid.sak);
  Serial.println(rfid.PICC_GetTypeName(piccType));

  // Check is the PICC of Classic MIFARE type
  while (piccType != MFRC522::PICC_TYPE_MIFARE_MINI &&  
    piccType != MFRC522::PICC_TYPE_MIFARE_1K &&
    piccType != MFRC522::PICC_TYPE_MIFARE_4K) {
    Serial.println(F("Your tag is not of type MIFARE Classic."));
    
    u8g.firstPage();
     do {
      u8g.setFont(u8g_font_courB10);
      u8g.drawStr(5, 12, "Sorry:(");
      u8g.drawStr(5, 32, "ERROR CODE");
      u8g.drawStr(5, 52, "E01");
    }
    while( u8g.nextPage() );
    delay(1500);
    break;
    
  }
*/

  if (rfid.uid.uidByte[0] != nuidPICC[0] || 
    rfid.uid.uidByte[1] != nuidPICC[1] || 
    rfid.uid.uidByte[2] != nuidPICC[2] || 
    rfid.uid.uidByte[3] != nuidPICC[3] ) {
    Serial.println(F("A new card has been detected."));

    // Store NUID into nuidPICC array
    for (byte i = 0; i < 4; i++) {
      nuidPICC[i] = rfid.uid.uidByte[i];
    }
   
    Serial.println(F("The NUID tag is:"));
    Serial.print(F("In hex: "));
    printHex(rfid.uid.uidByte, rfid.uid.size);
    Serial.println();
    Serial.print(F("In dec: "));
    printDec(rfid.uid.uidByte, rfid.uid.size);
    Serial.println();
  }
  else Serial.println(F("Card read previously."));

  // Halt PICC
  rfid.PICC_HaltA();

  // Stop encryption on PCD
  rfid.PCD_StopCrypto1();Serial.print(F("PICC type: "));
 
}


void CheckTemperature() {
 
  //////체온 측정 전 3초 카운트다운 
  u8g.firstPage(); //oled 화면 구현
    do {
    u8g.setFont(u8g_font_courB14);
    u8g.drawStr(5, 22, "check after");
    u8g.drawStr(5, 42, "3sec");
  } while( u8g.nextPage() );
  delay(1000);

  u8g.firstPage(); //oled 화면 구현
    do {
    u8g.setFont(u8g_font_courB14);
    u8g.drawStr(5, 22, "check after");
    u8g.drawStr(5, 42, "2sec");
  } while( u8g.nextPage() );
  delay(1000);

  u8g.firstPage(); //oled 화면 구현
     do {
      u8g.setFont(u8g_font_courB14);
      u8g.drawStr(5, 22, "check after");
      u8g.drawStr(5, 42, "1sec");
   } while( u8g.nextPage() );
   delay(1000);

  u8g.firstPage(); //oled 화면 구현
     do {
      u8g.setFont(u8g_font_courB14);
      u8g.drawStr(5, 22, "checking...");
      u8g.drawStr(5, 42, "Please Wait");
   } while( u8g.nextPage() );
   delay(1000);
   
  /////체온 측정 시작
  mlx.begin(); 
  String strTemp = String("");
  strTemp += (int)(mlx.readObjectTempC());
  char buff[10];
  strTemp.toCharArray(buff, 5);
  buff[2] = 0x27;
  buff[3] = 'C';
  buff[4] = 0x00;

  
  MyTemp = mlx.readObjectTempC();
  drawTemp(buff);
  DataSave();
  delay(2000);
  DataRead();
}

//체온 측정결과 화면에 띄어주는 함수 
void drawTemp(char* strTemp) {
  // picture loop  
  u8g.firstPage();  
  do {
    // show text
    u8g.setFont(u8g_font_courB14);
    u8g.setFontRefHeightExtendedText();
    u8g.setDefaultForegroundColor();
    u8g.setFontPosTop();
    u8g.drawStr(5, 12, "your Temp.");
    u8g.drawStr(45, 40, strTemp);
  } while( u8g.nextPage() );
  delay(2000);
}

/////EEPROM에 데이터 저장
void DataSave() {
  
  EEPROM.write(address, MyTemp);
  address = address + 1;

  EEPROM.write(address, CardNum1);
  address = address + 1;
  EEPROM.write(address, CardNum2);
  address = address + 1;
  EEPROM.write(address, CardNum3);
  address = address + 1;
  EEPROM.write(address, CardNum4);
  address = address + 1;
}

/////EEPROM 데이터 읽어오기
void DataRead() {
  
  for (k = 0; k+1 < address; k += 5) {
    TempValue = EEPROM.read(k);
    CardValue1 = EEPROM.read(k+1);
    CardValue2 = EEPROM.read(k+2);
    CardValue3 = EEPROM.read(k+3);
    CardValue4 = EEPROM.read(k+4);
    Serial.print("체온, ");
    Serial.print(TempValue);
    Serial.print(", ");
    Serial.print("카드 번호, ");
    Serial.print(CardValue1);
    Serial.print(CardValue2);
    Serial.print(CardValue3);
    Serial.println(CardValue4);

  }
}

작동영상

 

 

========

@@@@ 기쁘게도 우수 과제로 뽑혔다!! @@@@

학교측과 커뮤니케이션 오류로 작품명이 이상하게 나오긴 했지만 어쨌든! 2학기에 그래도 열심히 하고 신경도 많이 쓴거였는데 이렇게 좋은 결과로 보답받으니까 정말 기분 좋다.

 

 

반응형