ROS i2c 通信(c++版本)

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
资源编排,不限时长
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
简介: ROS i2c 通信(c++版本)

WiringPi是一个用C语言编写的树莓派(RaspberryPi)软件包,可用于树莓派GPIO引脚控制、串口通信、SPI通信及I2C通信等功能,非常适合熟悉C/C++的人员在树莓派上进行软件开发。


WiringPi的作者是Gordon Henderson,其官方网址为http://wiringpi.com。WiringPi遵循GNU GPLv3公约,任何人都可以免费使用该软件包。


1、WiringPi的安装与更新


WiringPi预装(Pre-installed)在标准的树莓派操作系统Raspbin中。可以使用下面的命令进行安装:


sudo apt-get install wiringpi


如果需要更新WiringPi,可以使用系统更新命令:


sudo apt-get update
sudo apt-get upgrade


WiringPi安装完成后,可以使用下面的命令测试是否安装成功:


sudo gpio -v


如果系统中安装了WiringPi,该命令可以显示出其版本号、作者及当前树莓派的一些信息;如下图所示:


20210203150059999.png


2、WiringPi的引脚定义


WiringPi对树莓派物理引脚进行了封装,定义了一套自己的引脚编号。

如果要查看当前树莓派的引脚编号,可以使用如下命令:


sudo gpio readall


下面这张图是gpio readall读出的树莓派3B的引脚定义:


20210203150128336.png


树莓派的物理引脚、BCM引脚和WiringPi引脚是三种不同的定义,下面这张图看起来更清晰美观一些:


20210203150517532.png20210203150138227.png



3、WiringPi的库函数


WiringPi提供了很多函数用于各种功能,包括如下库:


  1. WiringPi配置函数(WiringPi Setup functions);
  2. WiringPi核心函数(WiringPi Core functions);
  3. 树莓派专用函数(Raspberry Pi Specific functions);
  4. 时间函数(Time functions);
  5. 程序优先级/中断/线程函数(Process priority/interrupts/thread functions);
  6. 串口通信库函数(Serial Library functions);
  7. SPI通信库函数(SPI Library functions);
  8. I2C通信库函数(IC2 Library functions);
  9. 移位库函数(Shift Library functions);
  10. 软件PWM库函数(Software PWM Library functions);
  11. 软件方波/音频库函数(Software Tone Library functions);


4、 代码编写


树莓派端


#include "stdio.h"
#include "wiringPi.h"
#include "wiringPiI2C.h"
#include "pthread.h"
#include "unistd.h"
void *pthread_fun(void *arg)
{
  int fd = *((int*)arg);  
  int Tx_buf = 12;
  while(1)
  {
      wiringPiI2CWrite(fd, Tx_buf);
      sleep(1);
  }
  return NULL;
}
int main(int argc, char *argv[])
{
  int fd, err;
  int Rx_buf;
  pthread_t tid;
  //对wiringPi初始化
  if(wiringPiSetup() != 0)
  {
    printf("wiringPi error!\n");
    return -1;
  }
  //指定i2c从机设备,并初始化i2c
  fd = wiringPiI2CSetup(0x28);
  if(fd < 0)
  {
    printf("wiringPiI2CSetup error!\n");
    return fd;
  }
  err = pthread_create(&tid, NULL, pthread_fun, &fd);
  if(err != 0)
  {
    printf("create pthread error\n"); 
    return -2;
  }
  while(1)
  {
    Rx_buf = 0;
    //读取数据
    Rx_buf = wiringPiI2CRead(fd);
    //判断是否读取成功
    if(Rx_buf != 0)
      printf("Temperature is %d ℃\n", Rx_buf);
    sleep(1);
  }
  return 0;
}


STM32F103硬件i2c代码


