使用GPIO口实现模拟I2C通信

在gpio_i2c.c中加入:
#include "gpio_i2c.h"

#define AW_I2C_SCL_1() HAL_GPIO_WritePin(i2c_hw_info.SCL_GPIO_INFO.GPIOx, i2c_hw_info.SCL_GPIO_INFO.gpio_pin, GPIO_PIN_SET)
#define AW_I2C_SCL_0() HAL_GPIO_WritePin(i2c_hw_info.SCL_GPIO_INFO.GPIOx, i2c_hw_info.SCL_GPIO_INFO.gpio_pin, GPIO_PIN_RESET)
#define AW_I2C_SDA_1() HAL_GPIO_WritePin(i2c_hw_info.SDA_GPIO_INFO.GPIOx, i2c_hw_info.SDA_GPIO_INFO.gpio_pin, GPIO_PIN_SET)
#define AW_I2C_SDA_0() HAL_GPIO_WritePin(i2c_hw_info.SDA_GPIO_INFO.GPIOx, i2c_hw_info.SDA_GPIO_INFO.gpio_pin, GPIO_PIN_RESET)
#define AW_I2C_SDA_READ() HAL_GPIO_ReadPin(i2c_hw_info.SDA_GPIO_INFO.GPIOx, i2c_hw_info.SDA_GPIO_INFO.gpio_pin)

#define AW_I2C_DELAY_US(x) soft_udelay(1)

//clock = 72Hz

static void soft_udelay(unsigned int us){
    int i = 50;
    while(us!=0){
        i=50;
        while(i!=0)
            i--;
        us--;
    }
}


static I2C_HWINFO_STRUCT i2c_hw_info = {
    //scl info
    {
        GPIOB,
        GPIO_PIN_10,
    },
    //sda info
    {
        GPIOB,
        GPIO_PIN_11,
    },
};

static void aw_i2c_stop(void){
    AW_I2C_SCL_1();
    AW_I2C_SDA_0();
    AW_I2C_DELAY_US(1);
    AW_I2C_SDA_1();
    AW_I2C_DELAY_US(3);
    
};

static void aw_i2c_start(void){
    AW_I2C_SDA_1();
    AW_I2C_DELAY_US(1);
    AW_I2C_SCL_1();
    AW_I2C_DELAY_US(1);
    AW_I2C_SDA_0();
    AW_I2C_DELAY_US(1);
};

static signed char aw_i2c_wait_ack(void){
    unsigned char i=0;
    AW_I2C_SCL_1();
    for(i=0;i<5;i++){
        if(0 == AW_I2C_SDA_READ()){
            AW_I2C_DELAY_US(1);
            AW_I2C_SCL_0();
            AW_I2C_DELAY_US(1);
            return 0;
        }
        AW_I2C_DELAY_US(1);
    }
    aw_i2c_stop();
    return -1; // timeout
    
}

static void aw_i2c_master_send_ack(void){
    AW_I2C_SDA_0();
    AW_I2C_SCL_1();
    AW_I2C_DELAY_US(1);
    AW_I2C_SCL_0();
    AW_I2C_DELAY_US(1);
}

static signed char aw_i2c_send_byte(unsigned char data){
    unsigned char i=0;
    data &= 0xFF;
    AW_I2C_SCL_0();
    AW_I2C_DELAY_US(1);
    for(i=0;i<8;i++){
        if(data>>(7-i)&0x01){
            AW_I2C_SDA_1();
        }
        else{
            AW_I2C_SDA_0();
        }
        AW_I2C_SCL_1();
        AW_I2C_DELAY_US(1);
        AW_I2C_SCL_0();
        AW_I2C_DELAY_US(1);
    }
    return aw_i2c_wait_ack();
}

static char aw_i2c_receive_byte(unsigned char *data){
    unsigned char i = 0;
    *data = 0x00;
    for(i=0;i<8;i++){
        AW_I2C_SCL_1();
        AW_I2C_DELAY_US(1);
        *data <<= 1;
        if(AW_I2C_SDA_READ() == 0x01){
            *data = *data | 0x01;
        }
        AW_I2C_SCL_0();
        AW_I2C_DELAY_US(1);
    }
    aw_i2c_master_send_ack();
    return 0;
}
    

