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