
CAN 신호 타입 완벽 정리: Periodic vs Event vs Change vs Write
Periodic? Event? vs Change? vs Write?
들어가며
먼저 CANDB를 보시면 다양한 메시지 타입이 있습니다.
이게 여러가지죠
[P] Periodic
[E] On Event
[PE] Periodic and On Event
[C] On Change
[EC] On Event and On Change
[EW] On Event and On Write
다양하기도 합니다...
이 신호 타입들이 각각 무슨 의미인지 그리고 어떻게 쓰이는지 에 대해 알아보도록 할게요
일단 자동차 CAN 버스의 속도는 최대 1 Mbps (메가비트/초) 정도죠
1 Mbps = 1,000,000 비트/초
한 개의 CAN 메시지:
- 크기: 64 비트 (8바이트)
- 시간: 64 / 1,000,000 = 0.064ms = 64마이크로초
네트워크 오버헤드 포함하면:
- 실제 처리량: ~700-800 kbps
결론:
한 초에 최대 약 10,000 ~ 15,000개의 메시지만 전송 가능!
그런데 자동차에는 수천 개의 신호가 있습니다.
엔진 신호:
- RPM, 온도, 압력, 산소 센서, ... (100+)
변속기 신호:
- 기어, 입력 속도, 출력 속도, ... (50+)
바디 신호:
- 도어, 윈도우, 조명, 와이퍼, ... (100+)
배터리 신호:
- SOC, 전압, 전류, 온도, ... (20+)
샤시 신호:
- 속도, 가속도, 조향각, ... (50+)
... 총 1,000+ 신호!
모든 신호를 계속 보낼 수 없다. 그래서 신호 타입이 존재하게 됩니다
"이 신호는 언제 보낼 것인가?"
이 글에서는 6가지 CAN 신호 타입과 각각의 특징, 사용 시기, 실무 예시를 정리해봅시다

