I2C-读写EEROM

基于野火指南者STM32

I2C-读写EEROM

I2C协议简介

I2C 通讯协议(Inter-Integrated Circuit)是由Phiilps公司开发的,由于它引脚少 (2根),硬件实现简单,可扩展性强,不需要USART、CAN等通讯协议的外部收发设备,现在被广泛地使用在系统内多个集成电路(IC)间的通讯

I2C物理层的特点

在这里插入图片描述

I2C物理层的特点

•它是一个支持多设备的总线。“总线”指多个设备共用的信号线。在一个I2C通讯总线中,可连接多个I2C通讯设备,支持多个通讯主机及多个通讯从机。

•一个I2C总线只使用两条总线线路,一条双向串行数据线(SDA) ,一条串行时钟线 (SCL)。数据线即用来表示数据,时钟线用于数据收发同步。

每个连接到总线的设备都有一个独立的地址,主机可以利用这个地址进行不同设备之间的访问。

•总线通过上拉电阻接到电源。当I2C设备空闲时,会输出高阻态,而当所有设备都空闲,都输出高阻态时,由上拉电阻把总线拉成高电平。

•多个主机同时使用总线时,为了防止数据冲突,会利用仲裁方式决定由哪个设备占用总线。

•具有三种传输模式:标准模式传输速率为100kbit/s ,快速模式为400kbit/s ,高速模式下可达 3.4Mbit/s,但目前大多I2C设备尚不支持高速模式。

•连接到相同总线的 IC 数量受到总线的最大电容 400pF 限制 。

上拉电阻通常为4.7kΩ,线与特性

所以要开漏输出,一般应用总线上上输出高阻态

I2C的协议层

I2C的协议定义了通讯的起始和停止信号、数据有效性、响应、仲裁、时钟同步和地址广播等环节。

1.I2C基本读写过程

主机写数据到从机:

在这里插入图片描述

在这里插入图片描述

主机由从机中读数据:

在这里插入图片描述

在这里插入图片描述

通讯复合格式:

在这里插入图片描述

在这里插入图片描述

2.通讯的起始和停止信号

在这里插入图片描述

•当 SCL 线是高电平时 SDA 线从高电平向低电平切换,这个情况表示通讯的起始。

•当 SCL 是高电平时 SDA 线由低电平向高电平切换,表示通讯的停止。

•起始和停止信号一般由主机产生。

3.数据有效性

I2C使用SDA信号线来传输数据,使用SCL信号线进行数据同步。 SDA数据线在SCL的每个时钟周期传输一位数据。

在这里插入图片描述

•SCL为高电平的时候SDA表示的数据有效,即此时的SDA为高电平时表示数据“1”,为低电平时表示数据“0”。

•当SCL为低电平时,SDA的数据无效,一般在这个时候SDA进行电平切换,为下一次表示数据做好准备。

4.地址及数据方向

•I2C总线上的每个设备都有自己的独立地址,主机发起通讯时,通过SDA信号线发送设备地址(SLAVE_ADDRESS)来查找从机。设备地址可以是7位或10位。

•紧跟设备地址的一个数据位R/W用来表示数据传输方向,数据方向位为“1”时表示主机由从机读数据,该位为“0”时表示主机向从机写数据。

在这里插入图片描述

5.响应

I2C的数据和地址传输都带响应。响应包括“应答(ACK)”和“非应答(NACK)”两种信号。

在这里插入图片描述

传输时主机产生时钟,在第9个时钟时,数据发送端会释放SDA的控制权,由数据接收端控制SDA,若SDA为高电平,表示非应答信号(NACK),低电平表示应答信号(ACK)。

STM32的I2C特性及架构

1.“软件模拟协议”:直接控制GPIO引脚电平产生通讯时序时,需要由CPU控制每个时刻的引脚状态

2.“硬件协议”:STM32的I2C片上外设专门负责实现I2C通讯协议, 只要配置好该外设,它就会自动根据协议要求产生通讯信号,收发数据并缓存起来, CPU只要检测该外设的状态和访问数据寄存器,就能完成数据收发。 这种由硬件外设处理I2C协议的方式减轻了CPU的工作,且使软件设计更加简单。

在这里插入图片描述

1.通讯引脚

