24c32,i2c原理

通讯主要就是scl,sda线,和电源-地。4线

地址由24c32器件的A0,A1,A2来决定。SCL,SDA需要接上拉。

本次说的都是主机端流程。

1.启动和stop

SCL=1,SDA下降沿表示启动。 SCL=1,SDA上升沿表示stop。

2.写

流程:start---->设备地址,最后一位为0表示写,等待ACK(ACK是传输每个字节都有,谁收数据谁发ACK,除最后一次ACK为1,其他ACK为0)----->2个字节数据地址------->写入数据---------->stop

注意一点:

1. 24c32每页32字节,32字节写缓存。写入的数据先到缓存区,收到stop时,写入储存区。

2. 如果写入数据大于32字节,需要分为n/32次发送,否则写缓存会被覆盖

3. 如果写如数据在页边界(如:写2个字节,31地址开始写,会导致32地址写不进去,需要先写第一页,在写第二页)

3.读

流程: start-------->设备地址(写,等应答ACK)------->写入2字节读取的地址------->restart--------->设备地址(读,等应答)-------->接收n个数据(每接收一个数据,应答ACK=0,最后一字节应答ACK=1)----->stop.

读的时候并没长度限制。启动操作变长了,先要写入地址,然后重新启动开始读取。可以把读分为写和读2个部分,写就和上面一样了,linux的I2C驱动就是这样写的。

4.仲裁失败,表示多个主机时,被别的主机抢占了总线。

linux系统中应用层使用:ioctl(fd, I2C_RDWR, &idata)来系统函数进行读写即可

参考主I2C程序:

#include "stm32f10x.h"

#define SCL_H         GPIOB->BSRR = IIC_SCL
#define SCL_L         GPIOB->BRR  = IIC_SCL 
   
#define SDA_H         GPIOB->BSRR = IIC_SDA
#define SDA_L         GPIOB->BRR  = IIC_SDA

#define SDA_read      GPIOB->IDR  & IIC_SDA



void I2C_delay(void)
{	
   	u16 i=50; //10-大概2us,50-大概7us,IIC速率大概80khz
   	while(i) 
   	{ 
     		i--; 
   	} 
}

u8 IIc_Start(void)
{
	SDA_H;
	SCL_H;
	I2C_delay();
	if(!SDA_read)return FALSE;	//SDA线为低电平则总线忙,退出
	SDA_L;
	I2C_delay();
	if(SDA_read) return FALSE;	//SDA线为高电平则总线出错,退出
	SDA_L;
	I2C_delay();
	return TRUE;
}

void IIc_Stop(void)
{
	SCL_L;
	I2C_delay();
	SDA_L;
	I2C_delay();
	SCL_H;
	I2C_delay();
	SDA_H;
	I2C_delay();
}

void Rd_Ack(void)
{	
	SCL_L;
	I2C_delay();
	SDA_L;
	I2C_delay();
	SCL_H;
	I2C_delay();
	SCL_L;
	I2C_delay();
}

 void Rd_NoAck(void)
{	
	SCL_L;
	I2C_delay();
	SDA_H;
	I2C_delay();
	SCL_H;
	I2C_delay();
	SCL_L;
	I2C_delay();
}

 u8 Wr_Ack(void) 	 //返回为:=1有ACK,=0无ACK
{
	SCL_L;
	I2C_delay();
	SDA_H;			
	I2C_delay();
	SCL_H;
	I2C_delay();
	if(SDA_read)
	{
      SCL_L;
      return FALSE;
	}
	SCL_L;
	return TRUE;
}

 void IIc_Send(u8 SendByte) //数据从高位到低位//
{
    u8 i=8;
    while(i--)
    {
        SCL_L;
        I2C_delay();
      if(SendByte&0x80)
        SDA_H;  
      else 
        SDA_L;   
        SendByte<<=1;
        I2C_delay();
		SCL_H;
        I2C_delay();
    }
    SCL_L;
}

 u8 IIc_Receive(void)  //数据从高位到低位//
{ 
    u8 i=8;
    u8 ReceiveByte=0;

    SDA_H;				
    while(i--)
    {
      ReceiveByte<<=1;      
      SCL_L;
      I2C_delay();
	  SCL_H;
      I2C_delay();	
      if(SDA_read)
      {
        ReceiveByte|=0x01;
      }
    }
    SCL_L;
    return ReceiveByte;
}

