F💻W/Coding

Atmega로 UART, SPI 통신 구현

천숭이 2023. 12. 4. 11:31

Atmega8A 칩을 사용해 UART, SPI 통신을 구현할 것입니다.

 

Atmega를 Master칩으로 설정하고, GPIO 핀을 활용해 연결된 Slave칩들의 핀들까지 컨트롤 할 것입니다.

 

따라서 코드를 그대로 적용할 시 작동이 안 될수도 있습니다,,!

 

그리고 데이터 시트에서 기초 통신 코드를 어셈블리코드와 C코드로 간략하게 기술되어 있습니다. 저도 그 코드를 일부 참고해서 작성했으니, 웬만하면 데이터시트를 먼저 참고해주세요 :>

 


 

< 데이터시트 참고해 SPI통신과 UART통신 설정>

 

1. SPI 설정

SPI통신에 필요한 네 개의 핀 확인

 

 

최소한의 기능으로 동작하기 위해서 라이브러리를 사용하지 않고, GPIO핀을 조작해 직접 SPI 구현할 것입니다.

 

SCK, MOSI, MISO, NSS 핀을 위 그림처럼 조작할 것입니다

 

- SPI_MasterInit() : 핀 설정

 

SCK, MOSI, NSS를 Output으로설정하고 MISO핀만 Input으로 설정합니다.

(내장라이브러리를 사용해 SPI를 구현할 것이면, SPCR |= (1<<SPE)|(1<<MSTR); 처럼 SPI 활성화 및 마스터설정을 해줘야 합니다.)

void SPI_MasterInit(void)  // GPIO
{
	// InOut Pin set
	DDRB |= (1<<SCK)|(1<<MOSI)|(1<<NSS);
	DDRB &= ~(1<<MISO); 
}

 

 

- SCK 핀을 1, 0으로 만들어주기 위한 매크로 구현

#define SCK_1		PORTB |= 1<<PORTB5;
#define SCK_0		PORTB &= ~(1<<PORTB5);

 

 

- SPI_Write() : addr 주소에 data 메모리 쓰기 구현

void SPI_WRITE(u8 addr, u8 data)
{
	u8 tmp;
	u8 mask = 0x80;  
    // MSB를 체크하며 1,0값을 핀에 실어서 보낸다
    // 왼쪽으로 쉬프트하면서 데이터를 스캔
	addr = (addr<<1)&0x7F;

	NSS_0  // SPI 통신 시작 - SCK핀에 따라서 동작 진행
    
    // SCK 핀을 올렸다 내렸다 8번 반복하며 MOSI 핀의 addr 데이터가 전송된다
	for (u8 i=0;i<8;i++)
	{
		if (addr & mask) {
			MOSI_1
		}
		else MOSI_0
		addr = addr<<1;
		SCK_1
		SCK_0
	}

	for (u8 i=0;i<8;i++)
    // SCK 핀을 올렸다 내렸다 8번 반복하며 MOSI 핀의 data 데이터가 전송된다
	{
		if (data & mask) {
			MOSI_1
		}
		else MOSI_0
		data = data<<1;
		SCK_1
		SCK_0
	}
    NSS_1

}

 

 

- SPI_READ()

u8 TRH_READ(u8 addr)
{
	u8 tmp;
    // MSB를 체크하며 1, 0값을 핀에 실어서 보낸다
    // 왼쪽으로 쉬프트하면서 데이터를 스캔
	u8 mask = 0x80;
	unsigned char result = 0;
	addr = (addr<<1)|0x80;

	NSS_0  // SPI 통신 시작 - SCK핀에 따라서 동작 진행
	for (u8 i=0;i<8;i++)
	{
		if (addr & mask) {
			MOSI_1
		}
		else {
			MOSI_0
		}
		addr = addr<<1;
		SCK_1
		SCK_0
	}
	
	for (u8 i=0;i<8;i++)
	{
		// 핀에 입력될때, result LSB += 1
		if(PINB & (0x10)) {  // INPUT = PIN!
			result += 0x01;
		}
		SCK_1
		SCK_0
		if (i != 7) result <<= 1;;
	}
	NSS_1
    
	return result;
}

 

 

 

2. UART 설정

UART는 데이터시트를 살펴보면 관련 레지스터가 있습니다.

 

- UBRRH (0x20) : Baud Rate 설정 레지스터

 

아래와 같이 설정하고자 하는 속도를 매크로로 정의했습니다.

#define BAUD 9600
#define MYUBRR FOSC/16/BAUD-1

 

 

- USART_Init() : 통신 속도 설정

 

초기화할때 설정한 MYUBRR을 매개로 실행합니다.     -> USART_Init(MYUBRR);

void USART_Init(unsigned long baud)
{
	UBRRH = (unsigned char)(baud>>8);
	UBRRL = (unsigned char)baud;

	/* Enable receiver and transmitter */
	UCSRB = (1<<RXEN)|(1<<TXEN);
	/* Set frame format: 8data, 2stop bit */
	UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);	
}

 

- USART_Transmit() :

UCSRA라는 Status 레지스터를 통해 UDR 버퍼가 제대로 비워지고 채워졌는지 확인할 수 있습니다.

void USART_Transmit( unsigned char data )
{
	/* Wait for empty transmit buffer */
	while ( !( UCSRA & (1<<UDRE)) )
	/* Put data into buffer, sends the data */
	UDR = data;
}