1、 stm32 之 IIC应用 iic协议是比较简单的双线协议,时钟线CLK和数据线SDA。 一般我们常见的还有spi总线,这种总线可以可以根据需要扩展,还有单总线等等 这次还以at240c2为例进行操作! PS:这就是传说中的iic时序图 硬件构造我们不过多的分析,今天用到库了!我们先从库函数硬件iic初始化说起! PB6 -- CLK PB7 -- SDA [cpp] view plaincopyprint? 1. void i2c_init(u8 addr,u32 clock) 2. { 3. I2C_InitTypeDef i
2、2c; 4. RCC->APB2ENR |= 1<<3; 5. GPIOB->CRL |= (u32)0xff<<(6*4); 6. 7. RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE); 8. i2c.I2C_Ack = I2C_Ack_Enable; 9. i2c.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; 10. i2c.I2C_ClockSpeed = clock*1
3、000; 11. i2c.I2C_DutyCycle = I2C_DutyCycle_2; 12. i2c.I2C_Mode = I2C_Mode_I2C; 13. i2c.I2C_OwnAddress1 = addr; 14. 15. I2C_Cmd(I2C1,ENABLE); 16. I2C_Init(I2C1,&i2c); 17. } void i2c_init(u8 addr,u32 clock) { I2C_InitTypeDef i2c; RCC->APB2ENR |= 1<<3;
4、 GPIOB->CRL |= (u32)0xff<<(6*4); RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE); i2c.I2C_Ack = I2C_Ack_Enable; i2c.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; i2c.I2C_ClockSpeed = clock*1000; i2c.I2C_DutyCycle = I2C_DutyCycle_2; i2c.I2C_Mode = I2C_Mode_I2C; i2c.I2C_
5、OwnAddress1 = addr; I2C_Cmd(I2C1,ENABLE); I2C_Init(I2C1,&i2c); } 在配置管脚方面,我还是喜欢用寄存器配置,因为我的两行代码可以解决库函数的N多行代码的问题! 还有在结构体变量命名方面也是属于我自己的独创吧,这样反正我觉得是既容易识别,也少打几个字! typedef struct { uint32_t I2C_ClockSpeed; //I2C时钟频率设置 uint16_t I2C_Mode; //I2C模式设置 uint16_t I2C_DutyCycle;
6、 //高低电平时间之比 uint16_t I2C_OwnAddress1; //主设备地址设置,也就是自己的地址 uint16_t I2C_Ack; //Check uint16_t I2C_AcknowledgedAddress; //地址长度,可以为7bit的也可以为10bit的 }I2C_InitTypeDef; IIC初始化完之后,我们开始来研究eeprom 看完这个写一个字节的协议之后,我们应该对这个写已经没有什么问题了,很简单的。 这个是写一个page 注:在eeprom里面写数据时,一次最多只能写一个p
7、age,一个page为8byte,同时这个也有字节对齐的要求! 比如我们从Address = 4开始写,那么我们最多一次性可写4个byte,如果我们从8开始写的话,我们就可以8个byte,最后偏移到15。 [cpp] view plaincopyprint? 1. void eeprom_write_byte(u8 wt_addr,u8 data) 2. { 3. 4. I2C_GenerateSTART(I2C1,ENABLE);delay(5); 5. I2C_Send7bitAddress(I2C1,EEPROM_ADDR,I2C_Di
8、rection_Transmitter); 6. while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); 7. I2C_SendData(I2C1,wt_addr);delay(5); 8. I2C_SendData(I2C1,data);delay(5); 9. I2C_GenerateSTOP(I2C1, ENABLE); 10. delay(20); 11. } void eeprom_write_byte(u8
9、wt_addr,u8 data) { I2C_GenerateSTART(I2C1,ENABLE);delay(5); I2C_Send7bitAddress(I2C1,EEPROM_ADDR,I2C_Direction_Transmitter); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); I2C_SendData(I2C1,wt_addr);delay(5); I2C_SendData(I2C1,data);delay(5); I2C_GenerateST
10、OP(I2C1, ENABLE); delay(20); } 由于stm32的i2c确实做的不怎么样,标着寄存器太多,也不容易识别,我们就不要检测这些标志寄存器,用延时了把他们隔离了。不过在把地址发送出去之后,要检测设备是否被选中,这个在我们的模拟的i2c里面也是必须检测的!可以认为是必不可少的! [cpp] view plaincopyprint? 1. void eeprom_write_page(u8 wt_addr,u8 *buff,u32 length) 2. { 3. int i = 0; 4. I2C_GenerateSTART
11、I2C1,ENABLE);delay(5);
5. I2C_Send7bitAddress(I2C1,EEPROM_ADDR,I2C_Direction_Transmitter);
6. while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
7. I2C_SendData(I2C1,wt_addr);delay(5);
8. for(i=0; i 12、Data(I2C1,buff[i]);delay(5);
11. }
12. I2C_GenerateSTOP(I2C1, ENABLE);
13. }
void eeprom_write_page(u8 wt_addr,u8 *buff,u32 length)
{
int i = 0;
I2C_GenerateSTART(I2C1,ENABLE);delay(5);
I2C_Send7bitAddress(I2C1,EEPROM_ADDR,I2C_Direction_Transmitter);
while(!I2C_CheckEven 13、t(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
I2C_SendData(I2C1,wt_addr);delay(5);
for(i=0; i 14、们首先要选中设备,然后选择我们要操作的地址,这时候不要stop,如果stop信号一发出,总线就被释放掉了,设备也就跟处理器断开,所以这里需要一个RSTART,跟START不一样,多了个R,这个可以理解为重新开始,这个信号不会选中其他设备,也不会丢失当前设备。
然后还有个注意点是,在读完第N个字节后,不要返回回应,直接stop,不然设备会以为你没有结束,会一直占据总线,等待下一个数据的发送,这样等你下一次来访问他的时候,他就不让你访问了,因为他还停留在给你传数据的状态,所以这里一定不要返回acK直接stop信号发出哦!
[cpp] view plaincopyprint?
1. unsig 15、ned char eeprom_read_byte(u8 rd_addr)
2. {
3. u8 temp = 0;
4.
5. I2C_GenerateSTART(I2C1,ENABLE);delay(5);
6.
7. I2C_Send7bitAddress(I2C1,EEPROM_ADDR,I2C_Direction_Transmitter);
8. while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
16、9.
10. I2C_Cmd(I2C1, ENABLE);
11. I2C_SendData(I2C1,rd_addr);delay(10);
12. I2C_GenerateSTART(I2C1,ENABLE);delay(5);
13.
14. I2C_Send7bitAddress(I2C1,EEPROM_ADDR,I2C_Direction_Receiver);
15. while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SE 17、LECTED));
16.
17. I2C_AcknowledgeConfig(I2C1, DISABLE);
18. while(!(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)));
19. temp = I2C_ReceiveData(I2C1);delay(5);
20.
21. I2C_GenerateSTOP(I2C1, ENABLE);
22. delay(20);
23. I2C_AcknowledgeC 18、onfig(I2C1, ENABLE);
24.
25. return temp;
26. }
unsigned char eeprom_read_byte(u8 rd_addr)
{
u8 temp = 0;
I2C_GenerateSTART(I2C1,ENABLE);delay(5);
I2C_Send7bitAddress(I2C1,EEPROM_ADDR,I2C_Direction_Transmitter);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_ 19、MODE_SELECTED));
I2C_Cmd(I2C1, ENABLE);
I2C_SendData(I2C1,rd_addr);delay(10);
I2C_GenerateSTART(I2C1,ENABLE);delay(5);
I2C_Send7bitAddress(I2C1,EEPROM_ADDR,I2C_Direction_Receiver);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
I2C_AcknowledgeConfig(I2C1, 20、 DISABLE);
while(!(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)));
temp = I2C_ReceiveData(I2C1);delay(5);
I2C_GenerateSTOP(I2C1, ENABLE);
delay(20);
I2C_AcknowledgeConfig(I2C1, ENABLE);
return temp;
}
还是有几个信号是必须确认的,设备地址发送出去,看设备是否有回应!
这里最后一个NOACK必须在发送最后一个字节前使能,在stop信号发出 21、后,记得吧ACK信号重新使能,因为我们刚刚开始是需要ack的,只是最后有时候不需要!
对于数据的读,在所读数据长度上,是没有要求的,也没有page限制,想读多少,读多少!
[cpp] view plaincopyprint?
1. void eeprom_read(u8 rd_addr,u8 *buff,u32 length)
2. {
3. int i = 0;
4. I2C_GenerateSTART(I2C1,ENABLE);delay(5);
5. I2C_Send7bitAddress(I2C1,EEPROM_ADDR,I2C 22、Direction_Transmitter);
6. while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
7. I2C_Cmd(I2C1, ENABLE);
8. I2C_SendData(I2C1,rd_addr);delay(20);
9. I2C_GenerateSTART(I2C1,ENABLE);delay(5);
10. I2C_Send7bitAddress(I2C1,EEPROM_ADDR,I2C_Directi 23、on_Receiver);
11. while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
12. for(i=0; i 24、RECEIVED)));
17. buff[i] = I2C_ReceiveData(I2C1);delay(5);
18. }
19. I2C_GenerateSTOP(I2C1, ENABLE);
20. I2C_AcknowledgeConfig(I2C1, ENABLE);
21. }
void eeprom_read(u8 rd_addr,u8 *buff,u32 length)
{
int i = 0;
I2C_GenerateSTART(I2C1,ENABLE);delay(5);
I2C_ 25、Send7bitAddress(I2C1,EEPROM_ADDR,I2C_Direction_Transmitter);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
I2C_Cmd(I2C1, ENABLE);
I2C_SendData(I2C1,rd_addr);delay(20);
I2C_GenerateSTART(I2C1,ENABLE);delay(5);
I2C_Send7bitAddress(I2C1,EEPROM_ADDR,I2C_Direction_Re 26、ceiver);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
for(i=0; i






