개념정리/기타

[IDEC] 지능형 자동차 내부 네트워크 기술 CAN(controller area network) 응용 실무 with AVR Studio(feat.ChatGPT)

funtastie 2023. 1. 26. 22:53
CAN이란 뭘까? 요즘 핫한 ChatGPT 형님에게 여쭤보았다.

Q) what is controller area network?

A) Controller Area Network (CAN) is a communication protocol used in automotive, industrial, and other applications where real-time control is required. It is a broadcast-based, multi-master, message-based protocol that allows multiple devices on the network to communicate with each other without a central controller. CAN is designed to be robust, with features such as error detection and fault tolerance, and it operates at high speeds, making it suitable for use in applications where data needs to be transmitted quickly and accurately.

""

CAN(Controller Area Network)은 실시간 제어가 필요한 자동차, 산업 및 기타 애플리케이션에 사용되는 통신 프로토콜이다. 이 프로토콜은 네트워크의 여러 장치가 중앙 컨트롤러 없이 서로 통신할 수 있도록 하는 브로드캐스트 기반의 멀티마스터 메시지 기반 프로토콜이다. CAN은 오류 감지, 내결함성 등의 기능을 갖추고 견고하게 설계되었으며, 고속으로 작동하여 데이터를 빠르고 정확하게 전송해야 하는 애플리케이션에서 사용하기에 적합합니다.

""

그렇다. 자동차 내에서 실시간 제어를 하는데 쓰이는 통신 프로토콜 중 하나이다.

 

그럼 CAN과 FlexRay의 차이점은 뭘까?

Q) what is difference about CAN and FlexRay

A) Controller Area Network (CAN) and FlexRay are both communication protocols used in automotive and industrial applications. However, there are some key differences between the two:

Speed: FlexRay supports faster data transfer rates than CAN, which makes it more suitable for use in high-bandwidth applications such as advanced driver assistance systems (ADAS) and autonomous vehicles.

Complexity: FlexRay is a more complex and sophisticated protocol than CAN, which makes it more challenging to implement and maintain.

Fault tolerance: CAN is designed to be more robust and fault-tolerant than FlexRay, with features such as error detection and recovery.

Network topology: FlexRay supports both star and daisy-chain topologies, which allows for more flexibility in network design.

Synchronization: FlexRay uses a time-triggered communication model which allows for better synchronization between nodes, and is suitable for applications requiring high determinism.

In summary, FlexRay is a more advanced and flexible protocol than CAN, but also more complex and require more resources. It's typically used in high-bandwidth and safety-critical applications where deterministic, low-latency communication is needed, such as ADAS and autonomous vehicles.

 

""

CAN(Controller Area Network)과 FlexRay는 모두 자동차 및 산업용 애플리케이션에 사용되는 통신 프로토콜입니다. 그러나 이 둘 사이에는 몇 가지 주요 차이점이 있습니다:

속도: FlexRay는 CAN보다 빠른 데이터 전송 속도를 지원하므로 ADAS(Advanced Driver Assistance System) 및 자율 주행 차량과 같은 고대역폭 애플리케이션에서 사용하기에 적합합니다.

복잡성: FlexRay는 CAN보다 더 복잡하고 정교한 프로토콜이므로 구현 및 유지 관리가 더 어렵습니다.

내결함성: CAN은 오류 감지 및 복구와 같은 기능을 통해 FlexRay보다 더 강력하고 내결함성이 있도록 설계되었습니다.

네트워크 토폴로지: FlexRay는 스타 및 데이지 체인 토폴로지를 모두 지원하므로 네트워크 설계의 유연성이 향상됩니다.

동기화: FlexRay는 노드 간에 더 나은 동기화를 가능하게 하는 시간 트리거 통신 모델을 사용하며, 높은 결정론이 필요한 애플리케이션에 적합합니다.

요약하면 FlexRay는 CAN보다 더 고급스럽고 유연한 프로토콜이지만 더 복잡하고 더 많은 리소스가 필요합니다. 일반적으로 ADAS 및 자율 주행 차량과 같이 결정론적이고 짧은 지연 시간의 통신이 필요한 고대역폭 및 안전에 중요한 애플리케이션에 사용됩니다.

""

역시 GPT형님, 모르시는게 없는건 둘째치고 이해하기 쉽게 잘 설명해주신다.

 

 

CAN Protocol을 좀 자세히 알아보자.

Q) Tell me about CAN Protocol deeply

A) The CAN protocol is based on the idea of a shared communication bus, which all devices on the network are connected to. Data is transmitted in the form of messages, which consist of an identifier (ID) and a data payload. The ID is used to identify the message and determine which device or devices should process it, while the data payload contains the actual data being transmitted.

One of the key features of the CAN protocol is its ability to support multiple message priority levels. This allows messages with higher priority to be transmitted and processed before messages with lower priority.

The CAN protocol also includes a number of mechanisms for ensuring the integrity and reliability of data transmission. For example, all messages include a cyclic redundancy check (CRC) value, which is used to detect errors in the data. Additionally, all nodes on the network continuously monitor the bus for errors and take appropriate action if any are detected.

The CAN protocol also supports a number of different operating modes, including normal, listen-only, and loop-back mode, which allows nodes to transmit and receive messages without interfering with other devices on the network.

In summary, the CAN protocol is a robust and reliable communication protocol that is well-suited for use in applications where real-time control is required. Its ability to support multiple message priority levels, error detection and fault tolerance, and different operating modes, make it suitable for a wide range of applications, such as industrial automation, medical equipment, and automotive systems.

 

""

CAN 프로토콜은 네트워크의 모든 장치가 연결되는 공유 통신 버스의 아이디어를 기반으로 합니다. 데이터는 식별자(ID)와 데이터 페이로드로 구성된 메시지 형태로 전송된다. ID는 메시지를 식별하고 처리해야 하는 장치 또는 장치를 결정하는 데 사용되며, 데이터 페이로드에는 전송되는 실제 데이터가 포함됩니다.

CAN 프로토콜의 주요 기능 중 하나는 다중 메시지 우선 순위 수준을 지원하는 기능입니다. 이렇게 하면 우선 순위가 높은 메시지를 낮은 메시지보다 먼저 전송하고 처리할 수 있습니다.