I2C1I2C2
SCLPB6/PB8(重映射)PB10
SDAPB7/PB9(重映射)PB11

2.时钟控制逻辑

SCL线的时钟信号,由I2C接口根据时钟控制寄存器(CCR)控制,控制的参数主要为时钟频率。

•可选择I2C通讯的“标准/快速”模式,这两个模式分别I2C对应100/400Kbit/s的通讯速率。

•在快速模式下可选择SCL时钟的占空比,可选Tlow/Thigh=2或Tlow/Thigh=16/9模式。

•CCR寄存器中12位的配置因子CCR,它与I2C外设的输入时钟源共同作用,产生SCL时钟。STM32的I2C外设输入时钟源为PCLK1。

在这里插入图片描述

3.数据控制逻辑

I2C的SDA信号主要连接到数据移位寄存器上,数据移位寄存器的数据来源及目标是数据寄存器(DR)、地址寄存器(OAR)、PEC寄存器以及SDA数据线。

•当向外发送数据的时候,数据移位寄存器以“数据寄存器”为数据源,把数据一位一位地通过SDA信号线发送出去;

•当从外部接收数据的时候,数据移位寄存器把SDA信号线采样到的数据一位一位地存储到“数据寄存器”中。

4.整体控制逻辑

整体控制逻辑负责协调整个I2C外设,控制逻辑的工作模式根据我们配置的“控制寄存器(CR1/CR2)”的参数而改变。

在外设工作时,控制逻辑会根据外设的工作状态修改“状态寄存器(SR1和SR2)”,只要读取这些寄存器相关的寄存器位,就可以了解I2C的工作状态。

STM32的I2C通讯过程

使用I2C外设通讯时,在通讯的不同阶段它会对“状态寄存器(SR1及SR2)”的不同数据位写入参数,通过读取这些寄存器标志来了解通讯状态。

1.主发送器

在这里插入图片描述

可使用STM32标准库函数来直接检测这些事件的复合标志,降低编程难度。

•控制产生起始信号(S),当发生起始信号后,它产生事件“EV5”,并会对SR1寄存器的“SB”位置1,表示起始信号已经发送;

•发送设备地址并等待应答信号,若有从机应答,则产生事件“EV6”及“EV8”,这时SR1寄存器的“ADDR”位及“TXE”位被置1,ADDR 为1表示地址已经发送,TXE为1表示数据寄存器为空;

•往I2C的“数据寄存器DR”写入要发送的数据,这时TXE位会被重置0,表示数据寄存器非空,I2C外设通过SDA信号线一位位把数据发送出去后,又会产生“EV8”事件,即TXE位被置1,重复这个过程,可以发送多个字节数据;

•发送数据完成后,控制I2C设备产生一个停止信号§,这个时候会产生EV2事件,SR1的TXE位及BTF位都被置1,表示通讯结束。

2.主接收器

在这里插入图片描述

•起始信号(S)是由主机端产生的,控制发生起始信号后,它产生事件“EV5”,并会对SR1寄存器的“SB”位置1,表示起始信号已经发送;

•发送设备地址并等待应答信号,若有从机应答,则产生事件“EV6”这时SR1寄存器的“ADDR”位被置1,表示地址已经发送。

•从机端接收到地址后,开始向主机端发送数据。当主机接收到这些数据后,会产生“EV7”事件,SR1寄存器的RXNE被置1,表示接收数据寄存器非空,读取该寄存器后,可对数据寄存器清空,以便接收下一次数据。此时可以控制I2C发送应答信号(ACK)或非应答信号(NACK),若应答,则重复以上步骤接收数据,若非应答,则停止传输;

•发送非应答信号后,产生停止信号§,结束传输。

I2C初始化结构体详解

在这里插入图片描述

•I2C_ClockSpeed

设置I2C的传输速率,在调用初始化函数时,函数会根据我们输入的数值经过运算后把时钟因子写入到I2C的时钟控制寄存器CCR。而我们写入的这个参数值不得高于400KHz。

实际上由于CCR寄存器不能写入小数类型的时钟因子,影响到SCL的实际频率可能会低于本成员设置的参数值,这时除了通讯稍慢一点以外,不会对I2C的标准通讯造成其它影响。