/*********************************************************************************************************
*                                              包含头文件
*********************************************************************************************************/
#include "iic.h"
/*********************************************************************************************************
*                                              宏定义
*********************************************************************************************************/
/*********************************************************************************************************
*                                              内部变量
*********************************************************************************************************/
u8 IIC1_Rx_Buff = 0;
u8 IIC1_Tx_Buff = 67;
//#define SIZE2 sizeof(IIC1_Tx_Buff)
uint32_t state;
/*********************************************************************************************************
*                                              内部函数声明
*********************************************************************************************************/
/*********************************************************************************************************
*                                              内部函数实现
*********************************************************************************************************/
/*********************************************************************************************************
* 函数名称:  
* 函数功能: 
* 输入参数: 
* 输出参数: 
* 返 回 值: 
* 创建日期:  
* 注 意:   
*********************************************************************************************************/ 
/*********************************************************************************************************
*                                              API函数实现
*********************************************************************************************************/
/*********************************************************************************************************
* 函数名称: InitI2C1
* 函数功能: 初始化I2C1
* 输入参数: void
* 输出参数: void
* 返 回 值: void
* 创建日期: 2019年4月21日 
* 注    意: PB6:SCL; PB7:SDA
*********************************************************************************************************/ 
void InitI2C1(void)
{
  GPIO_InitTypeDef GPIO_InitStruct;
  I2C_InitTypeDef I2C_InitStruct;
  NVIC_InitTypeDef NVIC_InitStruct;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
  //GPIO配置
  GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_6 | GPIO_Pin_7;
  GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_AF_OD;         //设置为复用开漏输出,实现iic的线与逻辑
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOB, &GPIO_InitStruct);
  //I2C1配置
  I2C_InitStruct.I2C_Ack                 = I2C_Ack_Enable; //使能ack
  I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; //7位设备地址
  I2C_InitStruct.I2C_DutyCycle           = I2C_DutyCycle_2;//占空比为1/2              
  I2C_InitStruct.I2C_ClockSpeed          = 100000;         //时钟频率为100k
  I2C_InitStruct.I2C_Mode                = I2C_Mode_I2C;
  I2C_InitStruct.I2C_OwnAddress1         = 0x50;           //设置硬件从机地址
  I2C_Init(I2C1, &I2C_InitStruct);
  //NVIC配置
  NVIC_InitStruct.NVIC_IRQChannel                   = I2C1_EV_IRQn;   //事件中断
  NVIC_InitStruct.NVIC_IRQChannelCmd                = ENABLE;
  NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStruct.NVIC_IRQChannelSubPriority        = 0;
  NVIC_Init(&NVIC_InitStruct);
  NVIC_InitStruct.NVIC_IRQChannel                   = I2C1_ER_IRQn;   //错误中断
  NVIC_InitStruct.NVIC_IRQChannelCmd                = ENABLE;
  NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStruct.NVIC_IRQChannelSubPriority        = 0;
  NVIC_Init(&NVIC_InitStruct);
  I2C_ITConfig(I2C1, I2C_IT_EVT | I2C_IT_ERR | I2C_IT_BUF, ENABLE);
  I2C_Cmd(I2C1, ENABLE);
}
/*********************************************************************************************************
* 函数名称: I2C1_EV_IRQHandler
* 函数功能: I2C1事件中断服务函数
* 输入参数: void
* 输出参数: void
* 返 回 值: void
* 创建日期: 2019年4月21日 
* 注    意: 
*********************************************************************************************************/
void I2C1_EV_IRQHandler(void)
{ 
  //static u8 s_iRdata;
  //static u8 s_iTdata;
  state = I2C_GetLastEvent(I2C1);
  switch(state)
  { 
    //EV1(receive)(从机匹配地址成功)
    case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED: 
       I2C_ReadRegister(I2C1, I2C_Register_SR1);   //读取SR1
       I2C_ReadRegister(I2C1, I2C_Register_SR2);   //读取SR2后,硬件自动将SR1->ADDR清零
       //s_iRdata = 0;
       break;
    //EV2(Byte received)
    case I2C_EVENT_SLAVE_BYTE_RECEIVED:
       IIC1_Rx_Buff = I2C_ReceiveData(I2C1);//读取DR寄存器硬件将自动将SR1->RxNE清零
       //IIC1_Rx_Buff[s_iRdata] = I2C_ReceiveData(I2C1);//读取DR寄存器硬件将自动将SR1->RxNE清零
       //s_iRdata++;
       break;
    //EV4(stop) 
    case I2C_EVENT_SLAVE_STOP_DETECTED:
       I2C_ReadRegister(I2C1, I2C_Register_SR1);   //读取SR1
       I2C1->CR1 |= 0x0001;                        //写CR1->PE为1,启动I2C1
       break;
    //EV1(transmitter)
    case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED:
       I2C_ReadRegister(I2C1, I2C_Register_SR1);   //读取SR1
       I2C_ReadRegister(I2C1, I2C_Register_SR2);   //读取SR2后,硬件自动将SR1->ADDR清零
       //s_iTdata = 0;  
       break;
    //EV3、EV3-1(Byte transmit)
    case I2C_EVENT_SLAVE_BYTE_TRANSMITTING:
    case I2C_EVENT_SLAVE_BYTE_TRANSMITTED:
       //I2C_SendData(I2C1, IIC1_Tx_Buff[s_iTdata++]); //写I2C->DR后硬件将自动清除TxE位
       I2C_SendData(I2C1, IIC1_Tx_Buff); //写I2C->DR后硬件将自动清除TxE位
       break;
    //EV3-2 
    case I2C_EVENT_SLAVE_ACK_FAILURE:
       I2C1->SR1 &= 0xFBFF;           //写SR1->AF = 0以清除AF位
       break;
    default:
       break;
  }
}
/*********************************************************************************************************
* 函数名称: I2C1_ER_IRQHandler
* 函数功能: I2C1错误中断服务函数
* 输入参数: void
* 输出参数: void
* 返 回 值: void
* 创建日期: 2019年4月21日 
* 注    意: 
*********************************************************************************************************/
void I2C1_ER_IRQHandler(void) 
{  
  if(I2C_GetITStatus(I2C1, I2C_IT_SMBALERT))
  {
    I2C_ClearITPendingBit(I2C1, I2C_IT_SMBALERT);
  }
  else if(I2C_GetITStatus(I2C1, I2C_IT_TIMEOUT))  
  {
    I2C_ClearITPendingBit(I2C1, I2C_IT_TIMEOUT);
  }
  else if(I2C_GetITStatus(I2C1, I2C_IT_PECERR))  
  {
    I2C_ClearITPendingBit(I2C1, I2C_IT_PECERR);
  }
  else if(I2C_GetITStatus(I2C1, I2C_IT_OVR))  
  {
    I2C_ClearITPendingBit(I2C1, I2C_IT_OVR);
  }
  else if(I2C_GetITStatus(I2C1, I2C_IT_AF))  
  {
    I2C_ClearITPendingBit(I2C1, I2C_IT_AF);
  }
  else if(I2C_GetITStatus(I2C1, I2C_IT_ARLO))  
  {
    I2C_ClearITPendingBit(I2C1, I2C_IT_ARLO);
  }
  else if(I2C_GetITStatus(I2C1, I2C_IT_BERR))  
  {
    I2C_ClearITPendingBit(I2C1, I2C_IT_BERR);
  }
  I2C1->CR1 |= 0x0001;       //启动I2C1
  I2C1->SR1 = 0;
  I2C1->SR2 = 0;
}


