raspberrypi spi인터페이스mcp3208 adc 및 아날로그 센서 (가변저항, 화염센서,...
Post on 20-Jul-2020
2 Views
Preview:
TRANSCRIPT
RaspberryPi SPI인터페이스 1
제11강
SPI Interface
SPI interface
MCP3208 ADC 및 아날로그 센서
(가변저항, 화염센서, 조도센서, 수분센서, 온도센서, 습도 센서, 적외선거리센서)
DotMatrix 모듈(MAX7219)
SSD1331 OLED(8p, SPI)
RaspberryPi SPI인터페이스 2
SPI 인터페이스
* SPI(serial peripheral interface) 인터페이스
: 한 두 개의 주변장치 간에 직렬통신으로 데이터를
교환할 수 있게 하는 모토롤라사가 개발한 인터페이스
: Full Duplex 방식으로 동작(양방향 동시전송 가)
: 일반적으로 CPU와 주변 디바이스간 통신에 사용
: 프로세서간 통신에도 활용
RaspberryPi SPI인터페이스 3
SPI 인터페이스(계속)
* 디바이스간 연결
: CE0, CE1활용하여 2개까지 연결 가능
신호 wPiBCM_
GPIO기능
SCLK #14 #11 Serial Clock(output from master)
MOSI #12 #10Master Out Slave In(data output from master)
MISO #13 #09Master In Slave Out(data output from slave)
CE0 #10 #08Slave Select(often active low output from master)
CE1 #11 #07 Slave Select(often active low output from master)
RaspberryPi SPI인터페이스 4
SPI 인터페이스(계속)
* SPI 전송모드(4가지 지원)
: CPOL, CPHA의 설정에 따라...
RaspberryPi SPI인터페이스 5
SPI 인터페이스(계속)
* SPI 활성화
$ sudo raspi-config
: 5 Interfacing Options, P4 SPI
$ sudo reboot
RaspberryPi SPI인터페이스 6
SPI 인터페이스(계속)
* SPI 활성화 확인
$ cat /boot/config.txt
dtparam=spi=on kfXjgw
* 두 채널을 위한 디바이스파일
$ $ ls /dev/spi*
/dev/spidev0.0 /dev/spidev0.1
RaspberryPi SPI인터페이스 7
SPI 인터페이스(계속)
* wringPiSPI.h 라이브러리
: SPI 통신을 위한 함수 제공
: 초기화 함수로 채널과 통신속도 설정int wiringPiSPISetupMode(int channel, int speed, int mode);
int wiringPiSPISetup(int channel, int speed); // mode 0로
: 슬레이브와 데이터 기록과 판독을 동시에 하는 함수int wiringPiSPIDataRW(int channel, unsigned char *data, int len);
: 파일기술자 확보 함수int wiringPiSPIGetFd(int channel);
RaspberryPi SPI인터페이스 8
MCP3208 ADC
* MCP3208 ADC .. 8ch, 12bit
: MCP3208 ADC의 핀구조 및 그 기능
RaspberryPi SPI인터페이스 9
MCP3208 ADC(계속)
* 채널 선택 제어 비트
: Single/Diff, 채널주소(D2, D1, D0)
RaspberryPi SPI인터페이스 10
MCP3208 ADC(계속)
* MCP3208 전송 데이터 포맷
: 3바이트로 구성
uint8_t buf[3];
buf[0] = 0x06 | ((aChAddr & 0x07) >> 2); // 0000_0 st sgl/di D2
buf[1] = ((aChAddr & 0x07) << 6); // D1 D0 00_0000
buf[2] = 0x00; // 0000_0000
RaspberryPi SPI인터페이스 11
MCP3208 ADC(계속)
* 전체적인 통신 절차
: 데이터의 기록 및 판독이 동시에 이루어짐(쉬프트방식)
RaspberryPi SPI인터페이스 12
MCP3208 ADC(계속)
* MCP3208 송수신후
: 2번째바이트 하위니블과 3번째바이트에 수신 데이터
: AD변환결과 조합
buf[1] = 0x0F & buf[1]; // masking lower nibble
val = (buf[1] << 8) | buf[2]; // 12 bits by concatenation
RaspberryPi SPI인터페이스 13
ADC 변환
[실습1] 가변저항 출력을 ADC I
:회로도 (CH0에 가변저항의 출력단 연결)
$ sudo nano spiMCP3208_01.c
//=======================================
// spiMCP3208_01.c
// MCP3208 + sensors
// CH0 : VR
// CH1 : Flame sensor
// CH2 : CDS sensor
RaspberryPi SPI인터페이스 14
// CH3 : moisture sensor
// CH4 : temperature sensor
// CH5 : humidity sensor
// CH6 : Infrared distance sensor
//=======================================
#include <stdio.h>
#include <stdint.h>
#include <wiringPi.h>
#include <wiringPiSPI.h> // SPI interface
#define P_MCP_CLK 14 // BCM_GPIO #11, SCLK, 연결
#define P_MCP_DIN 12 // BCM_GPIO #10, MOSI, 연결
#define P_MCP_DOUT 13 // BCM_GPIO #09, MISO, 연결
#define P_MCP_CS0 10 // BCM_GPIO #08, CE0, 연결
#define SPI_CHAN_0 0 // slave channel select 0
#define P_MCP_CS1 11 // BCM_GPIO #07, CE1
#define SPI_CHAN_1 1 // slave channel select 1
#define SPI_SPEED 1000000 // 1MHz int
// analog sensor list
RaspberryPi SPI인터페이스 15
enum analogSensor {VR=0, FLAME, CDS, MOIST, TEMP, HUMI, IRD};
// function prototype
int readMCP3208(int fd, uint8_t analogCh);
int main(void) {
enum analogSensor analogCh;
int fd;
int val;
printf("[SPI MCP3208 + sensors testing...]\n");
if(wiringPiSetup() == -1) {
return 1;
}
if((fd = wiringPiSPISetup(SPI_CHAN_0, SPI_SPEED)) == -1) {
return 1;
}
analogCh = VR; // VR
//analogCh = FLAME; // flame sensor
RaspberryPi SPI인터페이스 16
//analogCh = CDS; // CDS sensor
//analogCh = MOIST; // moisture sensor
//analogCh = TEMP; // temperature sensor
//analogCh = HUMI; // humidity sensor
//analogCh = IRD; // infrared distance sensor
while(1) {
val = readMCP3208(fd, analogCh);
printf("analogCh_%d Val = %d\n", analogCh, val);
delay(1000);
}
return 0;
}
int readMCP3208(int fd, uint8_t analogCh) {
uint8_t buf[3];
int val;
buf[0] = 0x06 | ((analogCh & 0x07) >> 2);
// 0000 0 start single D2
RaspberryPi SPI인터페이스 17
buf[1] = ((analogCh & 0x07) << 6); // D1 D0 00 0000
buf[2] = 0x00; // 0000 0000
wiringPiSPIDataRW(fd, buf, 3);
//wiringPiSPIDataRW(P_MCP_DIN, buf, 3);
buf[1] = 0x0F & buf[1]; // masking lower nibble
val = (buf[1] << 8) | buf[2]; // make 12 bits by concatnation
return val;
}
$ make spiMCP3208_01
$ ./spiMCP3208_01
RaspberryPi SPI인터페이스 18
ADC 변환(계속)
[실습2] 화염센서 출력을 ADC
: YG1006 화염센서 및 회로(CH1에 화염센서 출력단 연결)
: [실습1] 소스 활용 ... 채널선택부분 수정
$ sudo nano spiMCP3208_01.c
.....
//aChAddr = VR; // VR
aChAddr = FLAME; // flame sensor
//aChAddr = CDS; // CDS sensor
......
RaspberryPi SPI인터페이스 19
ADC 변환(계속)
[실습3] 조도센서 출력을 ADC
: 조도센서 및 회로(CH2에 조도센서 출력단 연결)
: [실습1] 소스 활용
RaspberryPi SPI인터페이스 20
ADC 변환(계속)
[실습4] 수분센서 출력을 ADC
: 수분센서 및 회로(CH3에 수분센서 출력단 연결)
:[실습1] 소스 활용
RaspberryPi SPI인터페이스 21
ADC 변환(계속)
[실습5] 온도 및 습도센서 출력을 ADC
:온/습도센서(CHIPCAP-L) 및 회로
(CH4에 온도센서, CH5에 습도센서 출력단 연결)
(pin#1: VCC, pin#2: GND, pin#3:습도센서, pin#4: 온도센서)
:[실습1] 소스 활용
RaspberryPi SPI인터페이스 22
ADC 변환(계속)
[실습6] 적외선거리센서 출력을 ADC
:SHARP 2Y0A21 적외선거리센서(10~30cm의 거리 측정)
:회로 연결 (CH6 채널과 연결)
:[실습1] 소스 활용
:유의) 거리변환식에서 수학함수(math.h) 사용시
–lm 옵션붙여 컴파일
$ gcc –o spiMCP3208_01 spiMCP3208_01.c –lwringPi –lm
RaspberryPi SPI인터페이스 23
도트매트릭스 모듈
* MAX7219 장착된 모듈
: SPI 통신 방식으로 제어 가능
: 회로도
: SPI 인터페이스 단자와의 연결
SCLK(CLK), MOSI(DIN), CE0(CS)
RaspberryPi SPI인터페이스 24
도트매트릭스 모듈(계속)
* SPI 데이터 전송포맷
: 2바이트로 구성
: 첫 번째 바이트(레지스터주소)
: 두 번째 바이트(패턴데이터)
void MAX7219_WRITE(uint8_t address, uint8_t data) {
uint8_t buf[2];
buf[0] = address;
buf[1] = data;
digitalWrite(P_MAX_CE0, LOW);
wiringPiSPIDataRW(P_MAX_MOSI, buf, 2);
digitalWrite(P_MAX_CE0, HIGH);
}
RaspberryPi SPI인터페이스 25
도트매트릭스(계속)
[실습7] 도트매트릭스 제어 I
: SPI를 이용하여 제어
: 최소한의 회로 연결은 SCLK, MOSI, CE0만 연결하여 구성
$ nano spiDotMtx_01.c
//=======================================// spiDotMtx_01.c// using SPI interface//=======================================#include <stdio.h>#include <stdint.h>#include <wiringPi.h>#include <wiringPiSPI.h> // SPI interface
#define P_MAX_SCLK 14 // BCM_GPIO #11, 연결#define P_MAX_MOSI 12 // BCM_GPIO #10, 연결#define P_MAX_MISO 13 // BCM_GPIO #9
RaspberryPi SPI인터페이스 26
#define P_MAX_CE0 10 // BCM_GPIO #8, 연결#define SPI_CHAN_0 0 // slave channel select 0
#define P_MAX_CE1 11 // BCM_GPIO #7
#define SPI_SPEED 1000000 // 1MHz int
const uint8_t image[] = { // 5x8 font0x1E, 0x12, 0x1E, 0x00, 0x04, 0x07, 0x04, 0x04, //마0x09, 0x15, 0x09, 0x01, 0x01, 0x01, 0x01, 0x01, //이0x1F, 0x01, 0x07, 0x01, 0x00, 0x1F, 0x00, 0x00, //크0x1F, 0x01, 0x1F, 0x10, 0x1F, 0x00, 0x04, 0x1F, //로0x1F, 0x0A, 0x0A, 0x1F, 0x00, 0x1F, 0x00, 0x00, //프0x1F, 0x01, 0x1F, 0x10, 0x1F, 0x00, 0x04, 0x1F, //로0x04, 0x0A, 0x11, 0x00, 0x05, 0x1D, 0x05, 0x05, //세0x04, 0x0A, 0x11, 0x00, 0x01, 0x1F, 0x01, 0x01 //서
};
const uint8_t allOff[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// function prototypevoid setup(void);void MAX7219_INIT(void);void MAX7219_WRITE(uint8_t address, uint8_t data);
int main(void) {
RaspberryPi SPI인터페이스 27
int i, j;
printf("[Dot Matrix testing....]\n");
if(wiringPiSetup() == -1)return 1;
if(wiringPiSPISetup(SPI_CHAN_0, SPI_SPEED) == -1) {return 1;
}
setup();
for(j=0; j<8; j++) { for(i=0; i<8; i++) {
MAX7219_WRITE(i+1, *(image+j*8+i));}delay(1000);
}
for(i=0; i<8; i++) {MAX7219_WRITE(i+1, *(allOff + i));
}delay(1000);
return 0;}
RaspberryPi SPI인터페이스 28
void setup(void) { pinMode(P_MAX_CS0, OUTPUT);
MAX7219_INIT();}
void MAX7219_INIT(void) { MAX7219_WRITE(0x09, 0x00);
// Decode Mode : no decode mode all digits(0x00) MAX7219_WRITE(0x0A, 0x0F);
// Intensity(0x00~0x0F) : max(0x0F) MAX7219_WRITE(0x0B, 0x07);
// Scan Limit : Digit 0 ~ Digit 7,(0x07) MAX7219_WRITE(0x0C, 0x01); // Shutdown : Normal(0x01)}
void MAX7219_WRITE(uint8_t address, uint8_t data) { uint8_t buf[2];
buf[0] = address; // MAX7219 register address buf[1] = data; // pattern data
digitalWrite(P_MAX_CS0, LOW); wiringPiSPIDataRW(P_MAX_DIN, buf, 2); digitalWrite(P_MAX_CS0, HIGH);}
RaspberryPi SPI인터페이스 29
$ make spiDotMtx_01
$ ./spiDotMtx_02
RaspberryPi SPI인터페이스 30
도트매트릭스(계속)
[실습8] 도트매트릭스 제어 II
: SPI를 이용하여 제어
: 상하좌우 스크롤링 효과를 수행하는 프로그램
$ nano spiDotMtx_02.c
//=======================================// spiDotMtx_02.c// using SPI interface// MAX7219 driver, scrolling//=======================================#include <stdio.h>#include <stdint.h>#include <wiringPi.h>#include <wiringPiSPI.h> // SPI interface
#define P_MAX_CLK 14 // BCM_GPIO #11, SCLK, 연결#define P_MAX_DIN 12 // BCM_GPIO #10, MOSI, 연결#define P_MAX_DOUT 13 // BCM_GPIO #9, MISO#define P_MAX_CS0 10 // BCM_GPIO #8, CE0, 연결
RaspberryPi SPI인터페이스 31
#define SPI_CHAN_0 0
#define P_MAX_CS1 11 // BCM_GPIO #7, CE1
#define SPI_SPEED 1000000 // 1MHz int
const uint8_t image[] = { // 5x8 font 0x1E, 0x12, 0x1E, 0x00, 0x04, 0x07, 0x04, 0x04, //마 0x09, 0x15, 0x09, 0x01, 0x01, 0x01, 0x01, 0x01, //이 0x1F, 0x01, 0x07, 0x01, 0x00, 0x1F, 0x00, 0x00, //크 0x1F, 0x01, 0x1F, 0x10, 0x1F, 0x00, 0x04, 0x1F, //로/* 0x1F, 0x0A, 0x0A, 0x1F, 0x00, 0x1F, 0x00, 0x00, //프 0x1F, 0x01, 0x1F, 0x10, 0x1F, 0x00, 0x04, 0x1F, //로 0x04, 0x0A, 0x11, 0x00, 0x05, 0x1D, 0x05, 0x05, //세 0x04, 0x0A, 0x11, 0x00, 0x01, 0x1F, 0x01, 0x01 //서*/ 0x00,0x18,0x3C,0x7E,0x3C,0x3C,0x3C,0x00, // left 0x00,0x3C,0x3C,0x3C,0x7E,0x3C,0x18,0x00, // right 0x00,0x10,0x3E,0x7E,0x7E,0x3E,0x10,0x00, // up 0x00,0x08,0x7C,0x7E,0x7E,0x7C,0x08,0x00 // down};
const uint8_t allOff[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t buf[8];
RaspberryPi SPI인터페이스 32
// function prototypevoid setup(void);void MAX7219_INIT(void);void MAX7219_WRITE(uint8_t address, uint8_t data);void shift_left(uint8_t *array);void shift_right(uint8_t *array);void shift_up(uint8_t *array);void shift_down(uint8_t *array);
int main(void) { int i, j; int k = 17;
printf("[Dot Matrix testing....]\n");
if(wiringPiSetup() == -1) return 1;
if(wiringPiSPISetup(SPI_CHAN_0, SPI_SPEED) == -1) { return 1; }
setup();
for(j=0; j<8; j++) { for(i=0; i<8; i++) { MAX7219_WRITE(i+1, *(image+j*8+i));
RaspberryPi SPI인터페이스 33
} delay(1000); }
for(i=0; i<8; i++) { MAX7219_WRITE(i+1, *(allOff + i)); } delay(1000);
// scrolling for(i=0; i<8; i++) // memcopy() buf[i] = image[i];
while(k--) { for(i=0; i<8; i++) { MAX7219_WRITE(i+1, *(buf+i)); } delay(100); shift_left(buf); // } delay(1000);
return 0;}
void setup(void) { pinMode(P_MAX_CS0, OUTPUT);
RaspberryPi SPI인터페이스 34
MAX7219_INIT();}
void MAX7219_INIT(void) { MAX7219_WRITE(0x09, 0x00);
// Decode Mode : no decode mode all digits(0x00) MAX7219_WRITE(0x0A, 0x0F);
// Intensity(0x00~0x0F) : max(0x0F) MAX7219_WRITE(0x0B, 0x07);
// Scan Limit : Digit 0 ~ Digit 7,(0x07) MAX7219_WRITE(0x0C, 0x01); // Shutdown : Normal(0x01)}
void MAX7219_WRITE(uint8_t address, uint8_t data) { uint8_t buf[2];
buf[0] = address; // MAX7219 register address buf[1] = data; // pattern data
digitalWrite(P_MAX_CS0, LOW); wiringPiSPIDataRW(P_MAX_DIN, buf, 2); digitalWrite(P_MAX_CS0, HIGH);}
void shift_left(uint8_t *array) { uint8_t temp; int i;
RaspberryPi SPI인터페이스 35
temp = array[0]; for(i=0; i<7; i++) { array[i] = array[i+1]; } array[7] = temp;}
void shift_right(uint8_t *array) { uint8_t temp; int i;
temp = array[7]; for(i=7; i>0; i--) { array[i] = array[i-1]; } array[0] = temp;}
void shift_up(uint8_t *array) { uint8_t temp; int i;
for(i=0; i<8; i++) { temp = array[i] & 0x80; array[i] <<= 1; array[i] |= (temp >> 7); }}
RaspberryPi SPI인터페이스 36
void shift_down(uint8_t *array) { uint8_t temp; int i;
for(i=0; i<8; i++) { temp = array[i] & 0x01; array[i] >>= 1; array[i] |= (temp << 7); }}
$ make spiDotMtx_02
$ ./spiDotMtx_02
RaspberryPi SPI인터페이스 37
응용과제
[응용1] AD 변환
: MCP3208 ADC
: 온습도센서, 적외선거리센서의 데이터를 실용성있게 재 표현
(변환식 활용)
RaspberryPi SPI인터페이스 38
RaspberryPi SPI인터페이스 39
OLED 모듈
* SSD1331 OLED 모듈 (SPI 방식)
참조)
http://blog.naver.com/PostView.nhn?blogId=chandong83&logNo=2209
17471910
RaspberryPi SPI인터페이스 40
GND - GND #6
VCC - 3.3V #1
SCL - BCM11 #23
SDA - BCM10 #19
RES - BCM25 #22
DC - BCM24 #18
CS - BCM23 #16
python 소스
import datetimeimport timeimport math
RaspberryPi SPI인터페이스 41
#pin 설정SSD1331_PIN_CS = 23SSD1331_PIN_DC = 24SSD1331_PIN_RST = 25
if __name__ == '__main__': # 라이브러리 로드 device = SSD1331.SSD1331(SSD1331_PIN_DC, SSD1331_PIN_RST, SSD1331_PIN_CS) try: # OLED 활성화 device.EnableDisplay(True) # 화면 지우기 device.Clear() today_last_time = "Unknown"
# 무한 반복 while True: # 현재 날짜/시간 얻어오기 my_now = datetime.datetime.now()
# 현재 날짜를 알아보기 좋게 문자열로 변환 today_date = my_now.strftime("%Y-%B-%d %A")
# 현재 시간을 알아보기 좋게 문자열로 변환 today_time = my_now.strftime("%H:%M")
RaspberryPi SPI인터페이스 42
# 현재 시간과 최종 시간이 같지 않다면? if today_time != today_last_time: # 화면 지우기 device.Clear() # 0.01초 대기 10ms time.sleep(0.01) # 시 각도 계산 hours_angle = 270 + (30 * (my_now.hour + (my_now.minute / 60.0))) hours_dx = int(math.cos(math.radians(hours_angle)) * 12) hours_dy = int(math.sin(math.radians(hours_angle)) * 12)
# 분 각도 계산 minutes_angle = 270 + (6 * my_now.minute) minutes_dx = int(math.cos(math.radians(minutes_angle)) * 18) minutes_dy = int(math.sin(math.radians(minutes_angle)) * 18)
# 원 그리기 중심점 x, y, 지름, 색상 device.DrawCircle(30, 32, 20, SSD1331.COLOR_WHITE)
# 선그리기 시작점 x, y, 끝점 x, y, 색상 # 시선 그리기 device.DrawLine(30, 32, 30 + hours_dx, 32 + hours_dy,
RaspberryPi SPI인터페이스 43
SSD1331.COLOR_WHITE) # 분선 그리기 device.DrawLine(30, 32, 30 + minutes_dx, 32 + minutes_dy, SSD1331.COLOR_WHITE) # 문자열 쓰기 x, y, 문자열, 색상 device.DrawString(60, 28, today_time, SSD1331.COLOR_WHITE)
# 시간 갱신 today_last_time = today_time
# 0.5초 대기 500ms time.sleep(0.5)
finally: #종료시 ctrl+c # OLED 비활성화 device.EnableDisplay(False)
# 라이브러리 제거 device.Remove()
top related