•I2C_Mode

选择I2C的使用方式,有I2C模式(I2C_Mode_I2C )和SMBus主、从模式(I2C_Mode_SMBusHost、 I2C_Mode_SMBusDevice ) 。

I2C不需要在此处区分主从模式,直接设置I2C_Mode_I2C即可。

•I2C_DutyCycle

设置I2C的SCL线时钟的占空比。该配置有两个选择,分别为低电平时间比高电平时间为2:1 ( I2C_DutyCycle_2)和16:9 (I2C_DutyCycle_16_9)。

其实这两个模式的比例差别并不大,一般要求都不会如此严格,这里随便选就可以了。

•I2C_OwnAddress1

配置STM32的I2C设备自己的地址,每个连接到I2C总线上的设备都要有一个自己的地址,作为主机也不例外。地址可设置为7位或10位(受下面I2C_AcknowledgeAddress成员决定),只要该地址是I2C总线上唯一的即可。

STM32的I2C外设可同时使用两个地址,即同时对两个地址作出响应,这个结构成员I2C_OwnAddress1配置的是默认的、OAR1寄存器存储的地址,若需要设置第二个地址寄存器OAR2,可使用I2C_OwnAddress2Config函数来配置,OAR2不支持10位地址。

•I2C_Ack_Enable

配置I2C应答是否使能,设置为使能则可以发送响应信号。一般配置为允许应答(I2C_Ack_Enable),这是绝大多数遵循I2C标准的设备的通讯要求,改为禁止应答(I2C_Ack_Disable)往往会导致通讯错误。

•I2C_AcknowledgeAddress

选择I2C的寻址模式是7位还是10位地址。这需要根据实际连接到I2C总线上设备的地址进行选择,这个成员的配置也影响到I2C_OwnAddress1成员,只有这里设置成10位模式时,I2C_OwnAddress1才支持10位地址。

配置完这些结构体成员值,调用库函数I2C_Init即可把结构体的配置写入到寄存器中。

I2C硬件读写

STM32的I2C片上外设专门负责实现I2C通讯协议, 只要配置好该外设,它就会自动根据协议要求产生通讯信号,收发数据并缓存起来, CPU只要检测该外设的状态和访问数据寄存器,就能完成数据收发。 这种由硬件外设处理I2C协议的方式减轻了CPU的工作,且使软件设计更加简单。


stm32地址可随意取值,只要不和从机地址一样, EEPROM的地址为0xA0 (7位地址(1010000) + 读/写位(0)),具体看手册.

代码断点测试最后得出,需要添加写入操作完成的函数,不然会卡在EV6事件中,STM32太快,时序发送还未完成!!! 同时EEPROM手册也有说明

断点测试代码可行说明大概率时间问题

EEPROM手册说明->Ackknowledge Polling!!!

#ifndef _BSP_I2C_H
#define _BSP_I2C_H

#include "stm32f10x.h"

#define STM32_I2C_ADDR					0x5f

//IIC EEPROM引脚定义

#define EEPROM_I2C									I2C1
#define EEPROM_I2C_CLK							RCC_APB1Periph_I2C1
#define EEPROM_I2C_APBxClkCmd				RCC_APB1PeriphClockCmd
#define EEPROM_I2C_BAUDRATE					400000

#define  EEPROM_SCL_GPIO_CLK           (RCC_APB2Periph_GPIOB)
#define  EEPROM_SDA_GPIO_CLK           (RCC_APB2Periph_GPIOB)
#define  EEPROM_I2C_GPIO_APBxClkCmd    RCC_APB2PeriphClockCmd
    
#define  EEPROM_I2C_SCL_GPIO_PORT       GPIOB   
#define  EEPROM_I2C_SCL_GPIO_PIN        GPIO_Pin_6
#define  EEPROM_I2C_SDA_GPIO_PORT       GPIOB
#define  EEPROM_I2C_SDA_GPIO_PIN        GPIO_Pin_7

#define  EEPROM_ADDR										0XA0

void I2C_EE_Config(void);
void EEPROM_Byte_Write(uint8_t addr, uint8_t data);
void EEPROM_Read(uint8_t addr, uint8_t *data,uint8_t numByteToRead);
void EEPROM_WaitForWriteEnd(void);
void Delay(uint32_t count);
void EEPROM_Page_Write(uint8_t addr, uint8_t *data, uint8_t numByteToWrite);


