

Вход
Регистрация | Забыли пароль?
Поиск
Рубрики
Рейтинг
Облако тэгов
windows, raspberry pi 3, raspbian, умный дом, gpio, ubuntu, osmc, windows 10, linux, игры, python, установка ос, raspberry pi 2, raspberry pi zero, raspberry pi zero w, слежение, самолёт, http, diy, 1c-битрикс, нейросеть, сеть, кластер, бесперебойник, акустикаБоковое меню
Обмен данными по SPI между Raspberry Pi и Arduino
Для задач робототехники, когда хочется применять вычисления на Python, использовать компьютерное зрение, ROS возникает необходимость быстрого и надежного обмена данными с микроконтроллером, который уже рулит всевозможными моторами, сервоприводами и датчиками.

Первое, о чем пришлось позаботиться - это согласование логических уровней двух устройств. Arduino работает на 5V, Raspberry на 3.3V. Для этого используется устройство LogicLevelConverter на 4 канала.

Порты для подключения на устройствах строго определены
Arduino Uno(Nano):
13 - SCK - тактовые импульсы для работы протокола SPI
12 - MISO (Master Input Slave Output) - передача данных от ведомого устройства (Arduino) к ведущему (Raspberry)
11 - MOSI (Master Output Slave Input) - передача данных от ведущего устройства (Raspberry) к ведомому (Arduino)
10 - CS или SS (Chip Select или Slave Select) - выбор устройства для работы. Raspberry может работать с 2 устройствами SPI сразу, и этот порт используется для указания, с каким идет обмен данными

Arduino Mega:
52 - SCK - тактовые импульсы для работы протокола SPI
50 - MISO (Master Input Slave Output) - передача данных от ведомого устройства (Arduino) к ведущему (Raspberry)
51 - MOSI (Master Output Slave Input) - передача данных от ведущего устройства (Raspberry) к ведомому (Arduino)
53 - CS или SS (Chip Select или Slave Select) - выбор устройства для работы. Raspberry может работать с 2 устройствами SPI сразу, и этот порт используется для указания, с каким идет обмен данными

Raspberry PI:
23 - SCK - тактовые импульсы для работы протокола SPI
21 - MISO (Master Input Slave Output) - передача данных от ведомого устройства (Arduino) к ведущему (Raspberry)
19 - MOSI (Master Output Slave Input) - передача данных от ведущего устройства (Raspberry) к ведомому (Arduino)
24 - CS или SS (Chip Select или Slave Select) - выбор устройства для работы. Raspberry может работать с 2 устройствами SPI сразу, и этот порт используется для указания, с каким идет обмен данными

Также к Logic level converter подключается рабочее напряжение каждого устройства и земля
Теперь к коду:
На Raspberry Pi необходимо включить SPI:
sudo raspi-config
Interfacing options - SPI

Включаем SPI

Далее устанавливаем библиотеку spidev
pip3 install spidev
И используем заготовку кода для передачи данных
import spidev
import time
from camer2 import getCherry
def list_int_to_bytes(input_list):
# Split list int values to list ready for transfer by SPI
# every value from -32768 to 32767
# will be replaced two values from -255 to 255
# Original values must be collected by Arduino after transmission
output_list = []
for int_data in input_list:
output_list.append(int_data >> 8)
output_list.append(int_data & 255)
return output_list
def spi_send(txData):
# Send and recieve 40 bytes
N = 40
spi = spidev.SpiDev()
spi.open(0, 0)
spi.max_speed_hz = 1000000
txData = list_int_to_bytes(txData)
txData = txData+[0]*(N-len(txData))
rxData = []
_ = spi.xfer2([240]) # 240 - b11110000 - start byte
for i in range(40):
rxData.append(spi.xfer2([txData[i]])[0])
spi.close()
return rxData
recieved_data = spi_send([1,2,3,4,5,6])
Функция spi_send принимает на вход список до 20 значений от -32768 до 32767, которые разбиваются в 40 байт и передаются в Arduino. В ответ функция возвращает 40 байт, полученных из Arduino
Код для Arduino:
#include
#define DATA_SIZE 40
byte data[DATA_SIZE];//массив, в которые получаем исходные данные
int int_data[DATA_SIZE / 2];//массив в котором будут значения, полученные от Raspberry
byte sendData[DATA_SIZE];//массив, значения которого будут переданы на Raspberry
volatile byte counter = 0;
volatile byte in_byte = 0;
volatile byte spiTranferEnd = 0;
volatile byte spiTranferStarted = 0;
void fillSendData() {//заполняем массив числами, чтобы проверить корректность передачи
for (byte i = 1; i < 40; i++) {
sendData[i] = i;
}
}
void setup() {
Serial.begin(9600);
pinMode(MISO, OUTPUT);
SPCR |= _BV(SPE);//переводим SPI в режим Slave
SPI.attachInterrupt();//включаем прерывания по SPI
fillSendData();
}
ISR (SPI_STC_vect)//обработка прерывания, получение и передача данных
{
in_byte = SPDR;
if (in_byte == 240 and !spiTranferStarted) {
spiTranferStarted = 1;
counter = 0;
SPDR = sendData[counter];
}
if (spiTranferStarted and counter > 0) {
data[counter - 1] = in_byte;
SPDR = sendData[counter];
}
counter++;
if (counter == DATA_SIZE) {
SPDR = sendData[counter - 1];
counter = 0;
spiTranferStarted = 0;
spiTranferEnd = 1;
}
}
void joinRecievedBytes() {//функция, которая собирает 40 байт в 20 значений, которые передавались
for (int i = 0; i < DATA_SIZE; i += 2) {
int_data[i / 2] = data[i] << 8 | data[i + 1];
}
spiTranferEnd = 0;
}
void printSpiData() {//вывод в монитор порта полученных значений
for (int i = 0; i < DATA_SIZE / 2; i++) {
Serial.print(int_data[i]);
Serial.print(" ");
}
Serial.println();
}
void loop () {
if (spiTranferEnd) {//если эта переменная стала равна true, значит мы получили все 40 байт
joinRecievedBytes();//собираем из 40 байт 20 значений
// Тут можно написать действия с массивом int_data
// if (int_data[0]==1) {
// что-то делаем
//}
printSpiData();//выводим данные в монитор порта. Только для тестов!
//ПОТОМ ОТКЛЮЧИТЬ, Т.К. ЗАМЕДЛЯЕТ РАБОТУ ПРОГРАММЫ
}
}
Такие дела! Успехов!
Источник