CAN 프로토콜은 또한 데이터 전송의 무결성 및 신뢰성을 보장하기 위한 다수의 메커니즘을 포함한다. 예를 들어 모든 메시지에는 데이터의 오류를 탐지하는 데 사용되는 CRC(순환 중복 검사) 값이 포함됩니다. 또한 네트워크의 모든 노드는 버스의 오류를 지속적으로 모니터링하고 오류가 감지되면 적절한 조치를 취합니다.

CAN 프로토콜은 또한 노드가 네트워크의 다른 장치와 간섭하지 않고 메시지를 송수신할 수 있는 일반, 수신 전용 및 루프백 모드를 포함하여 다양한 작동 모드를 지원합니다.

요약하면, CAN 프로토콜은 실시간 제어가 필요한 애플리케이션에서 사용하기에 적합한 강력하고 신뢰할 수 있는 통신 프로토콜입니다. 다중 메시지 우선순위 수준, 오류 감지 및 내결함성, 다양한 작동 모드를 지원하는 기능으로 산업 자동화, 의료 장비 및 자동차 시스템과 같은 광범위한 응용 분야에 적합합니다.

""

그렇다. 주요 2가지 기능은 다중 메시지 우선 순위 지원과 데이터의 오류 탐지 기능이다. 이것을 IDEC에서 배우는 CRC기술을 사용한다. 아래에 설명할 예정!

 

CAN의 특징

■ 경제적 솔루션

 1. 우수한 가격 대비 성능

 2. 자동차와 같은 대량 생산에 사용될 수 있는 저가 디바이스 풍부

■ 우수한 신뢰성

 1. 정교한 오류 검출과 오류 처리 구조 => 높은 전송 신뢰성

 2. 오류 메시지는 반복 재전송

 3. 심각한 오류 발생 노드는 버스 상에서 자동 방출

 4. 모든 노드에 오류가 알려지므로 시스템의 전체 데이터 일관성 유지 가능

 5. differential line => 전자파 간섭에 대한 강한 내성

■ 표준화

 1. ISO 11898(고속 애플리케이션)

 2. ISO 11519-2(저속 애플리케이션 : < 125Kbps)

■ 실시간성

 1. 최대 데이터 전송률 1M[bps] @ 25[m] bus length

 2. 전송 요청과 실제 전송 시작 사이의 짧은 지연 시간

 3. CSMA/CD 방식 버스 앣스 => 시간 손실 없이 우선 순위 순서로 메시지 전송

■ 유연성

 1. Multi-Master 구조 가능 : 모든 노드들이 독립적으로 bus access

 2. 노드 연결/분리 용이(Plug & Play)

■ 다중 전송/방송 성능

 1. 노드 지향형이 아닌 메시지 지향형

 2. 메시지 식별자가 메시지 내용과 우선순위 지정

 3. 메시지는 동시에 모든 노드들로 보내지고, 모든 노드들은 공통 데이터를 동시에 수신하고 작업 가능

 

자동차 어원 (강의의 첫 시작)

자체 엔진 혹은 모터로 승객 혹은 화물을 수송하는 바퀴를 가진 수송기계

 

FlexRay 사용량이 줄어들고 있다.

자료가 최신이 아님 (받은 강의 자료)

 

그럼 왜 FlexRay의 사용량이 줄어들까?

Q) why FlexRay using rate is declining?

A)

FlexRay is a communication protocol that was developed for use in advanced driver assistance systems (ADAS) and autonomous vehicles. While it has some advantages over other protocols, such as faster data transfer rates and better synchronization, it is also more complex and resource-intensive to implement and maintain.

There are several reasons why the use of FlexRay is declining:

  1. Cost: FlexRay requires more expensive hardware and software components than other protocols, which can make it more expensive to implement.
  2. Complexity: FlexRay is a more complex protocol than other options, such as CAN and Ethernet, which can make it more challenging to implement and maintain.
  3. Limited adoption: FlexRay has not been widely adopted in the automotive industry, which limits its potential for growth.
  4. Alternative solutions: other protocols such as Ethernet, have been developed and are gaining popularity as they offer similar performance and flexibility, but with less complexity and lower cost.
  5. CAN FD (Flexible Data Rate) is an extension of the CAN protocol that allows for faster data transfer rates, which makes it a more viable option for use in high-bandwidth applications such as ADAS and autonomous vehicles.

In summary, the use of FlexRay is declining because it is more expensive and complex to implement than other protocols, and it has not been widely adopted in the automotive industry. Alternative solutions such as Ethernet and CAN FD have emerged and provide similar performance and flexibility at lower costs.

""
FlexRay는 첨단 운전자 보조 시스템(ADAS) 및 자율 주행 차량에 사용하기 위해 개발된 통신 프로토콜입니다. 데이터 전송 속도가 빨라지고 동기화가 개선되는 등 다른 프로토콜에 비해 몇 가지 이점이 있지만 구현 및 유지 관리가 더 복잡하고 리소스 집약적입니다.

FlexRay 사용이 감소하는 몇 가지 이유는 다음과 같습니다:

비용: FlexRay는 다른 프로토콜보다 더 비싼 하드웨어 및 소프트웨어 구성 요소를 필요로 하므로 구현 비용이 더 많이 들 수 있습니다.

복잡성: FlexRay는 CAN 및 이더넷과 같은 다른 옵션보다 더 복잡한 프로토콜이므로 구현 및 유지 관리가 더 어려울 수 있습니다.

제한적 채택: FlexRay는 자동차 산업에서 널리 채택되지 않아 성장 가능성을 제한합니다.

대안 솔루션: 이더넷과 같은 다른 프로토콜이 개발되어 성능과 유연성은 비슷하지만 복잡성은 적고 비용은 저렴하기 때문에 인기를 얻고 있습니다.

CAN FD(Flexible Data Rate)는 데이터 전송 속도를 더 빠르게 할 수 있는 CAN 프로토콜의 확장으로, ADAS 및 자율 주행 차량과 같은 고대역폭 애플리케이션에서 사용할 수 있는 보다 실행 가능한 옵션입니다.

요약하자면 FlexRay는 다른 프로토콜에 비해 구현 비용이 많이 들고 복잡하기 때문에 사용이 감소하고 있으며, 자동차 산업에서 널리 채택되지 못하고 있습니다. 이더넷 및 CAN FD와 같은 대체 솔루션이 등장했으며 더 낮은 비용으로 유사한 성능과 유연성을 제공합니다.
""

