单片机
返回首页

STM32模拟I2C程序

2018-05-20 来源:eefocus

/*******************************************************************************

  测试平台: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;

}


进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • CCD图像传感器在微光电视系统中的应用

  • 光控音效发生器电路

  • 如何利用ESP8266制作一个简单的四轴飞行器

  • 非常简单的150W功放电路图

  • 一个简单的警笛电路图

  • 如何使用LED驱动器LM3915制作振动计

    相关电子头条文章