此文档是基于在STM32 F103C8T6的单片上,使用中断的方式实现I2C主机通信的代码实现过程。
注:slave的地址为0x16,在实际写入寄存器中的值为向左移动1位,实际的值为0x2C;在中断函数中可以通过变量的不同的值去写将地址写入数据寄存器中,通过此步bit0 值的不同实现master 当前是读数据还是写数据。
PORT口和I2C配置代码如下:
void IIC_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(IIC_SCL_PORT_RCC|IIC_SDA_PORT_RCC,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
GPIO_InitStructure.GPIO_Pin=IIC_SCL_PIN;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_OD;
// GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_Init(IIC_SCL_PORT,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN;
GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);
I2C_DeInit(I2C2);
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = 0x16; //从机地址,一定要设置正确
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress= I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = 100000;
I2C_Init(I2C2, &I2C_InitStructure);
//
NVIC_InitStructure.NVIC_IRQChannel = I2C2_EV_IRQn;//事件中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = I2C2_ER_IRQn;//错误中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
I2C_ITConfig(I2C2, I2C_IT_BUF | I2C_IT_EVT |I2C_IT_ERR, ENABLE);
I2C_Cmd(I2C2, ENABLE);
// IIC_SCL=1;
// IIC_SDA=1;
}
中断服务函数如下:
注:在读数据过程中通过发送停止位和NACK的方式停止读数据。(读数据长度的控制还未详细实现)
void I2C2_EV_IRQHandler(void)
{
I2C_STS1_TypeDef STS1R;
I2C_STS2_TypeDef STS2R;
STS1R.reg = I2C2->SR1;
STS2R.reg = I2C2->SR2;
if(STS2R.Bit.MSMODE == 1) //this mode is master
{
if(STS1R.Bit.STARTBF) //EV5
{
if(I2C2_Send_Or_Recv == 1) //read
{
I2C2->DR= 0x2d; //slave addr
}
else if(I2C2_Send_Or_Recv == 2)
{
I2C2->DR= 0x2c;
}
STS1R.reg = 0;
STS2R.reg = 0;
send_cnt++;
I2C_MR_cnt = 0;
I2C_MS_cnt = 0;
}
if(STS1R.Bit.ADDRF == 1) //EV6
{
STS1R.reg = 0;
STS2R.reg = 0;
}
if(STS1R.Bit.RXDATNE == 1) //EV7 and EV7_1
{
I2C_MR_buf[I2C_MR_cnt] = I2C2->DR;
I2C_MR_cnt ++;
if(I2C_MR_cnt >= 40)
{
I2C_MR_cnt = 0;
}
if(I2C_MR_cnt >= 30)
{
// I2C2->CR1 |= (1<<8);
I2C2->CR1 |= (1<<9); //stop generstion
I2C2->CR1 &= ~(1<<10); //disable ack for general NACK
}
STS1R.reg = 0;
STS2R.reg = 0;
}
if(STS1R.Bit.TXDATE == 1)
{
I2C2->DR = I2C_MS_buf[I2C_MS_cnt];
I2C_MS_cnt ++;
if(I2C_MS_cnt >= 5)
{
I2C2->CR1 |= (1<<9); //stop generstion
}
STS1R.reg = 0;
STS2R.reg = 0;
}
}
else {}; // not handle
I2C2->SR1 = 0;
I2C2->SR2 = 0;
}
void I2C2_ER_IRQHandler(void) {
__IO uint32_t SR1Register =0;
__IO uint32_t SR2Register =0;
SR1Register = I2C2->SR1;
SR2Register = I2C2->SR2;
if(I2C_GetITStatus(I2C2 ,I2C_IT_SMBALERT)) {
}
else if(I2C_GetITStatus(I2C2, I2C_IT_TIMEOUT)) {
}
else if(I2C_GetITStatus(I2C2, I2C_IT_PECERR)) {
}
else if(I2C_GetITStatus(I2C2, I2C_IT_OVR)) {
}
else if(I2C_GetITStatus(I2C2, I2C_IT_AF)) {
I2C_ClearITPendingBit(I2C2, I2C_IT_AF);
}
else if(I2C_GetITStatus(I2C2, I2C_IT_ARLO)) {
}
else if(I2C_GetITStatus(I2C2, I2C_IT_BERR)) {
}
I2C2->CR1 |= 0x0001;
SR1Register = 0;
SR2Register = 0;
}
触发I2C Master读写操作的函数如下:
(I2C2_Send_Or_Recv 值的不同可以表明当前是写数据还数读数据,具体实现过程的通过在中断函数中填入数据寄存器的值不一样区别,bit01为read、bit00为write)
void I2C2_Read_test()
{
I2C2_Send_Or_Recv = 1;
I2C2->CR1 |= (1<<8); //Start generation
I2C2->CR1 |= (1<<10);
}
void I2C2_Send_test()
{
I2C2_Send_Or_Recv = 2;
I2C2->CR1 |= (1<<8); //Start generation
I2C2->CR1 |= (1<<10);
}