FlexRay는 기존에 주로 사용된 CAN보다 전송속도는 빠르지만 값이 비싸고 유지보수, 복잡하다는 단점으로 자동차 산업에서 잘 사용되지 않는다. CAN의 단점을 보완하는 CAN FD는 CAN보다 5배 빠른 성능이기 때문에 전체 베이스를 뜯어 고치지 않아도 되는 장점으로 CAN FD 솔루션을 채택한다.

 

개발목적

- universally usable bus connection

케이블 연결방식

- 2가닥의 Twisted pair를 이용한 케이블링

- 최대 1km의 전송거리 (50kbps의 통신속도의 경우),  거리가 길어질수록 통신속도가 줄어들기 때문

통신속도 (최대 1Mbps)

- 일반적으로, 500kbps가 사용됨

- 전체 대역폭의 약 50% 이하의 트랙픽을 유지할 것을 권장

통신방식

- ID 경쟁을 위한 이벤트기반 통신방식(priority-controlled)

 

물리 계층(Physical Layer)

CAN Cabling - bus length (길이를 얼마나 길게 할 수 있을까)

Length와 Data-Rata는 반비례

 

 

CAN 프로토콜

▲ Data Link Layer

 

▲ Frame Coding

High가 5번 나오면 STUFF Low 엔코딩

STUFFED 하는 이유 : 에러를 파악하기 위해

 

▲ Cyclic Redundancy Check(CRC) Error

-

 

▲ Format Error

ITM은 고정값이 와야하는데, 반환값이 왔다 -> 에러가 났다 판단

 

▲ Acknowledge Error

Node A 송신 B 수신

정확하게 받았다면 Low상태로 변경

 

▲ Stuff Error

일련의 6개 값이 같으면 Error 판단

 

▲ Error Signaling

- Error를 감지한 Node가 6 dominant bit를 출력하면 다른 node는 이에 반응하여 6 dominant bit를 출력(stuff error)

- 6 ~ 12 dominant bits (Error Flag,우성) + 8 recessive bits (Error delimiter,열성)로 구성

- Superposition(중첩) : Node들이 출력하는 Error flag의 순서에 따라 중첩될 수 있음

 

▲ 데이터링크 계층

   버스 중재 - AMP(Arbitration by Message Priority)

    - 2번에서 노드2가 High일 때 노드 1번과 2번이 Low로 데이터 전송

    - 3번에서 노드 3은 LOW, 노드1은 HIGH로  노드1은 열성으로 빠지고, 노드3가 계속해서 데이터 전송

 

▲ CAN Bus 특성

- Wired-AND Logic

- Logic High "1" : recessive bit

- Logic Low "0" : dominant bit

 

 


AVRStudio 실습(언어 C)

오프라인에선 제품을 가지고 실습을 진행하지만, 온라인으로 듣는 나는 직접 확인하기 어렵다.

실습예제1 : timer_counter_led
#define F_CPU 16000000L
#include <avr/io.h>
#include <avr/interrupt.h>	
#include <util/delay.h>

unsigned int cnt_1ms=0;

void Init_TIMER0_COMPA(void)
{
	TCCR0A |= (1<<CS01)|(1<<CS00);	// clk/64 Prescaler 
	TCNT0 = 0;
	OCR0A = 250;					// 1cycle->1000us 
	TIMSK0 = (1<<OCIE0A);			// T/C0 Output Compare Match Interrup Enable
}

SIGNAL(TIMER0_COMP_vect)	
{
	cnt_1ms++;			// 20usec 단위 업 카운트
	if(cnt_1ms==1000)
	{
		PORTB^=0x80;
		cnt_1ms=0;
	}		  
}
 		
void Port_Init(void)
{
	DDRB  |= 0x80;	
}

int main(void)
{
	Port_Init();			// 입출력 포트 초기화
	Init_TIMER0_COMPA();
	_delay_ms(1000);

	sei();					// INT 인에이블 

	while(1)
	{
		_delay_ms(50);	
	}
}

TCCR0A |= (1<<CS01)|(1<<CS00)

은 

TCCR0A = TCCR0A | (1<<CS01);

TCCR0A = TCCR0A | (1<<CS00);

2개로 나눌 수 있음

TIMSK0 = (1<<OCIE0A);

1ms마다 인터럽트가 계속 발생한다.

SIGNAL(TIMER0_COMP_vect)	
{
	cnt_1ms++;			// 20usec 단위 업 카운트
	if(cnt_1ms==1000)
	{
		PORTB^=0x80;
		cnt_1ms=0;
	}		  
}

1ms마다 서비스루틴이 실행된다.

PORTB^=0x80;

TB7에 LED 포트가 달려있기에 동작시키는 코드(ON/OFF)

주기는 2초

빌드(컴파일)하는 버튼

실습이라.. 하드웨어가 없어서 결과를 확인해 볼 수 없었다. 온라인 교육의 한계

모듈이 해당 연구실에만 있는 제품이라 구입이 불가능하다고 하신다.

 

실습예제2 : timer_counter_sw
#define F_CPU 16000000L
#include <avr/io.h>
#include <avr/interrupt.h>	
#include <util/delay.h>

unsigned int cnt_1ms=0;

void Init_TIMER0_COMPA(void)
{
	TCCR0A |= (1<<CS01)|(1<<CS00);	// clk/64 Prescaler
	TCNT0 = 0;
	OCR0A = 250;					// 1cycle->1000us 
	TIMSK0 = (1<<OCIE0A);			// T/C0 Output Compare Match Interrup Enable
}

SIGNAL(TIMER0_COMP_vect)	
{
	static char s2_old, s2_new, s3_old, s3_new;

	cnt_1ms++;			
	if(cnt_1ms==20)
	{
		s2_old=s2_new;
		s3_old=s3_new;
		s2_new=PIND & 0x01;
		s3_new=(PIND & 0x02)>>1;

		if(s2_old==1 && s2_new==0)
		{
			PORTB |=0x80;
		}
		else if(s3_old==1 && s3_new==0)
		{
			PORTB &=~0x80;
		}		
		cnt_1ms=0;
	}		  
}
 		
void Port_Init(void)
{
	DDRD &=~0x03;  	// S2, S3 Input
	DDRB  |= 0x80;	// LED	
}

int main(void)
{
	Port_Init();			// 입출력 포트 초기화
	Init_TIMER0_COMPA();
	_delay_ms(1000);

	sei();					// INT 인에이블 

	while(1)
	{
		_delay_ms(50);	
	}
}

LED가 켜지는 것을 확인할 수 있다.

