I2C接口电池和eeprom读写

内核中对i2c读写函数有如下定义:

SMBus Read Byte:  i2c_smbus_read_byte_data()
============================================

This reads a single byte from a device, from a designated register.
The register is specified through the Comm byte.

S Addr Wr [A] Comm [A] S Addr Rd [A] [Data] NA P


SMBus Read Word:  i2c_smbus_read_word_data()
============================================

This operation is very like Read Byte; again, data is read from a
device, from a designated register that is specified through the Comm
byte. But this time, the data is a complete word (16 bits).

S Addr Wr [A] Comm [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P

Note the convenience function i2c_smbus_read_word_swapped is
available for reads where the two data bytes are the other way
around (not SMBus compliant, but very popular.)
SMBus Write Byte:  i2c_smbus_write_byte_data()
==============================================

This writes a single byte to a device, to a designated register. The
register is specified through the Comm byte. This is the opposite of
the Read Byte operation.

S Addr Wr [A] Comm [A] Data [A] P
SMBus Write Word:  i2c_smbus_write_word_data()
==============================================

This is the opposite of the Read Word operation. 16 bits
of data is written to a device, to the designated register that is
specified through the Comm byte. 

S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A] P

Note the convenience function i2c_smbus_write_word_swapped is
available for writes where the two data bytes are the other way
around (not SMBus compliant, but very popular.)

/

这四个函数的原型

/**
 * i2c_smbus_read_byte_data - SMBus "read byte" protocol
 * @client: Handle to slave device
 * @command: Byte interpreted by slave
 *
 * This executes the SMBus "read byte" protocol, returning negative errno
 * else a data byte received from the device.
 */
s32 i2c_smbus_read_byte_data(const struct i2c_client *client, u8 command)
{
	union i2c_smbus_data data;
	int status;

	status = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
				I2C_SMBUS_READ, command,
				I2C_SMBUS_BYTE_DATA, &data);
	return (status < 0) ? status : data.byte;
}
EXPORT_SYMBOL(i2c_smbus_read_byte_data);

/**
 * i2c_smbus_write_byte_data - SMBus "write byte" protocol
 * @client: Handle to slave device
 * @command: Byte interpreted by slave
 * @value: Byte being written
 *
 * This executes the SMBus "write byte" protocol, returning negative errno
 * else zero on success.
 */
s32 i2c_smbus_write_byte_data(const struct i2c_client *client, u8 command,
			      u8 value)
{
	union i2c_smbus_data data;
	data.byte = value;
	return i2c_smbus_xfer(client->adapter, client->addr, client->flags,
			      I2C_SMBUS_WRITE, command,
			      I2C_SMBUS_BYTE_DATA, &data);
}

/**
 * i2c_smbus_read_word_data - SMBus "read word" protocol
 * @client: Handle to slave device
 * @command: Byte interpreted by slave
 *
 * This executes the SMBus "read word" protocol, returning negative errno
 * else a 16-bit unsigned "word" received from the device.
 */
s32 i2c_smbus_read_word_data(const struct i2c_client *client, u8 command)
{
	union i2c_smbus_data data;
	int status;

	status = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
				I2C_SMBUS_READ, command,
				I2C_SMBUS_WORD_DATA, &data);
	return (status < 0) ? status : data.word;
}
EXPORT_SYMBOL(i2c_smbus_read_word_data);

/**
 * i2c_smbus_write_word_data - SMBus "write word" protocol
 * @client: Handle to slave device
 * @command: Byte interpreted by slave
 * @value: 16-bit "word" being written
 *
 * This executes the SMBus "write word" protocol, returning negative errno
 * else zero on success.
 */
s32 i2c_smbus_write_word_data(const struct i2c_client *client, u8 command,
			      u16 value)
{
	union i2c_smbus_data data;
	data.word = value;
	return i2c_smbus_xfer(client->adapter, client->addr, client->flags,
			      I2C_SMBUS_WRITE, command,
			      I2C_SMBUS_WORD_DATA, &data);
}

常用的i2c接口设备主要有eeprom,时钟,lcd,电池芯片等

1. 读写i2c从设备电池芯片

//i2c相关的头文件
#include <linux/i2c-dev.h>
#include <linux/i2c.h> 


#define CHIP      "/dev/i2c-1"  //从设备连接到开发板的i2c的接口节点

