자동차 통신 프로토콜 3부: CAN (1부) - 기초와 메시지 구조 완벽 이해
CAN이란?

들어가며
안녕하세요 버그없는토마토입니다
제일 먼저 자동차가 왜 여러 프로토콜을 써야 하는지 배웠어요.
LIN CAN CANFD 등등등 여러가지를 슬쩍 봤죠.
그리고 저번 게시물에서 우리는 LIN (느리지만 저렴한)을 배웠어요.
이제 자동차의 진정한 "표준" 통신: CAN을 배워야 할 차례예요.
CAN만 배워도 사실 끝입니다.
CAN에 대해 마스터 했다면 (CANFD까진..ㅎ) 그다음 게시물은 팔짱끼고 편히 보셔도돼요.
그러니까 힘내보자고요~!
차에 문제가 생겼어요:
진단기가 스캔을 시작합니다.
↓
진단기: "어? DTC가 있네. P0117이라고?"
(O2 센서 오류)
↓
엔진 ECU와 변속기 ECU는?
계속 CAN 버스를 통해 데이터를 주고받음! (BUS 개념)
엔진 ECU: "현재 RPM 3000이에요"
(CAN ID 0x100으로 전송)
변속기 ECU: "기어 D에요"
(CAN ID 0x200으로 전송)
ABS ECU: "제동압 100 kPa입니다"
(CAN ID 0x300으로 전송)
↓
동시에 3개의 메시지가 CAN 버스를 사용해도?
CAN이 자동으로 중재!
"0x100이 가장 중요하니까 먼저 보내!"(우선순위 위주)
↓
전부 정상 작동! ✓
이게 모두 CAN의 힘입니다
우리가 자동차 통신에서 하고자 하는 모든 것을 이뤄주죠.
자동차 언어의 기본이고 끝이라고 할 수 있습니다.
그럼 본격적으로 알아볼까요 CAN에 대해
이 글에서는 CAN이 뭔지, 메시지 구조는 어떤지, 신호가 뭔지, 데이터는 어떻게 인코딩되는지 상세하게 설명해보겠습니다
렛츠기릿
📌 3분 요약
바쁜 당신을 위한 핵심 3줄:
🚗 CAN = 자동차 표준 통신 (500 kbps)
📨 메시지 = ID + DLC + Data + CRC
🔑 신호 = 메시지 안의 작은 데이터 (DBC 파일에 정의)
엔진, 변속, 제동 같은 핵심 제어용 통신이에요.

🚗 CAN이란?
CAN의 정의
CAN = Controller Area Network
자동차에서 표준 통신 프로토콜이에요. 모~~~~~~~든 자동차 제조사가 사용합니다.
특징:
├─ 속도: 500 kbps (표준), 1 Mbps (고속)
├─ 거리: ~40m
├─ 메시지: 최대 8바이트
├─ 구조: 모두가 같은 버스 공유 (Broadcast)
├─ 신뢰성: 매우 높음
├─ 비용: $$$ (중가)
└─ 용도: 엔진, 변속, 제동 (핵심 제어)
CAN의 위상
자동차 통신 피라미드:
(안전 시스템)
▲
│ FlexRay (극도의 신뢰성)
│
●●●●●●●●●
│ CAN ★ │ ← 자동차의 척추!
●●●●●●●●●
│
│ LIN (편의 기능)
▼
(저속 편의)
CAN의 위치:
✅ 표준 프로토콜 (모든 차가 사용)
✅ 신뢰성 높음 (에러 감지/처리 뛰어남)
✅ 속도 적당 (500 kbps = 현실적)
✅ 비용 합리적 (LIN보다 비싸지만 가치 있음)
→ 자동차 통신의 "황금 표준"!

