「Qtの基礎 - SPI通信」の版間の差分

ナビゲーションに移動 検索に移動
(ページの作成:「== 概要 == SPI (Serial Peripheral Interface) は、マイコンやSoCと周辺機器の間で使用される同期式シリアル通信プロトコルである。<br> 高速かつ全二重通信が可能であり、主にセンサ、ディスプレイ、メモリチップ等との通信に利用される。<br> <br> Qtフレームワーク自体に組み込まれた専用のクラスや機能は存在しない。<br> 代わりに、OSが提供するSPIインター…」)
 
71行目: 71行目:


== SPI通信の受信 ==
== SPI通信の受信 ==
以下の例では、非同期およびストリーミング処理を使用して、SPI通信でデータを受信している。<br>
<br>
<syntaxhighlight lang="c++">
// SpiReader.hファイル
#include <QObject>
#include <QFile>
#include <QFuture>
#include <QtConcurrent>
#include <sys/ioctl.h>
#include <linux/spi/spidev.h>
#include <fcntl.h>
#include <unistd.h>
class SpiReader : public QObject
{
    Q_OBJECT
private:
    QString          m_devicePath;
    std::atomic<bool> m_stopReading{false};
public:
    explicit SpiReader(const QString& devicePath, QObject* parent = nullptr) : QObject(parent), m_devicePath(devicePath)
    {}
    void startReading(int bufferSize = 1024)
    {
      QFuture<void> future = QtConcurrent::run([this, bufferSize]() {
          QFile spiDevice(m_devicePath);
          if (!spiDevice.open(QIODevice::ReadOnly)) {
            emit errorOccurred("SPIデバイスのオープンに失敗: " + spiDevice.errorString());
            return;
          }
          int fd = spiDevice.handle();
          uint8_t mode  = SPI_MODE_0;
          uint8_t bits  = 8;
          uint32_t speed = 500000;
          if (ioctl(fd, SPI_IOC_WR_MODE, &mode) < 0 || ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits) < 0 ||
              ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) < 0) {
            emit errorOccurred("SPIの設定に失敗");
            spiDevice.close();
            return;
          }
          QByteArray buffer(bufferSize, 0);
          while (!m_stopReading) {
            ssize_t ret = read(fd, buffer.data(), buffer.size());
            if (ret < 0) {
                emit errorOccurred("SPIの読み込みに失敗");
                break;
            }
            else if (ret > 0) {
                emit dataRead(buffer.left(ret));
            }
          }
          spiDevice.close();
          emit readingFinished();
      });
    }
    void stopReading()
    {
      m_stopReading = true;
    }
signals:
    void dataRead(const QByteArray& data);
    void errorOccurred(const QString& error);
    void readingFinished();
};
</syntaxhighlight>
<br>
<syntaxhighlight lang="c++">
// main.cppファイル
#include <QCoreApplication>
#include <QTimer>
#include "SpiReader.h"
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    SpiReader reader("/dev/spidev0.0");
    QObject::connect(&reader, &SpiReader::dataRead, [](const QByteArray& data) {
      qDebug() << "受信したデータ: " << data.toHex();
    });
    QObject::connect(&reader, &SpiReader::errorOccurred, [](const QString& error) {
      qDebug() << "エラーが発生: " << error;
    });
    reader.startReading();
    QTimer::singleShot(10000, [&reader, &a]() {
      reader.stopReading();
      a.quit();
    });
    return a.exec();
}
</syntaxhighlight>
<br><br>
== SPI通信の受信 ==
以下の例では、非同期処理を使用して、SPI通信でデータを送信している。<br>
<br>
<syntaxhighlight lang="c++">
// SpiWriter.hファイル
#include <QObject>
#include <QFile>
#include <QFuture>
#include <QtConcurrent>
#include <sys/ioctl.h>
#include <linux/spi/spidev.h>
#include <fcntl.h>
#include <unistd.h>
class SpiWriter : public QObject
{
    Q_OBJECT
public:
    explicit SpiWriter(const QString& devicePath, QObject* parent = nullptr) : QObject(parent), m_devicePath(devicePath)
    {}
    void writeData(const QByteArray& data)
    {
      QFuture<void> future = QtConcurrent::run([this, data]() {
          QFile spiDevice(m_devicePath);
          if (!spiDevice.open(QIODevice::WriteOnly)) {
            emit errorOccurred("SPIデバイスのオープンに失敗: " + spiDevice.errorString());
            return;
          }
          int fd = spiDevice.handle();
          uint8_t mode  = SPI_MODE_0;
          uint8_t bits  = 8;
          uint32_t speed = 500000;
          if (ioctl(fd, SPI_IOC_WR_MODE, &mode) < 0 ||
            ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits) < 0 ||
            ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) < 0) {
            emit errorOccurred("SPIの設定に失敗");
            spiDevice.close();
            return;
          }
          ssize_t ret = write(fd, data.constData(), data.size());
          if (ret < 0) {
            emit errorOccurred("SPIの書き込みに失敗");
          }
          else {
            emit dataWritten(ret);
          }
          spiDevice.close();
      });
    }
signals:
    void dataWritten(int bytes);
    void errorOccurred(const QString& error);
};
</syntaxhighlight>
<br>
<syntaxhighlight lang="c++">
// main.cppファイル
#include <QCoreApplication>
#include <QTimer>
#include "SpiWriter.h"
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    SpiWriter writer("/dev/spidev0.0");
    QObject::connect(&writer, &SpiWriter::dataWritten, [](int bytes) {
      qDebug() << bytes << "バイトのデータを送信";
    });
    QObject::connect(&writer, &SpiWriter::errorOccurred, [](const QString& error) {
      qDebug() << "エラーが発生: " << error;
    });
    QTimer::singleShot(5000, [&writer]() {
      writer.writeData(QByteArray::fromHex("0102030405"));
    });
    return a.exec();
}
</syntaxhighlight>
<br><br>
<br><br>


案内メニュー