우측 하단 LED는 우측 버튼 2,3번 스위치를 키고 끄면 확인가능하다.

업로드시 hex파일 업로드!

 

실습 예제 3 : LcdDisplay1
#define F_CPU 16000000L
#include <avr/io.h>
#include <stdio.h>		
#include <util/delay.h>

#define LCD_RS_1  (PORTG |= 0x01) // PG0=1; (0번 비트를 1로). (PORTG |= 0b00000001) 와 같은 의미
#define LCD_RS_0  (PORTG &= 0xFE) // PG0=0; ~0X01  
#define LCD_RW_1  (PORTG |= 0x02) // PG1=1;
#define LCD_RW_0  (PORTG &= 0xFD) // PG1=0;
#define EN_1  	  (PORTG |= 0x04) // PG2=1;
#define EN_0      (PORTG &= 0xFB) // PG2=0;
//신호를 왜 만들까? : 타이밍을 위해
char lcd_line1[16]="Hello Everyone!";
char lcd_line2[16]="[LCD TEST EXAM]";

void E_Pulse(void)
{
	EN_1;
	_delay_us(100);
	EN_0;
    // 어떤 의미? : EN이 1이되고, EN이 0이되고. 그 사이에 100마이크로sec 준다.(Pulse)
}

void LCD_Init(void)
{
	_delay_ms(40);

	PORTC = 0x38;	// Function Set
	E_Pulse();
    _delay_us(40);

	PORTC = 0x0c; 	// DisPlay ON/OFF Control
	_delay_us(40);
	E_Pulse();
	
	PORTC = 0x01; 	// Display Clear
	_delay_ms(2);
	E_Pulse();

	PORTC = 0x06; 	// Entry Mode Set
	E_Pulse();
}

void Write_Char(unsigned char buf)    //문자를 LCD에 쓰는 것(출력)
{   // Write_String과는 무슨 차이? : 스트링은 여러 문자를 씀
	LCD_RS_1;
	LCD_RW_0;
	PORTC=buf;
	E_Pulse();
}	

void LCD_Move(char x,char y)
{
	LCD_RS_0;
	LCD_RW_0;

	if(y==0) PORTC = x + 0x80;
	else if(y==1) PORTC = x + 0xc0;
	E_Pulse();
}
 
void LCD_Write_Char(char x, char y, unsigned char ch)
{
	LCD_Move(x,y);
	Write_Char(ch);
}

void LCD_Write_String(char x, char y,char *str)
{
	LCD_Move(x,y);  //위치변동시킴
	while(*str)  // 배열의 주소값이 마지막에 null이기 때문에 반복해서 Write_Char while
	Write_Char(*str++);   // Write_Char는 while안에 있다고 생각해야
}

// 입출력 초기화 
void Port_Init(void)
{
	DDRC  = 0xff;	// LCD 데이터 및 명령 
	PORTC = 0xff;
	DDRG  = 0xff;	// LCD 제어 출력 (RS, RW, E)
}

int main(void)
{
	Port_Init();	// 입출력 포트 초기화
    LCD_Init();	// LCD 초기화

	while(1)
	{	
		// LCD의 1라인에 table1 배열에 저장된 문자열 출력  (Hello Everyone!)
		LCD_Write_String(0,0,lcd_line1);  //열,행번호,배열의 주소 
		_delay_ms(50);
		// LCD의 2라인에 table2 배열에 저장된 문자열 출력 (LCD TEST EXAM)
		LCD_Write_String(0,1,lcd_line2);
		_delay_ms(50);
	}
}
컴파일 결과

Hello everyone!과 [LCD TEST EXAM] 이 LCD에 표시되어 있음을 확인할 수 있다.

 

실습 예제 4 : LcdDisplay2
#define F_CPU 16000000L
#include <avr/io.h>
#include <stdio.h>		
#include <util/delay.h>

#define LCD_RS_1  (PORTG |= 0x01)
#define LCD_RS_0  (PORTG &= 0xFE)
#define LCD_RW_1  (PORTG |= 0x02)
#define LCD_RW_0  (PORTG &= 0xFD)
#define EN_1  	  (PORTG |= 0x04)
#define EN_0      (PORTG &= 0xFB)

char lcd_line1[16]="Hello Everyone!";
char lcd_line2[16]="[LCD TEST EXAM]";

void E_Pulse(void)
{
	EN_1;
	_delay_us(100);
	EN_0;
}

void LCD_Init(void)
{
	_delay_ms(40);

	PORTC = 0x38;	// Function Set
	E_Pulse();
    _delay_us(40);

	PORTC = 0x0c; 	// DisPlay ON/OFF Control
	_delay_us(40);
	E_Pulse();
	
	PORTC = 0x01; 	// Display Clear
	_delay_ms(2);
	E_Pulse();

	PORTC = 0x06; 	// Entry Mode Set
	E_Pulse();
}

void LCD_Command(unsigned char cmd)
{
	LCD_RS_0;
	LCD_RW_0;
	PORTC=cmd;
	E_Pulse();
}	

void Write_Char(unsigned char buf)
{
	LCD_RS_1;
	LCD_RW_0;
	PORTC=buf;
	E_Pulse();
}	

void LCD_Move(char x,char y)
{
	LCD_RS_0;
	LCD_RW_0;

	if(y==0) PORTC = x + 0x80;
	else if(y==1) PORTC = x + 0xc0;
	E_Pulse();
}
 
void LCD_Write_Char(char x, char y, unsigned char ch)
{
	LCD_Move(x,y);
	Write_Char(ch);
}

void LCD_Write_String(char x, char y,char *str)
{
	LCD_Move(x,y);
	while(*str)
	Write_Char(*str++);
}

// 입출력 초기화 
void Port_Init(void)
{
	DDRC  = 0xff;	// LCD 데이터 및 명령 
	PORTC = 0xff;
	DDRG  = 0xff;	// LCD 제어 출력 (RS, RW, E)
}