/*****************向有子地址器件发送多字节数据函数*************/
u8 Fm24cl64_WritenBytes(u8 sla,u16 suba,u8 *s,u16 no)
{
	u16 i;
	u8 error = TRUE;
	
	if(no==0) return error;
	IIc_Start();               /*启动总线*/
	IIc_Send(sla);             /*发送器件物理地址*/
	if(Wr_Ack() == FALSE)
	{
		error = FALSE;
		goto exit1;
	}
	
	i=(u8)(suba>>8);
	IIc_Send(i);               /*发送器件子地址高字节*/
	if(Wr_Ack() == FALSE)
	{
		error = FALSE;
		goto exit1;
	}
	i=(u8)suba;          /*发送器件子地址低字节*/
	IIc_Send(i);
	if(Wr_Ack() == FALSE)
	{
		error = FALSE;
		goto exit1;
	}
	for(i=0;i<no;i++)
	{   
		IIc_Send(*(s+i));           /*发送数据*/
		if(Wr_Ack() == FALSE)
		{
			error = FALSE;
			break;
		}
	} 
exit1:	
	IIc_Stop();                 /*结束总线*/ 
	return error;
}
/***********向有子地址器件读取多字节数据函数*****************/
u8 Fm24cl64_ReadnBytes(u8 sla,u16 suba,u8 *s,u16 no)
{
	u16  i;
	u8 error = TRUE;
	
	if(no==0) return error;
	IIc_Start();              /*启动总线*/

	IIc_Send(sla);           /*发送器件地址*/
	if(Wr_Ack() == FALSE)
	{
		error = FALSE;
		goto exit;
	}
	i=(u8)(suba>>8);
	IIc_Send(i);            /*发送器件子地址高字节*/
	if(Wr_Ack() == FALSE)
	{
		error = FALSE;
		goto exit;
	}
	i=(u8)suba;          /*发送器件子地址低字节*/

	IIc_Send(i); 
	if(Wr_Ack() == FALSE)
	{
		error = FALSE;
		goto exit;
	}
	IIc_Start();  
	IIc_Send(sla|0x01);
	if(Wr_Ack() == FALSE)
	{
		error = FALSE;
		goto exit;
	}
	for(i=0;i<no-1;i++)
	{   
		*(s+i)=IIc_Receive();          /*发送数据*/
		Rd_Ack();           /*发送就答位*/  
	} 
	*(s+i)=IIc_Receive();
	Rd_NoAck();               /*发送非应位*/
exit:	
	IIc_Stop();               /*结束总线*/ 
	return error;
}
/*****************清除FM24cl64 从suba开始的地址空间0000-0X1FFF*************/
u8 FM24CL64_Clr(u8 sla,u16 suba)
{
	u8  i;
	u16 y;
	u8 error = TRUE;
	
	
	IIc_Start();               /*启动总线*/
	IIc_Send(sla);             /*发送器件物理地址*/
	if(Wr_Ack() == FALSE)
	{
		error = FALSE;
		goto exit1;
	}
	
	i=(u8)(suba>>8);
	IIc_Send(i);               /*发送器件子地址高字节*/
	if(Wr_Ack() == FALSE)
	{
		error = FALSE;
		goto exit1;
	}
	i=(u8)suba;          /*发送器件子地址低字节*/
	IIc_Send(i);
	if(Wr_Ack() == FALSE)
	{
		error = FALSE;
		goto exit1;
	}
	for(y=0;y<(0x2000 - 40);y++)
	{   
		IIc_Send(0);           /*发送数据*/
		if(Wr_Ack() == FALSE)
		{
			error = FALSE;
			break;
		}
	} 
exit1:	
	IIc_Stop();                 /*结束总线*/ 
	return error;
}

linux应用层代码。前提底层已经把i2c指定到了/dev/i2c-x

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <stdint.h>
#include <time.h>
#include <sys/timeb.h>
#include <string>

