【树莓派】用于处理 I2C、SPI 和 UART 的C++库

一、说明

        Raspberry Pi 是一款单板计算机,现在有 4 个修订版和一个简约的零变体。它是不同项目的热门选择,因为它体积小,功耗高,处理速度快,并且是一台完整的基于Linux的计算机。

        连接多台单板计算机和/或微控制器的一种方法是直接布线。为此,最常用的协议是I2C,SPI和UART。博客系列的前几篇文章解释了这些协议的原理,并介绍了Arduino的特定C库。在本文中,我将解释C++能够在 Raspberry Pi 上使用这些协议的库。对于每个协议,我研究了可用的库,并给出了一个简短的解释和代码示例。请不要说这些示例不是我开发的,而是来自库文档,应该作为具体工作示例的基础。

这篇文章最初出现在我的博客 admantium.com

二、I2C

        借助 SMBus 协议可以支持 I2C,该协议被描述为 I2C 总线的特定变体。此协议可作为 Linux 内核模块使用。要使用它,您需要配置树莓派。在终端中,运行 、 选择 和 。raspi-config3 Interfacing OptionsP5 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 */
} 

三、SPI

        要使用 SPI,您还需要添加一个特定的内核模块:Spidev。树莓派支持此模块,需要通过调用来配置它,然后选择 和 。raspi-config3 Interfacing OptionsP4 SPI

        要使用 C/C++ 访问 SPI 函数,可以使用 spidev 包装器库。按照示例代码,您需要配置 SPI 连接,然后打开要连接到的设备,然后使用 library 方法读取和写入数据。

//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;
} 

四、UART

        UART 连接可以与公共 C 库建立。按照本文中非常详细的说明,您将需要打开设备,然后使用 定义 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; 

五、通用 GPIO 访问

库libgpiod提供对任何运行Linux的设备的GPIO的通用访问。它检测可用的 GPIO,可以读取和写入数据,并等待触发事件。有了这个,您可以编写 ow 代码来将 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 的二进制文件。请参阅以下示例。./toolsgpiodetectgpioinfo

 ./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
... 

        如果要使用该库,请阅读本文以获取详细说明。

六、结论

        为了在Raspberry Pi上使用I2C,SPI和UART,不仅可以使用Python,还可以使用C++库。具体来说,您需要通过 激活 I2C 和 SPI 函数,这会以地方式加载相应的内核模块。然后选择客户端库和其他必要的C++标头。使用库遵循相同的原则:确定连接的设备文件,配置连接对象,打开设备文件,然后读取/写入它。最后,方便的库libgpiod可以帮助您直接访问所有GPIO引脚,这对调试很有帮助。raspi-config

猜你喜欢

转载自blog.csdn.net/gongdiwudu/article/details/131913868