1. CAN 신호란?
1.1 CAN 메시지 vs CAN 신호
CAN 메시지:
┌──────────────────────────────────┐
│ ID: 0x100 │
│ DLC: 8 바이트 │
│ Data: 12 34 56 78 9A BC DE F0 │
└──────────────────────────────────┘
CAN 신호:
CAN 메시지 안의 각 정보
Data: 12 34 56 78 9A BC DE F0
││ ││ ││ ││ ││ ││ ││ ││
││ ││ ││ ││ ││ ││ ││ └─ 신호 8: 배터리 SOC (0%)
││ ││ ││ ││ ││ ││ └──── 신호 7: 배터리 전압
││ ││ ││ ││ ││ └─────── 신호 6: 온도
││ ││ ││ ││ └────────── 신호 5: 압력
││ ││ ││ └───────────── 신호 4: 속도
││ ││ └──────────────── 신호 3: 기어
││ └─────────────────── 신호 2: RPM (하위)
└────────────────────── 신호 1: RPM (상위)
한 메시지에 여러 신호가 포함됨!
1.2 신호의 주기성
신호의 특징:
[1] 항상 필요함
├─ RPM (엔진 속도)
├─ 속도 (차량 속도)
└─ 온도 (엔진 온도)
→ Periodic (계속 보냄)
[2] 필요할 때만
├─ 에러/경고
├─ 비상상황
└─ 중요 이벤트
→ On Event (발생 시에만)
[3] 변할 때만
├─ 도어 열림/닫힘
├─ 조명 ON/OFF
└─ 기어 변화
→ On Change (변화 시만)
[4] 효율과 안정성의 결합
├─ 중요 신호 (브레이크, 스티어링)
└─ 안전 신호
→ Periodic + Event / Periodic + Change
2. [P] Periodic (주기적)
2.1 정의
Periodic = 일정 주기로 계속 전송하는 신호
┌──────┐
│ 신호 │ (Periodic 100ms)
└──────┘
│
├─── 0ms: 전송 ✓
├─── 100ms: 전송 ✓
├─── 200ms: 전송 ✓
├─── 300ms: 전송 ✓
└─── ... 계속 반복
수신자는 항상 최신 데이터를 가짐
2.2 장단점
장점:
-> 예측 가능 (수신자가 타이밍 알 수 있음)
-> 데이터 신선도 확인 (주기 이상 안 오면 에러)
-> 구현 간단 (타이머로 주기 관리)
-> 시간 동기화 용이
단점:
!! 불필요한 대역폭 사용
(값이 안 바뀌어도 계속 보냄)
!! CAN 버스 혼잡 가능
!! 에너지 낭비 (항상 활성화)
2.3 사용 사례
자동차에서 Periodic 신호:
엔진 신호:
- Engine RPM (주기: 10ms)
- Engine Temperature (주기: 100ms)
- Fuel Pressure (주기: 50ms)
구동 신호:
- Vehicle Speed (주기: 20ms)
- Acceleration (주기: 50ms)
- Steering Angle (주기: 100ms)
배터리 신호:
- Battery Voltage (주기: 100ms)
- Battery Current (주기: 100ms)
- Battery SOC (주기: 500ms)
왜 Periodic?
→ 항상 최신 정보 필요
→ 다른 시스템이 계속 모니터링
→ 신선한 데이터 중요
2.4 코드 예시
// Periodic 신호 전송
void SendPeriodicSignals() {
// 100ms 주기 타이머에서 호출
uint16_t rpm = GetEngineRPM();
uint8_t temp = GetEngineTemp();
uint8_t speed = GetVehicleSpeed();
// CAN 메시지 구성
uint8_t can_data[8];
can_data[0] = (rpm >> 8) & 0xFF; // RPM 상위
can_data[1] = rpm & 0xFF; // RPM 하위
can_data[2] = temp; // 온도
can_data[3] = speed; // 속도
// 항상 전송 (주기 타이머마다)
SendCANMessage(0x100, can_data, 8);
}
void Init_PeriodicTimer() {
// 100ms 주기 타이머 설정
SetupTimer(100, SendPeriodicSignals);
}
3. [E] On Event (이벤트 발생 시)
3.1 정의
On Event = 특정 이벤트 발생할 때만 전송
┌──────────────┐
│ 에러 신호 │ (On Event)
└──────────────┘
│
├─── 이벤트 발생 없음
├─── 이벤트 발생! → 전송 ✓
├─── 이벤트 해결 → 해결 신호 전송 ✓
└─── 이벤트 발생! → 전송 ✓
전송 시기가 불규칙함
3.2 장단점
장점:
-> 대역폭 효율적 (필요할 때만)
-> CAN 버스 덜 혼잡
-> 에너지 절약 (대기 중 비활성)
-> 중요한 순간에 즉시 알림
단점:
!! 응답 지연 가능
!! 예측 불가능한 트래픽
!! 누락 위험 (메시지 손실 시)
!! 수신자가 타이밍 모름
3.3 사용 사례
자동차에서 On Event 신호:
에러/경고:
- Battery Low Warning
- Engine Temperature High
- Fault Detection
비상 상황:
- Airbag Deployment
- ABS Activation
- Stability Control
예외 상황:
- Door Ajar
- Seatbelt Unbuckled
- Fuel Low
왜 On Event?
→ 자주 발생하지 않음
→ 발생할 때만 중요
→ 즉시 알림 필요
3.4 코드 예시
// On Event 신호 전송
void OnBatteryError() {
// 배터리 오류 감지!
uint8_t can_data[8] = {0};
can_data[0] = 0x01; // 배터리 오류 코드
// 이벤트 발생 시에만 전송
SendCANMessage(0x200, can_data, 8);
printf("Battery error event sent!\n");
}
void OnTemperatureHigh() {
// 과열 감지!
uint8_t can_data[8] = {0};
can_data[0] = 0x02; // 과열 코드
can_data[1] = GetEngineTemp();
// 이벤트 발생 시에만 전송
SendCANMessage(0x200, can_data, 8);
printf("Temperature high event!\n");
}
// 에러 감지 ISR
void ErrorDetectionISR() {
if (IsBatteryError()) {
OnBatteryError();
}
if (IsTemperatureHigh()) {
OnTemperatureHigh();
}
}
4. [PE] Periodic and On Event (주기 + 이벤트)
4.1 정의
PE = 주기적으로 전송 + 이벤트 시 즉시 전송
┌──────────────────┐
│ 중요 신호 (PE) │
└──────────────────┘
│
├─── 0ms: 주기 전송 ✓
├─── 50ms: 주기 전송 ✓
├─── 80ms: 이벤트 발생! → 즉시 전송 ✓
├─── 100ms: 주기 전송 ✓
├─── 150ms: 이벤트! → 즉시 전송 ✓
└─── 200ms: 주기 전송 ✓
정기적 + 필요 시 추가 전송
4.2 장단점
장점:
-> 안정성 높음 (주기적 업데이트)
-> 긴급 대응 가능 (이벤트 즉시)
-> 예측 가능 + 유연성
-> 안전 신호에 최적
단점:
!! 구현 복잡 (타이머 + 이벤트)
!! 대역폭 더 많이 사용
!! 관리 어려움
4.3 사용 사례
자동차에서 PE 신호:
안전 관련:
- Brake Pressure (주기 20ms + 급제동 시 즉시)
- Steering Angle (주기 50ms + 조향 변화 시)
- Accelerator (주기 50ms + 급가속 시)
중요 시스템:
- Engine RPM (주기 10ms + 과회전 감지 시)
- Transmission Gear (주기 100ms + 기어 변화 시)
- Battery Status (주기 100ms + 비정상 시)
왜 PE?
→ 안정성과 응답성 모두 필요
→ 안전 크리티컬 신호
→ 정상/비정상 모두 감시 필요
4.4 코드 예시
// PE 신호: 주기 + 이벤트
uint8_t brake_pressure_last = 0;
void SendBrakePressure() {
uint8_t pressure = GetBrakePressure();
uint8_t can_data[8] = {0};
can_data[0] = pressure;
// 1. 주기적 전송 (20ms마다)
SendCANMessage(0x150, can_data, 8);
// 2. 이벤트 전송 확인
if (IsHardBraking(pressure)) {
// 급제동 감지!
can_data[1] = 0xFF; // 긴급 플래그
SendCANMessage(0x150, can_data, 8);
printf("Hard braking event!\n");
}
brake_pressure_last = pressure;
}
void Init_BrakePE() {
// 20ms 주기 타이머
SetupTimer(20, SendBrakePressure);
}
5. [C] On Change (변화 시)
5.1 정의
On Change = 값이 변했을 때만 전송
┌──────────┐
│ 상태신호 │ (On Change)
└──────────┘
│
├─── 값: 0 (안 보냄)
├─── 값: 0 (안 보냄)
├─── 값: 1 (변함!) → 전송 ✓
├─── 값: 1 (같음, 안 보냄)
├─── 값: 1 (같음, 안 보냄)
├─── 값: 0 (변함!) → 전송 ✓
└─── 값: 0 (같음, 안 보냄)
변화가 있을 때만 전송
5.2 장단점
장점:
-> 매우 효율적 (변화 없으면 안 보냄)
-> 대역폭 최소
-> 변화 감지 명확
->저전력
단점:
!! 변화 감지 어려움 (노이즈)
!! 누락 위험 높음
!! 수신자의 마지막 상태 불명확
!! 디버깅 어려움
5.3 사용 사례
자동차에서 On Change 신호:
상태 정보:
- Door Status (Open/Closed)
- Window Status (Up/Down)
- Light Status (On/Off)
- Gear Position (P/R/N/D)
스위치:
- Wiper Activated
- Headlight Activated
- Turn Signal
모드:
- Cruise Control (On/Off)
- Parking Mode (On/Off)
왜 On Change?
→ 자주 변하지 않음
→ 변했다는 것이 중요
→ 상태 정보
5.4 코드 예시
// On Change 신호
static uint8_t door_status_last = 0;
void SendDoorStatus() {
uint8_t door_status = GetDoorStatus();
// 변화 감지?
if (door_status != door_status_last) {
// 변했다! 전송
uint8_t can_data[8] = {0};
can_data[0] = door_status;
SendCANMessage(0x300, can_data, 8);
printf("Door status changed to: %d\n", door_status);
door_status_last = door_status;
}
// 변화 없으면 아무것도 안 함
}
void MainLoop() {
// 10ms마다 확인 (변화 감지하기 위해)
SendDoorStatus();
}
6. [EC] On Event and On Change (이벤트 + 변화)
6.1 정의
EC = 이벤트 발생 시 또는 값이 변했을 때 전송
┌──────────────┐
│ 복합 신호 │ (On Event + On Change)
└──────────────┘
│
├─── 값: 0 (안 보냄)
├─── 이벤트 발생! → 전송 ✓
├─── 값: 1 (변함!) → 전송 ✓
├─── 값: 2 (변함!) → 전송 ✓
├─── 이벤트 발생! → 전송 ✓
└─── 값: 1 (변함!) → 전송 ✓
이벤트 또는 변화 감지 시 전송
6.2 사용 사례
자동차에서 EC 신호:
배터리 신호:
- Battery Voltage (값 변화 + 비정상 이벤트)
- Battery Temperature (값 변화 + 과열 이벤트)
엔진 신호:
- Oil Pressure (값 변화 + 저압 경고)
- Coolant Temperature (값 변화 + 과열 경고)
시스템 신호:
- DPF Status (상태 변화 + 재생 이벤트)
- Transmission Health (상태 변화 + 오류 이벤트)
왜 EC?
→ 정상 변화도 중요 (모니터링)
→ 이상 상황도 중요 (경고)
→ 둘 다 감지 필요
6.3 코드 예시
static uint8_t battery_voltage_last = 0;
static uint8_t battery_error_sent = 0;
void SendBatteryStatus() {
uint8_t voltage = GetBatteryVoltage(); // 0~255 범위
uint8_t is_error = IsBatteryError();
uint8_t should_send = 0;
// 1. 값이 변했는가?
if (voltage != battery_voltage_last) {
should_send = 1;
battery_voltage_last = voltage;
}
// 2. 에러 이벤트 발생했는가?
if (is_error && !battery_error_sent) {
should_send = 1;
battery_error_sent = 1;
} else if (!is_error && battery_error_sent) {
should_send = 1;
battery_error_sent = 0;
}
// 전송
if (should_send) {
uint8_t can_data[8] = {0};
can_data[0] = voltage;
can_data[1] = is_error ? 0xFF : 0x00;
SendCANMessage(0x400, can_data, 8);
printf("Battery status: V=%d, Error=%d\n", voltage, is_error);
}
}
7. [EW] On Event and On Write (이벤트 + 쓰기)
7.1 정의
EW = 이벤트 발생 또는 외부에서 값을 쓸 때 전송
┌──────────────────────┐
│ 제어/진단 신호 (EW) │
└──────────────────────┘
│
├─── 내부 값: 0
├─── 외부에서 값 쓰기! → 전송 ✓
├─── 이벤트 발생! → 전송 ✓
├─── 내부 값: 1
└─── 외부에서 값 쓰기! → 전송 ✓
외부 제어 + 이벤트 감지
7.2 사용 사례
자동차에서 EW 신호:
진단/제어:
- Diagnostic Command (진단 도구에서 쓰기)
- Test Mode (테스트 중 제어)
- Calibration Value (캘리브레이션)
소프트웨어 업데이트:
- OTA Update Command
- Bootloader Mode
- Firmware Version
특별 기능:
- Service Mode (정비 중 제어)
- Engineering Mode
왜 EW?
→ 외부 명령 실행 필요 (진단 도구)
→ 이벤트도 감시 (상태 변화)
→ 명시적 제어 + 모니터링
7.3 코드 예시
static uint8_t diag_command_last = 0;
void SendDiagnosticStatus() {
uint8_t diag_command = GetDiagnosticCommand();
uint8_t diag_event = GetDiagnosticEvent();
uint8_t should_send = 0;
// 1. 진단 명령이 써졌는가? (외부 제어)
if (diag_command != diag_command_last) {
should_send = 1;
diag_command_last = diag_command;
printf("Diagnostic command received: %d\n", diag_command);
}
// 2. 진단 이벤트 발생?
if (diag_event) {
should_send = 1;
}
// 전송
if (should_send) {
uint8_t can_data[8] = {0};
can_data[0] = diag_command;
can_data[1] = diag_event;
SendCANMessage(0x700, can_data, 8);
}
}
// 외부에서 진단 명령 쓰기 (진단 도구)
void WriteDiagnosticCommand(uint8_t cmd) {
SetDiagnosticCommand(cmd);
// → SendDiagnosticStatus()에서 감지하여 전송
}
8. 신호 타입 비교 및 선택
8.1 비교표
신호 타입 주기 이벤트 변화 외부제어 대역폭 응답성 구현도
────────────────────────────────────────────────────────────
P ✓ ✗ ✗ ✗ 높 낮 낮
E ✗ ✓ ✗ ✗ 낮 높 낮
C ✗ ✗ ✓ ✗ 최저 중 중
PE ✓ ✓ ✗ ✗ 중~높 높 높
EC ✗ ✓ ✓ ✗ 중 높 중
EW ✗ ✓ ✗ ✓ 낮 높 높
8.2 선택 기준
신호를 선택할 때:
1단계: 신호의 특성 파악
└─ 항상 필요? → P (Periodic)
└─ 가끔 필요? → E (Event)
└─ 변할 때? → C (Change)
2단계: 안정성 요구
└─ 높음 → P 포함 (Periodic 포함)
└─ 중간 → PE, EC 고려
└─ 낮음 → E, C 가능
3단계: 대역폭 고려
└─ 여유 있음 → PE (안정성 우선)
└─ 부족 → C, E (효율성 우선)
└─ 부족함 → E or C만 (최소)
4단계: 외부 제어 필요?
└─ 필요 → EW
└─ 불필요 → 제외
9. 실무 시나리오
9.1 엔진 제어 신호
엔진 RPM:
- 특성: 항상 필요, 중요
- 안정성: 높음
- 선택: Periodic (10ms)
→ 엔진 제어에 항상 필요
엔진 온도:
- 특성: 항상 필요, 변화 느림
- 안정성: 높음 + 경고 필요
- 선택: Periodic + On Event (100ms + 과열 시)
→ PE (주기 100ms + 과열 경고)
엔진 오류:
- 특성: 가끔, 중요
- 안정성: 높음
- 선택: On Event
→ E (오류 발생 시에만)
9.2 도어 제어 신호
도어 잠금:
- 특성: 상태 정보, 자주 안 바뀜
- 안정성: 중간
- 선택: On Change
→ C (잠금/해제 시만)
도어 열림:
- 특성: 상태 정보 + 경고 필요
- 안정성: 높음
- 선택: Periodic + On Change
→ PC (주기 100ms + 변화 시)
또는 PE (주기 + 열린 경고)
9.3 배터리 신호
배터리 전압:
- 특성: 항상 필요 + 변화도 중요
- 안정성: 높음
- 선택: Periodic + On Change
→ PC (주기 100ms + 변화 시)
배터리 오류:
- 특성: 이벤트 + 값 변화도 중요
- 안정성: 높음
- 선택: On Event + On Change
→ EC (오류 발생 + 전압 변화)
10. 자주 하는 실수
10.1 신호 타입 선택 오류
!! 잘못된 예:
// 브레이크 압력을 On Change로 설정
// → 주기적 모니터링 불가능
// → 급제동 감지 지연 가능
-> 올바른 예:
// 브레이크 압력: Periodic + On Event
// → 안정적 모니터링 + 즉각 응답
10.2 주기 설정 오류
!! 잘못된 예:
// 엔진 RPM을 1000ms (1초) 주기로 설정
// → 엔진 제어 지연, 응답 불가능
-> 올바른 예:
// 엔진 RPM: 10ms 주기
// → 빠른 응답, 안정적 제어
10.3 이벤트 조건 모호
!! 잘못된 예:
if (temperature > 100) {
// 과열 이벤트
// 100도 정확히일 때는?
// 노이즈 때문에 반복 전송?
}
-> 올바른 예:
#define TEMP_THRESHOLD 100
#define TEMP_HYSTERESIS 5
if (temperature > TEMP_THRESHOLD && !overheating_flag) {
// 과열 시작
overheating_flag = 1;
SendEvent();
} else if (temperature < (TEMP_THRESHOLD - TEMP_HYSTERESIS) && overheating_flag) {
// 과열 해제
overheating_flag = 0;
SendEvent();
}
11. 핵심 정리
CAN 신호 타입:
[P] Periodic
└─ 항상 필요한 신호
└─ 고정 주기로 계속 전송
└─ 예: RPM, 온도, 속도
[E] On Event
└─ 이벤트 발생 시만
└─ 경고, 오류, 비상
└─ 예: 에러 코드, 경고음
[PE] Periodic + Event
└─ 안정성 + 응답성
└─ 중요 신호
└─ 예: 브레이크, 스티어링
[C] On Change
└─ 상태 정보
└─ 변화 없으면 미전송
└─ 예: 도어, 조명, 기어
[EC] Event + Change
└─ 이벤트 + 값 변화
└─ 예: 배터리, 센서
[EW] Event + Write
└─ 이벤트 + 외부 제어
└─ 예: 진단, 제어
선택 기준:
- 신호의 중요도
- 변화 빈도
- 안정성 요구
- 대역폭 제약
- 외부 제어 여부
'자동차 소프트웨어' 카테고리의 다른 글
| ECU Sleep/WakeUp 완벽 정리: 차량 전력 관리 및 저전력 아키텍처 실무 가이드 (0) | 2026.01.15 |
|---|---|
| CSMS(Cybersecurity Management System) 완벽 정리: 자동차 사이버보안 관리 시스템 실무 가이드 (3) | 2026.01.14 |
| OTA(Over-The-Air) 업데이트 완벽 정리: 자동차 펌웨어 무선 업데이트 실무 가이드 (0) | 2026.01.09 |
| Git Fork와 Merge: 협업 개발의 필수 개념 (0) | 2026.01.05 |
| 🚗 Watchdog이란? 자동차 소프트웨어에서 왜 꼭 필요할까? (0) | 2025.12.13 |