#endif /*_BSP_I2C_H*/

#include "bsp_i2c.h"

/*
1,初始化IIC相关的GPIO
2.配置IIC外设的工作模式
3.编写IIC写入EEPROM的Byte write函数
4.编写IIC读取EEPROM的RANDOM_Read函数
5,使用read函数及write函数进行读写校验
6,编写page write及seq read函数并校验
*/

void Delay(uint32_t count)
{
	for(;count != 0; count--);
}


void I2C_EE_Config(void)
{	
	
	GPIO_InitTypeDef GPIO_InitStructure;
	I2C_InitTypeDef I2C_InitStructure;

	// 打开IIC GPIO的时钟
	EEPROM_I2C_GPIO_APBxClkCmd(EEPROM_SCL_GPIO_CLK|EEPROM_SDA_GPIO_CLK, ENABLE);
	
	// 打开IIC外设的时钟
	EEPROM_I2C_APBxClkCmd(EEPROM_I2C_CLK, ENABLE);

	// 将IIC SCL的GPIO配置为复用开漏模式
	GPIO_InitStructure.GPIO_Pin = EEPROM_I2C_SCL_GPIO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(EEPROM_I2C_SCL_GPIO_PORT, &GPIO_InitStructure);

  // 将IIC SDA的GPIO配置为复用开漏模式
	GPIO_InitStructure.GPIO_Pin = EEPROM_I2C_SDA_GPIO_PIN;
	GPIO_Init(EEPROM_I2C_SDA_GPIO_PORT, &GPIO_InitStructure);
	
	
	// 配置IIC的工作参数
	I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; //使能应答
	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; 
	I2C_InitStructure.I2C_ClockSpeed = EEPROM_I2C_BAUDRATE;
	I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
	I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
	I2C_InitStructure.I2C_OwnAddress1 = STM32_I2C_ADDR;
	
	I2C_Init(EEPROM_I2C,&I2C_InitStructure);
	
	// 使能IIC
	I2C_Cmd(EEPROM_I2C, ENABLE);	    
}


//向EEPROM写入一个字节
void EEPROM_Byte_Write(uint8_t addr, uint8_t data)
{
	//产生起始信号

	I2C_GenerateSTART (EEPROM_I2C, ENABLE);
	while(I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_MODE_SELECT) == ERROR);
	
	//EV5事件被检测,发送设备地址
	I2C_Send7bitAddress(EEPROM_I2C,EEPROM_ADDR,I2C_Direction_Transmitter);

	while(I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == ERROR);
	
	//EV6事件被检测,发送要操作的存储单元地址
	I2C_SendData(EEPROM_I2C,addr);
	while(I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTING) == ERROR);

	//EV8事件被检测,发送要存储的数据
	I2C_SendData(EEPROM_I2C,data);
	while(I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == ERROR);

	//数据传输完成
	I2C_GenerateSTOP (EEPROM_I2C,ENABLE);
}

//向EEPROM写入多个字节(页写入),每次写入不能超过8个字节
void EEPROM_Page_Write(uint8_t addr, uint8_t *data, uint8_t numByteToWrite)
{
	//产生起始信号
	I2C_GenerateSTART (EEPROM_I2C, ENABLE);

	while(I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_MODE_SELECT) == ERROR);
	
	
	//EV5事件被检测,发送设备地址
	I2C_Send7bitAddress(EEPROM_I2C,EEPROM_ADDR,I2C_Direction_Transmitter);
	while(I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == ERROR);

	//EV6事件被检测,发送要操作的存储单元地址
	I2C_SendData(EEPROM_I2C,addr);
	while(I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTING) == ERROR);

	while(numByteToWrite)
	{
		//EV8事件被检测,发送要存储的数据
		I2C_SendData(EEPROM_I2C,*data);
		while(I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == ERROR);
		data++;
		numByteToWrite--;
	}
	//数据传输完成
	I2C_GenerateSTOP (EEPROM_I2C,ENABLE);
}