int main(void)
{
	Port_Init();	// 입출력 포트 초기화
    LCD_Init();	// LCD 초기화
	_delay_ms(1000);

	// LCD의 1라인에 table1 배열에 저장된 문자열 출력  
	LCD_Write_String(0,0,lcd_line1);
	_delay_ms(50);
	// LCD의 2라인에 table2 배열에 저장된 문자열 출력
	LCD_Write_String(0,1,lcd_line2);
	_delay_ms(1000);

	while(1)
	{	
		LCD_Command(0x08);	// display off
		_delay_ms(1000);

		LCD_Command(0x0c);	// display on
		_delay_ms(1000);

		LCD_Command(0x01);	// clear display
		_delay_ms(1000);

		LCD_Write_String(0,0,"line1");
		_delay_ms(50);
		LCD_Write_String(0,1,"line3");
		_delay_ms(1000);


		LCD_Write_String(5,0,"line2");
		_delay_ms(50);
		LCD_Write_String(5,1,"line4");
		_delay_ms(1000);

		LCD_Command(0x0e);	// cursor on
		_delay_ms(1000);

		LCD_Command(0x0f);	// blink on
		_delay_ms(1000);

	}
}
컴파일 결과

line 1,2 출력 후,  line2 뒤에 커서가 깜빡임 -> Display clear  반복되는 결과를 볼 수 있음

 


CAN 통신

실습 예제 5 : can_polling - CanControlNode1
#define F_CPU 16000000L
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdio.h>

#define LCD_RS_1  (PORTG |= 0x01)
#define LCD_RS_0  (PORTG &= 0xFE)
#define LCD_RW_1  (PORTG |= 0x02)
#define LCD_RW_0  (PORTG &= 0xFD)
#define EN_1  	  (PORTG |= 0x04)
#define EN_0      (PORTG &= 0xFB)

//CAN 관련 매크로  ======================================
#define STD		0x00
#define EXT		0x01
#define _SEND_FAIL	0
#define _SEND_OK	1
#define _RECE_FAIL	0
#define _RECE_OK	1

// CAN 보레이트(baud rate)===============================
#define b1M		1
#define b500k 	2
#define b250k	3
#define b200k	4
#define	b125k	5
#define b100k	6

char lcd_line1[16]="               ";
char lcd_line2[16]="               ";

//MOb 구조체 선언  ======================================
struct MOb
{
	unsigned long id;
	unsigned char rtr;
	unsigned char ide;
	unsigned char dlc;
	unsigned char data[8];
};

struct MOb msgTx = {0x41, 0, EXT, 8, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};


void Port_Init(void)
{
	DDRC  = 0xff;	// LCD 데이터 및 명령 
	PORTC = 0xff;
	DDRG  = 0xff;	// LCD 제어 출력 (RS, RW, E)
	DDRF  = 0xfc;	// 아날로그 입력 
}

void E_Pulse(void)
{
	EN_1;
	_delay_us(100);
	EN_0;
}

void LCD_Init(void)
{
	_delay_ms(40);
	PORTC = 0x38;	// Function Set
	E_Pulse();
    _delay_us(40);
	PORTC = 0x0c; 	// DisPlay ON/OFF Control
	_delay_us(40);
	E_Pulse();	
	PORTC = 0x01; 	// Display Clear
	_delay_ms(2);
	E_Pulse();
	PORTC = 0x06; 	// Entry Mode Set
	E_Pulse();
}

void Write_Char(unsigned char buf)
{
	LCD_RS_1;
	LCD_RW_0;
	PORTC=buf;
	E_Pulse();
}	

void LCD_Move(char x,char y)
{
	LCD_RS_0;
	LCD_RW_0;
	if(y==0) PORTC = x + 0x80;
	else if(y==1) PORTC = x + 0xc0;
	E_Pulse();
}
 
void LCD_Write_Char(char x, char y, unsigned char ch)
{
	LCD_Move(x,y);
	Write_Char(ch);
}

void LCD_Write_String(char x, char y,char *str)
{
	LCD_Move(x,y);
	while(*str)
	Write_Char(*str++);
}

//***************************************************************
// CAN 초기화 	
// 1. CAN 제어기 리셋 
// 2. 보레이트 설정 
// 3. MOb 모드/상태 초기화 
// 4. MOb IDT, Mask 초기화 
// 5. CAN General 인터럽트 클리어(CAN 인터럽트 사용하지 않음) 
// 6. CAN MOb 인터럽트 클리어(CAN MOb 인터럽트 사용하지 않음)
// 7. CAN 제어기 인에이블 모드 설정 
// 8. CAN 제어기 동작 확인 후 초기화 완료  									
//***************************************************************
void can_init (char baudRate)	
{
	unsigned char i, j;	
	CANGCON |= (1<<SWRES);	// CAN 제어기 리셋
							// CAN General Control Register						
	//보레이트 설정 ==============================================
	switch(baudRate){
		case b1M:
			CANBT1= 0x00;
			CANBT2= 0x0c;
			CANBT3= 0x37;
			break;
		case b500k:
			CANBT1= 0x02;
			CANBT2= 0x0c;
			CANBT3= 0x37;			
			break;
		case b250k:
			CANBT1= 0x06;	// CAN보레이트 설정 
			CANBT2= 0x0c;	// bit timing: datasheet 264 (check table)
			CANBT3= 0x37;	// 250kbps, 16 MHz CPU Clock(0.250usec)
			break;
		case b200k:
			CANBT1= 0x08;
			CANBT2= 0x0c;
			CANBT3= 0x37;
			break;
		case b125k:
			CANBT1= 0x0E;
			CANBT2= 0x0c;
			CANBT3= 0x37;
			break;

		case b100k:
			CANBT1= 0x12;
			CANBT2= 0x0c;
			CANBT3= 0x37;													
			break;
	}
	
	for(i=0; i<15; i++)		// Reset all MObs, 15개 
	{
		CANPAGE = (i<<4);	// MOBNB3~0
							// MOb Number Select(0~14)
		CANCDMOB = 0;		// ALL Disable MOb
		CANSTMOB = 0;		// Clear status
		CANIDT1 = 0;		// Clear ID
		CANIDT2 = 0;		// Clear ID
		CANIDT3 = 0;		// Clear ID
		CANIDT4 = 0;		// Clear ID
		CANIDM1 = 0;		// Clear mask
		CANIDM2 = 0;		// Clear mask
		CANIDM3 = 0;		// Clear mask
		CANIDM4 = 0;		// Clear mask

		for(j=0; j<8; j++)  // page MOB register가 가르키는 CAN data byte
		                    // auto increment 
			CANMSG = 0;		// CAN Data Message Register
							// Clear data
	}
							
							// Clear CAN interrupt registers
	CANGIE = 0;				// CAN General Interrupt Enable Register 
							// None Interrupts
	CANIE1 = 0;				// CAN Enable INT MOb Registers 1
							// None Interrupts on MObs
	CANIE2 = 0;				// CAN Enable INT MOb Registers 2
							// None Interrupts on MObs
	CANSIT1 = 0;			// CAN Status INT MOb Registers 1
							// None Interrupts on MObs
	CANSIT2 = 0;			// CAN Status INT MOb Registers 2
							// None Interrupts on MObs

	//CANGCON = (1<<TTC );	// TTC mode *******************************************
	
	CANGCON |= (1<<ENASTB);	// CAN General Control Register 
							// Enable Mode (11 Recessive Bits has Been read)
							// Start CAN interface
	while (!(CANGSTA & (1<<ENFG))); // CAN General Status Register (Enable Flag)
									// Wait until module ready
}

