从51的时候就学习了I2C通信协议,但51的功能就那些,内部没有集成I2C模块,所以只能通过模拟I2C通信的时序来和EEPROM进行通信,stm32内部集成了I2C通信的片上外设,但由于内部I2C外设复杂和不稳定行,所以用的人不是很多,而基本上使用I2C的通信都是通过模拟时序的方式来实现的
首先I2C是同步半双工的通信方式,需要两条线即可,SCL时钟线,同步时钟由主机产生,SDA数据线用来发送接收数据,任何时候只能一台主机发送数据。
在编程的时候碰到了很多问题,其中一项就是等待从机的应答程序
开始的时候编写如下
void iic_wait_ack() 错误 void iic_wait_ack() 正确的程序
{ {
iic_sda_in(); SCL=1;
delay_us(2); delay_us(2);
SDA=1; SDA=1;
while(SDAIN); while(SDAIN);
SCL=0; SCL=0;
} }
程序运行的时候总是死在红色部分的程序,后来用debug单步调试,慢慢的发现了规律,以下为个人观点,不敢保证一定正确:
上图为I2C通信的时序图
其中起始信号:在SCL为高电平时,SDA电平由高变低,且高电平SDA高电平持续时间要大于4.7us,在SCL由高电平变低时,SDA的低电平持续时间要大于4us
终止信号:在SCL为高电平期间,SDA电平由低变高,且高电平持续时间大于4.7us,低电平持续时间大于4us
起始信号和终止信号无论何时都是由主设备产生的
数据帧:在SCL为高电平期间,SDA的电平保持稳定
主向从写数据
地址发送完成之后,等待从器件的应答信号,切记此时要将SDA配置为上拉输入模式
然后再发送要写入数据的地址,收到应答再写入数据,最后是停止信号
首先先配置IO口,PB10为SCL,PB.11为SDA
#include
void gpio_init()
{
}
void iic_sda_out()//此时为主器件发送数据
{
}
void iic_sda_in()//此时为主器件接收数据或等待从器件发送应答信号
{
}
然后是为头文件iic.h,如下
#define iic_write 0xa0
#define iic_read 0xa1
void iic_start(void);//起始信号
void iic_end(void);//终止信号
void iic_senddata(u8 data);//主器件发送一个字节数据
void iic_master_ack(void);//主机应答信号
void iic_master_nack(void);//主机非应答信号
void iic_wait_ack(void);//等待从机应答信号
void iic_master_write(u8 type,u8 address,u8 data);
u8 iic_master_read(u8 address);
u8 iic_readdata(void);
iic.c文件如下
#include
#include"gpio.h"
#include"delay.h"
#include"iic.h"
#include"sys.h"
void iic_start()
{
}
void iic_end(void)
{
}
void iic_senddata(u8 data)
{
SDA=(data>>i);
SCL=1;
delay_us(5);
SCL=0;
}
}
void iic_master_ack()
{
}
void iic_master_nack()
{
}
void iic_wait_ack()
{
}
void iic_master_write(u8 type,u8 address,u8 data)
{
}
u8 iic_master_read(u8 address)
{
}
u8 iic_readdata()
{
delay_us(2);
SCL=1;
receive<<=1;
if(SDAIN==1)
receive|=1<<0;
else
receive&=~(1<<0);
}
主程序
#include
#include"delay.h"
#include"usart1.h"
#include"sys.h"
#include"gpio.h"
#include"iic.h"
int main()
{
}