stm32 硬件i2c 进不去中断

xuxuhaha 2016-01-14 07:49:55
调试stm32f103c8t6的硬件i2c,一直不进事件中断,初始化代码如下,请各位高手帮忙看看
void i2c1_rccconfig(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1 , ENABLE);
}
void i2c1_gpioconfig(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
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);
}
void i2c1_config(void)
{
I2C_InitTypeDef I2C_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
I2C_DeInit(I2C1);
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = 0x30;
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_ITConfig(I2C1, I2C_IT_EVT|I2C_IT_ERR, ENABLE);
I2C_Cmd(I2C1, ENABLE);

NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
...全文
2184 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
zhujinqiang 2016-06-17
  • 打赏
  • 举报
回复
楼主问题解决了吗?
nineyole 2016-06-14
  • 打赏
  • 举报
回复
请问i2c从机调试怎么样?,能否提供一下源码~~~
paul_zhang0932 2016-01-27
  • 打赏
  • 举报
回复
I2C协议读写都不需要用到中断的,用中断不但容易打断原来程序的时序,也增加程序阅读的难度,附上代码,这个代码在stm32上面能够正常使用的。 /********************************************* * *I2c.c ********************************************/ void I2C1_delay(void){ u8 i= 15; while(i--){} } void I2C1_GPIO_Config(void){ GPIO_InitTypeDef GPIO_InitStructure; /* Configure I2C1 pins: SCL and SDA */ GPIO_InitStructure.GPIO_Pin = SCL1 | SDA1; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; GPIO_Init(GPIOB, &GPIO_InitStructure); SDA1_H; SCL1_H; } ErrorStatus I2C1_Start(void){ u16 waittime = 1000; SDA1_H; SCL1_H; I2C1_delay(); while ((!SDA1_Read | !SCL1_Read)&(SDA1_Read | SCL1_Read)){ if (waittime-- == 0) return ERROR ;//等待总线空闲 I2C1_delay(); } SDA1_L; I2C1_delay(); //>0.6uS ≈3.2uS if(SDA1_Read) {//SDA线拉不下,为高电平则总线出错,退出 SDA1_H; return ERROR ; } SCL1_L; return SUCCESS; } void I2C1_Stop(void){ SCL1_L; SDA1_L; I2C1_delay(); SCL1_H; I2C1_delay(); SDA1_H; I2C1_delay(); } void I2C1_Ack(void){ SDA1_L; I2C1_delay(); SCL1_H; I2C1_delay(); SCL1_L; } void I2C1_NoAck(void){ SDA1_H; I2C1_delay(); SCL1_H; I2C1_delay(); SCL1_L; } ErrorStatus I2C1_WaitAck(void){ SDA1_H; I2C1_delay(); SCL1_H; if(SDA1_Read){ I2C1_delay(); SCL1_L; return ERROR; } I2C1_delay(); SCL1_L; return SUCCESS; } void I2C1_SendByte(u8 SendByte){ u8 i=8; while(i--){ if(SendByte&0x80) SDA1_H; else SDA1_L; I2C1_delay(); SendByte <<= 1; SCL1_H; I2C1_delay(); SCL1_L; } } u8 I2C1_ReceiveByte(void){ u8 i=8; u8 ReceiveByte=0; SDA1_H; while(i--){ ReceiveByte<<=1; SCL1_L; I2C1_delay(); SCL1_H; if(SDA1_Read) ReceiveByte|=0x01; I2C1_delay(); } SCL1_L; return ReceiveByte; } ErrorStatus I2C1_WriteNByte(u8 WriteAddress,uc8* pBuffer,u16 length){ u8 rp;//重试次数 for (rp=0; rp<3; rp++){ if(I2C1_Start()==ERROR ) return ERROR; I2C1_SendByte(CAM_ADDR); if(I2C1_WaitAck()==SUCCESS)break; I2C1_Stop(); if (rp==2) return ERROR ; Delay_uS(2000); } I2C1_SendByte(WriteAddress); if(I2C1_WaitAck()==ERROR ){ I2C1_Stop(); return ERROR; } while(length--){ I2C1_SendByte(* pBuffer); if(I2C1_WaitAck()==ERROR ){ I2C1_Stop(); return ERROR; } pBuffer++; } I2C1_Stop(); return SUCCESS; } ErrorStatus I2C1_ReadNByte(u8 ReadAddress,u8* pBuffer,u16 length){ u8 rp; for (rp=0; rp<3; rp++){ if(I2C1_Start()==ERROR) return ERROR ; I2C1_SendByte(CAM_ADDR); if(I2C1_WaitAck()==SUCCESS) break; I2C1_Stop(); if (rp==2) return ERROR ; Delay_uS(2000) } I2C1_SendByte(ReadAddress); I2C1_WaitAck(); I2C1_Start(); I2C1_SendByte(CAM_ADDR | 0x01); if(I2C1_WaitAck() == ERROR){ I2C1_Stop(); return ERROR; } while(length){ *pBuffer = I2C1_ReceiveByte(); if(length == 1)I2C1_NoAck(); else I2C1_Ack(); pBuffer++; length--; } I2C1_Stop(); return SUCCESS; } /**************************************** * *I2C.H ******************************************/ #ifndef __I2C_Cam_H #define __I2C_Cam_H #define SCL1_H GPIOB->BSRR = SCL1 #define SCL1_L GPIOB->BRR = SCL1 #define SDA1_H GPIOB->BSRR = SDA1 #define SDA1_L GPIOB->BRR = SDA1 #define SCL1_Read GPIOB->IDR & SCL1 #define SDA1_Read GPIOB->IDR & SDA1 extern void I2C1_GPIO_Config(void); ErrorStatus I2C1_WriteNByte(u8 WriteAddress,uc8* pBuffer,u16 length); ErrorStatus I2C1_ReadNByte(u8 ReadAddress,u8* pBuffer,u16 length); #endif
xuxuhaha 2016-01-25
  • 打赏
  • 举报
回复
最后用写寄存器的办法直接写了一个从机通过了,但是被写一次后再读会有多出来一条全FFFFFFFFFFFFFFFFFFFFFFFFF的错误包,初步定位是写完后DR寄存器为非空状态,导致读的时候无法写入,但是被连读两次就行了,也是奇怪。 目前没找到直接清DR寄存器的办法,在收到数据后直接复位了总线,主机等待1秒(实时性没有要求)再读。 有谁知道如何直接清除DR寄存器吗,使非空标志清除掉,寄存器为可写入状态? 代码如下: void IIc1_Init(u8 ADDR) { /* Configure IO connected to IIC*********************/ RCC->APB2ENR|=1<<3; //使能PORTB时钟 GPIOB->CRL&=0X00FFFFFF;//PB6、7 复用开漏输出 手册中要求 GPIOB->CRL|=0XFF000000; // GPIOB->ODR|=3<<6; //PB6、7 输出高 RCC->APB1ENR|=1<<21; //使能i2c1口时钟 RCC->APB1RSTR|=1<<21; //复位I2C1 RCC->APB1RSTR&=~(1<<21);//复位结束i2c1 I2C1->CR1|=1<<15;//复位CR1 I2C1->CR1&=~(1<<15); //复位结束 //时钟设置, I2C1->CR1&=~(1<<1);//选择i2c模块 I2C1->CR2|=36<<0;//I2C->FREQR这个值是在主模式下产生正确的scl时序,与I2C1->TRISE配合 I2C1->CCR|=1<<15;//设置成快速模式 I2C1->CCR&=~(1<<14);// 占空比设置为2 I2C1->CCR|=30<<0;//时钟控制分频系数设置为30(400KHz = 2.5us =36MHz/(2+1)*CCR) // I2C1->TRISE |= 37; //主模式下scl,从模式下不需要设置 I2C1->OAR1&=~(1<<15); //寻址模式 响应7位地址 I2C1->OAR1|= 1<<14; //必须始终由软件保持为 1 I2C1->OAR1|= ADDR<<1; //设置接口地址的 7~1位(接口地址设为0X30) I2C1->CR2 |= 3<<9; //事件中断使能 I2C1->CR2 |= 1<<8; //出错中断使能 I2C1->CR1 &=~(1<<7); //允许时钟延长 I2C1->CR1 |= 1<<0; //开启I2C1 I2C1->CR1 |= 1<<10; //打开ack应答 MY_NVIC_Init(1,2,I2C1_EV_IRQn,2); MY_NVIC_Init(1,1,I2C1_ER_IRQn,2); //出错中断的优先级要比事件中断高 } /*从库函数移植过来 */ u32 I2C_GetLastEvent(void) { u32 lastevent = 0; u32 flag1 = 0, flag2 = 0; /* Check the parameters */ // assert_param(IS_I2C_ALL_PERIPH(I2Cx)); //检查输入的参数是否有误 /* Read the I2Cx status register */ flag1 = I2C1->SR1; flag2 = I2C1->SR2; flag2 = flag2 << 16; /* Get the last event value from I2C status register */ lastevent = (flag1 | flag2) & 0x00FFFFFF; /* Return status */ return lastevent; } /*读时序改为无写入版本*/ void I2C_Slave_Handler(void) { static u8 temp1=0,temp2=0; //char sendstr[22]="a"; u8 ch_get = 0x00; switch (I2C_GetLastEvent()) { //------得到主机发送信息信号,将将本地接收指针指向接收缓存头------------// case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED: //EV1:ADDR=1,主机发生的地址与从机地址匹配,读SR1然后读SR2清除ADDR标志位 //w_start++; temp1 = 0; break; //------得到主机读取本地响应信号,将本地发送指针指向发送缓存头---------// //------并且填充发送缓存的第一个字节到发送区---------------------------// case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED: //EV1及EV3-1:读SR1然后读SR2清除ADDR标志位 temp2 = 0; //r_start++; //buff_test[temp2]=i2c_RSP[temp2]; I2C1->DR=i2c_RSP[temp2]; //I2C1->DR = sendstr[0]; break; /* *收到主机停止发送的命令之前不停发送缓存里的内容 *如果缓存区的有效数据发送完了就发0x00填充 */ case I2C_EVENT_SLAVE_BYTE_TRANSMITTING: //EV3:写DR清除该事件 //r_buff++; temp2++; if(temp2 > 9) temp2 = 9; I2C1->DR=i2c_RSP[temp2]; //buff_test[temp2]=i2c_RSP[temp2]; break; case I2C_EVENT_SLAVE_BYTE_TRANSMITTED: //EV3:写DR清除该事件 //ev3_done++; //num_of_trans++; //i2c_RSP[9] = num_of_trans ; //I2C1->DR=i2c_RSP[9]; break; /* *收到主机停止发送命令,清空所有发送缓存 */ case I2C_EVENT_SLAVE_ACK_FAILURE: //EV3-2 从机发送结束 // r_stop++; for(temp2 = 0;temp2<10;temp2++) { i2c_RSP[temp2] = 0; } I2C1->SR1 &= 0xFBFF; break; /* *主机开始发送数据体来,不停的接收主机发来的数据,存到本地缓存 */ case I2C_EVENT_SLAVE_BYTE_RECEIVED: //EV2: 读DR将清除该事件_ok //w_buff++; ch_get = I2C1->DR; if(ch_get == 0x7E) { start_rev = 1; } if(start_rev) { if(ch_get == 0x0D) { start_rev = 0; } i2c_RecviceDate[temp1]=ch_get; temp1++; } break; /* *主机停止发送,在本地处理接收到的数据 */ case I2C_EVENT_SLAVE_STOP_DETECTED: //EV4: 对SR1进行读操作及对CR1进行写操作 清除该事件 i2cresetf = 1; //在这里设置复位标志,出中断后马上复位总线 start_rev = 0; I2C1->CR1 |= 1<<9; //CR1进行写操作 清除该事件 break; } } void I2C_Slave_Err_Handler(void) { if(I2C1->SR1&(1<<10)) { I2C1->SR1 &=~(1<<10); //清除AF标志位 IIc1_Init(0x30); } else if(I2C1->SR1 & 1<<14) //超时 { I2C1->SR1 &=~(1<<14); //清除中断 } else if(I2C1->SR1 & 1<<11) //过载/欠载 { I2C1->SR1 &=~(1<<11); //清除中断 } else if(I2C1->SR1 & 1<<9) //仲裁丢失 { I2C1->SR1 &=~(1<<9); //清除中断 } else if(I2C1->SR1 & 1<<8) //总线出错 { I2C1->SR1 &=~(1<<8); //清除中断 } } void I2C1_EV_IRQHandler(void) { I2C_Slave_Handler(); } void I2C1_ER_IRQHandler(void) { I2C_Slave_Err_Handler(); }
瓜枣三郎 2016-01-23
  • 打赏
  • 举报
回复
模拟i2c 最近在学,也想写硬件的
lr2131 2016-01-15
  • 打赏
  • 举报
回复
如果不是把STM32的I2C作为从机使用,非常不建议使用I2C的硬件固件来做开发,还不如使用io模拟,不然后面还会遇到很多问题。 大家都知道STM32的I2C固件是有bug的,一直到现在都没解决,如果想用做产品,绝大部分人都是用的io模拟。 请悉知!

27,520

社区成员

发帖
与我相关
我的任务
社区描述
硬件/嵌入开发 单片机/工控
社区管理员
  • 单片机/工控社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