//***************************************************************
// CAN 메시지 전송 (폴링 방식)	
// 처리 순서 
// 1. MOb 선택 
// 2. MOb 상태 클리어
// 3. CANCDMOB 클리어 (모드 설정, 자동 응답, IDE, DLC)
// 4. ID 설정 
// 5. IDE 설정 
// 6. DLC 설정 
// 7. RTR 설정 
// 8. 메시지 데이터 대입 
// 9. 메시지 송신 	
// 변수 
//		obj; MOb 번호 
//		msg; 메시지 구조체 
//		rtr; RTR r결정(0; 데이터 프레임, 1; 리모트 프레임)	
//***************************************************************
char can_tx (unsigned char obj, struct MOb *msg, char rtr)	
{
	char send_result = _SEND_FAIL;
	unsigned char i;	
	unsigned long can_id= msg->id;
	
							// Enable MOb1, auto increment index, start with index = 0
	CANPAGE = (obj<<4);		// CAN Page MOb Register
							// MOb Number Select

	CANSTMOB = 0x00;
	CANCDMOB = 0x00;

	if(msg->ide== 0x00)	// standard
	{
		CANIDT1= (unsigned char)(can_id>>3);
		CANIDT2= (unsigned char)(can_id<<5);
		CANCDMOB &= ~0x10;		// Set IDE bit 2.0A 11bits
	}
	else						// extended
	{
		CANIDT1= (unsigned char)(can_id>>21);
		CANIDT2= (unsigned char)(can_id>>13);
		CANIDT3= (unsigned char)(can_id>>5);
		CANIDT4= (unsigned char)(can_id<<3);

		CANCDMOB |= 0x10;		// Set IDE bit 2.0B 29bits
	}

	CANCDMOB |= (msg->dlc<<DLC0);	// set data length

	CANIDT4 |= (rtr & 0x04);     	// RTRTAG 설정;

	CANIDT4 &= ~0x02;		   		// RB1TAG=0;
	CANIDT4 &= ~0x01;		   		// RB0TAG=1;

	//put data in mailbox
	for(i=0; i<msg->dlc; i++)
		CANMSG = msg->data[i];	// full message 

	//enable transmission		
	CANCDMOB |= (1<<CONMOB0);

	while (!(CANSTMOB & (1<<TXOK)));	

	send_result= _SEND_OK;

	//reset flag
	CANSTMOB &= ~(1<<TXOK);

	return(send_result);
}

int main(void)
{
	unsigned char tx_data1=0;
	unsigned char tx_data2=0;

	Port_Init();		
	LCD_Init();
	can_init(b250k);

	while(1)
	{	
		msgTx.data[0]=tx_data1++; // Tx data 8개중 tx data 1씩 증가
		msgTx.data[1]=tx_data2--; // 데이터2를 1씩 감소
		can_tx(7, &msgTx, 0);

 		sprintf(lcd_line1,"CAN CONTROL:Tx");
		LCD_Write_String(0,0,lcd_line1);
		sprintf(lcd_line2,"tx1=%3d,tx2=%3d", tx_data1, tx_data2);
		LCD_Write_String(0,1,lcd_line2);

		_delay_ms(500);
	}
 
	return 0;
}

인터럽트는 즉각적으로 처리하지만, 폴링은 시간이 필요함

실습 예제 5 : can_polling - CanControlNode2
#define F_CPU 16000000L
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdio.h>

#define LCD_RS_1  (PORTG |= 0x01)
#define LCD_RS_0  (PORTG &= 0xFE)
#define LCD_RW_1  (PORTG |= 0x02)
#define LCD_RW_0  (PORTG &= 0xFD)
#define EN_1  	  (PORTG |= 0x04)
#define EN_0      (PORTG &= 0xFB)

//CAN 관련 매크로  ======================================
#define STD		0x00
#define EXT		0x01
#define _SEND_FAIL	0
#define _SEND_OK	1
#define _RECE_FAIL	0
#define _RECE_OK	1

// CAN 보레이트(baud rate)===============================
#define b1M		1
#define b500k 	2
#define b250k	3
#define b200k	4
#define	b125k	5
#define b100k	6

char lcd_line1[16]="               ";
char lcd_line2[16]="               ";

//MOb 구조체 선언  ======================================
struct MOb
{
	unsigned long id;
	unsigned char rtr;
	unsigned char ide;
	unsigned char dlc;
	unsigned char data[8];
};

struct MOb msg1;

void Port_Init(void)
{
	DDRC  = 0xff;	// LCD 데이터 및 명령 
	PORTC = 0xff;
	DDRG  = 0xff;	// LCD 제어 출력 (RS, RW, E)
	DDRF  = 0xfc;	// 아날로그 입력 

	DDRE  = 0xff;
	PORTE &= 0x1b;
	PORTE |= 0x44;
}

void E_Pulse(void)
{
	EN_1;
	_delay_us(100);
	EN_0;
}

void LCD_Init(void)
{
	_delay_ms(40);
	PORTC = 0x38;	// Function Set
	E_Pulse();
    _delay_us(40);
	PORTC = 0x0c; 	// DisPlay ON/OFF Control
	_delay_us(40);
	E_Pulse();	
	PORTC = 0x01; 	// Display Clear
	_delay_ms(2);
	E_Pulse();
	PORTC = 0x06; 	// Entry Mode Set
	E_Pulse();
}

void Write_Char(unsigned char buf)
{
	LCD_RS_1;
	LCD_RW_0;
	PORTC=buf;
	E_Pulse();
}	

void LCD_Move(char x,char y)
{
	LCD_RS_0;
	LCD_RW_0;
	if(y==0) PORTC = x + 0x80;
	else if(y==1) PORTC = x + 0xc0;
	E_Pulse();
}
 