//向EEPROM读取数据
void EEPROM_Read(uint8_t addr, uint8_t *data,uint8_t numByteToRead)
{
	//产生起始信号
	I2C_GenerateSTART(EEPROM_I2C, ENABLE);
	while(I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_MODE_SELECT) == ERROR);
	
	
	//EV5事件被检测,发送设备地址
	I2C_Send7bitAddress(EEPROM_I2C,EEPROM_ADDR,I2C_Direction_Transmitter);
	while(I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == ERROR);
	
	//EV6事件被检测,发送要操作的存储单元地址
	I2C_SendData(EEPROM_I2C,addr);
	while(I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTING) == ERROR);
	
	//第二次起始信号
	I2C_GenerateSTART (EEPROM_I2C, ENABLE);
	while(I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_MODE_SELECT) == ERROR);
	
	//EV5事件被检测,发送设备地址
	I2C_Send7bitAddress(EEPROM_I2C,EEPROM_ADDR,I2C_Direction_Receiver);
	while(I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED ) == ERROR);
	
	while(numByteToRead)
	{
		
		if(numByteToRead == 1)
		{
			//最后一个字节
			I2C_AcknowledgeConfig(EEPROM_I2C,DISABLE);
		}
		//EV6事件被检测
		while(I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_BYTE_RECEIVED ) == ERROR);
		
		//EV7事件被检测到,即数据寄存器有新的有效数据
		*data = I2C_ReceiveData  ( EEPROM_I2C );
		data++;
		numByteToRead--;
	}
	//数据传输完成
	I2C_GenerateSTOP (EEPROM_I2C,ENABLE);
	
	//重新配置ACK使能,以便下次通讯
	I2C_AcknowledgeConfig(EEPROM_I2C,ENABLE);

}

//等待EEPROM内部时序完成!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
void EEPROM_WaitForWriteEnd(void)
{
	do
	{
		I2C_GenerateSTART (EEPROM_I2C, ENABLE);
		while(I2C_GetFlagStatus(EEPROM_I2C,I2C_FLAG_SB) == RESET);
	
	//EV5事件被检测,发送设备地址
		I2C_Send7bitAddress(EEPROM_I2C,EEPROM_ADDR,I2C_Direction_Transmitter);
	
	}
	while(I2C_GetFlagStatus(EEPROM_I2C,I2C_FLAG_ADDR) == RESET);
	
	//内部时序传输完成
	I2C_GenerateSTOP (EEPROM_I2C, ENABLE);
}

#include "stm32f10x.h"	
#include "bsp_led.h"
#include "bsp_usart.h"
#include "./i2c/bsp_i2c.h"

uint8_t readData[10] = {0};
uint8_t writeData[8] = {4,5,6,7,8,9,10,11};

int main(void)
{
	uint8_t i = 0;
	USART_Config();
	printf("这是一个IIC通讯实验\n");
	I2C_EE_Config();
//	EEPROM_Byte_Write(11, 0x55);
//	
//	//等待写入操作完成
//	EEPROM_WaitForWriteEnd();
//	
//	EEPROM_Byte_Write(12, 0x52);
//	
//	//等待写入操作完成
//	EEPROM_WaitForWriteEnd();
	
	//addr&8 == 0,即为地址对齐,不然读数出错
	EEPROM_Page_Write(16,writeData,8);
	
	//等待写入操作完成
	EEPROM_WaitForWriteEnd();

	EEPROM_Read(16, readData,8);
	
	for(i=0;i<8;i++)
	{
		printf("%d ",readData[i]);
	}
	
//	printf("\r\n接收到的数据为0x%x 0x%x\r\n",readData[0],readData[1]);
	while(1)
	{}
	
  
}

I2C软件读写

