• STM32L151之IIC


    用STM32L151(以下简称151吧)有一段时间了,151主要应用于低功耗领域,例如电子标签,低功耗性能不错。

    正题:由于所用板子上的IIC器件一直没有上拉电阻所以一直用IO口模拟IIC(IIC器件是加速度传感器ADXL346),最近新版子上多了一个IIC器件(温湿度传感器SI7005),带有上拉电阻,我本想先不焊接上拉电阻,用以前模拟IIC的程序检测一下器件是否焊接良好,结果不通,我检查了几遍程序,将IO口改成ADXL346的驱动端口是可以读取出器件ID的,但是SI7005就是不行。我检查焊接好像没问题,然后用示波器看了下波形,在写器件地址时没有应答信号。

    ADXL346程序:

    #define I2C_SLAVE_ADDRESS7 0xA6
    #define I2C_SCL_0 GPIO_ResetBits(GPIOB,GPIO_Pin_10)
    #define I2C_SCL_1 GPIO_SetBits(GPIOB,GPIO_Pin_10)
    #define I2C_SDA_0 GPIO_ResetBits(GPIOB,GPIO_Pin_11)
    #define I2C_SDA_1 GPIO_ResetBits(GPIOB,GPIO_Pin_11)
    #define I2C_SDA_STAT GPIO_ReadInputDataBit(GPIO,GPIO_Pin_11)
    #define I2C_ACK 0
    #define I2C_NACK 1
    #define I2C_READY 0
    #define I2C_BUSY 1
    #define I2C_ERROR 3
    void I2C_NOP(void)
    {
        uint8_t i = 5;
        while(i--);
    }
    
    void TWI_Initialize(void)//没有上拉电阻将SDA和SCL设置成推挽输出
    { 
        GPIO_InitTypeDef GPIO_InitStructure;  
        GPIO_InitStructure.GPIO_Speed=GPIO_Speed_10MHz; 
        GPIO_InitStructure.GPIO_OType=GPIO_OType_PP; 
        GPIO_InitStructure.GPIO_Pin=GPIO_Pin_7 | GPIO_Pin_6; 
        GPIO_Init(GPIOB,&GPIO_InitStructure);
    }
    
    uint8_t I2C_Start(void)
    {
        I2C_SDA_1;
        NOP();
        I2C_SCL_1;
        NOP();
        if(!I2C_SDA_STAT)
        {
            return I2C_BUSY;
        }
        I2C_SDA_0;
        NOP();
        I2C_SCL_0;
        NOP();
        if(I2C_SDA_STAT)
        {
            return I2C_ERROR;
        }
        return I2C_READY;
    }
    
    void I2C_STOP(void)
    {
        I2C_SDA_0;
        NOP();
        I2C_SCL_1;
        NOP();
        I2C_SDA_1;
        NOP();
    } 
    
    uint8_t I2C_SendByte(uint8_t data)
    {
        uint8_t i,err;
        I2C_SCL_0;
        for(i=0;i<8;i++)
        {
            if(data&0x80)
            {
                I2C_SDA_1;
            }
            else
            {
                I2C_SDA_0;
            }
            data<<=1;
            NOP();//产生一个上升沿
             I2C_SCL_1;
            NOP();
            I2C_SCL_0;
            NOP();
        }
        I2C_SDA_1;//接收从机应答
         NOP();
        I2C_SCL_1;
        NOP();
        while(I2C_SDA_STAT)
        {
            err++;
            if(err>250)
            {
                I2C_SCL_0;
                I2C_SDA_1;
                return I2C_NACK;
            }
        }
        I2C_SCL_0;
        I2C_SDA_1;
        return I2C_ACK;
    }
    
    void I2C_ReceveByte(void)
    {
        uint8_t i,data;
        I2C_SDA_1;
        I2C_SCL_0;
        data=0;
        for(i=0;i<8;i++)
        {
            I2C_SCL_1;
            NOP();
            data<<=1;
            if(I2C_SDA_STAT)
            {
                data|=0x01;
            }
            I2C_SCL_0;
            NOP();
        }
        return data;
    }

    用上面同样的程序驱动SI7005没有应答,焊上上拉电阻后,将SDA和SCL引脚设置成开漏输出,成功读出器件ID。
    我一直没弄明白为啥都是IIC协议ADXL346能够成功读取ID,而SI7005不能。我感觉两种器件的应答信号不太一样?

    焊上上拉电阻后我决定用硬件IIC了,不再模拟:

    void RCC_Configuration(void)
    {
        GPIO_InitTypeDef GPIO_InitStructure;
        I2C_InitTypeDef I2C_InitStructure;
    
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIO,ENABLE);
        RCC_AHB1PeriphClock(RCC_APB1Periph_I2C1,ENABLE);
    
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_6;
        GPIO_InitStructure.GPIO_Speed=GPIO_Speed_40MHz;
        GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;
        GPIO_InitStructure.GPIO_OType=GPIO_OType_OD;
        GPIO_Init(GPIOB,&GPIO_InitStructure);
    
        GPIO_PinAFConfig(GPIOB,GPIO_PinSource7,GPIO_AF_I2C1);
        GPIO_PinAFConfig(GPIOB,GPIO_PinSource6,GPIO_AF_I2C1);
    
        I2C_InitStructure.I2C_Mode=I2C_Mode_I2C;
        I2C_InitStructure.I2C_DutyCycle=I2C_DutyCycle_2;
        I2C_InitStructure.OwnAddress1 = ADLX346_SLAVE_ADDRESS7;
        I2C_InitStructure.I2C_Ack=I2C_Ack_Enable;
        I2C_InitStructure.I2C_AcknowledgedAddress=I2C_AcknowledgedAddress_7bit;
        I2C_InitStructure.I2C_ClockSpeed = 200000;
        I2C_Init(I2C1,&I2C_InitStructure);
        I2C_Cmd(I2C1,ENABLE);
    }
    
    unsigned char I2C_ReadByte(unsigned char  ReadAddr, unsigned char Address)
    {  
         //等待I2C不忙
        while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));
         //产生起始信号
        I2C_GenerateSTART(I2C1, ENABLE);
         //EV5
        while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
        //发送地址
       I2C_Send7bitAddress(I2C1, Address, I2C_Direction_Transmitter);
        //EV6
        while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
        //重新设置可以清楚EV6   
        I2C_Cmd(I2C2, ENABLE);
        //发送读得地址
       I2C_SendData(I2C1, ReadAddr);  
       //EV8 
        while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
        //重新发送
       I2C_GenerateSTART(I2C1, ENABLE);
        //EV5
        while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
        //发送地址
       I2C_Send7bitAddress(I2C1, Address, I2C_Direction_Receiver);
       //EV6  
       while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
        //关闭应答和停止条件产生
       I2C_AcknowledgeConfig(I2C1, DISABLE);
        I2C_GenerateSTOP(I2C1, ENABLE);
        //等待EV7
        while(!(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)));
           
        return = I2C_ReceiveData(I2C1);
    }
    
     
    
    void I2C_WriteByte(unsigned char buff,unsigned char WriteAddr,unsigned char Address)
    {
         //产生起始条件
        I2C_GenerateSTART(I2C1,ENABLE);
         //等待ACK
        while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
        //向设备发送设备地址
        I2C_Send7bitAddress(I2C1,Address,I2C_Direction_Transmitter);
        //等待ACK
        while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
        //寄存器地址
       I2C_SendData(I2C1, WriteAddr);
        //等待ACK
        while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
        //发送数据
       I2C_SendData(I2C1, buff);
         //发送完成
        while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
        //产生结束信号
       I2C_GenerateSTOP(I2C1, ENABLE);
    }
  • 相关阅读:
    C# Net 合并int集合为字符串,如:输入1,2,3,4,8 输出1~4,8
    sql server 安装出现需要sqlncli.msi文件,错误为 microsoft sql server 2012 native client
    C# Form 实现桌面弹幕
    C# Net 去除图片白边
    SQL common keywords examples and tricks
    Excel formula and tricks
    HIghcharts cheatsheet
    CSS common keywords examples and tricks
    小白终于弄懂了:c#从async/await到Task再到Thread
    LeetCode 2: single-number II
  • 原文地址:https://www.cnblogs.com/zpehome/p/2839004.html
Copyright © 2020-2023  润新知