调试了一晚上,终于一点点把stm32可怕的i2c消灭了,这里分享一下遇到的问题。
最严重的一次卡住居然是在这句话上
/* Send START condition */
I2C_GenerateSTART(I2C1, ENABLE);
/* Test on EV5 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
执行到第二句就怎么也过不去了,后来才很气愤的发现这是stm32的硬件bug,把fsmc关掉才能使用i2c1的非重影射引脚,关掉以后一切正常。害得我干瞪了两个小时屏幕。
第二次被卡住是在
I2C_Send7bitAddress(I2C1, 0xD2, I2C_Direction_Transmitter);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
错误的原因是传输的地址要左移一位。虽然地址是7位的,但是必须在后面而不是前面补零,变成8位地址再传递。
第三次是在
I2C_GenerateSTOP(I2C1, ENABLE);//产生 I2Cx传输 STOP条件
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));
原因是必须要先产生终止再检查数据。仔细读手册就解决了这个问题
已经凌晨一点了,终于长舒一口气。这里把代码贴上来,是一个调试陀螺仪l3g4200d的程序,直接调用GYRO_Test()即可,但是必须先调用GYRO_Init(),初始化GPIO和RCC,并添加相应的头文件。
#define WHO_AM_I 0x0F
#define CTRL_REG1 0x20
#define CTRL_REG2 0x21
#define CTRL_REG3 0x22
#define CTRL_REG4 0x23
#define CTRL_REG5 0x24
#define REFERENCE 0x25
#define OUT_TEMP 0x26
#define STATUS_REG 0x27
#define OUT_X_L 0x28
#define OUT_X_H 0x29
#define OUT_Y_L 0x2A
#define OUT_Y_H 0x2B
#define OUT_Z_L 0x2C
#define OUT_Z_H 0x2D
#define FIFO_CTRL_REG 0x2E
#define FIFO_SRC_REG 0x2F
#define INT1_CFG 0x30
#define INT1_SRC 0x31
#define INT1_TSH_XH 0x32
#define INT1_TSH_XL 0x33
#define INT1_TSH_YH 0x34
#define INT1_TSH_YL 0x35
#define INT1_TSH_ZH 0x36
#define INT1_TSH_ZL 0x37
#define INT1_DURATION 0x38
void I2C_Configuration(void)
{
I2C_InitTypeDef I2C_InitStructure;
I2C_DeInit(I2C1);
/* I2C configuration */
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = 0xD2;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = 400000;
/* I2C Peripheral Enable */
I2C_Cmd(I2C1, ENABLE);
/* Apply I2C configuration after enabling it */
I2C_Init(I2C1, &I2C_InitStructure);
}
void GYRO_Write(INT8U addr, INT8U data)//write a byte to gyroscope
{
int dummy;
/* Send STRAT condition */
I2C_GenerateSTART(I2C1, ENABLE);
/* Test on EV5 and clear it */
while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS);
/* Send EEPROM address for write */
dummy=I2C1->SR1;
I2C_Send7bitAddress(I2C1, 0xD2, I2C_Direction_Transmitter);
/* Test on EV6 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
/* Send the EEPROM's internal address to write to */
I2C_SendData(I2C1, addr);
/* Test on EV8 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
/* Send the byte to be written */
I2C_SendData(I2C1, data);
/* Test on EV8 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
/* Send STOP condition */
I2C_GenerateSTOP(I2C1, ENABLE);
}
INT8U GYRO_Read(INT8U addr)//read a byte from gyroscope
{
INT8U data;
/* Send START condition */
I2C_GenerateSTART(I2C1, ENABLE);
/* Test on EV5 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
/* In the case of a single data transfer disable ACK before reading the data */
I2C_AcknowledgeConfig(I2C1, DISABLE);
/* Send EEPROM address for write */
I2C_Send7bitAddress(I2C1, 0xD2, I2C_Direction_Transmitter);
/* Test on EV6 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
/* Send the EEPROM's internal address to write to */
I2C_SendData(I2C1, addr);
/* Test on EV8 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
/* Send STRAT condition a second time */
I2C_GenerateSTART(I2C1, ENABLE);
/* Test on EV5 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
/* Send EEPROM address for read */
I2C_Send7bitAddress(I2C1, 0xD2, I2C_Direction_Receiver);
/* Test on EV6 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
/* Send STOP Condition */
I2C_GenerateSTOP(I2C1, ENABLE);
/* Test on EV7 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));
/* Read a byte from the EEPROM */
data = I2C_ReceiveData(I2C1);
return data;
}
void GYRO_Init(){
I2C_Configuration();
GYRO_Write(CTRL_REG1, 0xEF);
GYRO_Write(CTRL_REG2, 0x00);
GYRO_Write(CTRL_REG3, 0x08);
GYRO_Write(CTRL_REG4, 0x10);
GYRO_Write(CTRL_REG5, 0x00);
}
void GYRO_Test(){
int value1=0,value2=0,value3=0;
value1= GYRO_Read(OUT_X_H)*0x100 + GYRO_Read(OUT_X_L);
if(value1 > 0x7FFF)
value1=value1-0x10000;
value2= GYRO_Read(OUT_Y_H)*0x100 + GYRO_Read(OUT_Y_L);
if(value2 > 0x7FFF)
value2=value2-0x10000;
value3= GYRO_Read(OUT_Z_H)*0x100 + GYRO_Read(OUT_Z_L);
if(value3 > 0x7FFF)
value3=value3-0x10000;
printf("%d %d %d\n",value1,value2,value3);
}
运行结果(串口接到的部分数据):
20 33 -51
16 15 -60
19 36 -74
51 -227 -29
-6 34 -32
23 -252 -61
5 26 -40
16 36 -75
34 48 -52
-2 27 -35