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