signed char aw_gpio_i2c_read_exc(unsigned char dev_addr, unsigned char reg_addr, unsigned char *p_data, unsigned int data_num){
    int re = 0;
    unsigned char i=0;
    aw_i2c_start();
    //write flag
    re = aw_i2c_send_byte(dev_addr<<1&(~(0x01)));
    re = aw_i2c_send_byte(reg_addr);
    if(re < 0){
        return -1;
    }
    aw_i2c_start();
    // read flag
    re = aw_i2c_send_byte(dev_addr<<1|0x01);
    for(i=0;i<data_num;i++){
        re = aw_i2c_receive_byte(p_data+i);
        if(re < 0){
            aw_i2c_stop();    
            return -1;
        }
    }
    aw_i2c_stop();
    return 0;
}

signed char aw_gpio_i2c_write_exc(unsigned char dev_addr, unsigned char reg_addr, unsigned char *p_data, unsigned int data_num){
    signed char re = 0;
    unsigned char i=0;
    aw_i2c_start();
    re = aw_i2c_send_byte(dev_addr<<1&(~0x01));
    re = aw_i2c_send_byte(reg_addr);
    if(re < 0){
        return -1;
    }
    for(i=0;i<data_num;i++){
        re = aw_i2c_send_byte((unsigned char)*(p_data+i));
        if(re < 0){
            return -1;
        }
    }
    aw_i2c_stop();    
    return 0;
}

signed char aw_gpio_i2c_read_reg(unsigned char dev_addr, unsigned char reg_addr, unsigned char *value){
    return aw_gpio_i2c_read_exc(dev_addr, reg_addr, value, 1);
}

signed char aw_gpio_i2c_write_reg(unsigned char dev_addr, unsigned char reg_addr, unsigned int value){
    unsigned char val = (unsigned char)value;
    return aw_gpio_i2c_write_exc(dev_addr, reg_addr, &val, 1);
}

void i2c_gpio_init(void){
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    __HAL_RCC_GPIOB_CLK_ENABLE();
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pin = i2c_hw_info.SCL_GPIO_INFO.gpio_pin;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(i2c_hw_info.SCL_GPIO_INFO.GPIOx, &GPIO_InitStruct);
    GPIO_InitStruct.Pin = i2c_hw_info.SDA_GPIO_INFO.gpio_pin;
    HAL_GPIO_Init(i2c_hw_info.SDA_GPIO_INFO.GPIOx, &GPIO_InitStruct);
}

在gpio_i2c.h中加入:

#ifndef __GPIO_I2C_H__
#define __GPIO_I2C_H__
#include "stm32l4xx_hal.h"
#include "stm32l4xx_hal_gpio.h"
#include "stm32l4xx_hal_rcc.h"


typedef struct{
    GPIO_TypeDef * GPIOx;
    uint16_t gpio_pin;
}GPIO_INFO_STRUCT;


typedef struct{
    GPIO_INFO_STRUCT SCL_GPIO_INFO;
    GPIO_INFO_STRUCT SDA_GPIO_INFO;
}I2C_HWINFO_STRUCT;

extern void i2c_gpio_init(void);
extern signed char aw_gpio_i2c_read_reg(unsigned char dev_addr, unsigned char reg_addr, unsigned char *value);
extern signed char aw_gpio_i2c_write_reg(unsigned char dev_addr, unsigned char reg_addr, unsigned int value);
extern signed char aw_gpio_i2c_read_exc(unsigned char dev_addr, unsigned char reg_addr, unsigned char *p_data, unsigned int data_num);
extern signed char aw_gpio_i2c_write_exc(unsigned char dev_addr, unsigned char reg_addr, unsigned char *p_data, unsigned int data_num);


#endif
 


版权声明:本文为qweqwe1233333原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。