#申请原创# #有奖活动# #技术资源# 用II2C通讯,我们首先要知道硬件II2C和软件II2C的区别
(1)所谓硬件I2C对应芯片上的I2C外设,有相应I2C驱动电路,其所使用的I2C管脚也是专用的;
软件I2C一般是用GPIO管脚,用软件控制管脚状态以模拟I2C通信波形。
(2)硬件I2C的效率要远高于软件的,而软件I2C由于不受管脚限制,接口比较灵活。
(3)硬件i2c程序员只要调用i2c的控制函数即可,不用直接的去控制SCL,SDA高低电平的输出。但是有些单片机的硬件i2c不太稳定,调试问题较多。
(4) 硬件IIC速度比模拟快,并且可以用DMA。
项目中一般要用DMA的话,还是硬件II2C用的较多。本次实验是用硬件II2C实现对EEPROM进行读写操作
烧录用的是J-LINK
下面是II2C读写EEPROM部分,本次用的是PB6和PB7脚。
其中通讯过程中有个等待函数是十分重要的
这个函数每次写完都要进行调用用来判断数据是否写入。
#define EEPROM_I2Cx I2C1
#define EEPROM_ADDRESS 0xA0
void MYI2C_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStruct;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE ); //使能GPIOB时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); //使能I2C1时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode =GPIO_Mode_AF_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
I2C_DeInit(I2C1);
I2C_InitStruct.I2C_Ack =I2C_Ack_Enable;
I2C_InitStruct.I2C_AcknowledgedAddress =I2C_AcknowledgedAddress_7bit ;
I2C_InitStruct.I2C_ClockSpeed =400000;
I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2 ;
I2C_InitStruct.I2C_Mode =I2C_Mode_I2C;
I2C_InitStruct.I2C_OwnAddress1 =0x00;
I2C_Init(I2C1,&I2C_InitStruct);
I2C_Cmd(I2C1,ENABLE);//DISABLE ENABLE
}
void I2C_WriteOneByte(u8 RegAddr,u8 date)
{
while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY));
I2C_GenerateSTART(I2C1,ENABLE);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT));//EV5
I2C_Send7bitAddress(I2C1,EEPROM_ADDRESS,I2C_Direction_Transmitter);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//EV6
I2C_SendData(I2C1,RegAddr);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTING ));//EV8
I2C_SendData(I2C1,date);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED ));//EV8—2
I2C_GenerateSTOP(I2C1,ENABLE);
I2C_EE_WaitEepromStandbyState();
}
void I2C_WriteLenByte(u8 RegAddr,u8* sbufdate,u8 Len)
{
while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY));
I2C_GenerateSTART(I2C1,ENABLE);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT));//EV5
I2C_Send7bitAddress(I2C1,EEPROM_ADDRESS,I2C_Direction_Transmitter);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//EV6发送
I2C_SendData(I2C1,RegAddr);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED ));//EV8
while(Len--)
{
I2C_SendData(I2C1,*sbufdate);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED ));//EV8
sbufdate++;
}
I2C_GenerateSTOP(I2C1,ENABLE);
I2C_EE_WaitEepromStandbyState();
}
void I2C_ReadOneByte(u8 RegAddr,u8 *da)
{
while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY));
I2C_GenerateSTART(I2C1,ENABLE);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT));//EV5
I2C_Send7bitAddress(I2C1,EEPROM_ADDRESS,I2C_Direction_Transmitter);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//EV6
I2C_SendData(I2C1,RegAddr);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED ));//EV8
I2C_GenerateSTART(I2C1,ENABLE);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT));//EV5
I2C_Send7bitAddress(I2C1,EEPROM_ADDRESS,I2C_Direction_Receiver );
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));//EV6 接收
I2C_AcknowledgeConfig(I2C1,DISABLE);//最后有一个数据时关闭应答位
I2C_GenerateSTOP(I2C1,ENABLE);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED));//
*da=I2C_ReceiveData(I2C1);
// delay_ms(10);
// I2C_AcknowledgeConfig(I2C1,ENABLE);
}
void I2C_ReadLenByte(u8 RegAddr,u8* sbufdate,u8 len)
{
while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY));
I2C_GenerateSTART(I2C1,ENABLE);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT));//EV5
I2C_Send7bitAddress(I2C1,EEPROM_ADDRESS,I2C_Direction_Transmitter);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//EV6发送
I2C_SendData(I2C1,RegAddr);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED ));//EV8
I2C_GenerateSTART(I2C1,ENABLE);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT));//EV5
I2C_Send7bitAddress(I2C1,EEPROM_ADDRESS,I2C_Direction_Receiver );
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));//EV6 接收
while(len)
{
if(len==1)
{
I2C_AcknowledgeConfig(I2C1,DISABLE);//最后有一个数据时关闭应答位
I2C_GenerateSTOP(I2C1,ENABLE);
}
*sbufdate=I2C_ReceiveData(I2C1);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED));
sbufdate++;
len--;
}
I2C_AcknowledgeConfig(I2C1,ENABLE);
}
void I2C_EE_WaitEepromStandbyState(void)
{
vu16 SR1_Tmp = 0;
do
{
I2C_GenerateSTART(EEPROM_I2Cx, ENABLE);
SR1_Tmp = I2C_ReadRegister(EEPROM_I2Cx, I2C_Register_SR1);
I2C_Send7bitAddress(EEPROM_I2Cx, EEPROM_ADDRESS, I2C_Direction_Transmitter);
}while(!(I2C_ReadRegister(EEPROM_I2Cx, I2C_Register_SR1) & 0x0002));
I2C_ClearFlag(EEPROM_I2Cx, I2C_FLAG_AF);
I2C_GenerateSTOP(EEPROM_I2Cx, ENABLE);
}
下面是主函数中代码
u8 sbuf[9];
u8 buf[9]={3,1,2,8,4,4,5,6,6};
int main (void)
{
u8 i;
u8 *dat;
MYI2C_Init();
Usart_Init();
dat=sbuf;
for(i=0;i<9;i++)
{
I2C_WriteOneByte(i,buf[i]);
I2C_ReadOneByte(i,dat++);
printf("%d \r\n",sbuf[i]);
}
while(1)
{
}
}
我设置的是一个9位数组,写入一个9位数组,然后设置了一个指针利用for循坏,调用II2C写函数将数组当中的一个个变量写入,然在将SBUF的地址通过指针赋值给DAT,然后读出DAT的值,这样就可以判断II2C读写是否正常了。
由上图可知,写入和读取都是正常的,这个程序在极海和STM上都能够正常运行。这就是极海单片机兼容软件的强大之处。小伙伴们好了本次就到这里了 |