- 转自:https://i-blog.csdnimg.cn/blog_migrate/2ba95093bc3337971608db850e104b80.png IIC详解
![](https://i-blog.csdnimg.cn/blog_migrate/2ba95093bc3337971608db850e104b80.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2ba95093bc3337971608db850e104b80.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2ba95093bc3337971608db850e104b80.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2ba95093bc3337971608db850e104b80.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2ba95093bc3337971608db850e104b80.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2ba95093bc3337971608db850e104b80.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2ba95093bc3337971608db850e104b80.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2ba95093bc3337971608db850e104b80.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2ba95093bc3337971608db850e104b80.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2ba95093bc3337971608db850e104b80.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2ba95093bc3337971608db850e104b80.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2ba95093bc3337971608db850e104b80.png)
-
- #define I2C_SCL GPIO_Pin_6
- #define I2C_SDA GPIO_Pin_7
- #define GPIO_I2C GPIOB
- #define I2C_SCL_H GPIO_SetBits(GPIO_I2C, I2C_SCL) //把PB6置高
- #define I2C_SCL_L GPIO_ResetBits(GPIO_I2C, I2C_SCL) //把PB6置低
- #define I2C_SDA_H GPIO_ResetBits(GPIO_I2C, I2C_SDA) //把PB7置高
- #define I2C_SCL_L GPIO_ResetBits(GPIO_I2C, I2C_SDA) //把PB7置低
![](https://i-blog.csdnimg.cn/blog_migrate/2ba95093bc3337971608db850e104b80.png)
转自:IIC时序详解——http://blog.csdn.net/drivermonkey/article/details/7695547
AT24C02是由ATMEL公司提供的,IIC总线串行EEPROM(electronic eraser programmer read only memory),其容量为2kbit(256B),工作电压在2.7v"5.5v之间,生产工艺是CMOS。
一般数字芯片都在左下角和右上角为GND,VCC。容量的计算方法:AT24Cxx :01"1024
容量 = xx * 1kbit。
写入过程:
AT24C系列EEPROM芯片的固定部分为1010,A2,A1,A0引脚接高低电平后得到确定的3位编码,形成7位编码即为该器件的地址码。
单片机进行写操作时,首先发送该器件的7位地址码和写方向位”0”(共8位,即一个字节),发送完后释放SDA线并在SCL线上产生第9个时钟信号。被选中的存储器器件在确认是自己的地址后,在SDA线上产生一个应答信号作为响应,单片机收到应答后就可以传送数据了。传送数据时,单片机首先发送一个字节的被写入存储器的首地址,收到存储器器件的应答后,单片机就逐个发送数据字节,但每发送一个字节后都要等待应答。AT24C系列片内地址在接收到每一个数据字节地址后自动加1,在芯片的“一次装载字节数”限度内,只需输入首地址。装载字节数超过芯片的“一次装载字节数”时,数据地址将“上卷”,前面的数据将被覆盖。
字节写:
页写:
读入过程:
单片机先发送该器件的7位地址码和写方向位“0”(“伪写”),发送完后释放SDA线并在SCL线上产生第9个时钟信号。被选中的存储器器件在确认是自己的地址后,在SDA线上产生一个应答信号作为回应。
然后,再发一个字节的要读出器件的存储区的首地址,收到应答后,单片机要重复一次起始信号并发出器件地址和读方向位(“1”),收到器件应答后就可以读出数据字节,每读出一个字节,单片机都要回复应答信号。当最后一个字节数据读完后,单片机应返回以“非应答”(高电平),并发出终止信号以结束读出操作。
当前地址读:
随机读:
有序读:
IIC总线模拟时序图:
IIC总线应答时序图:
设备地址:
写周期:
两次写之间要有一个10ms的twR间隔
转自:http://bbs.21ic.com/icview-236765-1-1.html
终于弄出来了,用IO口模拟的,但是最后一位不知道为什么总是为0呢 #include<avr/io.h> #define uint unsigned int #define uchar unsigned char #define BIT(x) (1<<x) //PORTA0=SCL //PORTA1=SDA void delay1(uint n) { uint i,j; for(i=0;i<n;i++) for(j=0;j<367;j++); } void delay() { asm("NOP"); asm("NOP");asm("NOP"); } void start() //开始信号 { PORTA|=BIT(1); delay(); PORTA|=BIT(0); delay(); asm("NOP");asm("NOP"); PORTA&=~BIT(1); delay(); asm("NOP");asm("NOP"); PORTA&=~BIT(0); delay(); } void stop() //停止 { PORTA&=~BIT(1); delay(); PORTA|=BIT(0); delay();asm("NOP");asm("NOP");asm("NOP");asm("NOP"); PORTA|=BIT(1); delay();asm("NOP");asm("NOP");asm("NOP");asm("NOP"); } void respons() //应答 { //uchar i; PORTA&=~BIT(1); delay(); PORTA|=BIT(0); delay();asm("NOP");asm("NOP");asm("NOP");asm("NOP"); PORTA&=~BIT(0); delay(); } /* void respons_send() //应答 { uchar i; PORTA|=BIT(0); delay(); while(((PORA&BIT(1))==1)&&(i<250))i++; PORTA&=~BIT(0); delay(); } */ void init() { PORTA|=BIT(1); delay(); PORTA|=BIT(0); delay(); } void write_byte(uchar date) { uchar i,temp; for(i=0;i<8;i++) //要传送的数据长度为8位 { if((date<<i)&0x80) PORTA|=BIT(1); //判断发送位 else PORTA&=~BIT(1); delay(); PORTA|=BIT(0); //置时钟线为高,通知被控器开始接收数据位 delay(); delay(); //在此期间取走数据 PORTA&=~BIT(0); delay(); delay(); } PORTA&=~BIT(0); delay(); PORTA|=BIT(1); delay(); } uchar read_byte() { uchar i,k,temp=0; PORTA&=~BIT(0); delay(); PORTA|=BIT(1); //释放数据线SDA delay(); for(i=0;i<8;i++) { PORTA|=BIT(0); delay(); DDRA&=~BIT(1); PORTA|=BIT(1); delay(); temp=(PINA&0x02); k=((k<<1)|temp); // DDRA|=BIT(1); PORTA&=~BIT(0); delay(); } DDRA|=BIT(1); delay(); return k; } void write_add(uchar address,uchar date) { start(); write_byte(0x56); respons(); write_byte(address); respons(); write_byte(date); respons(); stop(); } uchar read_add(uchar address) { uchar date; start(); write_byte(0x57); respons(); write_byte(address); respons(); date=read_byte(); stop(); return date; } main() { DDRA=0xff; DDRB=0xFF; init(); write_add(0x03,0x3f); delay(); write_add(0x00,0x41); delay(1); write_add(0x08,0xab); delay1(10); PORTB=read_add(0x08); delay(); // PORTB=0XFF; delay(); while(1); } |
转自:AVR模拟IIC总线-https://download.csdn.net/download/iamfengpeng/1913080
#include <iom128.h>
#include <stdio.h>
#include "iic.h"
#define uchar unsigned char
#define uint unsigned int
/********************************************************************
此程序是I2C操作平台(主方式的软件平台)的底层的C子程序,如发送数据
及接收数据,应答位发送,并提供了几个直接面对器件的操作函数,它很方便的
与用户程序连接并扩展.....
注意:函数是采用软件延时的方法产生SCL脉冲,固对高晶振频率要作
一定的修改....(本例是1us机器周期,即晶振频率要小于12MHZ)
********************************************************************/
#define uchar unsigned char /*宏定义*/
#define uint unsigned int
#define _Nop() asm("nop") /*定义空指令*/
/* 常,变量定义区 */
/*端口位定义*/
#define SDA PORTA_Bit1 /*模拟I2C数据传送位*/
#define SCL PORTA_Bit0 /*模拟I2C时钟控制位*/
#define SDA_pin DDRA_Bit1 /*SDA输入输出*/
#define SCL_pin DDRA_Bit0
#define SDA_in PINA_Bit1
#define iic_delay() delay_us(1) // 根据系统时钟进行调整
uchar TAB_T[]={ 0x31,0x06,0x10,//秒,分,时
0x13,0x01,0x07,0x08};//日,星期,月,年.
void delay_us( uchar us )
{
uchar dly;
while ( us -- )
{
for(dly=0;dly<8;dly++);
}
}
/*状态标志*/
uchar ack; /*应答标志位*/
/*******************************************************************
起动总线函数
函数原型: void Start_I2c();
功能: 启动I2C总线,即发送I2C起始条件.
********************************************************************/
void Start()
{
SCL_pin=0;
SDA_pin=0;
SDA=1; /*发送起始条件的数据信号*/
_Nop();
SCL=1;
iic_delay();/*起始条件建立时间大于4.7us,延时*/
SDA_pin=1;
SDA=0; /*发送起始信号*/
iic_delay();/* 起始条件锁定时间大于4μs*/
SCL=0; /*钳住I2C总线,准备发送或接收数据 */
SCL_pin=1;
iic_delay();
}
/*******************************************************************
结束总线函数
函数原型: void Stop_I2c();
功能: 结束I2C总线,即发送I2C结束条件.
********************************************************************/
void Stop()
{
SDA=0; /*发送结束条件的数据信号*/
SDA_pin=1;
iic_delay(); /*发送结束条件的时钟信号*/
SCL_pin=0;
SCL=1;
iic_delay(); /*结束条件建立时间大于4μs*/
SDA_pin=0;
SDA=1; /*发送I2C总线结束信号*/
iic_delay();
}
/*******************************************************************
字节数据传送函数
函数原型: void SendByte(uchar c);
功能: 将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对
此状态位进行操作.(不应答或非应答都使ack=0 假)
发送数据正常,ack=1; ack=0表示被控器无应答或损坏。
********************************************************************/
void WriteByte(uchar c)
{
uchar BitCnt;
for(BitCnt=0;BitCnt<8;BitCnt++) /*要传送的数据长度为8位*/
{
if((c<<BitCnt)&0x80)
{
SDA_pin=0;
SDA=1; /*判断发送位*/
}
else
{
SDA=0;
SDA_pin=1;
}
_Nop();
SCL_pin=0;
SCL=1; /*置时钟线为高,通知被控器开始接收数据位*/
iic_delay(); /*保证时钟高电平周期大于4μs*/
SCL=0;
SCL_pin=1;
}
iic_delay() ;
SDA_pin=0;
SDA=1; /*8位发送完后释放数据线,准备接收应答位*/
iic_delay() ;
SCL_pin=0;
SCL=1;
iic_delay();
if(SDA_in==1)
ack=0;
else
ack=1; /*判断是否接收到应答信号*/
SCL=0;
SCL_pin=1;
iic_delay() ;
}
/*******************************************************************
字节数据传送函数
函数原型: uchar RcvByte();
功能: 用来接收从器件传来的数据,并判断总线错误(不发应答信号),
发完后请用应答函数。
********************************************************************/
uchar ReadByte()
{
uchar retc;
uchar BitCnt;
retc=0;
SDA_pin=0;
SDA=1; /*置数据线为输入方式*/
for(BitCnt=0;BitCnt<8;BitCnt++)
{
SCL=0; /*置时钟线为低,准备接收数据位*/
SCL_pin=1;
iic_delay(); /*时钟低电平周期大于4.7μs*/
SCL_pin=0;
SCL=1; /*置时钟线为高使数据线上数据有效*/
iic_delay();
retc=retc<<1;
if(SDA_in==1)retc=retc+1; /*读数据位,接收的数据位放入retc中 */
iic_delay();
}
SCL=0;
SCL_pin=1;
iic_delay();
return(retc);
}
/********************************************************************
应答子函数
原型: void Ack_I2c(bit a);
功能:主控器进行应答信号,(可以是应答或非应答信号)
********************************************************************/
void Ack_I2c(uchar a)
{
if(a==0)
{
SDA_pin=1;
SDA=0; /*在此发出应答或非应答信号 */
}
else
{
SDA_pin=0;
SDA=1;
}
iic_delay();
SCL_pin=0;
SCL=1;
iic_delay(); /*时钟低电平周期大于4μs*/
iic_delay();
SCL=0; /*清时钟线,钳住I2C总线以便继续接收*/
SCL_pin=1;
iic_delay();
}
void Write8563(uchar ucAddr,uchar ucData)
{
Start();
WriteByte(0xa2);
WriteByte(ucAddr);
WriteByte(ucData);
Stop();
}
uchar Read8563(uchar ucAddr)
{
uchar ucData;
Start();
WriteByte(0xa2); //写器件地址
WriteByte(ucAddr); //写字节地址
Start();
WriteByte(0xa3); //写器件地址,最低为1表示读
ucData=ReadByte(); //写字节地址
Stop();
return ucData; //读数据
}
void Init8563(void)
{
uchar i,ucAddr=0x02;
Write8563(0x0d,0x80);
i = Read8563(0x0D);
Write8563(0x00,0x00);
Write8563(0x01,0x11);
i = Read8563(0x00);
i = Read8563(0x01);
for(i=0;i<7;i++)
{
Write8563(ucAddr,TAB_T[i]);
ucAddr++;
}
}
void GetTime(void)
{
uchar i,ucData1,ucData2,ucAddr=0x02;
uchar *pTime=TAB_T;
for(i=0;i<7;i++)
{
pTime[i]=Read8563(ucAddr);
ucAddr++;
}
pTime[0]&=0x7f; //屏蔽无效位
pTime[1]&=0x7f;
pTime[2]&=0x3f;
pTime[3]&=0x3f;
pTime[4]&=0x07;
pTime[5]&=0x1f;
// for(i=0;i<7;i++)
//
// {
//
// ucData1=pTime[i]/16; //BCD码转十六进制
//
// ucData2=pTime[i]%16;
//
// pTime[i]=ucData1*10+ucData2;
//
// }
}
/* 完毕 */