直接控制GPIO引脚电平产生通讯时序时,需要由CPU控制每个时刻的引脚状态,具体软件读写代码在I2C_OLED章节有示例.

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: Linux I2C读写程序是用于控制I2C总线上的设备的程序。I2C总线是一种串行通信协议,用于连接微控制器和外围设备。在Linux系统中,可以使用i2c-tools和libi2c-dev库来进行I2C通信。通过编写I2C读写程序,可以实现对I2C设备的控制和数据传输。在程序中需要指定I2C设备的地址、寄存器地址和数据等参数,然后通过调用相应的函数来进行读写操作。常用的函数包括i2c_smbus_read_byte_data、i2c_smbus_write_byte_data、i2c_smbus_read_word_data、i2c_smbus_write_word_data等。通过编写Linux I2C读写程序,可以实现对各种I2C设备的控制和数据传输,从而实现各种应用。 ### 回答2: i2c是一种用于在电路板和芯片之间进行数字数据通信的串行通信协议。在linux系统下,我们可以使用i2c-tools工具来检查和控制i2c设备。但是如果需要自己编写i2c读写程序,可以在linux系统下使用sysfs接口或者使用C语言编写i2c读写程序。 使用sysfs接口: 在linux系统中,i2c设备通过/sys/bus/i2c/devices/目录下的文件进行读写。可以通过以下步骤进行读写i2c设备: 1. 在/sys/bus/i2c/devices/目录下查找设备的路径,例如设备号为i2c-1,设备地址为0x50,则该设备路径应该为/sys/bus/i2c/devices/1-0050/。 2. 在设备路径下找到名为“device”、“name”、“of_node”等文件,通过读这些文件获得设备的信息。 3. 在设备路径下找到名为“reg”、“modalias”、“power”等文件,通过对这些文件的写入和读取来控制设备的状态。 4. 在设备路径下找到名为“eeprom”、“i2c-dev”、“new_device”等文件,通过对这些文件的写入和读取来读写i2c设备。 使用C语言编写i2c读写程序: 使用C语言编写i2c读写程序相对比较复杂,需要用到i2c-dev.h头文件和open()、ioctl()、write()、read()等函数。以下是使用C语言编写的一个i2c读写程序示例: #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <linux/i2c-dev.h> int main(int argc, char** argv) { int fd; char buf[2]; fd = open("/dev/i2c-1", O_RDWR); if(fd < 0) { perror("open"); exit(1); } /* 设置要写入的从设备地址 */ if(ioctl(fd, I2C_SLAVE, 0x50) < 0) { perror("ioctl"); exit(1); } /* 写入数据, buf[0]为要写入的寄存器,buf[1]为要写入的数据 */ buf[0] = 0x01; buf[1] = 0x0F; if(write(fd, buf, 2) != 2) { perror("write"); exit(1); } /* 读取数据, buf[0]为要读取的寄存器 */ buf[0] = 0x01; if(write(fd, buf, 1) != 1) { perror("write"); exit(1); } if(read(fd, buf, 1) != 1) { perror("read"); exit(1); } printf("Read data: %x\n", buf[0]); close(fd); return 0; } 以上程序实现了对i2c从设备地址为0x50的寄存器进行写入和读取。程序中使用了open()函数打开/dev/i2c-1设备文件,通过ioctl()函数设置要写入的从设备地址,通过write()和read()函数进行数据的写入和读取。 总之,使用sysfs接口和C语言编写i2c读写程序都是可行的,但是前者相对简单易懂,后者需要理解更多的底层知识。 ### 回答3: Linux I2C读写程序可以用于通过I2C总线与外设进行通信。I2C总线是一种串行通信协议,它可以同时连接多个从设备到一个主设备。在Linux内核中,通过i2c-dev模块来实现I2C读写操作。 I2C设备节点的路径为/dev/i2c-N,其中N代表I2C总线的编号。在打开设备节点之前,需要先查询设备的地址,可以通过i2cdetect命令来扫描I2C总线上所有设备的地址。一旦确定设备的地址,就可以打开设备节点,并设置I2C通信参数(如波特率,传输模式等)。 I2C读取数据的流程如下所示: 1.使用ioctl设置读取偏移量(register address); 2.使用read读取数据; 3.关闭设备节点。 I2C写入数据的流程如下所示: 1.使用ioctl设置写入偏移量(register address); 2.使用write写入数据; 3.关闭设备节点。 需要注意的是,I2C通信是一种半双工通信方式,读写数据时需要分别进行。同时,I2C通信还需要考虑字节序(Big Endian或Little Endian)等问题,以保证数据的正确性。 在Linux系统中,可以使用C语言或者Python等编程语言来编写I2C读写程序。此外,也可以使用已有的I2C库,如libi2c-dev等来简化编程过程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值