#define _I2C_DEBUG_
#ifdef _I2C_DEBUG_
u32 gAu32Tmp[100];
#endif
// I2C1中断服务程序.
void I2C1_EV_IRQHandler(void)
{
u32 lu32Event;
static u8 lu8BusyCount = 0;
static u16 lu16StaCounter = 0;
lu32Event = I2C_GetLastEvent(I2C1);
#ifdef _I2C_DEBUG_
if( lu32Event != I2C_EVENT_MASTER_BYTE_TRANSMITTING)
{
gAu32Tmp[lu16StaCounter++] = lu32Event;
if( lu16StaCounter >= 100 )
{
lu16StaCounter = 0;
}
}
#endif
if( (lu32Event & 0x00020000) == 0x00020000)
{
lu8BusyCount ++;
}
else
{
lu8BusyCount = 0;
}
switch ( lu32Event )
{
case I2C_EVENT_MASTER_MODE_SELECT: // 0x00030001. 发启动条件时产生的事件: EV5
if( gstruI2C_ComInst.m_u8Direct == CNT_I2C_TRANSMITTER )
{
// Master Transmitter, then Send slave Address for write.
I2C_Send7bitAddress(I2C1, gstruI2C_ComInst.m_u8DevAdd, I2C_Direction_Transmitter);
}
else
{
// Master Receiver, Send slave Address for read.
I2C_Send7bitAddress(I2C1, gstruI2C_ComInst.m_u8DevAdd, I2C_Direction_Receiver);
}
break;
// Master Transmitter, then Test on I2C1 EV6 and first EV8 and clear them.
case I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED: // 0x00070082. 发出写指定I2C从设备时产生的事件:EV8 just after EV6
// Send the first data.
I2C_SendData(I2C1, gstruI2C_ComInst.m_Au8SndOrRecBuf[gstruI2C_ComInst.m_u8DatIdx]);
gstruI2C_ComInst.m_u8DatIdx++;
break;
case I2C_EVENT_MASTER_BYTE_TRANSMITTING: // 0x00070080. 正在发送数据中......
lu8BusyCount = 0;
break;
// Test on I2C1 EV8 and clear it.
case I2C_EVENT_MASTER_BYTE_TRANSMITTED: // 0x00070084. 一个字节数据发送完成.
if(gstruI2C_ComInst.m_u8DatIdx < gstruI2C_ComInst.m_u8SndOrRecLen)
{
// Transmit I2C1 data
I2C_SendData(I2C1, gstruI2C_ComInst.m_Au8SndOrRecBuf[gstruI2C_ComInst.m_u8DatIdx]);
gstruI2C_ComInst.m_u8DatIdx ++;
}
else
{
// Send I2C1 STOP Condition
I2C_GenerateSTOP(I2C1, ENABLE);
delay( 50 ); // NOTE: 非常关键哟,不同的器件,延时可能不一样.
gstruI2C_ComInst.m_u8Finished = CNT_I2C_FINISHED_YES;
}
lu8BusyCount = 0; // 发送了数据,不为busy.
break;
// Master Receiver
case I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED: // 0x00030002. 发出读指定I2C从设备时产生的事件:EV6
if(gstruI2C_ComInst.m_u8SndOrRecLen == 1)
{
// Disable I2C1 acknowledgement
I2C_AcknowledgeConfig(I2C1, DISABLE);
// Send I2C1 STOP Condition
I2C_GenerateSTOP(I2C1, ENABLE);
}
break;
case I2C_EVENT_MASTER_BYTE_RECEIVED: //0x00030040. 主收到一个字节时产生的事件:EV7. // BUSY, MSL and RXNE flags.
case 0x00030044: // BUSY, MSL and RXNE, BTF flags.
// Store I2C1 received data
gstruI2C_ComInst.m_Au8SndOrRecBuf[gstruI2C_ComInst.m_u8DatIdx++] = I2C_ReceiveData(I2C1);
if( gstruI2C_ComInst.m_u8DatIdx >= gstruI2C_ComInst.m_u8SndOrRecLen )
{
gstruI2C_ComInst.m_u8Finished = CNT_I2C_FINISHED_YES;
}
// Disable ACK and send I2C1 STOP condition before receiving the last data
// 收到倒数第二个数后,应设置NACK和产生STOP标志.
if( gstruI2C_ComInst.m_u8DatIdx == (gstruI2C_ComInst.m_u8SndOrRecLen - 1))
{
// Disable I2C1 acknowledgement.
I2C_AcknowledgeConfig(I2C1, DISABLE);
// Send I2C1 STOP Condition.
I2C_GenerateSTOP(I2C1, ENABLE);
}
lu8BusyCount = 0; // 收到数据,不为busy.
break;
case 0x00030201:
case 0x00030401:
case 0x00030501:
I2C_GenerateSTOP(I2C1, ENABLE);
break;
default:
if( lu8BusyCount > 200 )
{
lu8BusyCount = 0;
I2C1_Configuration();
I2C_Cmd( I2C1, DISABLE );
I2C_Cmd( I2C1, ENABLE );
}
break;
}
}
I2C 传输的结构定义及常量
#define CNT_I2C_TRANSMITTER 0 // I2C的行为为发送.
#define CNT_I2C_RECEIVER 1 // I2C的行为为接收.
#define CNT_I2C_REC_SND_BUF 128 // 定义I2C的缓冲区大小.
#define CNT_I2C_FINISHED_NO 0 // 本次的I2C操作未结束
#define CNT_I2C_FINISHED_YES 1 // 本次的I2C操作已结束.
// I2C的状态. 用于中断方式
// 定义的I2C收发结构.
typedef struct
{
u8 m_u8DevAdd; // 设备地址.
u8 m_u8SndOrRecLen; // I2C需接收或发送的数据长度.
u8 m_u8DatIdx; // 接收到数据的下标.
u8 m_Au8SndOrRecBuf[CNT_I2C_REC_SND_BUF]; // 收发缓冲区
u8 m_u8Direct; // I2C的数据流向方向.是接收还是发送.
u8 m_u8Finished; // 本次的I2C操作结束否?
u8 m_u8I2CStatue; // I2C 的状态?
} struI2C_Com;
据说多发贴子挣分多。I2C结构的填写及启动发或收
/*******************************************************************************
* Function Name : RTC_WriteReg
* Description : 用中断方式对I2C寄存器设置.
* Input : -u8RegAdd: 寄存器地址.
* : -pu8Dat: 数据指针
* : -u8Count: 数据个数
* : -u16DelayMs: 超时时间.
* Output : 无.
* Return : 1: 成功
* : 0: 失败
*******************************************************************************/
u8 RTC_WriteReg( u8 u8RegAdd, u8 * pu8Dat, u8 u8Count, u16 u16DelayMs )
{
// 把寄存器地址写下去.
gstruI2C_ComInst.m_Au8SndOrRecBuf[0] = u8RegAdd;
// 把要发送的数据存放在I2C的发送缓冲区中.
if( u8Count > 0 )
{
memmove( &gstruI2C_ComInst.m_Au8SndOrRecBuf[1], &pu8Dat[0], u8Count );
}
// 记录要发送的数据长度.
gstruI2C_ComInst.m_u8SndOrRecLen = u8Count + 1;
// 设置发送完成标志为NO.
gstruI2C_ComInst.m_u8Finished = CNT_I2C_FINISHED_NO;
// 设置I2C方向为发送.
gstruI2C_ComInst.m_u8Direct = CNT_I2C_TRANSMITTER;
// 设置I2C的从设备地址为ISL12022M的地址
gstruI2C_ComInst.m_u8DevAdd = CNT_ISL12022M_ADD;
// 收发数据的下标
gstruI2C_ComInst.m_u8DatIdx = 0;
// 启动发送.
I2C_GenerateSTART(I2C1, ENABLE);
// 是否已写完寄存器数据. 10ms内是否已写完寄存器数据.
if ( delayMsUnitl( &gstruI2C_ComInst.m_u8Finished, CNT_I2C_FINISHED_YES, u16DelayMs ) == 1 )
{
return 1;
}
else
{
return 0;
}
}
再来I2C配置。
void I2C1_Configuration( void )
{
I2C_InitTypeDef I2C_InitStructure;
// I2C外设复位.
RCC_APB1PeriphResetCmd( RCC_APB1Periph_I2C1, ENABLE );
// delay( 100 );
RCC_APB1PeriphResetCmd( RCC_APB1Periph_I2C1, DISABLE );
I2C1_SCK_SDA_Reset(); // 做为IO口置高.
// I2C I0口初始化.
// Configure I2C1 pins: SCL and SDA ---------------------------------------
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// I2C配置.
I2C_DeInit( I2C1 );
// I2C1 configuration ---------------------------------------------
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = 0x88; // cortex的I2C地址为0x88;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = 400000;
I2C_Cmd(I2C1, ENABLE );
I2C_Init(I2C1, &I2C_InitStructure);
I2C_ITConfig( I2C1, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR, ENABLE );
}
以下代码可以保证用镊子碰碰I2C总线
if( GetISL12022MAllData( &lstrISL12022M ) > 0 )
{
lintI2CFailCount = 0;
SendStringAddCrlf( "读ISL12022M成功!" );
}
else
{
SendStringAddCrlf( "读ISL12022M失败!" );
if( lintI2CFailCount ++ > 5 )
{
lintI2CFailCount = 0;
I2C1_Configuration( ); // 不行了咱重来,说得挺悬乎,不就是重新初始化嘛。
}
}
我来顶一下楼主1
这 与 周老板那个ARM7中断方式读I2C比较接近的。
靠,穷怕了今天有裤子穿了,那得再来一段取数的。
u8 GetISL12022MAllData( struISL12022M_RTC * pstruISL12022M )
{
// 取所有的值需要2个步骤, 1 发送起始寄存器地址; 2 接收0x30个字节数据.
// 1. 发送起始寄存器地址
if( RTC_WriteReg( CNT_ISL12022M_RTC, NULL, 0, 50 ) == 1 )
{
// 发送成功.
// 2. 接收48个字节数据
// 记录要接收的数据长度.
gstruI2C_ComInst.m_u8SndOrRecLen = 48;
// 设置接收完成标志为NO.
gstruI2C_ComInst.m_u8Finished = CNT_I2C_FINISHED_NO;
// 设置I2C方向为接收.
gstruI2C_ComInst.m_u8Direct = CNT_I2C_RECEIVER;
// 设置I2C的从设备地址为ISL12022M的地址
gstruI2C_ComInst.m_u8DevAdd = CNT_ISL12022M_ADD;
gstruI2C_ComInst.m_u8DatIdx = 0;
// I2C 应回应ACK.
I2C_AcknowledgeConfig(I2C1, ENABLE );
// 启动发送.
I2C_GenerateSTART(I2C1, ENABLE);
if( delayMsUnitl( &gstruI2C_ComInst.m_u8Finished, CNT_I2C_FINISHED_YES, 100 ) == 1 )
{
// 取到了48个字节数据.
memmove( pstruISL12022M, &gstruI2C_ComInst.m_Au8SndOrRecBuf[0], gstruI2C_ComInst.m_u8SndOrRecLen );
return 1;
}
else
{
return 0;
}
}
else
{
return 0;
}
}
能行吗 上传一个I2C项目文件吧 好心人
我试了百次(我自己参考ST库写的),就只能取到第一次的数据是正常的 (LM75收二个字节)
加了 停止位
I2C_GenerateSTOP(I2C1, ENABLE);
我用示波器看 就没信号了