Vì chủ đề này được trình bày rất kém và đoạn trích của Sebastião và đã giúp tôi giải quyết vấn đề này, tôi muốn thêm một giải pháp hoàn chỉnh về cách thiết lập RaspberryPi ngay tại đây (đã thử nghiệm trên RPi 3 và Zero W)!
Thiết lập một nô lệ làm việc:
Chuẩn bị
Hãy chắc chắn đã nhận xét dòng này trong /boot/config.txt của bạn :
dtparam=i2c_arm=on
Phụ thuộc
Tiếp theo, cài đặt g ++ và pigpio bằng lệnh này:
sudo apt install g++ pigpio
Chốt
Như đã nêu trong tài liệu, các chân là GPIO 18 (SDA) và 19 (SCL) .
Trang web này giúp định vị chúng trên RaspberryPi của bạn (bố cục phải giống với RaspberryPi 2, 3, Zero và Zero W)
Sơ đồ này từ trang web sẽ giúp:
Phần mềm
Giải trình
Như đã nói, giải pháp này dựa trên đoạn mã của Sebastião . Tôi đã sửa đổi nó với sự giúp đỡ của giải pháp của joan .
Tôi cũng đã cố gắng hiểu ý nghĩa của mã bằng cách sử dụng tài liệu cho hàm bscXfer
.
Trong mã nguồn, dữ liệu trong bsc_xfer_t
struct được sử dụng thêm hoặc nhận tin nhắn nhưng chúng chỉ được áp dụng khi bscXfer
được thực thi với địa chỉ cho struct (như joan đã chỉ ra trong giải pháp của mình).
Số nguyên bsc_xfer_t.control có một vai trò khá đặc biệt, trong đó nêu rõ nhiều thứ như địa chỉ I²C nô lệ và nhiều trạng thái khác được ghi lại trong tài liệu .
Để hiểu rõ hơn về điều này, tôi đã sao chép các phần quan trọng của tài liệu vào mã nguồn và thay đổi một số thứ hoặc thuê ngoài chúng thành các chức năng riêng biệt.
Mã nguồn
Địa chỉ có thể được thay đổi thành bất cứ điều gì bạn muốn (miễn là không vượt quá 127 (còn gọi là 7F (16) hoặc 1111111 (2) ).
Vì tôi không giỏi về C ++, bạn phải bình luận, những gì bạn muốn bạn sẽ không làm. Bạn nên chạy closeSlave
chức năng sau khi hoàn thành thử nghiệm của mình.
Ở đây tệp SlaveTest.cpp :
#include <pigpio.h>
#include <iostream>
using namespace std;
void runSlave();
void closeSlave();
int getControlBits(int, bool);
const int slaveAddress = 0x03; // <-- Your address of choice
bsc_xfer_t xfer; // Struct to control data flow
int main(){
// Chose one of those two lines (comment the other out):
runSlave();
//closeSlave();
return 0;
}
void runSlave() {
gpioInitialise();
cout << "Initialized GPIOs\n";
// Close old device (if any)
xfer.control = getControlBits(slaveAddress, false); // To avoid conflicts when restarting
bscXfer(&xfer);
// Set I2C slave Address to 0x0A
xfer.control = getControlBits(slaveAddress, true);
int status = bscXfer(&xfer); // Should now be visible in I2C-Scanners
if (status >= 0)
{
cout << "Opened slave\n";
xfer.rxCnt = 0;
while(1){
bscXfer(&xfer);
if(xfer.rxCnt > 0) {
cout << "Received " << xfer.rxCnt << " bytes: ";
for(int i = 0; i < xfer.rxCnt; i++)
cout << xfer.rxBuf[i];
cout << "\n";
}
//if (xfer.rxCnt > 0){
// cout << xfer.rxBuf;
//}
}
}else
cout << "Failed to open slave!!!\n";
}
void closeSlave() {
gpioInitialise();
cout << "Initialized GPIOs\n";
xfer.control = getControlBits(slaveAddress, false);
bscXfer(&xfer);
cout << "Closed slave.\n";
gpioTerminate();
cout << "Terminated GPIOs.\n";
}
int getControlBits(int address /* max 127 */, bool open) {
/*
Excerpt from http://abyz.me.uk/rpi/pigpio/cif.html#bscXfer regarding the control bits:
22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
a a a a a a a - - IT HC TF IR RE TE BK EC ES PL PH I2 SP EN
Bits 0-13 are copied unchanged to the BSC CR register. See pages 163-165 of the Broadcom
peripherals document for full details.
aaaaaaa defines the I2C slave address (only relevant in I2C mode)
IT invert transmit status flags
HC enable host control
TF enable test FIFO
IR invert receive status flags
RE enable receive
TE enable transmit
BK abort operation and clear FIFOs
EC send control register as first I2C byte
ES send status register as first I2C byte
PL set SPI polarity high
PH set SPI phase high
I2 enable I2C mode
SP enable SPI mode
EN enable BSC peripheral
*/
// Flags like this: 0b/*IT:*/0/*HC:*/0/*TF:*/0/*IR:*/0/*RE:*/0/*TE:*/0/*BK:*/0/*EC:*/0/*ES:*/0/*PL:*/0/*PH:*/0/*I2:*/0/*SP:*/0/*EN:*/0;
int flags;
if(open)
flags = /*RE:*/ (1 << 9) | /*TE:*/ (1 << 8) | /*I2:*/ (1 << 2) | /*EN:*/ (1 << 0);
else // Close/Abort
flags = /*BK:*/ (1 << 7) | /*I2:*/ (0 << 2) | /*EN:*/ (0 << 0);
return (address << 16 /*= to the start of significant bits*/) | flags;
}
Lưu ý rằng trong một số trường hợp, bạn muốn byte đầu tiên là byte lệnh chứ không phải là một phần của dữ liệu chung của bạn.
EDIT: Cũng lưu ý rằng, mặc dù điều này hoạt động tốt cho mục đích thử nghiệm, @crasic đã chỉ ra (nhận xét đầu tiên), rằng có một cách tốt hơn (nhưng cũng được ghi chép kém) với các sự kiện thay vì sử dụng một vòng lặp vô tận. Điều đó sẽ tốt hơn khi được sử dụng với nhiều ứng dụng.
Biên dịch & thực thi
Bạn có thể biên dịch cái này với
g++ slaveTest.cpp -lpthread -lpigpio -o slaveTest
và thực hiện với
sudo ./slaveTest
Kiểm tra với một bậc thầy
Để nhanh chóng kiểm tra nó một bản gốc, một tùy chọn phổ biến là sử dụng smbus, dễ dàng hơn nhiều và có thể được tìm thấy bằng cách tìm kiếm đơn giản với một công cụ tìm kiếm bạn chọn.
Lựa chọn của tôi trong ngắn hạn:
- Tra cứu các chân SDA, SCL (chúng khác nhau như một bậc thầy!)
- Chạy
sudo apt install python3 python3-smbus
- Sao chép đoạn mã dưới đây để ví dụ như masterI2C.py vào RPi của bạn
- Mở một vỏ python với đoạn trích này bằng cách sử dụng
python3 -i masterI2C.py
- Chạy
sendData(0x03, 'Hello World of I2C!')
để gửi dữ liệu
Bậc thầy trăn:
import smbus
bus = smbus.SMBus(1)
def sendData(slaveAddress, data):
intsOfData = list(map(ord, data))
bus.write_i2c_block_data(slaveAddress, intsOfData[0], intsOfData[1:])
Hình ảnh thử nghiệm này:
Tôi hy vọng rằng tôi có thể làm rõ chủ đề này cho những người khác.
(Khi gặp sự cố bất ngờ, khởi động lại pi Raspberry nô lệ của tôi thường giúp tôi.)