반응형

 

앞으로 자동차 CAN으로 간단하게 만들 것들이 많아질거 같아서 MCP2515를 이용하여 CAN 상태 값을 가져오는 예제를 시험삼아 만들어 보았다.

 

#include <mcp_can.h>
#include <SPI.h>

MCP_CAN CAN0(10);  // CS 핀 설정

void setup() {
  Serial.begin(115200);
  if (CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_8MHZ) == CAN_OK) {
    Serial.println("CAN 초기화 성공");
  } else {
    Serial.println("CAN 초기화 실패");
  }
  /*
  // 마스크 및 필터 설정
  CAN0.init_Mask(0, 0, 0x7FF);
  CAN0.init_Mask(1, 0, 0x7FF);
  CAN0.init_Filt(0, 0, 0x123);
  CAN0.init_Filt(1, 0, 0x123);
  CAN0.init_Filt(2, 0, 0x123);
  CAN0.init_Filt(3, 0, 0x123);
  CAN0.init_Filt(4, 0, 0x123);
  CAN0.init_Filt(5, 0, 0x123);
  */
  CAN0.setMode(MCP_NORMAL);
}

void loop() {
  // CAN 데이터 송신
  // // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  // unsigned char data[8] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
  // CAN0.sendMsgBuf(0x00, 0, 8, data);
  // delay(1000);
  // // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  long unsigned int rxId;
  unsigned char len = 0;
  unsigned char rxBuf[8];

  // CAN 데이터 수신
  if (CAN0.checkReceive() == CAN_MSGAVAIL) {
    CAN0.readMsgBuf(&rxId, &len, rxBuf);
    Serial.print(rxId, HEX);
    Serial.print("//");
    for (int i = 0; i < len; i++) {
      Serial.print(rxBuf[i], HEX);
      Serial.print(" ");
    }
    Serial.println();
  }
}

라이브러리는 coryjfowler의 mcp_can 라이브러리를 사용하였다.

내가 사용을 못하는건지 라이브러리 자체 버그인지 마스크하고 필터 함수가 먹히지 않아서 주석 처리하였다.

CAN 수신은 괜찮지만 송신측 코드는 잘못 사용하면 치명적(?) 동작을 만들 수 있으니 주의!!

 

테스트 차량은 TA모닝

테스트에 몇십만원을 태워 측정 장비를 살순 없으니 노가다로 데이터를 분석해본다.

 

구형 차량이라 그런지 CAN으로 할 수 있는게 많지 않다..

 

이런.. 계기판에도 CAN이 연결되어 있길래 계기판 정보를 CAN으로 읽을 수 있을줄 알았는데 막상 들어가보니 아날로그...

 

엔진과 트랜스미션하고 주고받는 정보는 어느정도 있는거 같아서 기어 단수 상태를 읽어 들이도록 만들어 보았다.

반응형
반응형

/*
RFID-RC522 - 아두이노
SDA - D10
SCK - D13
MOSI - D11
MISO - D12
IRQ - X
GND - GND
RST - D9
3.3V - 3.3V

스위치 - 아두이노
SW_IN - D7
SW_OUT - GND

피에조 부저 - 아두이노
+ - D8
- - GND
*/

#include <SPI.h>
#include <MFRC522.h>
#include <EEPROM.h>

#define SW_PIN 7
#define PIEZO_PIN 8
#define RST_PIN 9
#define SS_PIN 10

bool sw_push;
unsigned int sw_push_ms;
String saved_tag_uid, scan_tag_uid;

MFRC522 rfid(SS_PIN, RST_PIN);

void setup() {
  // 초기화
  Serial.begin(9600);
  pinMode(SW_PIN, INPUT_PULLUP);
  pinMode(PIEZO_PIN, OUTPUT);
  SPI.begin();
  rfid.PCD_Init();
  Serial.println("초기화 완료");

  // ROM에 저장된 태그 UID 읽어오기
  EEPROM.get(1, saved_tag_uid);
  Serial.print("등록 태그 UID : ");
  Serial.println(saved_tag_uid);
}

void loop() {
  // 등록된 태그 초기화 요청시(스위치 5초 이상 누르기)
  if (digitalRead(SW_PIN) == LOW) {
    sw_push = 1;
    if (sw_push_ms == 0) sw_push_ms = millis();
  }
  if (digitalRead(SW_PIN) == HIGH) {
    if (sw_push == 1 && millis() - sw_push_ms >= 5000) {
      tone(PIEZO_PIN, 1000, 500);
      saved_tag_uid = "";
      EEPROM.put(1, saved_tag_uid);
      Serial.println("등록 태그 초기화 완료");
    }
    sw_push = 0;
    sw_push_ms = 0;
  }

  // 태그 스캔부
  if (!rfid.PICC_IsNewCardPresent()) return;
  if (!rfid.PICC_ReadCardSerial()) return;
  else {
    scan_tag_uid = "";
    for (byte i = 0; i < 4; i++) {
      scan_tag_uid += String(rfid.uid.uidByte[i], HEX);
    }
    tone(PIEZO_PIN, 1000, 100);
    Serial.print(scan_tag_uid);

    // 등록된 태그가 없다면 스캔된 태그 등록
    if (saved_tag_uid == "") {
      saved_tag_uid = scan_tag_uid;
      EEPROM.put(1, saved_tag_uid);
      Serial.println(" 태그가 새로 등록 되었습니다.");
    } else {
      // 등록된 태그와 스캔된 태그가 같다면
      if (saved_tag_uid == scan_tag_uid) {
        Serial.println(" 태그는 등록된 태그입니다.");
      }
      // 등록된 태그와 스캔된 태그가 다르다면
      else {
        Serial.println(" 태그는 등록되지 않은 태그입니다.");
      }
    }
  }

  delay(500);
}

