+ 한국항공대학교 최차봉 교수님의 임베디드 SW 과목 내용을 정리한 글입니다.
< 첫 번째 실습: Counter 값 주고 받기 >
SPI를 이용하여 Master / Slave를 제작하라.
2명이 한 조가 되어 Master 1대, Slave 1대로 실습한다.
< Master >
Serial Monitor에서 명령을 받아 Slave로 전송한다.- 't' 명령을 입력 받아 Slave에 전송한다.- 동시에 Slave에서 한 Time 이전의 데이터를 입력 받고 Serial Monitor에 출력한다.
< Slave >Master에서 't'명령을 받으면 현재 Counter 값을 Master에 전송한다.- 매 초마다 1씩 증가하는 Counter를 유지한다.- ISR (Interrupt Service Routine)을 사용하여 데이터를 수신한다.- Master에 전송한 Counter 값을 Serial Monitor에 출력한다.- Counter의 Update는 loop에서 수행한다.
< Master >
#include <SPI.h>
#define SS 10
void setup(){
Serial.begin (9600);
digitalWrite(SS, HIGH); // SS의 초기 값을 HIGH로 설정
SPI.begin(); // SPI 통신 초기화
// 속도가 빠른 경우 데이터가 정확히 전달되지 않으므로 분주비를 높여 전송속도 감소
SPI.setClockDivider(SPI_CLOCK_DIV8);
}
byte transferAndWait(const byte what){
byte a = SPI.transfer(what);
// SPDR에 있던 값을 a에 저장(수신)하고, what을 SPDR에 저장(송신)한다.
delayMicroseconds(20);
return a;
}
void loop(){
if(Serial.available()){
byte c = Serial.read();
if(c == 't'){
digitalWrite(SS, LOW); // SS와 통신을 위해 LOW로 설정
byte a = transferAndWait(c);
digitalWrite(SS, HIGH); // 통신이 끝났으므로 HIGH로 설정
Serial.println(a);
}
}
}
< Slave >
#include <SPI.h>
byte count = 0;
void setup(){
Serial.begin(9600);
pinMode(SCK, INPUT);
// 13번 포트: Clock 신호를 Master에서 받으므로 INPUT
pinMode(MISO, OUTPUT);
// 12번 포트: 데이터를 Slave에서 Master로 송신하므로 OUTPUT
pinMode(MOSI, INPUT);
// 11번 포트: 데이터를 Master에서 Slave로 수신하므르 INPUT
pinMode(SS, INPUT);
// 10번 포트: 몇 번 Slave를 선택했는지를 입력 받으므로 INPUT
// SPCR: SPI 제어 레지스터
SPCR |= _BV(SPE);
// _BV: 비트 값 설정 함수
// SPE: SPI 비트 활성화
// SPCR 레지스터의 SPE 비트를 1로 설정하여 SPI 통신 활성화
SPCR &= ~_BV(MSTR);
// Master -> Slave로 설정
SPCR |= _BV(SPIE);
// SPIE: SPI 인터럽트 활성화
// SPCR 레지스터의 SPIE 비트를 1로 설정하여 SPI 인터럽트 활성화
SPI.setClockDivider(SPI_CLOCK_DIV8);
// Clock 속도 낮추기
}
// 데이터 수신 인터럽트 발생 시 호출되는 함수
ISR(SPI_STC_vect){
byte c = SPDR; // SPDR 8비트 레지스터에 있는 데이터 수신
if(c == 't'){
byte d = count; // 도중에 count가 증가될 수 있으므로 저장 후 전달한다.
SPDR = d; // SPDR 레지스터에 데이터 저장 (송신)
Serial.println(d);
}
}
void loop(){
count++;
delay(1000);
}
< 두 번째 실습: LED Blink 횟수 제어하기 >
SPI를 이용하여 Master / Slave를 제작하라.
3명이 한 조가 되어 Master 1대, Slave 2대로 실습한다.
< Message Format >
'#' + <id> + <bn> (3 Byte ASCII)
- <id>: <bn>을 전송할 Slave id이다. '0' 또는 '1'이다.
- <bn>: LED Blink 횟수이다. '0'~'9'이다.
< Master >
Serial Monitor에서 Message를 받아 Slave로 <bn>을 전송한다.
< Slave >
Master에서 전송 받은 <bn>만큼 LED를 점등한다.
- ACK를 만들어 Master에 전송한다.
- ACK = <bn> + <id>
< Master >
#include <SPI.h>
#define CS0 10
#define CS1 9
void setup(){
Serial.begin (9600);
pinMode(CS0, OUTPUT); // CS0과 연결된 pin10을 출력으로 설정
pinMode(CS1, OUTPUT); // CS1과 연결된 pin9을 출력으로 설정
digitalWrite(CS0, HIGH); // CS0의 초기 값을 HIGH로 설정
digitalWrite(CS1, HIGH); // CS1의 초기 값을 HIGH로 설정
SPI.begin();
SPI.setClockDivider(SPI_CLOCK_DIV8);
}
byte transferAndWait(const byte what){
byte a = SPI.transfer(what);
delayMicroseconds(20);
return a;
}
void loop(){
if(Serial.available()){
if(Serial.read() == '#'){
while(!Serial.available());
byte id = Serial.read();
while(!Serial.available());
byte n = Serial.read();
if(id == '0'){
digitalWrite(CS0, LOW); // 슬레이브 선택
int ACK = transferAndWait(n); // 1 Byte 데이터 전송 + 수신
Serial.print("Send '");
Serial.print(n - '0');
Serial.println("' to Slave 0");
digitalWrite(CS0, HIGH); // 슬레이브 선택 해제
Serial.print("ACK: '");
Serial.print(ACK);
Serial.println("'");
}
else if(id == '1'){
digitalWrite(CS1, LOW); // 슬레이브 선택
int ACK = transferAndWait(n); // 1 Byte 데이터 전송 + 수신
Serial.print("Send '");
Serial.print(n - '0');
Serial.println("' to Slave 1");
digitalWrite(CS1, HIGH); // 슬레이브 선택 해제
Serial.print("ACK: '");
Serial.print(ACK);
Serial.println("'");
}
}
}
}
< Slave 0 >
#include <SPI.h>
bool iflag = 0;
byte rd = 0;
void setup(){
Serial.begin(9600);
pinMode(7, OUTPUT);
pinMode(SCK, INPUT);
pinMode(MISO, OUTPUT);
pinMode(MOSI, INPUT);
pinMode(SS, INPUT);
SPCR |= _BV(SPE);
SPCR &= ~_BV(MSTR);
SPCR |= _BV(SPIE);
SPI.setClockDivider(SPI_CLOCK_DIV8);
}
ISR(SPI_STC_vect){
iflag = 1;
byte n = SPDR;
rd = n;
SPDR = rd - '0';
Serial.println("Interrupt");
}
void loop(){
if(iflag) {
iflag = 0;
int no = rd - '0';
Serial.print("No: ");
Serial.println(no);
rd = 0;
if(no > 0 && no < 10){
for(int i = 0; i < no; i++){
digitalWrite(7, HIGH);
delay(500);
digitalWrite(7, LOW);
delay(500);
}
}
}
}
< Slave 1 >
#include <SPI.h>
bool iflag = 0;
byte rd = 0;
void setup(){
Serial.begin(9600);
pinMode(7, OUTPUT);
pinMode(SCK, INPUT);
pinMode(MISO, OUTPUT);
pinMode(MOSI, INPUT);
pinMode(SS, INPUT);
SPCR |= _BV(SPE);
SPCR &= ~_BV(MSTR);
SPCR |= _BV(SPIE);
SPI.setClockDivider(SPI_CLOCK_DIV8);
}
ISR(SPI_STC_vect){
iflag = 1;
byte n = SPDR;
rd = n;
SPDR = (rd - '0') + 1;
Serial.println("Interrupt");
}
void loop(){
if(iflag) {
iflag = 0;
int no = rd - '0';
Serial.print("No: ");
Serial.println(no);
rd = 0;
if(no > 0 && no < 10){
for(int i = 0; i < no; i++){
digitalWrite(7, HIGH);
delay(500);
digitalWrite(7, LOW);
delay(500);
}
}
}
}
'Computer Science > Embedded Software' 카테고리의 다른 글
[Embedded Software] SPI Communication (0) | 2023.10.18 |
---|---|
[Embedded Software] UART Communications 실습 (0) | 2023.10.11 |
[Embedded Software] Serial Communications (0) | 2023.10.11 |
[Embedded Software] PWM 실습 (1) | 2023.10.05 |
[Embedded Software] Interrupt 실습 (0) | 2023.09.27 |