STM32 通用GPIO模拟I2C实现

STM32 通用GPIO模拟I2C实现

通用GPIO模拟I2C通信实现样例
1 GPIO初始化

#ifdef HW_I2C1	//硬件I2C初始化
    //PA8-I2C1_SCL
    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_I2C1);
#else	//模拟I2C初始化
    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_WriteBit(GPIOA, GPIO_Pin_8, Bit_SET);
    GPIO_Init(GPIOA, &GPIO_InitStructure);
#endif

#ifdef HW_I2C1 //硬件I2C初始化
    //PC9-I2C1_SDA
    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOC, &GPIO_InitStructure);
    GPIO_PinAFConfig(GPIOC, GPIO_PinSource9, GPIO_AF_I2C1);
#else  //模拟I2C初始化
    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_WriteBit(GPIOC, GPIO_Pin_9, Bit_SET);
    GPIO_Init(GPIOC, &GPIO_InitStructure);
#endif

2 模拟I2C实例代码

#define M24LC256_ADDR 0xAE
#define M24LC256_PAGESIZE 64
#define M24LC256_WRITE_DELAY delay_ms(15)
static const u32 I2C_CLK_STRETCHING_TIMEOUT = 60000;
static const u32 I2C_WAIT_ACK_TIMEOUT = 30000;
static u32 i2c_clk_stretching_timer = 0;
static u32 i2c_wait_ack_timer = 0;
#define SCL1_H GPIO_SetBits(GPIOA, GPIO_Pin_8)
#define SCL1_L GPIO_ResetBits(GPIOA, GPIO_Pin_8)
#define SDA1_H GPIO_SetBits(GPIOC, GPIO_Pin_9) 
#define SDA1_L GPIO_ResetBits(GPIOC, GPIO_Pin_9)
#define SDA1_READ (GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_9))
#define SCL1_READ (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_8))
static u8 I2C_Start(void)
{
    SDA1_H;
    I2C_delay();   //zyboy
    SCL1_H;
    I2C_delay();
    i2c_clk_stretching_timer = 0;
    while((!SCL1_READ) && i2c_clk_stretching_timer++<=I2C_CLK_STRETCHING_TIMEOUT);  
    if(!SDA1_READ)
        return 0; //SDA线为低电平则总线忙,退出
    SDA1_L;
    I2C_delay();
    if(SDA1_READ)
        return 0; //SDA线为高电平则总线出错,退出
    SCL1_L;
    I2C_delay();
    return 1;
}
static void I2C_Stop(void)
{
    SCL1_L;
    I2C_delay();
    SDA1_L;
    I2C_delay();
    SCL1_H;
    i2c_clk_stretching_timer = 0;
    while((!SCL1_READ) && i2c_clk_stretching_timer++<=I2C_CLK_STRETCHING_TIMEOUT); 
    I2C_delay();
    SDA1_H;
    I2C_delay();
}
static void I2C_Ack(void)
{
    SCL1_L;
    I2C_delay();
    SDA1_L;
    I2C_delay();
    SCL1_H;
    i2c_clk_stretching_timer = 0;
    while((!SCL1_READ) && i2c_clk_stretching_timer++<=I2C_CLK_STRETCHING_TIMEOUT); 
    I2C_delay();
    SCL1_L;
    I2C_delay();
}
static void I2C_NoAck(void)
{
    SCL1_L;
    I2C_delay();
    SDA1_H;
    I2C_delay();
    SCL1_H;
    i2c_clk_stretching_timer = 0;
    while((!SCL1_READ) && i2c_clk_stretching_timer++<=I2C_CLK_STRETCHING_TIMEOUT);   
    I2C_delay();
    SCL1_L;
    I2C_delay();
}
static u8 I2C_WaitAck(void) //返回为:=1有ACK,=0无ACK
{
    delay_us(10);
    SCL1_L;
    I2C_delay();
    SDA1_H;
    I2C_delay(); 
    i2c_wait_ack_timer = 0;
    while((SDA1_READ) && i2c_wait_ack_timer++<=I2C_WAIT_ACK_TIMEOUT);  
    if(!SDA1_READ)
    {
        SCL1_H;
        i2c_clk_stretching_timer = 0;
        while((!SCL1_READ) && i2c_clk_stretching_timer++<=I2C_CLK_STRETCHING_TIMEOUT);  
        I2C_delay();
        SCL1_L;
        return 1;
    }
    return 0;
}
static void I2C_SendByte(u8 SendByte) //数据从高位到低位
{
    u8 i = 8;
    while(i--)
    {
        SCL1_L;
        I2C_delay();
        if(SendByte&0x80)
            SDA1_H;
        else
            SDA1_L;
        SendByte<<=1;
        I2C_delay();
        SCL1_H;
        i2c_clk_stretching_timer = 0;
        while((!SCL1_READ) && i2c_clk_stretching_timer++<=I2C_CLK_STRETCHING_TIMEOUT);  
        I2C_delay();
    }
    SCL1_L;
}
static u8 I2C_ReceiveByte(void) //数据从高位到低位
{
    u8 i = 8;
    u8 ReceiveByte = 0;
    SDA1_H;
    while(i--)
    {
        ReceiveByte <<= 1;
        SCL1_L;
        I2C_delay();
        SCL1_H;
        i2c_clk_stretching_timer = 0;
        while((!SCL1_READ) && i2c_clk_stretching_timer++<=I2C_CLK_STRETCHING_TIMEOUT); 
        I2C_delay();
        if(SDA1_READ)
        {
            ReceiveByte |= 0x01;
        }
    }
    SCL1_L;
    return ReceiveByte;
}
static u8 Deal_IIC_Data(u8 slave_addr, u8 *sdata, u16 slen, u8 *rdata, u16 rlen)
{
    u16 i = 0;
    
    if(slen > 0)
    {
        if(!I2C_Start())
            return 0;

        I2C_SendByte(slave_addr);
        if(!I2C_WaitAck())
        {
            I2C_Stop();
            return 0;
        }        
        for(i = 0; i < slen; i++)
        {
            I2C_SendByte(sdata[i]);
            if(!I2C_WaitAck())
            {
                I2C_Stop();
                return 0;
            }
        }
    }
        if(rlen > 0)
    {
        if(!I2C_Start())
            return 0;

        I2C_SendByte(slave_addr | 0x01);
        if(!I2C_WaitAck())
        {
            I2C_Stop();
            return 0;
        }
        for(i = 0; i < rlen; i++)
        {
            rdata[i] = I2C_ReceiveByte();

            if(i == (rlen-1))
            {
                I2C_NoAck();
            }
            else
            {
                I2C_Ack();
            }
        }
    }
    I2C_Stop();
    return 1;
}
void M24LC256_Program_Page(u16 addr, u8 *data, u16 len)
{
	u16 i = 0;
	u8 *sdata;
	sdata = (u8 *)malloc(len+2);
	sdata[0] = addr / 0x100;
	sdata[1] = addr % 0x100;
	for(i = 0; i < len; i++)
	{
		sdata[2+i] = data[i];
	}
	Deal_IIC_Data(M24LC256_ADDR, sdata, len+2, NULL, 0);
	
  M24LC256_WRITE_DELAY;

	free(sdata);
}
void M24LC256_Program_Byte(u16 addr, u8 data)
{
	u8 sdata[3];

	sdata[0] = addr / 0x100;
	sdata[1] = addr % 0x100;
	sdata[2] = data;

	Deal_IIC_Data(M24LC256_ADDR, sdata, 3, NULL, 0);
    M24LC256_WRITE_DELAY;
}

