1. 説明
Raspberry Pi は、現在 4 つのリビジョンとミニマルな Zero バリアントが提供されているシングルボード コンピューターです。サイズが小さく、消費電力が高く、処理速度が速く、完全な Linux ベースのコンピューターであるため、さまざまなプロジェクトで人気の選択肢です。
複数のシングルボード コンピュータやマイクロコントローラを接続する方法の 1 つは、直接配線です。このために最も一般的に使用されるプロトコルは、I2C、SPI、および UART です。ブログ シリーズの以前の投稿では、これらのプロトコルの原理を説明し、Arduino 固有の C ライブラリを紹介しました。この記事では、Raspberry Pi でこれらのプロトコルを使用できるようにする C++ ライブラリについて説明します。各プロトコルについて、利用可能なライブラリを調査し、簡単な説明とコード例を示します。これらの例は私が開発したものではなく、ライブラリのドキュメントからのものであり、具体的な動作例の基礎として役立つはずであるとは言わないでください。
この記事はもともと私のブログ admantium.comに掲載されたものです。
二、I2C
I2C は、I2C バスの特定のバリアントとして説明される SMBus プロトコル経由でサポートされます。このプロトコルは、 Linux カーネル モジュールとして利用できます 。これを使用するには、Raspberry Pi を設定する必要があります。ターミナルで、実行し、選択し、 を選択します。raspi-config
3 Interfacing Options
P5 I2C
kernel.org のコード例 に従って 、接続された I2C デバイスを表すデバイス ファイルを開き、デバイス レジスタに書き込んで SMBus コマンドを送信する必要があります。
// SOURCE: https://www.kernel.org/doc/Documentation/i2c/dev-interface */
#include <linux/i2c-dev.h>
#include <i2c/smbus.h>int file;
int adapter_nr = 2;
char filename[20];snprintf(filename, 19, "/dev/i2c-%d", adapter_nr);
file = open(filename, O_RDWR);
if (file < 0) {
exit(1);
} int addr = 0x40;if (ioctl(file, I2C_SLAVE, addr) < 0) {
exit(1);
}__u8 reg = 0x10;
__s32 res;
char buf[10];res = i2c_smbus_read_word_data(file, reg);
if (res < 0) {
/* ERROR HANDLING: i2c transaction failed */
} else {
/* res contains the read word */
}buf[0] = reg;
buf[1] = 0x43;
buf[2] = 0x65;
if (write(file, buf, 3) != 3) {
/* ERROR HANDLING: i2c transaction failed */
}
3.SPI
SPI を使用するには、特定のカーネル モジュールSpidev を追加する必要もあります。Raspberry Pi はこのモジュールをサポートしています。呼び出して構成し、[and] を選択する必要があります。raspi-config
3 Interfacing Options
P4 SPI
C/C++ を使用して SPI 関数にアクセスするには、 spidev ラッパー ライブラリを使用できます。サンプル コードに従って、SPI 接続を構成し、接続するデバイスを開いて、ライブラリ メソッドを使用してデータの読み取りと書き込みを行う必要があります。
//SOURCE: https://raw.githubusercontent.com/milekium/spidev-lib/master/sample/spidev-testcpp.cc
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <spidev_lib++.h>spi_config_t spi_config;
uint8_t tx_buffer[32];
uint8_t rx_buffer[32];int main( void)
{ SPI *mySPI = NULL; spi_config.mode=0;
spi_config.speed=1000000;
spi_config.delay=0;
spi_config.bits_per_word=8; mySPI=new SPI("/dev/spidev1.0",&spi_config); if (mySPI->begin())
{
memset(tx_buffer,0,32);
memset(rx_buffer,0,32);
sprintf((char*)tx_buffer,"hello world");
printf("sending %s, to spidev2.0 in full duplex \n ",(char*)tx_buffer);
mySPI->xfer(tx_buffer,strlen((char*)tx_buffer),rx_buffer,strlen((char*)tx_buffer));
printf("rx_buffer=%s\n",(char *)rx_buffer);
//mySPI->end();
delete mySPI;
}
return 1;
}
4.UART
共通Cライブラリを使用してUART接続が可能です。この記事の非常に詳細な手順に従って、デバイスを開いて、TTY デバイスを定義するさまざまなプロパティを使用して、シリアル ポートへの書き込みとシリアル ポートからの読み取りを行う必要があります。termios struct
// SOURCE: https://blog.mbedded.ninja/programming/operating-systems/linux/linux-serial-ports-using-c-cpp/
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <unistd.h>int main() {
int serial_port = open("/dev/ttyUSB0", O_RDWR); struct termios tty; if(tcgetattr(serial_port, &tty) != 0) {
printf("Error %i from tcgetattr: %s\n", errno, strerror(errno));
return 1;
} tty.c_cflag &= ~PARENB;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8;
tty.c_cflag &= ~CRTSCTS;
tty.c_cflag |= CREAD | CLOCAL; tty.c_lflag &= ~ICANON;
tty.c_lflag &= ~ECHO;
tty.c_lflag &= ~ECHOE;
tty.c_lflag &= ~ECHONL;
tty.c_lflag &= ~ISIG;
tty.c_iflag &= ~(IXON | IXOFF | IXANY);
tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL); tty.c_oflag &= ~OPOST;
tty.c_oflag &= ~ONLCR; tty.c_cc[VTIME] = 10;
tty.c_cc[VMIN] = 0; cfsetispeed(&tty, B9600);
cfsetospeed(&tty, B9600); if (tcsetattr(serial_port, TCSANOW, &tty) != 0) {
printf("Error %i from tcsetattr: %s\n", errno, strerror(errno));
return 1;
} unsigned char msg[] = { 'H', 'e', 'l', 'l', 'o', '\r' };
write(serial_port, "Hello, world!", sizeof(msg)); char read_buf [256]; memset(&read_buf, '\0', sizeof(read_buf); int num_bytes = read(serial_port, &read_buf, sizeof(read_buf)); if (num_bytes < 0) {
printf("Error reading: %s", strerror(errno));
return 1;
} printf("Read %i bytes. Received message: %s", num_bytes, read_buf); close(serial_port)
return 0;
5. 一般的な GPIO アクセス
ライブラリ libgpiod は、 Linux を実行しているデバイスの GPIO への汎用アクセスを提供します。使用可能な GPIO を検出し、データの読み取りと書き込みが可能で、トリガー イベントを待機します。これにより、接続されたデバイスと UART を通信するためのコードを作成できます。
インストールするには、次のコマンドを実行します。
apt-get install autoconf autoconf-archive libtool libkmod-dev pkg-config
git clone https://github.com/brgl/libgpiod.gitcd libgpiod
./autogen.sh --enable-tools=yes --prefix=/usr/local/bin
make
sudo make install
コンパイルとインストールが成功すると、GPIO の参照に使用できるバイナリがサブフォルダー内に見つかります。以下の例を参照してください。./tools
gpiodetect
gpioinfo
./tools/gpiodetect
gpiochip0 [pinctrl-bcm2711] (58 lines)
gpiochip1 [raspberrypi-exp-gpio] (8 lines)./tools/gpioinfo
gpiochip0 - 58 lines:
line 0: "ID_SDA" unused input active-high
line 1: "ID_SCL" unused input active-high
line 2: "SDA1" unused input active-high
line 3: "SCL1" unused input active-high
line 4: "GPIO_GCLK" unused input active-high
line 5: "GPIO5" unused input active-high
...
ライブラリを使用する場合は、この記事の詳細な手順をお読みください。
6. 結論
Raspberry Pi で I2C、SPI、UART を使用するには、Python だけでなく C++ ライブラリも使用できます。具体的には、対応するカーネル モジュールをローカルにロードする I2C および SPI 機能をアクティブにする必要があります。次に、クライアント ライブラリとその他の必要な C++ ヘッダーを選択します。ライブラリの使用も同じ原則に従います。つまり、接続用のデバイス ファイルを決定し、接続オブジェクトを構成し、デバイス ファイルを開き、デバイス ファイルの読み取り/書き込みを行います。最後に、便利なライブラリ libgpiod を使用すると、すべての GPIO ピンに直接アクセスでき、デバッグに役立ちます。raspi-config