//接下来就可以像读文件一样进行操作

int fd_i2c = -1;

int get_charge_info() //设置从设备的 i2c 接口,只需要调用一次
{
	fd_i2c = open(CHIP,O_RDWR);
	if(fd_i2c < 0)
	{
		printf("main -> %s open fail\r\n",CHIP);
		return -1;
	}
	
	printf("main -> %s open done\r\n",CHIP);
	ioctl(fd_i2c, I2C_SLAVE_FORCE, 0x70);//从设备地址
	ioctl(fd_i2c, I2C_TIMEOUT, 3);//设置超时时间
	ioctl(fd_i2c, I2C_RETRIES, 1);//设置重发次数
	return 0;
}

int i2c_read(int fd_i2c) // 读取我们需要的信息, 可以添加到线程中,设置调用频率
{	
	short rd_value = 0;
	float f_voltage = 0;
	float f_status = 0;
	
	rd_value = i2c_smbus_read_word_data(fd_i2c,0x0f); //剩余容量 
	f_voltage = (float)rd_value*0.001;
	printf("RemainingCapacity  %04x %.2f A\t",rd_value,f_voltage);
	
	rd_value = i2c_smbus_read_word_data(fd_i2c,0x16); //电池状态 
	f_status = (float)rd_value*0.001;
	printf("BatteryStatus  %04x %.2f A\t",rd_value,f_status);
}

根据datasheet 设置i2c_smbus_read_word_data(client,command);

2. 读写i2c从设备(eeprom)

struct  i2c_rdwr_ioctl_data   i2c_data;    /* I2C总线ioctl方法所使用的结构体 */
const char  *i2c_dev = "/dev/i2c-0";       /*设备文件路径*/
unsigned char buftmp[32];
int fd = -1;

static int open_i2c_dev(void)
{
    fd = open(i2c_dev, O_RDWR);
    if(fd <0)
    {
        printf("open i2c device error \n");
        return -1;
    }
}

static void eeprom_init(int fd, unsigned char *buff)
{
    ioctl(fd, I2C_TIMEOUT, 1);    //设置超时时间
    ioctl(fd, I2C_RETRIES, 2);    //设置重发次数
    memset(buff, 0, 32);  
}

static int malloc_mem(int fd, int mode)  /* 分配内存*/
{
    if(mode == read ) /*读需要两个msg, 1个用来发读register的地址, 一个读数据*/
        i2c_data.nmsgs = 2;
    else if(mode == write) /*写的话只要一个msg即可*/
        i2c_data.nmsgs = 1;
    i2c_data.msgs = (struct i2c_msg *)malloc(i2c_data.nmsgs *sizeof(struct i2c_msg));
    if (i2c_data.msgs == NULL)     
	{         
		printf("malloc error\n");        
		close(fd);        
		return -1;   
	} 
}

static int read_write_ioctl(int fd)
{   
    int ret = ioctl(fd, I2C_RDWR, (unsigned long)&i2c_data); 
    if (ret < 0)  
    {
        printf("read or write eeprom data error\n");
        free(i2c_data.msgs);
        return -1;
    }
    free(i2c_data.msgs);
    close(fd);
}

static int print_data(int len, unsigned char *buff)  /* print data */
{
    for(int i = 0; i < len; i++)
    {
        printf(" 0x%02x",buff[i]);
    }
    printf("\n");
}

/*
 * @ device_addr :从设备地址
 * @ sub_addr : 寄存器地址
 * @ buff :缓存区
 * @ ByteNo: 读取长度
 */


unsigned char i2c_read(unsigned char device_addr, unsigned char sub_addr, unsigned char *buff, int b_len)
{
    /*从设备地址是7bit,发送的时候必须右移1bit,以便和相邻的读写标志位组合成1Byte*/
    device_addr >>= 1;

    //读的nmsg为什么是两个,先写一次reg地址才能读数据  
    //xxxxxxxxxxxxxxxxxxx
    //函数调用
    //xxxxxxxxxxxxxxxxxxx
    
         
	//write reg
    memset(buftmp, 0, 32);
    buftmp[0] = sub_addr;
    i2c_data.msgs[0].len = 1;
    i2c_data.msgs[0].addr = device_addr;
    i2c_data.msgs[0].flags = 0;     // 0: write 1:read
    i2c_data.msgs[0].buf = buftmp;

    //read data
    i2c_data.msgs[1].len = b_len;
    i2c_data.msgs[1].addr = device_addr;
    i2c_data.msgs[1].flags = 1; 
    i2c_data.msgs[1].buf = buff;
}