지문 인식 모듈을 활용해서 만들어볼게 있었는데 모듈이 아직 배송중이라 RC522와 관련 RFID 라이브러리를 이용하여 태그 인식 예제를 하나 간단히 만들어 보았다. EEPROM을 이용한 태그 값 저장은 자매품.

 

전원 인가 시 초기화를 하면서 ROM에 저장되어 있는 태그 값을 시리얼 모니터로 알려주고 저장되어 있는 태그 값이 없다면 첫번째로 인식되는 태그의 값을 저장(등록)한다.

 

이후 스캔 때마다 등록되어 있는 태그인지 판별하고 스위치를 5초 동안 길게 누르면 등록되어 있는 태그 값을 초기화 시켜주는 예제이다.

 

피에조 부저까지 같이 구성 해보았다.

등록 태그를 여러 개로 만들고 싶으면 배열을 활용하면 된다.

 

RC522 모듈은 3cm 정도의 거리까지 태그를 인식할 수 있는 것으로 알려져 있다.

태그와 리더기 사이의 장애물이 없다면 자동차 유리 정도의 장애물은 문제없이 인식이 되는 것을 확인하였다.

반응형
반응형

 

주택가에서 예열하거나 지나가면서 시끄러워서 눈치 보일 때, 가변배기 모듈로 조용하게.

반응형
반응형

플로팅 현상이란?

직역하면 "떠 있는, 떠다니는"이다.

신호 입력을 받는 핀에서 5V, GND 신호가 아닌 입력 받는 신호가 없을 때 일어난다.

아래 예제를 통해 더 알아보겠다.

 


void setup() {
  Serial.begin(9600);
  pinMode(9, INPUT);
}

void loop() {
  Serial.println(digitalRead(9));
}

위 소스코드를 예제로 진행해 보겠다.

9번 핀을 입력 핀으로 설정하고 입력받은 결과를 출력하는 예제이다.

 

회로는 위와 같이 구성하였다.

스위치를 누르면 5볼트의 전원이 입력 핀에 인가되는 회로이다.

 

예상되는 결과로는 스위치를 누를 때마다 1을 결과로 출력 해야 하는데 중간중간 0과 1을 교차하며 결과를 출력하는 것을 볼 수 있다. 맨손으로 입력 핀 근처 스위치를 대고 있었을 경우 교차하는 횟수는 더 잦았을 것이다.

 

위와 같은 현상이 플로팅 현상이다.

 


플로팅 현상 해결 방법

위와 같이 플로팅 현상은 스위치를 누르고 있지 않는 상태, 즉 입력받는 신호가 없을 때 일어난다.

해결 방법은 스위치를 누르고 있지 않는 상태일 때 입력받는 신호를 저항을 통해 연결해 만들어주는 것이다.

아래 풀다운, 풀업 저항 회로 예제를 통해 더 알아보겠다.

 


저항과 입력받을 핀이 더 생겼다.

이렇게 스위치를 누르고 있지 않는 상태에서는 GND 신호를 읽게 하는 것이다. 이것이 풀다운 저항 회로이다.

그럼 평소에는 0의 값만 입력을 받다가 스위치를 누르면 1의 값을 입력받을 것이다.

전류는 저항이 작은 곳으로 흐르기 때문에 스위치를 누르면 5V가 바로 GND 쪽으로 흐르지 않고 비교적 저항이 작은 입력 핀 쪽으로 흐르게 된다.

 

이렇게 즉각즉각 5V의 1의 값을 입력받는 것을 볼 수 있다.

 

바로 이어서 풀업 저항 회로도 알아보자

풀다운 저항 회로에서 저항과 스위치의 위치가 바뀌었다.

 

풀다운과는 반대로 평소에는 1의 값을 입력받다가 스위치를 누르면 0의 값을 입력받는 것을 볼 수 있다.

 

하지만 아두이노에서는 풀다운 저항 회로를 구성할 필요가 없다.

아두이노 보드에 기본적으로 기능이 탑재되어 있기 때문이다.

 

void setup() {
  Serial.begin(9600);
  pinMode(9, INPUT_PULLUP);
}

void loop() {
  Serial.println(digitalRead(9));
}

원래의 예제 소스코드 핀 모드를 INPUT에서 INPUT_PULLUP으로 바꿔주기만 하면 내장된 풀업 저항을 사용할 수 있다.

 

회로는 위와 같이 구성하였다.

첫 번째 예제는 5V를 직접 입력 핀에 인가하는 회로였는데 지금은 GND를 직접 입력 핀에 인가하는 회로이다.

첫 번째 예제의 결과를 겪었다면 플로팅 현상이 나타날 것이라고 예상할 것이다.

 

하지만 풀업 저항 회로를 구성하지 않았음에도 불구하고 내장된 풀업 저항 기능으로 플로팅 현상 없이 풀업 저항 회로를 구성한 것과 같이 동작하는 것을 볼 수 있다.

 

반응형

+ Recent posts