编译


gcc i2c_wiringPi.c -o i2c_wiringPi -lpthread -lwiringPi
./i2c_wiringPi


20210203150848126.png


Tip: 此外在检索中已经有大神封装好了这部分的工作,各位也可以直接调用。


相关实践学习
使用ROS创建VPC和VSwitch
本场景主要介绍如何利用阿里云资源编排服务,定义资源编排模板,实现自动化创建阿里云专有网络和交换机。
阿里云资源编排ROS使用教程
资源编排(Resource Orchestration)是一种简单易用的云计算资源管理和自动化运维服务。用户通过模板描述多个云计算资源的依赖关系、配置等,并自动完成所有资源的创建和配置,以达到自动化部署、运维等目的。编排模板同时也是一种标准化的资源和应用交付方式,并且可以随时编辑修改,使基础设施即代码(Infrastructure as Code)成为可能。 产品详情:https://www.aliyun.com/product/ros/
相关文章
|
1月前
|
NoSQL 网络协议 Linux
Redis的实现一:c、c++的网络通信编程技术,先实现server和client的通信
本文介绍了使用C/C++进行网络通信编程的基础知识,包括创建socket、设置套接字选项、绑定地址、监听连接以及循环接受和处理客户端请求的基本步骤。
46 6
|
1月前
|
Linux 编译器 测试技术
【C++】CentOS环境搭建-快速升级G++版本
通过上述任一方法,您都可以在CentOS环境中高效地升级G++至所需的最新版本,进而利用C++的新特性,提升开发效率和代码质量。
160 64
|
1月前
|
Linux 编译器 测试技术
【C++】CentOS环境搭建-快速升级G++版本
通过上述任一方法,您都可以在CentOS环境中高效地升级G++至所需的最新版本,进而利用C++的新特性,提升开发效率和代码质量。
193 63
|
1月前
|
网络协议 Linux 网络性能优化
Linux C/C++之TCP / UDP通信
这篇文章详细介绍了Linux下C/C++语言实现TCP和UDP通信的方法,包括网络基础、通信模型、编程示例以及TCP和UDP的优缺点比较。
36 0
Linux C/C++之TCP / UDP通信
|
2月前
|
算法 机器人 C语言
ROS仿真支持C++和C语言
ROS仿真支持C++和C语言
68 1
|
3月前
|
XML 网络协议 机器人
ROS1 Noetic主从机通信使用详解
这篇文章详细介绍了在ROS1 Noetic环境下配置主从机通信的步骤,包括获取IP和主机名、设置`/etc/hosts`文件、配置ROS环境变量以及测试通信是否成功。同时,文章还提供了一些ROS环境变量的相关知识和参考资料链接。
78 0
|
3月前
|
缓存 C++ Windows
Inno setup 脚本判断 Microsoft Visual C++ Redistributable 不同版本区别
Inno setup 脚本判断 Microsoft Visual C++ Redistributable 不同版本区别
|
4月前
|
Ubuntu 机器人 Linux
Ubuntu查看ros版本-linux查看ros版本
通过上述方法,您可以轻松检查和确认您的Ubuntu或其他Linux系统上安装的ROS版本,以确保您的机器人项目能够顺利进行。
1326 0
|
5月前
|
Linux vr&ar C语言
Linux怎样更新Centos下Gcc版本支持C17?Centos7快速安装gcc8.3.1 可支持C++17(附gcc相关链接整理)
Linux怎样更新Centos下Gcc版本支持C17?Centos7快速安装gcc8.3.1 可支持C++17(附gcc相关链接整理)
302 2
|
6月前
|
存储 网络协议 数据可视化
C++实现socket通信
了解如何实现socket通信以及TCP连接的过程中发生了什么
97 1

推荐镜像

更多