#define DEBUG_LEVEL_DEF 5 // do not use value, this is common print.you can use logdbg in project
// extern int DEBUG_LEVEL_DEF;
#define PRINTF_DEF(lev, fmt, lprt, ...)                                                                                \
    do                                                                                                                 \
    {                                                                                                                  \
        if (DEBUG_LEVEL_DEF >= lev)                                                                                    \
        {                                                                                                              \
            struct timeb tnow;                                                                                         \
            struct tm *tmnow;                                                                                          \
            ftime(&tnow);                                                                                              \
            tmnow = localtime(&tnow.time);                                                                             \
            printf("[%d-%02d-%02d %02d:%02d:%02d.%03d][%s][%s,%d]" fmt "\n", tmnow->tm_year + 1900, tmnow->tm_mon + 1, \
                   tmnow->tm_mday, tmnow->tm_hour, tmnow->tm_min, tmnow->tm_sec, tnow.millitm % 1000,                  \
                   lprt, __func__, __LINE__, ##__VA_ARGS__);                                                           \
        }                                                                                                              \
    } while (0);
#define printfat(fmt, ...) PRINTF_DEF(0, fmt, "fat", ##__VA_ARGS__)
#define printerr(fmt, ...) PRINTF_DEF(1, fmt, "err", ##__VA_ARGS__)
#define printwarn(fmt, ...) PRINTF_DEF(2, fmt, "war", ##__VA_ARGS__)
#define printinfo(fmt, ...) PRINTF_DEF(3, fmt, "inf", ##__VA_ARGS__)
#define printdbg(fmt, ...) PRINTF_DEF(4, fmt, "dbg", ##__VA_ARGS__)
#define printtra(fmt, ...) PRINTF_DEF(5, fmt, "tra", ##__VA_ARGS__)

class i2cOperateClass
{
public:
    i2cOperateClass(std::string i2DevFile = "/dev/i2c-0")
    {
        optFileName = i2DevFile;
        optFd = -1;
    }
    ~i2cOperateClass()
    {
    }
    static i2cOperateClass &instance()
    {
        static i2cOperateClass i2work;
        return i2work;
    }
    void closeOpt()
    {
        if (optFd <= 0)
        {
            return;
        }
        close(optFd);
        optFd = -1;
    }
    int initopt()
    {
        if (optFileName == "")
        {
            printerr("");
            return -1;
        }

        optFd = open(optFileName.c_str(), O_RDWR);
        if (optFd < 0)
        {
            printerr("%s:open fail!", optFileName.c_str());
            return -1;
        }
        ioctl(optFd, I2C_RETRIES, 2);
        return 0;
    }
    int readopt(uint8_t slaveDeviceAddress, uint16_t registerAddress, std::string &readstr, uint16_t readsize,
                uint16_t registerSize = 1)
    {
        readstr = "";
        if (optFd < 0)
        {
            printerr("%s:open fail!", optFileName.c_str());
            return -1;
        }
        uint8_t registerBuffer[4];
        if (registerSize == 1)
        {
            registerBuffer[0] = registerAddress;
        }
        else if (registerSize == 2)
        {
            registerBuffer[0] = registerAddress >> 8;
            registerBuffer[1] = registerAddress;
        }
        else
        {
            printerr("%d", registerSize);
            return -1;
        }
        printdbg("dev:0x%x, register:0x%x, readsize:%d", slaveDeviceAddress, registerAddress, readsize);
        readstr.resize(readsize);
        struct i2c_msg msgs[2] =
            {
                {slaveDeviceAddress, 0, registerSize, registerBuffer},
                {slaveDeviceAddress, I2C_M_RD, readsize, (uint8_t *)readstr.data()},
            };
        struct i2c_rdwr_ioctl_data idata =
            {
                msgs,
                2
            };
        if (ioctl(optFd, I2C_RDWR, &idata) < 0)
        {
            printerr("%s:open fail!", optFileName.c_str());
            return -2;
        }
        return readsize;
    }
    int writeopt(uint8_t slaveDeviceAddress, uint16_t registerAddress, std::string writestr,
                 uint16_t registerSize = 1)
    {
        if (optFd < 0)
        {
            printerr("%s:open fail!", optFileName.c_str());
            return -1;
        }
        uint8_t registerBuffer[4];
        if (registerSize == 1)
        {
            registerBuffer[0] = registerAddress;
        }
        else if (registerSize == 2)
        {
            registerBuffer[0] = registerAddress >> 8;
            registerBuffer[1] = registerAddress;
        }
        else
        {
            printerr("%d", registerSize);
            return -1;
        }
        std::string tmpWriteStr;
        tmpWriteStr.append((const char *)registerBuffer, registerSize);
        tmpWriteStr.append(writestr);
        printdbg("%x", tmpWriteStr.size());
        struct i2c_msg msgs[2] =
            {
                {slaveDeviceAddress, 0, tmpWriteStr.size(), (uint8_t *)tmpWriteStr.data()},
            };
        struct i2c_rdwr_ioctl_data idata =
            {
                msgs,
                1
            };
        if (ioctl(optFd, I2C_RDWR, &idata) < 0)
        {
            printerr("%s:write fail!", optFileName.c_str());
            return -2;
        }
        return writestr.size();
    }

private:
    std::string optFileName;
    int optFd;
};

int main()
{
    std::string tmpstr;
    int tmpflag;
    const unsigned char channel[] = {0x00, 0x04, 0x01, 0x05, 0x02, 0x06, 0x03, 0x07};
    i2cOperateClass::instance().initopt();

    for(int i = 0; i < 8; i++)
    {
        uint16_t tmpregister = 0x84;
        tmpregister |= (channel[i] << 4);
        i2cOperateClass::instance().readopt(0x48, tmpregister, tmpstr, 1);
        if(tmpstr.size() < 1)
        {
            printerr("");
        }
        printdbg("%d", tmpstr[0]);
    }

    for(int i = 0; i < 8; i++)
    {
        uint16_t tmpregister = 0x84;
        tmpregister |= (channel[i] << 4);
        i2cOperateClass::instance().readopt(0x49, tmpregister, tmpstr, 1);
        if(tmpstr.size() < 1)
        {
            printerr("");
        }
        printdbg("%d", tmpstr[0]);
    }

    for(int i = 0; i < 8; i++)
    {
        uint16_t tmpregister = 0x84;
        tmpregister |= (channel[i] << 4);
        i2cOperateClass::instance().readopt(0x4A, tmpregister, tmpstr, 1);
        if(tmpstr.size() < 1)
        {
            printerr("");
        }
        printdbg("%d", tmpstr[0]);
    }

    for(int i = 0; i < 8; i++)
    {
        uint16_t tmpregister = 0x84;
        tmpregister |= (channel[i] << 4);
        i2cOperateClass::instance().readopt(0x4B, tmpregister, tmpstr, 1);
        if(tmpstr.size() < 1)
        {
            printerr("");
        }
        printdbg("%d", tmpstr[0]);
    }

    i2cOperateClass::instance().closeOpt();
    return 1;
}

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值