2019. 7. 12. 22:34ㆍavr-atmega128
모토롤라에서 개발한 근거리용 통신규격 MCU나 주변장치와 직렬 통신을 위한 규격.
4개의 신호선으로 구성

I2C(TWI)와 비교하면 비교적 덜복잡한 편이다(?)
일반적으로 1 byte로 데이터가 전송되지만 딱히 얼마를 보내라고 실제로 정해져있지않고 /SS의 조정 타이밍, bit전송순서도 규정되어 있지않아 비교적 자유로은 통신방식에 속한다
ATmega128 의 SPI 신호선
PB7(SCK, Serial Clock)
PB6(MISO, Master Input Slave Output)
PB5(MOSI, Master Output Slave Input)
PB4(/ss, Slave Select)
SPCR, SPSR. SPDR3가지 register로 제어
SCK의 파형과 샘플링 시점을 제어하는데는 4가지 방법이 있으며 통신하고자하는 대상과 맞춰서 사용하면된다.
CPOL CPHA SPI mode
0 0 0
0 1 1
1 0 2
1 1 3

1.CPOL=0, CPHA=0
leading edge는 rising edge이며 leading edge에서 sampling이 일어난다.
2.CPOL=0, CPHA=0
leading edge는 rising edge이며 trailing edge에서 sampling이 일어난다.
3.CPOL=1, CPHA=0
leading edge는 falling edge이며 leading edge에서 sampling이 일어난다.
4.CPOL=1, CPHA=1
leading edge는 falling edge이며 triling edge에서 sampling이 일어난다.
lis3lv02dq 3축가속도 센서를 이용한 spi통신

PB0 <-> CS
PB1 <-> SCL
PB2 <-> SDA
PB3 <-> SDO 로 연결하면 된다.
해당내용은 atmega128이 master모드로 동작한다는 가정하에 작성한 내용입니다.
atmega128과 li3lv02dq의 datasheet의 SPI통신내용을 참조
#include <avr/io.h>
#include <avr/signal.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define F_CPU 16000000UL
#define OUTX_L 0x28
#define OUTX_H 0x29
#define OUTY_L 0x2a
#define OUTY_H 0x2b
#define OUTZ_L 0x2c
#define OUTZ_H 0x2d
#define GAIN_X 0x19
#define GAIN_Y 0x1a
#define GAIN_Z 0x1b
#define SPI_CS_LOW() PORTB &=0
#define SPI_CS_HIGH() PORTB |=1
void Putch0(char data)
{
while(!(UCSR1A & 0x20));
UDR1 = data;
}
char Getch0(void)
{
while(!(UCSR1A & 0x80));
return UDR1;
}
unsigned char Accel_Read_Reg(unsigned char reg_data)//이하동작은 비슷하나 읽기 동작을 수행해야하기때문에 reg_data전송시 MSB를 1로 지정해줘야한다.(lis3lv02dq datasheet참조)
{
unsigned char ret_data =0;
SPI_CS_LOW();
SPDR = 0x80|reg_data; // MSB를 1로 set시켜서 read동작을 수행하도록함.
while(!(SPSR & 0x80));
ret_data = SPDR; //받아오지않으면 사라짐으로 주의
SPDR = 0;
while(!(SPSR & 0x80));
ret_data = SPDR;
SPI_CS_HIGH();
return ret_data;
}
void Accel_Write_Reg(unsigned char reg_data, unsigned char data_write){
SPI_CS_LOW(); // CS를 LOW로 내리면서 SPI통신을 시작(단, 이때 HW적으로 자동적으로 내려주지 않기때문에 사용자가 SW적으로 직접내려줘야한다.
SPDR = reg_data; // data를 SPDR에 load
while(!(SPSR & 0x80)); // 센서로 전송이 끝나면 SPIF가 set(이때 SPIE를 set시켰다면 interrupt루틴을 실행하게 된다.)
SPDR = data_write; // 다음 전송될 byte는 어떻게 처리되는지 lis3lv02dq의 datasheet를 참조. reg_data의 data값을 쓰게된다.
while(!(SPSR & 0x80));// write동작완료시 SPIF가 set
SPI_CS_HIGH(); //통신종료
}
void UART_initialize(void)
{
UCSR1A = 0x0;
UCSR1B = 0b00011000;
UCSR1C = 0b00000110;
UBRR1H = 0;
UBRR1L = 8;
}
int main(void)
{
signed short accelx, accely, accelz;
float x_f, y_f, z_f;
FILE *fp;
fp = fdevopen(Putch0, Getch0);
DDRA=0xff;
UART_initialize();
printf("start");
//intialize SPI
DDRB=0xf7;
SPI_CS_HIGH();
SPCR=0x50; //atmega128 SPI초기설정
Accel_Write_Reg(0x20,0xc7);
while(1)
{
PORTA=0xff;
_delay_ms(100);
accelx = Accel_Read_Reg(OUTX_L);
accelx |= Accel_Read_Reg(OUTX_H)<<8;
accely =Accel_Read_Reg(OUTY_L);
accely |=Accel_Read_Reg(OUTY_H)<<8;
accelz =Accel_Read_Reg(OUTZ_L);
accelz |=Accel_Read_Reg(OUTZ_H)<<8;
x_f = (float)accelx*0.0923;
y_f = (float)accely*0.0923;
z_f = (float)accelz*0.0923;
printf("\n\r [X]=%3.2f, [Y]=%3.2f, [Z]=%3.2f", x_f, y_f, z_f);
PORTA=0x00;
_delay_ms(100);
}
}
출처
그리고 혹시... stk500을 이용해서 In System Programming을 할때 갑자기 동작을 하지않을때는 애꿎은 장비탓 하지말고 USB드라이버를 지웠다가 다시 설치해보시기바랍니다.
'avr-atmega128' 카테고리의 다른 글
Analog To Digital Converter (0) | 2019.11.02 |
---|---|
16bit Timer/Counter (0) | 2019.10.25 |
8bit Timer/Counter (0) | 2019.10.25 |
외부인터럽트 (0) | 2019.10.22 |
직렬통신 (0) | 2019.10.18 |