SPI hoặc giao tiếp ngoại vi nối tiếp được Motorola phát triển vào những năm 1980 như một giao diện tiêu chuẩn, chi phí thấp và đáng tin cậy giữa vi điều khiển (Vi điều khiển của Motorola lúc đầu) và các IC ngoại vi của nó.
Nhờ giao diện đơn giản, linh hoạt và dễ sử dụng, SPI đã trở thành một tiêu chuẩn và các nhà sản xuất bán dẫn khác bắt đầu sử dụng giao thức này trong các chip của mình.
Trong giao thức SPI, các thiết bị được kết nối trong một mối quan hệ Master – Slave trong một giao diện đa điểm. Trong loại giao diện này, một thiết bị được coi là Master của bus (thường là một vi điều khiển) và tất cả các thiết bị khác (IC ngoại vi hoặc thậm chí các vi điều khiển khác) đều được coi là Slave.
Trong giao thức SPI, có thể chỉ có một thiết bị Master nhưng nhiều thiết bị Slave.
Bus SPI bao gồm 4 tín hiệu hoặc chân. Chúng là
- Master – Out / Slave – In (MOSI hay SI): cổng ra của bên Master, cổng vào của bên Slave, dành cho việc truyền dữ liệu từ thiết bị Master đến thiết bị Slave .
- Master – In / Slave – Out (MISO hay SO): cổng vào của bên Master, cổng ra của bên Slave, dành cho việc truyền dữ liệu từ thiết Slave đến thiết bị Master.
- Serial Clock (SCK hay SCLK): xung giữ nhịp cho giao tiếp SPI
- Chip Select (CS) hay Slave Select (SS): chọn chip
Code Master (STM32)
#include <Arduino.h>
#include <SPI.h>
#include <HardwareSerial.h>
#define SS PB12
HardwareSerial Serial_Mon(PA10, PA9);
String buff_send = ""; // Biến nhận dữ liệu từ Serial Port
byte buf[2]; // Mảng chứa giá trị analog của Slave gửi lên
bool TransmitControl = false; //Điều khiển quá trình gửi nhận dữ liệu
void setup()
{
Serial_Mon.begin(9600);
pinMode(SS, OUTPUT);
digitalWrite(SS, HIGH);
SPI.setSCLK(PB13);
SPI.setMISO(PB14);
SPI.setMOSI(PB15);
SPI.begin(); // Mặc định - SCK: PA5 - MISO: PA6 - MOSI: PA7
SPI.setClockDivider(SPI_CLOCK_DIV16); // Cài đặt tốc độ truyền cho SPI
}
void SPI_Tranmit(String s)
{
digitalWrite(SS, LOW); // lựa chọn Slave để gửi dữ liệu
int i = 0;
while (i < buff_send.length())
{
delayMicroseconds(20);
SPI.transfer(s[i]);
i++;
}
digitalWrite(SS, HIGH); // Tắt Slave
TransmitControl = false;
}
int BytesToInt(byte lowerByte, byte higherbyte)
{
int val = (higherbyte << 8) | lowerByte;
return val;
}
void SPI_Request()
{
digitalWrite(SS, LOW); // lựa chọn Slave để gửi dữ liệu
delayMicroseconds(20);
buf[0] = SPI.transfer(0);
buf[1] = SPI.transfer(1);
digitalWrite(SS, HIGH); // Tắt Slave
Serial_Mon.println(BytesToInt(buf[1], buf[0]));
}
void loop()
{
while (Serial_Mon.available())
{
char c = (char)Serial_Mon.read();
buff_send += c;
if (c == '\n')
{
TransmitControl = true;
SPI_Tranmit(buff_send);
buff_send = "";
}
}
if (!TransmitControl)
SPI_Request();
}
Code Slave (Uno)
#include <SPI.h>
#define LED 5
volatile char buf; // biến nhận dữ liệu request từ master
volatile int ai0; // Biến giá trị analog gửi lên master
volatile byte* buff_response; // Lưu giá trị của analog dạng bye array
void setup()
{
pinMode (LED, OUTPUT);
SPI.setClockDivider(SPI_CLOCK_DIV16); // cài đặt tốc độ của SPI
Serial.begin (115200);
SPCR |= _BV(SPE); // Bật chế độ Slave
pinMode (MISO, OUTPUT);
SPI.attachInterrupt(); // Kích hoạt ngắt SPI
}
ISR (SPI_STC_vect) // Hàm ngắt của SPI
{
buf = SPDR; // Lưu giá trị của Master vào biến buf
if(buf == '1'){
digitalWrite(LED, LOW);
}
if(buf == '0'){
digitalWrite(LED, HIGH);
}
if((int)buf== 0)
SPDR = buff_response[0]; // Byte thấp của giá trị analog
if((int)buf== 1)
SPDR = buff_response[1]; // Byte cao của giá trị analog
}
void loop ()
{
ai0 = analogRead(A0);
buff_response = IntToBytes(ai0);
}
byte* IntToBytes(int val){ //Hàm chuyển đổi số nguyên thành mảng byte
static byte* arr = new byte[2];
arr[0] = byte(val);
arr[1] = byte(val >> 8);
return arr;
}
No comments:
Post a Comment