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);
}

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM