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

 

 

 

posted @ 2013-01-22 15:19  zpehome  阅读(3750)  评论(1编辑  收藏  举报