void LCD_Write_Char(char x, char y, unsigned char ch)
{
	LCD_Move(x,y);
	Write_Char(ch);
}

void LCD_Write_String(char x, char y,char *str)
{
	LCD_Move(x,y);
	while(*str)
	Write_Char(*str++);
}

//***************************************************************
// CAN 초기화 	
// 1. CAN 제어기 리셋 
// 2. 보레이트 설정 
// 3. MOb 모드/상태 초기화 
// 4. MOb IDT, Mask 초기화 
// 5. CAN General 인터럽트 클리어(CAN 인터럽트 사용하지 않음) 
// 6. CAN MOb 인터럽트 클리어(CAN MOb 인터럽트 사용하지 않음)
// 7. CAN 제어기 인에이블 모드 설정 
// 8. CAN 제어기 동작 확인 후 초기화 완료  									
//***************************************************************
void can_init (char baudRate)	
{
	unsigned char i, j;	
	CANGCON |= (1<<SWRES);	// CAN 제어기 리셋
							// CAN General Control Register						
	//보레이트 설정 ==============================================
	switch(baudRate){
		case b1M:
			CANBT1= 0x00;
			CANBT2= 0x0c;
			CANBT3= 0x37;
			break;
		case b500k:
			CANBT1= 0x02;
			CANBT2= 0x0c;
			CANBT3= 0x37;			
			break;
		case b250k:
			CANBT1= 0x06;	// CAN보레이트 설정 
			CANBT2= 0x0c;	// bit timing: datasheet 264 (check table)
			CANBT3= 0x37;	// 250kbps, 16 MHz CPU Clock(0.250usec)
			break;
		case b200k:
			CANBT1= 0x08;
			CANBT2= 0x0c;
			CANBT3= 0x37;
			break;
		case b125k:
			CANBT1= 0x0E;
			CANBT2= 0x0c;
			CANBT3= 0x37;
			break;

		case b100k:
			CANBT1= 0x12;
			CANBT2= 0x0c;
			CANBT3= 0x37;													
			break;
	}
	
	for(i=0; i<15; i++)		// Reset all MObs, 15개  CANPAGE초기화
	{
		CANPAGE = (i<<4);	// MOBNB3~0
							// MOb Number Select(0~14)
		CANCDMOB = 0;		// ALL Disable MOb
		CANSTMOB = 0;		// Clear status
		CANIDT1 = 0;		// Clear ID
		CANIDT2 = 0;		// Clear ID
		CANIDT3 = 0;		// Clear ID
		CANIDT4 = 0;		// Clear ID
		CANIDM1 = 0;		// Clear mask
		CANIDM2 = 0;		// Clear mask
		CANIDM3 = 0;		// Clear mask
		CANIDM4 = 0;		// Clear mask

		for(j=0; j<8; j++)  // page MOB register가 가르키는 CAN data byte
		                    // auto increment 
			CANMSG = 0;		// CAN Data Message Register
							// Clear data
	}
							
							// Clear CAN interrupt registers
	CANGIE = 0;				// CAN General Interrupt Enable Register 
							// None Interrupts
	CANIE1 = 0;				// CAN Enable INT MOb Registers 1
							// None Interrupts on MObs
	CANIE2 = 0;				// CAN Enable INT MOb Registers 2
							// None Interrupts on MObs
	CANSIT1 = 0;			// CAN Status INT MOb Registers 1
							// None Interrupts on MObs
	CANSIT2 = 0;			// CAN Status INT MOb Registers 2
							// None Interrupts on MObs

	//CANGCON = (1<<TTC );	// TTC mode *******************************************
	
	CANGCON |= (1<<ENASTB);	// CAN General Control Register 
							// Enable Mode (11 Recessive Bits has Been read)
							// Start CAN interface
	while (!(CANGSTA & (1<<ENFG))); // CAN General Status Register (Enable Flag)
									// Wait until module ready
}

//***************************************************************
// CAN 메시지 수신 (폴링 방식)
// 1. 수신 MOb 선택 
// 2. 수신 완료 확인 
// 3. 표준 혹은 확장 버전 확인 
// 4. ID 수신 처리 
// 5. IDE 수신 처리 
// 6. DLC 수신 처리 
// 7. Data 수신 처리 
//***************************************************************
char can_rx(unsigned char obj, struct MOb *msg)		
{
	char rece_result = _RECE_FAIL;
	unsigned char i;	
	unsigned long can_id= 0;
	
	CANPAGE = (obj<<4);				// 수신 MOb 선택 

	// 수신 완료될 때까지 대기함 
	while(!(CANSTMOB&(1<<RXOK)));
	// 수신이 완료되면 
	// CANIDT, CANCDMOB, CANMSG에 수신 메시지가 저장됨 
	// get CANIDT and CANCDMOB and CANMSg
	rece_result = _RECE_OK;

	// 표준 혹은 확장 포맷에 맞추어 ID, IDE 결정 
	if((CANCDMOB & 0x10) == 0x00){	// IDE standard ?
		msg->ide= STD;
		can_id  = ((unsigned long)CANIDT1)<<8;
		can_id |= ((unsigned long)CANIDT2);
		can_id>>=5;
	}
	else{
		msg->ide= EXT;
		can_id  = ((unsigned long)CANIDT1)<<24;
		can_id |= ((unsigned long)CANIDT2)<<16;
		can_id |= ((unsigned long)CANIDT3)<<8;
		can_id |= ((unsigned long)CANIDT4);
		can_id>>=3;
	}
	msg->id= can_id;			// 구조체 변수로 CANID 대입 

	msg->rtr= CANIDT4 & 0x04;   

	msg->dlc= CANCDMOB & 0x0f;	// 수신 메시지 길이 구조체 변수에 대입 

	// get data
	for(i=0; i<(CANCDMOB&0xf); i++){
		msg->data[i] = CANMSG;	// 메시지 데이터 배열에 저장 
	}

	CANSTMOB = 0x00;			// 상태 초기 화 
	// enable reception mode and ide set
	CANCDMOB |= (1<<CONMOB1); 	// 수신 IDE 유지하고 수신 모드 설정
	// reset flag
	CANSTMOB &= ~(1<<RXOK);		// 수신대기 
	return(rece_result);
}

