從51的時(shí)候就學(xué)習(xí)了I2C通信協(xié)議,但51的功能就那些,內(nèi)部沒有集成I2C模塊,所以只能通過模擬I2C通信的時(shí)序來和EEPROM進(jìn)行通信,stm32內(nèi)部集成了I2C通信的片上外設(shè),但由于內(nèi)部I2C外設(shè)復(fù)雜和不穩(wěn)定行,所以用的人不是很多,而基本上使用I2C的通信都是通過模擬時(shí)序的方式來實(shí)現(xiàn)的
首先I2C是同步半雙工的通信方式,需要兩條線即可,SCL時(shí)鐘線,同步時(shí)鐘由主機(jī)產(chǎn)生,SDA數(shù)據(jù)線用來發(fā)送接收數(shù)據(jù),任何時(shí)候只能一臺(tái)主機(jī)發(fā)送數(shù)據(jù)。
在編程的時(shí)候碰到了很多問題,其中一項(xiàng)就是等待從機(jī)的應(yīng)答程序
開始的時(shí)候編寫如下
void iic_wait_ack() 錯(cuò)誤 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;
} }
程序運(yùn)行的時(shí)候總是死在紅色部分的程序,后來用debug單步調(diào)試,慢慢的發(fā)現(xiàn)了規(guī)律,以下為個(gè)人觀點(diǎn),不敢保證一定正確:
上圖為I2C通信的時(shí)序圖
其中起始信號(hào):在SCL為高電平時(shí),SDA電平由高變低,且高電平SDA高電平持續(xù)時(shí)間要大于4.7us,在SCL由高電平變低時(shí),SDA的低電平持續(xù)時(shí)間要大于4us
終止信號(hào):在SCL為高電平期間,SDA電平由低變高,且高電平持續(xù)時(shí)間大于4.7us,低電平持續(xù)時(shí)間大于4us
起始信號(hào)和終止信號(hào)無論何時(shí)都是由主設(shè)備產(chǎn)生的
數(shù)據(jù)幀:在SCL為高電平期間,SDA的電平保持穩(wěn)定
主向從寫數(shù)據(jù)
地址發(fā)送完成之后,等待從器件的應(yīng)答信號(hào),切記此時(shí)要將SDA配置為上拉輸入模式
然后再發(fā)送要寫入數(shù)據(jù)的地址,收到應(yīng)答再寫入數(shù)據(jù),最后是停止信號(hào)
首先先配置IO口,PB10為SCL,PB.11為SDA
#include
void gpio_init()
{
}
void iic_sda_out()//此時(shí)為主器件發(fā)送數(shù)據(jù)
{
}
void iic_sda_in()//此時(shí)為主器件接收數(shù)據(jù)或等待從器件發(fā)送應(yīng)答信號(hào)
{
}
然后是為頭文件iic.h,如下
#define iic_write 0xa0
#define iic_read 0xa1
void iic_start(void);//起始信號(hào)
void iic_end(void);//終止信號(hào)
void iic_senddata(u8 data);//主器件發(fā)送一個(gè)字節(jié)數(shù)據(jù)
void iic_master_ack(void);//主機(jī)應(yīng)答信號(hào)
void iic_master_nack(void);//主機(jī)非應(yīng)答信號(hào)
void iic_wait_ack(void);//等待從機(jī)應(yīng)答信號(hào)
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()
{
}