🎯 CAN의 특징 (7가지) - 중요
(저 때 강의 시험문제였죠..ㅎ)
특징 1️⃣: Broadcast (모두가 공유)
CAN 버스 구조:
┌─────────────────────────────────┐
│ 엔진 ECU 변속기 ECU ABS ECU │
│ ↓ ↓ ↓ │
└──────────────┬──────────────────┘
│ (2개 선: CAN_H, CAN_L)
CAN 버스
│
┌──────────────┴──────────────────┐
│ 모든 ECU가 같은 버스를 사용! │
│ │
│ - 엔진 ECU가 메시지 보냄 │
│ - 변속기 ECU도 받음 (필요하면) │
│ - ABS ECU도 받음 (필요하면) │
│ │
│ = 모두가 브로드캐스트! │
└──────────────────────────────────┘
비유: 라디오 방송
- LIN: 교장선생님이 학생에게 직접 지시
- CAN: 라디오 방송국이 신호를 보냄
→ 자신이 필요한 프로그램만 듣는 것처럼
특징 2️⃣: ID 기반 (메시지 이름)
CAN ID란?
"메시지의 이름"
예시:
0x100 = EngineData (엔진 데이터)
└─ 누가 보냄? 엔진 ECU
└─ 누가 받음? 변속기, ABS, 진단 ECU (필요한 곳)
└─ 뭐가 들어있나? RPM, 토크, 온도
0x200 = TransmissionData (변속기 데이터)
└─ 누가 보냄? 변속기 ECU
└─ 누가 받음? 엔진, ABS, 진단 ECU
└─ 뭐가 들어있나? 기어, 오일온도
0x300 = BrakeData (제동 데이터)
└─ 누가 보냄? ABS ECU
└─ 누가 받음? 엔진, 변속, 진단 ECU
└─ 뭐가 들어있나? 제동압, 바퀴 속도
중요:
ID가 작을수록 높은 우선순위!
0x100 > 0x200 > 0x300
특징 3️⃣: 높은 신뢰성
CAN의 신뢰성 기법:
1️⃣ CRC (순환 중복 검사)
- 모든 메시지에 포함
- "데이터가 손상되지 않았나?" 확인
- 손상되면 자동 재전송
2️⃣ 에러 감지
- Bit Error: 보낸 비트와 다른 비트 수신
- Stuff Error: 5개 연속 같은 비트 감지
- CRC Error: 체크섬 불일치
- Frame Error: 포맷 이상
3️⃣ 에러 프레임
- 모든 ECU가 오류 감지
- 에러 프레임 전송
- 자동 재전송
결과:
= 데이터 손실 거의 없음!
= 매우 신뢰할 수 있음!
특징 4️⃣: 견고성 (노이즈 내성)
CAN의 물리 계층:
신호: 차동 신호
├─ CAN_H (high): 3.5V
├─ CAN_L (low): 1.5V
└─ 차이: 2V
왜 차동?
- 노이즈에 강함
- 예: 번개가 쳐도
CAN_H = +10V (노이즈)
CAN_L = +10V (노이즈)
→ 차이 = 0 (변함 없음!)
→ 신호 정상!
자동차 환경:
- 번개, 모터 노이즈, 고주파 간섭 많음
- CAN은 이 모든 걸 무시!
- 신호 신뢰성 최고!
비유: 두 귀로 듣기
- 왼쪽 귀와 오른쪽 귀의 소리 차이를 비교
- 노이즈는 양쪽에 동일하게 들리니까 무시됨
특징 5️⃣: 표준화 (전 자동차 제조사) - 별4개
누가 CAN을 써?
✅ 현대 (쏘나타, EV9 등)
✅ 기아 (K5, EV6 등)
✅ 도요타 (카롤라, 프리우스 등)
✅ 혼다, BMW, 벤츠, 포르쉐...
✅ 거의 모든 자동차!
왜?
1️⃣ 표준화 (ISO 11898)
- 누구나 읽을 수 있음
- 호환성 좋음
2️⃣ 검증됨 (30년 역사)
- 신뢰성 증명됨
- 문제점 다 해결됨
3️⃣ 싸다 (대량생산)
- 칩셋이 저가
- 개발 비용 낮음
→ "자동차 표준"이 된 이유!
특징 6️⃣: 결정성 (타이밍 예측 가능)
결정성이란?
"언제 메시지가 올지 예측 가능한가?"
CAN:
- ID가 낮을수록 먼저 옴
- 높은 ID는 잠깐 기다림
- 하지만 충돌은 없음!
- 모두 결국 전송됨
예측:
- 엔진 데이터 (0x100): 항상 먼저 옴
- 변속기 데이터 (0x200): 그 다음
- 진단 데이터 (0x300): 마지막
→ 순서가 정해져 있음!
장점:
- 타이밍 계획 가능
- 소프트웨어 설계 쉬움
- 예측 가능 = 신뢰성!
특징 7️⃣: 비용 효율
비용 비교:
LIN:
- 칩셋: $1
- 전체 비용: 저가
CAN:
- 칩셋: $5
- 전체 비용: 중가
FlexRay:
- 칩셋: $50+
- 전체 비용: 고가
Ethernet:
- 칩셋: $20+
- 전체 비용: 고가
선택:
"신뢰성과 비용의 황금 비율!" → CAN!
📊 CAN 메시지 구조 (완전 분해) - (별 10개)
메시지 전체 흐름
┌─────────────────────────────────────────┐
│ CAN 메시지 (총 길이: 약 2ms) │
├─────────────────────────────────────────┤
│ 1️⃣ SOF (Start of Frame) │
│ └─ 시작 신호 (1비트) │
├─────────────────────────────────────────┤
│ 2️⃣ Arbitration Field (중재 필드) │
│ ├─ ID (11비트) [Standard CAN] │
│ │ 또는 29비트 [Extended CAN] │
│ └─ RTR (원격 프레임 요청, 1비트) │
├─────────────────────────────────────────┤
│ 3️⃣ Control Field (제어 필드) │
│ ├─ IDE (ID 확장 비트) │
│ └─ DLC (데이터 길이, 4비트) │
├─────────────────────────────────────────┤
│ 4️⃣ Data Field (데이터 필드) │
│ └─ 실제 데이터 (0~8바이트) │
├─────────────────────────────────────────┤
│ 5️⃣ CRC Field (오류 검사) │
│ ├─ CRC (15비트) │
│ └─ CRC Delimiter (1비트) │
├─────────────────────────────────────────┤
│ 6️⃣ ACK Field (수신 확인) │
│ ├─ ACK Slot (1비트) │
│ └─ ACK Delimiter (1비트) │
├─────────────────────────────────────────┤
│ 7️⃣ EOF (End of Frame) │
│ └─ 종료 신호 (7비트) │
└─────────────────────────────────────────┘
각 필드 상세 설명
1️⃣ SOF (Start of Frame)
━━━━━━━━━━━━━━━━━━━━━━━━━━
역할: "신호 시작합니다!"
길이: 1비트
값: Low (0V)
동작:
Master가 CAN_H를 Low로 당김
→ 모든 노드가 "신호 오는군!" 준비
2️⃣ ID (Identifier) - 메시지 이름!
━━━━━━━━━━━━━━━━━━━━━━━━━━
Standard CAN: 11비트 (0x000~0x7FF)
Extended CAN: 29비트 (거의 안 씀)
예시:
0x100 = 000100000000 (11비트)
0x200 = 001000000000
0x300 = 001100000000
중요:
ID가 낮을수록 우선순위 높음!
(이걸 Arbitration이라고 함)
3️⃣ DLC (Data Length Code)
━━━━━━━━━━━━━━━━━━━━━━━━━━
역할: "데이터가 몇 바이트인가?"
길이: 4비트
범위: 0~8
예시:
DLC = 0: 데이터 없음
DLC = 2: 2바이트
DLC = 8: 8바이트 (최대)
4️⃣ Data (실제 데이터)
━━━━━━━━━━━━━━━━━━━━━━━━━━
역할: "실제 정보"
길이: DLC에 따라 0~8바이트
예시:
EngineData (0x100):
[바이트 0] [바이트 1] [바이트 2] ...
각 바이트 안에 여러 신호가 들어있음!
5️⃣ CRC (Cyclic Redundancy Check)
━━━━━━━━━━━━━━━━━━━━━━━━━━
역할: "데이터가 손상되지 않았나?"
길이: 15비트
방식: 다항식 계산
동작:
송신: CRC 계산 → 메시지 끝에 추가
수신: CRC 다시 계산 → 일치하면 정상!
손상되면:
계산 결과 ≠ 받은 CRC
→ 에러! → 재전송!
6️⃣ ACK (Acknowledgement)
━━━━━━━━━━━━━━━━━━━━━━━━━━
역할: "받았습니다!"
길이: 1비트
값: Low (0V)
동작:
송신 ECU: "메시지 보냈어"
수신 ECU들: ACK 슬롯에 Low 전송
(모두가 동시에!)
송신 ECU: "아, 누군가는 받았구나!"
안 받으면:
ACK 없음 → "어? 아무도 안 받았나?"
→ 에러 신호!
🔑 신호 정의 (DBC 파일)
DBC 파일이란?
DBC = Database Configuration
"CAN 메시지 안에 어떤 신호들이 들어있나?"를 정의하는 파일
예:
EngineData (ID 0x100, 8바이트)에는?
├─ RPM (엔진 속도) - Byte 0-1 (16비트)
├─ Torque (토크) - Byte 2-3 (16비트)
├─ CoolantTemp (냉각수 온도) - Byte 4 (8비트)
└─ ...
= DBC 파일에 모두 정의됨!
DBC 파일 예시
BO_ 256 EngineData: 8 EngineECU
SG_ EngineRPM : 0|16@1+ (0.25,0) [0|8000] "rpm" TransmissionECU,ABSECU
SG_ EngineTorque : 16|16@1+ (1,0) [0|400] "Nm" TransmissionECU
SG_ CoolantTemperature : 32|8@1+ (1,-40) [-40|215] "C" ABSECU
BO_ 512 TransmissionData: 8 TransmissionECU
SG_ CurrentGear : 0|4@1+ (1,0) [0|15] "gear" EngineECU,ABSECU
SG_ OilTemp : 4|8@1+ (1,-40) [-40|215] "C" EngineECU
해석:
BO_: 메시지 정의 시작
256: CAN ID (10진수 = 0x100)
EngineData: 메시지 이름
8: 길이 (8바이트)
EngineECU: 송신 ECU
SG_: 신호 정의
EngineRPM: 신호 이름
0: 시작 비트 (Byte 0, Bit 0)
16: 길이 (16비트)
@1+: 형식 (1바이트 기준, unsigned)
(0.25, 0): Scaling (값 × 0.25 + 0)
[0|8000]: 범위 (0~8000 rpm)
"rpm": 단위
TransmissionECU: 수신 ECU
📈 데이터 인코딩 (신호 → 바이트)
예시: 엔진 RPM 전송
상황:
엔진이 3000 rpm으로 회전 중
Step 1️⃣: DBC 파일 확인
EngineRPM: 시작 비트 0, 길이 16비트
Scaling: (값 × 0.25 + 0)
Step 2️⃣: 역 계산 (Scaling 역계산)
실제 값: 3000 rpm
DBC: 값 × 0.25 = 3000
값 = 3000 / 0.25 = 12000
= 0x2EE0 (16진수)
Step 3️⃣: 비트 배치
12000 = 0x2EE0 = 0010111011100000 (16비트)
Byte 0 (LSB): 11100000 = 0xE0
Byte 1 (MSB): 00101110 = 0x2E
Step 4️⃣: CAN 메시지에 넣기
[바이트 0] = 0xE0
[바이트 1] = 0x2E
[바이트 2-7] = [다른 신호들...]
Step 5️⃣: CAN 버스에 전송!
메시지: [ID=0x100] [DLC=8]
[0xE0, 0x2E, 0x50, 0x32, ...]
Step 6️⃣: 수신 측 처리
다른 ECU가 메시지 수신
데이터: [0xE0, 0x2E, ...]
역 계산: 0x2EE0 = 12000
스케일링: 12000 × 0.25 = 3000
결과: RPM = 3000! ✓
신호의 특징
신호 = 메시지 안의 작은 데이터
특징:
1️⃣ 위치: 특정 바이트와 비트에 위치
2️⃣ 길이: 8비트, 16비트, 4비트 등 다양
3️⃣ 타입: Signed (음수 가능) vs Unsigned (양수만)
4️⃣ Scaling: (값 × a + b) 변환
5️⃣ 범위: 최솟값 ~ 최댓값
6️⃣ 단위: rpm, Nm, ℃ 등
예시:
신호: EngineRPM
├─ 위치: Byte 0-1 (16비트)
├─ 길이: 16비트
├─ 타입: Unsigned (음수 불가)
├─ Scaling: × 0.25
├─ 범위: 0~8000 rpm
└─ 단위: rpm
중요:
모든 신호는 DBC 파일에 정의됨!
→ 누군가는 DBC를 만들어야 함
→ 자동차 개발팀이 만듦!
📊 CAN 메시지 실제 예시
[상황]
엔진이 3000 rpm, 200 Nm 토크, 90℃ 온도일 때
[DBC 정의]
EngineData (ID 0x100, 8바이트):
├─ EngineRPM: Byte 0-1, Scale (×0.25+0)
├─ EngineTorque: Byte 2-3, Scale (×1+0)
├─ CoolantTemp: Byte 4, Scale (×1-40)
└─ ...
[인코딩 과정]
RPM 3000:
역스케일: 3000 / 0.25 = 12000 = 0x2EE0
→ Byte 0 = 0xE0, Byte 1 = 0x2E
Torque 200:
역스케일: 200 / 1 = 200 = 0x00C8
→ Byte 2 = 0xC8, Byte 3 = 0x00
CoolantTemp 90:
역스케일: (90 + 40) / 1 = 130 = 0x82
→ Byte 4 = 0x82
[최종 CAN 메시지]
ID: 0x100
DLC: 8
Data: [0xE0, 0x2E, 0xC8, 0x00, 0x82, 0x00, 0x00, 0x00]
[CRC 계산 후 전송]
CAN 버스에 메시지 전송!
[수신 및 해석]
변속기 ECU가 받음:
Data: [0xE0, 0x2E, 0xC8, 0x00, 0x82, ...]
RPM 추출: (0x2EE0) × 0.25 = 3000 rpm ✓
Torque 추출: (0x00C8) × 1 = 200 Nm ✓
Temp 추출: (0x82) × 1 - 40 = 90℃ ✓
결과: 완벽한 통신! ✓
🎯 면접 예상 질문
Q1: "CAN이 뭐고, 왜 중요한가요?"
A: "CAN은 자동차 표준 통신 프로토콜입니다.
모든 자동차가 사용하며, 엔진, 변속, 제동 같은
핵심 제어에 사용됩니다. 신뢰성이 높고
표준화되어 있다는 게 가장 큰 장점입니다."
Q2: "CAN의 Broadcast 방식을 설명해주세요"
A: "모든 ECU가 같은 버스를 공유하고,
각자가 필요한 메시지만 받습니다.
LIN의 Master-Slave와는 달리,
CAN은 모두가 주인입니다."
Q3: "CAN ID가 뭐죠?"
A: "메시지의 이름이에요. 0x100, 0x200 같은
숫자로 표현되며, ID가 낮을수록 우선순위가 높습니다.
EngineData는 0x100, TransmissionData는 0x200 같은 식으로 정해져요."
Q4: "DBC 파일이 뭐예요?"
A: "CAN 메시지 안에 어떤 신호들이 들어있는지 정의하는 파일입니다.
'EngineRPM은 Byte 0-1에 있고, Scaling은 0.25이다' 같은
정보를 담고 있어요."
Q5: "데이터 인코딩 과정을 설명해주세요"
A: "신호 값을 DBC 파일의 Scaling을 역계산해서 정수로 바꾼 후,
CAN 메시지의 정해진 위치에 바이트로 넣습니다.
예를 들어 RPM 3000을 (×0.25) Scaling으로 보내려면
12000을 2바이트로 변환해서 Byte 0-1에 넣어요."
📌 CAN 기초의 핵심
| 항목 | 설명 |
|---|---|
| 정의 | 자동차 표준 통신 프로토콜 |
| 속도 | 500 kbps (표준), 1 Mbps (고속) |
| 구조 | Broadcast (모두가 공유) |
| 메시지 | ID + DLC + Data + CRC |
| 신호 | 메시지 안의 작은 데이터 (DBC 정의) |
| 신뢰성 | 매우 높음 (CRC, 에러 감지) |
| 견고성 | 노이즈에 강함 (차동 신호) |
| 표준화 | 모든 자동차 (ISO 11898) |
| 비용 | $$$ (저가는 아니지만 가치 있음) |
| 용도 | 엔진, 변속, 제동 (핵심) |
마치며
CAN에 대해 배워봤는데요...
조금 어렵죠?
이해합니다
취준생 분들이라면 생소해서 어려울 테고
입문자라면 아직 다뤄본적이 없어서 어려울거예요
초급자라면 뭔가 알것 같이 모르는 기분을 느낄건데요
두번만 읽으시면 대충 감은 올거예요
이제 업계에 있는동안은 지겹도록 들을 단어니까
하루에도 수천번씩 듣게됩니다...
처음에 기강잡고 시작하자고요 !
'통신 프로토콜' 카테고리의 다른 글
| ISO-TP : CAN으로 큰 데이터를 보내는 방법 (3) | 2025.12.31 |
|---|---|
| 자동차 통신 프로토콜 4부: CAN (2부) – Arbitration과 에러 처리 완전 이해 (0) | 2025.12.26 |
| 자동차 통신 프로토콜 2부: LIN (Local Interconnect Network) 완벽 이해 (0) | 2025.12.24 |
| 자동차 통신 프로토콜 1부: 왜 자동차에는 여러 통신 프로토콜이 필요할까? (0) | 2025.12.21 |
| 📌 CAN 통신과 CAN FD란? 자동차가 데이터를 주고받는 방법 쉽게 정리 (0) | 2025.12.10 |