/*
 * @ device_addr :从设备地址
 * @ sub_addr : 寄存器地址
 * @ buff :缓存区
 * @ ByteNo: 读取长度
 */

unsigned char _i2c_write(unsigned char device_addr, unsigned char sub_addr, unsigned char *buff, int b_len)
{
    /*从设备地址是7bit,发送的时候必须右移1bit,以便和相邻的读写标志位组合成1Byte*/
    device_addr >>= 1;
    //xxxxxxxxxxxxxxxxxxx
    //函数调用
    //xxxxxxxxxxxxxxxxxxx
    buftmp[0] = sub_addr;    //写入寄存器的地址
    memcpy(buftmp + 1, buff, ByteNo);     //将需要写入的数据加上寄存器地址拷贝到buftmp
    i2c_data.msgs[0].len = b_len+ 1;    //写入的数据长度 
    i2c_data.msgs[0].addr = device_addr;  // 设备地址
    i2c_data.msgs[0].flags = 0;           // 写
    i2c_data.msgs[0].buf = buftmp;        //将buftmp数据写入到buf中
}

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 硬件连接 首先,我们需要将EEPROM连接到STM32微控制器的I2C总线上。在本示例中,我们将使用STM32F4Discovery开发板,并将EEPROM连接到其I2C1总线。以下是硬件连接图: ![image.png](attachment:image.png) 2. STM32CubeIDE设置 在STM32CubeIDE中,我们需要启用I2C总线并配置它。以下是步骤: - 打开STM32CubeIDE并创建一个新项目。 - 选择“STM32F4xx”系列微控制器和您的开发板型号。 - 启用I2C总线。在“Pinout & Configuration”选项卡中,选择“I2C1”并启用它。 - 配置I2C总线。在“Configuration”选项卡中,选择“I2C1”并进行必要的配置,例如时钟速度和地址模式等。 3. 代码实现 现在,我们可以开始编代码来EEPROM。以下是基本的代码框架: ```c #include "stm32f4xx_hal.h" #include "stdio.h" I2C_HandleTypeDef hi2c1; #define EEPROM_ADDR 0xA0 void EEPROM_Write(uint16_t addr, uint8_t data); uint8_t EEPROM_Read(uint16_t addr); int main(void) { HAL_Init(); __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_I2C1_CLK_ENABLE(); GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_7; GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF4_I2C1; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); hi2c1.Instance = I2C1; hi2c1.Init.ClockSpeed = 100000; hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; hi2c1.Init.OwnAddress1 = 0; hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c1.Init.OwnAddress2 = 0; hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; if (HAL_I2C_Init(&hi2c1) != HAL_OK) { Error_Handler(); } uint8_t data = 0x55; EEPROM_Write(0x0001, data); uint8_t read_data = EEPROM_Read(0x0001); while (1) { } } void EEPROM_Write(uint16_t addr, uint8_t data) { uint8_t tx_data[3] = {addr >> 8, addr & 0xFF, data}; HAL_I2C_Master_Transmit(&hi2c1, EEPROM_ADDR, tx_data, 3, 1000); } uint8_t EEPROM_Read(uint16_t addr) { uint8_t tx_data[2] = {addr >> 8, addr & 0xFF}; uint8_t rx_data[1]; HAL_I2C_Master_Transmit(&hi2c1, EEPROM_ADDR, tx_data, 2, 1000); HAL_I2C_Master_Receive(&hi2c1, EEPROM_ADDR, rx_data, 1, 1000); return rx_data[0]; } ``` 在此示例中,我们定义了两个函数:`EEPROM_Write()`和`EEPROM_Read()`。`EEPROM_Write()`函数将一个字节EEPROM,`EEPROM_Read()`函数从EEPROM取一个字节。这两个函数使用STM32 HAL库中的I2C主机传输函数。 4. 测试 现在,我们可以将代码下载到STM32F4Discovery开发板上并测试代码。在本示例中,我们将向地址0x0001入0x55,并从该地址取数据。如果一切正常,我们应该能够入的数据(0x55)。 以上就是使用STM32CubeIDE进行I2C接口EEPROM的步骤和代码示例。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值