STM32模拟I2C程序

修改自cleanflight

/*******************************************************************************
  测试平台:STM32F103ZET6最小系统
*******************************************************************************/
static void i2cDelay()
{
    volatile int i = 7;
    while (i)
    i--;
}

// SCL高电平期间,SDA出现下降沿为起始信号
static bool i2cStart()
{
    SDA_OUT;
    SCL_H;
    SDA_H;
    i2cDelay();
    if (!sdaRead)  // 如果SDA为低电平,则总线忙,退出
        return false;
    SDA_L;
    if (sdaRead)  // 如果SDA为高电平,则总线忙,退出
        return false;
    SDA_L;
    return true;
}

// SCL高电平期间,SDA出现上升沿为停止信号
static void i2cStop(void)
{
    SDA_OUT;
    SCL_L; 
    SDA_L;
    i2cDelay();  // STOP:when CLK is high DATA from low to high 
    SCL_H;
    SDA_H;  
    i2cDelay();
}

static void i2cAck(void)
{
    SDA_OUT;
    SCL_L;
    i2cDelay();
    SDA_L;
    i2cDelay();
    SCL_H;
    i2cDelay();
    SCL_L;
}

static void i2cNoAck(void)
{
    SDA_OUT;
    SCL_L;
    i2cDelay();
    SDA_H;
    i2cDelay();
    SCL_H;
    i2cDelay();
    SCL_L;
}

// SCL高电平期间,SDA电平被从设备拉低表示应答
static bool i2cWaitAck(void)
{
    uint8_t errTimes = 0;

    SDA_IN;
    SDA_H;
    i2cDelay();
    SCL_H;
    i2cDelay();
    while (sdaRead) {
        if (errTimes++ > 20) {
            SCL_L;
            return false;
        }           
        i2cDelay();
    }
    SCL_L;
    return true;
}

// 发送数据,数据从高位到低位传输  
static void i2cSendByte(uint8_t byte)  
{
    uint8_t i = 8;

    SDA_OUT;
    while (i--) {      
        SCL_L;  // 时钟信号为低电平期间,允许数据线电平变化
        i2cDelay();
        if (byte & 0x80)
            SDA_H;
        else
            SDA_L; 
        byte <<= 1; 
        i2cDelay();
        SCL_H;
        i2cDelay();
    }
    SCL_L;
}

static uint8_t i2cReceiveByte()  
{
    uint8_t i = 8;
    uint8_t byte = 0;

    SDA_IN;
    SDA_H;
    while (i--) {
        byte <<= 1;
        SCL_H;
        i2cDelay();
        if (sdaRead) {
            byte |= 0x01;
        }
        SCL_L;
        i2cDelay();
    }
    SCL_L;
    return byte; 
}


void i2cInit()
{
    GPIO_InitTypeDef GPIO_InitStructure;

    /* Enable GPIOB clock */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    /* Configure GPIOB.6 & GPIOB.7 as open-drain output */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(GPIOB, &GPIO_InitStructure);
}

/**
 * 通过I2C总线写一字节数据
 * @param[in] dev:设备I2C地址
 * @param[in] reg:寄存器地址
 * @param[in] data:要写入的数据
 */
bool i2cWriteOneByte(uint8_t dev, uint8_t reg, uint8_t data)
{
    if (!i2cStart())        
        return false;
    i2cSendByte(dev << 1);  // 从机地址由高7位+读写位构成   
    if (!i2cWaitAck()) {     
        i2cStop();
        return false;
    }
    i2cSendByte(reg);       
    i2cWaitAck();
    i2cSendByte(data);     
    i2cWaitAck();
    return true;
}

/**
 *  
 * @param[in] dev:设备I2C地址
 * @param[in] reg:寄存器地址
 * @param[in] len:字节数 
 * @param[in] data:待写入的数据 
 */
bool i2cWriteBytes(uint8_t dev, uint8_t reg, uint8_t len, uint8_t *data)
{
    uint8_t i;

    if (!i2cStart())        
        return false;
    i2cSendByte(dev << 1);          
    if (!i2cWaitAck()) {     
        i2cStop();
        return false;
    }
    i2cSendByte(dev);   
    i2cWaitAck();
    for (i = 0; i < len; i++) {
        i2cSendByte(data[i]);
        if (!i2cWaitAck()) {
            i2cStop();
            return false;
        }
    }
    i2cStop();
    return true;
}


/**
 * 从I2C设备中读取数据
 * @param[in] dev:设备I2C地址
 * @param[in] reg:寄存器地址
 * @param[in] len:数据字节数
 * @param[out] data:读出的数据
 */
bool i2cReadBytes(uint8_t dev, uint8_t reg, uint8_t len, uint8_t *data)
{
    if (!i2cStart())        
        return false;
    i2cSendByte(dev << 1);      
    if (!i2cWaitAck()) {     
        i2cStop();
        return false;
    }
    i2cSendByte(reg);     
    i2cWaitAck();
    i2cStart();           
    i2cSendByte((dev << 1) | 0x01);  // 器件地址+读命令    
    i2cWaitAck();
    while (len) {
        *data = i2cReceiveByte();
        if (len == 1)
            i2cNoAck();  // 最后一个字节不应答
        else
            i2cAck();
        data++;
        len--;
    }
    i2cStop();
    return true;
}






  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32是一种广泛应用的嵌入式单片机,具有强大的功能和灵活的软件开发能力。在STM32中,I2C(Inter-Integrated Circuit)是一种通信协议,用于连接各个外设并实现数据传输。 软件模拟I2C程序是指在STM32中使用软件模拟的方式实现I2C协议的功能。这种方法可以在硬件不支持I2C功能或者I2C总线被其他外设占用的情况下,使用GPIO引脚模拟I2C信号线,通过软件控制来实现I2C通信。 实现软件模拟I2C程序的关键步骤如下: 1. 设置GPIO引脚模拟I2C的SDA(数据线)和SCL(时钟线)。 2. 初始化GPIO引脚,并配置为输出模式。 3. 实现I2C的起始信号,将SDA线由高电平变为低电平时,同时将SCL线保持为高电平。 4. 实现I2C的停止信号,将SDA线由低电平变为高电平时,同时将SCL线保持为高电平。 5. 实现I2C数据传输,包括发送和接收。 6. 在发送数据时,先将数据写入SDA线,再将SCL线由高电平变为低电平,完成一次数据传输。 7. 在接收数据时,先将SCL线由高电平变为低电平,再读取SDA线上的数据。 8. 根据I2C协议的需要,可能还需要设置ACK信号等功能。 需要注意的是,软件模拟I2C程序在速度上可能无法达到硬件I2C的要求,因此在使用时需根据具体应用场景进行性能上的优化调整。 总之,通过软件模拟I2C程序,我们可以在STM32上实现I2C通信的功能,为嵌入式开发提供了更多的灵活性和可扩展性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值