ROS i2c 通信(c++版本)

举报
Hermit_Rabbit 发表于 2022/08/02 14:53:49 2022/08/02
【摘要】 WiringPi是一个用C语言编写的树莓派(RaspberryPi)软件包,可用于树莓派GPIO引脚控制、串口通信、SPI通信及I2C通信等功能,非常适合熟悉C/C++的人员在树莓派上进行软件开发。WiringPi的作者是Gordon Henderson,其官方网址为http://wiringpi.com。WiringPi遵循GNU GPLv3公约,任何人都可以免费使用该软件包。 1、Wir...

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,该命令可以显示出其版本号、作者及当前树莓派的一些信息;如下图所示:

在这里插入图片描述

2、WiringPi的引脚定义

WiringPi对树莓派物理引脚进行了封装,定义了一套自己的引脚编号。
如果要查看当前树莓派的引脚编号,可以使用如下命令:

sudo gpio readall

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

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

在这里插入图片描述

在这里插入图片描述

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

在这里插入图片描述

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

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。