//****************************************************************/
// CAN 수신 MOb 설정 
// 변수:
//		obj; MOb 번호 
//		id; CAN ID
//		ide; 메시지 포맷(0:2.0A, 1:2.0B)
//		dlc; 메시지 데이터 길이 (최대 8bytes)
//		idmask; CAN ID 수신 마스크 
//		rtrIdemask; RTR 비트와 IDE 마스크 			
//****************************************************************/
void can_rx_set(char obj, unsigned long id, char ide, unsigned char dlc, 
				unsigned long idmask, unsigned char rtrIdemask)
{
	CANPAGE = obj<<4;		// set MOb number

	CANSTMOB = 0x00;		// clear status

	if(ide== STD)			// standard
	{
		CANIDT1= (unsigned char)(id>>3);
		CANIDT2= (unsigned char)(id<<5);

		CANIDM1= (unsigned char)(idmask>>3);
		CANIDM2= (unsigned char)(idmask<<5);
		CANIDM4=0;

		CANCDMOB &= ~0x10;	// clear IDE =0, standard 11 bits
	}
	else					// extended
	{
		CANIDT1= (unsigned char)(id>>21);
		CANIDT2= (unsigned char)(id>>13);
		CANIDT3= (unsigned char)(id>>5);
		CANIDT4= (unsigned char)(id<<3);

		CANIDM1= (unsigned char)(idmask>>21);
		CANIDM2= (unsigned char)(idmask>>13);
		CANIDM3= (unsigned char)(idmask>>5);
		CANIDM4= (unsigned char)(idmask<<3);

		CANCDMOB |= 0x10;		// set IDE =1, extended 29 bits
	}
	CANCDMOB |= (dlc & 0x0f);	// set data length
	CANIDM4 |= (unsigned char)(rtrIdemask & 0x07);
	CANCDMOB |= 0x80;			// receive enable 
}
	
int main(void)
{
	unsigned char rx_data1=0;
	unsigned char rx_data2=0;

	Port_Init();			
	LCD_Init();	
	can_init(b250k);
	// CAN 수신기 초기화 : mob 1, extended, all pass 
	can_rx_set(1, 0x00, EXT, 8, 0x00000000, 0x00);
		
	while(1)
	{	
		can_rx(1, &msg1);			
		rx_data1=msg1.data[0];
		rx_data2=msg1.data[1];

 		sprintf(lcd_line1,"CAN CONTROL:Rx");
		LCD_Write_String(0,0,lcd_line1);
		sprintf(lcd_line2,"rx1=%3d,rx2=%3d", rx_data1, rx_data2);
		LCD_Write_String(0,1,lcd_line2);
	}
 
	return 0;
}
컴파일 결과

1번 노드는 Tx, 2번은 Rx로  polling구조로 확인

tx와 rx가  1씩 증가 감소됨을 확인할 수 있었다.

 

polling을 사용하는 이유

Q) Why using CAN polling?

A)

CAN polling is a method of accessing the CAN bus in which a device repeatedly checks the bus for new messages. This is in contrast to interrupt-based CAN communication, in which a device is notified by an interrupt when a new message is received on the bus.

There are several reasons why a device might use CAN polling:

  1. Simplicity: Polling is a simple method of accessing the bus and can be easily implemented in software.
  2. Low overhead: Polling does not require the use of interrupts, which can consume additional processing resources.
  3. Power efficiency: In low-power applications, it's important to minimize power consumption, and polling can reduce the power consumption of the device compared to interrupt-based communication.
  4. Real-time performance: Polling can be used in real-time systems where the response time to new messages is critical.
  5. Compatibility: Polling is compatible with all CAN controllers, whereas interrupt-based communication may not be supported by all controllers.

However, it's important to note that polling can increase the load on the CPU and may not be suitable for systems with high-bandwidth communication requirements.

 

""

CAN 폴링은 장치가 버스에서 새 메시지를 반복적으로 확인하는 CAN 버스 액세스 방법입니다. 이는 버스에서 새로운 메시지가 수신될 때 장치가 인터럽트에 의해 알림을 받는 인터럽트 기반 CAN 통신과는 대조적이다.

장치가 CAN 폴링을 사용할 수 있는 몇 가지 이유는 다음과 같습니다:

단순성: 폴링은 버스에 액세스하는 간단한 방법이며 소프트웨어에서 쉽게 구현할 수 있습니다.

낮은 오버헤드: 폴링은 추가 처리 리소스를 소비할 수 있는 인터럽트를 사용할 필요가 없습니다.

전력 효율성: 저전력 애플리케이션에서는 전력 소비를 최소화하는 것이 중요하며, 폴링은 인터럽트 기반 통신에 비해 장치의 전력 소비를 줄일 수 있다.

실시간 성능: 새 메시지에 대한 응답 시간이 중요한 실시간 시스템에서 폴링을 사용할 수 있습니다.

호환성: 폴링은 모든 CAN 컨트롤러와 호환되는 반면, 인터럽트 기반 통신은 일부 컨트롤러에서 지원되지 않을 수 있습니다.

그러나 폴링은 CPU의 부하를 증가시킬 수 있으며 고대역폭 통신 요구사항이 있는 시스템에는 적합하지 않을 수 있습니다.

""

 

CAN Baudrate

Q) tell me about CAN BaudRate deeply

A

)The baud rate of a Controller Area Network (CAN) bus is the speed at which data is transmitted on the bus. It is measured in bits per second (bps) and is typically set during the initialization of the CAN controller. Common baud rates for CAN include 10 kbps, 20 kbps, 50 kbps, 125 kbps, 250 kbps, 500 kbps, and 1 Mbps. The baud rate must be the same for all devices connected to the bus, and it is important that the baud rate is set correctly to ensure proper communication between devices. The baud rate is also a key factor in determining the maximum length of the bus and the maximum number of nodes that can be connected to the bus.

 

""

CAN(Controller Area Network) 버스의 보드 속도는 버스에서 데이터가 전송되는 속도입니다. 이 값은 초당 비트(bps)로 측정되며 일반적으로 CAN 컨트롤러 초기화 중에 설정됩니다. CAN의 일반적인 보드 속도는 10kbps, 20kbps, 50kbps, 125kbps, 250kbps, 500kbps 및 1Mbps입니다. 보드 속도는 버스에 연결된 모든 장치에 대해 동일해야 하며, 장치 간의 적절한 통신을 보장하기 위해 보드 속도를 올바르게 설정하는 것이 중요합니다. 보드 속도는 버스의 최대 길이와 버스에 연결할 수 있는 최대 노드 수를 결정하는 핵심 요소이기도 합니다.

""

 

 

Quiz