AT89C51 마이크로컨트롤러에서 SPI(Serial Peripheral Interface)를 비트뱅 방식으로 구현한 C 코드를 소개합니다. 이 코드는 SCLK, MOSI, MISO, SS 라인을 소프트웨어로 제어하며, SPI 모드(0~3)를 사용자가 선택할 수 있도록 설계되었습니다. 8051 기반 SPI 통신을 배우는 초보자부터 고급 개발자까지 활용 가능한 예제입니다.
키워드: 8051 SPI, AT89C51, 비트뱅, SPI 모드 선택, 마이크로컨트롤러 통신
1. 하드웨어 설정
- 마이크로컨트롤러: AT89C51 (8051 기반)
- SPI 핀:
- SCLK: P2.0 (클럭)
- MOSI: P2.1 (마스터 출력, 슬레이브 입력)
- MISO: P2.2 (마스터 입력, 슬레이브 출력)
- SS: P2.3 (슬레이브 선택)
- 컴파일러: Keil uVision 또는 SDCC
- 속도: 약 100kHz (비트뱅 방식, 대략적 타이밍)
- SPI 모드:
- Mode 0: CPOL=0, CPHA=0 (SCLK 기본 LOW, 첫 번째 에지 샘플링)
- Mode 1: CPOL=0, CPHA=1 (SCLK 기본 LOW, 두 번째 에지 샘플링)
- Mode 2: CPOL=1, CPHA=0 (SCLK 기본 HIGH, 첫 번째 에지 샘플링)
- Mode 3: CPOL=1, CPHA=1 (SCLK 기본 HIGH, 두 번째 에지 샴플링)
참고: SPI 모드는 슬레이브 장치 데이터시트에 따라 설정하세요.
2. SPI 비트뱅 코드
아래는 AT89C51에서 SPI 비트뱅을 구현한 C 코드로, 모드 선택 기능을 포함합니다.
#include <reg51.h> // AT89C51 헤더 파일
#include <intrins.h> // _nop_() 함수를 위한 헤더
// SPI 핀 정의
sbit SCLK = P2^0; // SCLK: 클럭 (P2.0)
sbit MOSI = P2^1; // MOSI: 마스터 출력 (P2.1)
sbit MISO = P2^2; // MISO: 마스터 입력 (P2.2)
sbit SS = P2^3; // SS: 슬레이브 선택 (P2.3)
// SPI 모드 설정 구조체
typedef struct {
bit cpol; // 클럭 폴리티 (0: LOW, 1: HIGH)
bit cpha; // 클럭 페이즈 (0: 첫 번째 에지, 1: 두 번째 에지)
} SPI_Mode;
// 전역 SPI 모드 변수
SPI_Mode spi_mode;
// 지연 함수 (타이밍 조정을 위해)
void SPI_Delay(void) {
_nop_(); _nop_(); _nop_(); _nop_(); // 약 5us 지연 (12MHz 클록 기준)
}
// SPI 초기화
void SPI_Init(unsigned char mode) {
// SPI 모드 설정 (0~3)
switch (mode) {
case 0: spi_mode.cpol = 0; spi_mode.cpha = 0; break; // Mode 0
case 1: spi_mode.cpol = 0; spi_mode.cpha = 1; break; // Mode 1
case 2: spi_mode.cpol = 1; spi_mode.cpha = 0; break; // Mode 2
case 3: spi_mode.cpol = 1; spi_mode.cpha = 1; break; // Mode 3
default: spi_mode.cpol = 0; spi_mode.cpha = 0; // 기본값: Mode 0
}
SS = 1; // SS HIGH (슬레이브 비활성화)
SCLK = spi_mode.cpol; // SCLK를 CPOL에 따라 초기화
MOSI = 0; // MOSI 초기화
MISO = 1; // MISO 입력 모드
}
// SPI 바이트 전송 및 수신
unsigned char SPI_Transfer(unsigned char dat) {
unsigned char i, rx_dat = 0;
// 8비트 데이터 전송 및 수신
for (i = 0; i < 8; i++) {
if (spi_mode.cpha == 0) {
// CPHA=0: 첫 번째 에지에서 데이터 설정, 두 번째 에지에서 샘플링
MOSI = (dat & 0x80) ? 1 : 0; // MSB 먼저 설정
dat <<= 1; // 다음 비트로 이동
SCLK = !spi_mode.cpol; // 첫 번째 에지
SPI_Delay();
rx_dat <<= 1; // 수신 데이터 비트 이동
rx_dat |= MISO; // MISO에서 비트 읽기
SCLK = spi_mode.cpol; // 두 번째 에지
SPI_Delay();
} else {
// CPHA=1: 첫 번째 에지에서 샘플링, 두 번째 에지에서 데이터 설정
SCLK = !spi_mode.cpol; // 첫 번째 에지
SPI_Delay();
rx_dat <<= 1; // 수신 데이터 비트 이동
rx_dat |= MISO; // MISO에서 비트 읽기
SCLK = spi_mode.cpol; // 두 번째 에지
SPI_Delay();
MOSI = (dat & 0x80) ? 1 : 0; // MSB 먼저 설정
dat <<= 1; // 다음 비트로 이동
}
}
return rx_dat;
}
// SPI 데이터 쓰기
void SPI_Write(unsigned char device_addr, unsigned char reg_addr, unsigned char data) {
SS = 0; // 슬레이브 활성화
SPI_Delay();
SPI_Transfer(device_addr); // 장치 주소 전송
SPI_Transfer(reg_addr); // 레지스터 주소 전송
SPI_Transfer(data); // 데이터 전송
SS = 1; // 슬레이브 비활성화
SPI_Delay();
}
// SPI 데이터 읽기
unsigned char SPI_Read(unsigned char device_addr, unsigned char reg_addr) {
unsigned char dat;
SS = 0; // 슬레이브 활성화
SPI_Delay();
SPI_Transfer(device_addr | 0x80); // 장치 주소 (읽기: MSB=1)
SPI_Transfer(reg_addr); // 레지스터 주소 전송
dat = SPI_Transfer(0xFF); // 더미 데이터 전송하여 데이터 읽기
SS = 1; // 슬레이브 비활성화
SPI_Delay();
return dat;
}
// 메인 함수
void main(void) {
SPI_Init(0); // SPI 초기화 (Mode 0, 필요 시 0~3으로 변경)
// 예제: SPI 장치에 데이터 쓰기 및 읽기
SPI_Write(0x00, 0x10, 0xAA); // 주소 0x10에 0xAA 쓰기
unsigned char data = SPI_Read(0x00, 0x10); // 주소 0x10에서 데이터 읽기
while (1); // 무한 루프
}
3. 코드 설명
- 핀 정의:
- SCLK(P2.0), MOSI(P2.1), MISO(P2.2), SS(P2.3) 사용. 다른 포트로 변경 가능.
- MISO는 입력 모드로 설정.
- SPI 모드 선택:
- SPI_Mode 구조체로 CPOL(클럭 폴리티)와 CPHA(클럭 페이즈) 정의.
- SPI_Init(mode)에서 0~3 값을 받아 모드 설정 (Mode 0 기본).
- 지연 함수:
- SPI_Delay()는 12MHz 클록 기준 약 5us 지연. 클록 속도에 따라 _nop_() 횟수 조정.
- SPI 전송 함수:
- SPI_Transfer(): CPHA에 따라 데이터 설정/샘플링 타이밍 처리.
- SPI_Write()와 SPI_Read()로 장치 주소, 레지스터 주소, 데이터 처리.
- 메인 함수:
- Mode 0으로 초기화. 다른 모드는 SPI_Init(1~3)으로 변경 가능.
- 예제는 장치 주소 0x00, 레지스터 0x10에 데이터 쓰기/읽기 수행.
4. 주의사항
- 모드 설정: SPI_Init()의 모드 값(0~3)을 슬레이브 장치 데이터시트에 맞게 설정.
- 타이밍 조정: SPI_Delay()는 12MHz 클록 기준. 다른 클록에서는 타이머 사용 권장.
- 슬레이브 주소: SPI는 표준 주소 체계가 없으므로 데이터시트 확인 필수.
- 하드웨어 연결: SS는 슬레이브마다 별도 제어. MISO는 입력 모드.
5. 디버깅 팁
- 오실로스코프 사용: SCLK, MOSI, MISO, SS 신호의 타이밍과 무결성 확인.
- 모드 호환성: SPI 모드가 슬레이브 장치와 맞는지 데이터시트로 점검.
- 시뮬레이터: Keil uVision 디버거로 코드 동작 확인.
6. 관련 자료
- 8051 I2C 비트뱅 코드: I2C 프로토콜 비트뱅 구현.
'MCU > 8051' 카테고리의 다른 글
8051 SPI 비트뱅(bit-bang)을 STM32 HAL API 스타일로 코드 구현 (0) | 2025.08.02 |
---|---|
8051 I2C 비트뱅(bit-bang)를 STM32 HAL API 스타일로 코드 구현 (0) | 2025.08.02 |
8051 I2C 비트뱅(bit-bang) 코드 구현 (0) | 2025.08.02 |