一、定义
IIC 即Inter-Integrated Circuit(集成电路总线),这种总线类型是由菲利浦半导体公司在八十年代初设计出来的,主要是用来连接整体电路(ICS),IIC是一种多向控制总线,也就是说多个芯片可以连接到同一总线结构下,同时每个芯片都可以作为实施数据传输的控制源。这种方式简化了信号传输总线。
I2C串行总线一般有两根信号线,一根是双向的数据线SDA,另一根是时钟线SCL。所有接到I2C总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。
与SPI相同的是,都是多选一,即可以有多个从设备,但是一次通信的时候,只能选择其中的一个。且IIC的从设备选择上,有7位地址,谁控制了时钟线,谁就是从机,而不是像SPI那样通过片选信号线CS来选择。
二、读写AT24C02
(1)电路原理图如下:WP引脚接地,表明可读可写,如果接VCC只读不可写。
(2)引脚说明图如下:
A0-A2,接在了GND,代表是0,R/-W,W的上面是有一横的,代表0有效,读是1有效,所以读操作是0XA0,写操作是0XA1。
(3)地址说明:
(4)通信过程
(1)起始信号:由上图可知,读写的速率为100KHZ,那么1/100khz= 10us,在起始信号的时候,高地电平各占一半,即至少需要持续5us。SCL持续高电平,直到SDA线由高电平到低电平变化,SCL才变为低电平。可以写出代码:
GPIO初始化
void i2c_init(void)
{
//使能GPIOB时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
//PB8 PB9初始化设置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9; //8号和9号引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //普通输出模式,
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽输出,驱动LED需要电流驱动
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化GPIOB,把配置的数据写入寄存器
//i2c引脚初始化状态,默认为高电平
SCL =1;
SDA_W=1;
}
自定义更改输入输出模式
void i2c_sda_mode(uint32_t iomode)
{
//PB9初始化设置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //9号引脚
GPIO_InitStructure.GPIO_Mode = iomode; //输出模式/输入模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽输出,驱动LED需要电流驱动
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化GPIOB,把配置的数据写入寄存器
}
起始信号
void i2c_start(void)
{
//保证SDA引脚为输出模式
i2c_sda_mode(GPIO_Mode_OUT);
SCL =1;
SDA_W=1;
delay_us(5);//100KHz通信速率,但是不能超过400KHz
SDA_W=0;
delay_us(5);
SCL =0; //保持占用I2C总线,允许数据改变
}
(2)结束信号
读上图,输出模式,SCL和SDA都为低电平,延时一段时间,SCL变为高电平,延时一段时间,SDA变为高电平,持续一段时间即可。
void i2c_stop(void)
{
//保证SDA引脚为输出模式
i2c_sda_mode(GPIO_Mode_OUT);
SCL =0;
SDA_W=0;
delay_us(5);
SCL =1;
delay_us(5);
SDA_W=1;
delay_us(5);
}
(3)发送1字节数据
拉低时钟SCL,允许数据进行变化,延时一段时间;
然后判断传进来的data每一位的值,如果读取的data位7为1,那么SDA=1;如果位7为0,那么SDA=0;然后拉高SCL延时一段时间,这样就完成了一位的发送,以此循环八次。因为要允许下一次循环可以改变数据,所以还要把SCL变为低电平。
void i2c_send_byte(uint8_t txd)
{
uint32_t i=0;
//保证SDA引脚为输出模式
i2c_sda_mode(GPIO_Mode_OUT);
//保证SCL引脚开始的时候为低电平,允许数据的改变
SCL =0;
delay_us(5);
//连续发送8个bit,采用最高有效位优先进行发送
for(i=0; i<8; i++)
{
if(txd & (1<<(7-i)))
SDA_W=1;
else
SDA_W=0;
delay_us(5);
//锁存数据,让从机进行识别
SCL=1;
delay_us(5);
//允许改变数据,从机无视该数据
SCL=0;
delay_us(5);
}
}
(4)等待从机应答
有应答:低电平;无应答;高电平
uint8_t i2c_wait_ack(void)
{
uint8_t ack=0;
//保证SDA引脚为输入模式
i2c_sda_mode(GPIO_Mode_IN);
SCL=1;
delay_us(5);
//有应答为低电平,无应答为高电平
if(SDA_R) //无应答
{
ack=1;
i2c_stop();
}
else //有应答
ack=0;
SCL =0; //保持占用I2C总线,允许数据改变
delay_us(5);
return ack;
}
(5)整合上面四部分的代码
void at24c02_write(uint8_t addr,uint8_t *pbuf,uint8_t len)
{
uint8_t ack=0;
//发送启动信号
i2c_start();
//发送寻址地址为0xA0,写访问操作
i2c_send_byte(0xA0);
//等待应答
ack = i2c_wait_ack();
if(ack)
{
printf("24c02 ack device address failrn");
return;
}
printf("24c02 is onlinern");
//发送数据存储地址
i2c_send_byte(addr);
//等待应答
ack = i2c_wait_ack();
if(ack)
{
printf("24c02 ack word address failrn");
return;
}
printf("24c02 word address okrn");
while(len--)
{
//发送数据
i2c_send_byte(*pbuf++);
//等待应答
ack = i2c_wait_ack();
if(ack)
{
printf("24c02 ack send data failrn");
return;
}
}
//发送停止信号,整个通信过程结束
i2c_stop();
printf("24c02 write okrn");
}
主函数调用
i2c_init();
printf("24c02 write addr 0 data is 1rn");
memset(buf,2,sizeof buf);
//页编程最大是8个字节
at24c02_write(0,buf,8);
delay_ms(500);
memset(buf,0,sizeof buf);
printf("24c02 read addr 0 data is:rn");
(6)读数据,从机发送数据,主机发送应答。
读1字节数据
uint8_t i2c_recv_byte(void)
{
uint32_t i=0;
uint8_t rxd=0;
//保证SDA引脚为输出模式
i2c_sda_mode(GPIO_Mode_IN);
//保证SCL引脚开始的时候为低电平,允许数据的改变
SCL =0;
delay_us(5);
//连续接收8个bit,采用最高有效位优先进行接收
for(i=0; i<8; i++)
{
//delay_us(5);
//锁存数据
SCL=1;
delay_us(5);
if(SDA_R)
rxd|=1<<(7-i);
//允许改变数据
SCL=0;
delay_us(5);
}
return rxd;
}
主机发送应答
void i2c_ack(uint8_t ack)
{
//保证SDA引脚为输出模式
i2c_sda_mode(GPIO_Mode_OUT);
//保证SCL引脚开始的时候为低电平,允许数据的改变
SCL =0;
delay_us(5);
if(ack)
SDA_W=1;
else
SDA_W=0;
delay_us(5);
//锁存数据,让从机进行识别
SCL=1;
delay_us(5);
//允许改变数据,从机无视该数据
SCL=0;
delay_us(5);
}
读取数据函数
void at24c02_read(uint8_t addr,uint8_t *pbuf,uint8_t len)
{
uint8_t ack=0;
//发送启动信号
i2c_start();
//发送寻址地址为0xA0,写访问操作
i2c_send_byte(0xA0);
//等待应答
ack = i2c_wait_ack();
if(ack)
{
printf("24c02 ack device address failrn");
return;
}
printf("24c02 is onlinern");
//发送数据存储地址
i2c_send_byte(addr);
//等待应答
ack = i2c_wait_ack();
if(ack)
{
printf("24c02 ack word address 1 failrn");
return;
}
printf("24c02 word address okrn");
//重新发送启动信号
i2c_start();
//发送寻址地址为0xA1,读访问操作
i2c_send_byte(0xA1);
//等待应答
ack = i2c_wait_ack();
if(ack)
{
printf("24c02 ack device address 2 failrn");
return;
}
len=len-1;
while(len--)
{
//接收数据
*pbuf++=i2c_recv_byte();
//主动发送应答给从机
i2c_ack(0);
}
//接收数据
*pbuf=i2c_recv_byte();
//主动发送无应答给从机
i2c_ack(1);
//发送停止信号,整个通信过程结束
i2c_stop();
printf("24c02 read okrn");
}
调用
at24c02_read(0,buf,8);
for(i=0;i<8;i++)
{
printf("%02X ",buf[i]);
}
注意;在写和读直接需要加延时
上一篇:STM32的RS485通信
下一篇:STM32模拟SPI通信
推荐阅读最新更新时间:2024-11-16 19:51
推荐帖子
- 关于如何学习嵌入式 高手 们进啊
- 大家好,我是一名大三的学生,学的是嵌入式方向的,但我们现在才学嵌入式操作系统,都TMD还是理论,学了等于没学,就上学期还学了个汇编,现在一学期都快过完了,感觉什么关于嵌入式方面的都没学到,如果靠下学期再来学点东西,以后出去就别想混了,自己感觉嵌入式这方面以后还是有发展的,但就不知道现在该从何入手,如果按学校老师来,估计学不了什么东东,希望高手们能给我一些意见,从哪方面开始,有什么好书没,,就是关于实际操作的,关于应用程序,驱动程序的都可以。本人感觉自己C、C++还行。同道中人就进来顶一下吧高
- spurray 嵌入式系统
- 【复旦微车规MCU FM33FT0A 系列】--LCD屏显示
- 经过一段时间的了解熟悉,本篇实现LCD显示功能。一.硬件了解开发板板载LCD显示屏,分辨率172(H)RGBx320(V),驱动ICST7789V3,MCU通过SPI接口驱动控制。开发板硬件原理如下图1:LCD原理图连接LCD屏引脚MCUPIN功能LCD_CSPE1片选信号,低电平有效LCD_DCPE2显示数据/命令引脚.低电平时写命令,高电平时写数据LC
- dirty 汽车电子
- CS+下载时找不到动态链接库
- file:///C:\Users\WPJ\Documents\TencentFiles\594049947\Image\Group\MS(A0BZX%Z{3IMGTUfile:///C:\Users\WPJ\Documents\TencentFiles\594049947\Image\Group\MS(A0BZX%Z{3IMGTU这是为什么呢?打开所有工程都是这样CS+下载时找不到动态链接库更新一下,或者重新安装软件,看能不能正常下载
- worldwpj 瑞萨电子MCU
- 感谢团购TI 430 LaunchPad的网友,让EEWORLD成长
- 这几天感觉经历了很多,心情也像过山车,起起伏伏。当初策划团购25元的430LaunchPad开发板活动,内部也很兴奋,觉得这是EEWORLD回馈网友的一个好机会,大家可以一起热闹、一起High。而事情就如我们预期的,网友的反响非常热烈。可是周末,当得到这块板子中没有触摸板时,整个周末也变得晦暗。因为这次团购不是生意,我想大家也都算得出来,板子+邮费。正因为如此,我们更珍惜网友的感受、更珍惜EEWORLD的信誉。我看着帖子,有些网友退货了,我理解,毕竟买到的不是自己想要的,邮费E
- 向农 微控制器 MCU
- Din 4芯 插座 主要用在哪上面的?
- RT小批量的厂家都不卖给你Din4芯插座主要用在哪上面的?
- wowozx 医疗电子
- NXP LPC1114资料
- 哪位大佬有LPC1114的详细资料,手头有个开发板,想学习一下。NXPLPC1114资料NXP官网上应该有,估计已经停产了吧,不过资料还是能用的很老的型号了,不过的确好用。我读研的时候就是这块开发板。当时还是周立功在推呢 感谢!我去看看 是的,我的就是周立功的十多年前入门单片机就学的它,也是周立功的,官网有资料,很全的。NXP的这个芯片还有产品在用吗?LPC824,LPC1768多年前都用过,现在好像没人用了
- 孙玉qq 综合技术交流
设计资源 培训 开发板 精华推荐
- 使用 ROHM Semiconductor 的 BU4244 的参考设计
- 用于工业应用的 C8051F502 MCU 的 C8051F500DK、8051 开发系统
- STM32平衡车(F103C8T6)
- 喷墨打印机可调升压电源/PD诱骗+USB总线引出
- 用于负载瞬态响应的 LR8 高输入电压线性稳压器的典型应用
- DM160225, 3D Touch Pad Board 是一种 PC 外设,用于扩展具有 3D 手势的 2D 触摸板
- ADP2139CB-1.2EVALZ,ADP2138 评估板,800 mA,输出电压 1.2 V,3 MHz 降压稳压器
- LT1086CM-3.3 电池后备稳压电源的典型应用
- L7885C大电流稳压器的典型应用
- LT3595 16 通道降压模式 LED 驱动器的典型应用