void M24LC256_Read_Bytes(u16 addr, u8 *data, u16 len)
{
	u8 sdata[2];

	sdata[0] = addr / 0x100;
	sdata[1] = addr % 0x100;

	Deal_IIC_Data(M24LC256_ADDR, sdata, 2, data, len);
}
void M24LC256_Program(u16 addr, u8 *data, u16 len)	//此接口存在bug,需优化
{
    u8 page_num = 0, single_num = 0, current_addr = 0, first_page_num = 0;
    current_addr = addr % M24LC256_PAGESIZE; //写入地址是开始页的第几位
    first_page_num = M24LC256_PAGESIZE - current_addr; //在开始页要写入的个数
    page_num = len / M24LC256_PAGESIZE; //要写入的页数
    single_num = len % M24LC256_PAGESIZE; //不足一页的个数

    if(current_addr == 0) //写入地址是页的开始
    {
        if(page_num == 0) //数据小于一页
        {
            M24LC256_Program_Page(addr, data, single_num); //写少于一页的数据
        }
        else //数据大于等于一页
        {
            while(page_num) //要写入的页数
            {
                M24LC256_Program_Page(addr, data, M24LC256_PAGESIZE); //写一页的数据
                addr += M24LC256_PAGESIZE;
                data += M24LC256_PAGESIZE;
                page_num--;
            }
            if(single_num != 0) //剩余数据小于一页
            {
                M24LC256_Program_Page(addr, data, single_num); //写少于一页的数据
            }
        }
    }
    else //写入地址不是页的开始
    {
        if(page_num == 0) //数据小于一页
        {
            M24LC256_Program_Page(addr, data, single_num); //写少于一页的数据
        }
        else //数据大于等于一页
        {
            len -= first_page_num;
            page_num = len / M24LC256_PAGESIZE; //重新计算要写入的页数
            single_num = len % M24LC256_PAGESIZE; //重新计算不足一页的个数

            if(first_page_num != 0)
            {
                M24LC256_Program_Page(addr, data, first_page_num); //将开始的空间写满一页
                addr += first_page_num;
                data += first_page_num;
            }

            while(page_num--) //要写入的页数
            {
                M24LC256_Program_Page(addr, data, M24LC256_PAGESIZE); //写一页的数据
                addr += M24LC256_PAGESIZE;
                data += M24LC256_PAGESIZE;
            }
            if(single_num != 0) //剩余数据小于一页
            {
                M24LC256_Program_Page(addr, data, single_num); //写少于一页的数据
            }
        }
    }
}

你可能感兴趣的:(ARM/STM32)