赞
踩
今天学习了一下AT89C52编写IIC总线通讯,通讯时序方面还可以接受,但是容易记混,重复了两遍过程,熟悉了很多,以后害的多看多学多记多用。使用的是AT24c02来模拟的I2C的通讯时序
原理讲解:
- /*====================================
- 函数 :At24c02Write(uchar ADDR, DAT)
- 参数 :ADDR 单元地址0-255,DAT 需要输入的数据0-255
- 返回值 :无
- 描述 :At24c02指定单元写入一个字节数据
- ====================================*/
-
- void AT24c02Write(uchar ADDR,DAT)//写进AT24c02
- {
- I2cStart(); //I2C起始信号
- I2cSendByte(AT24c02ADDR + I2cWrite);//IC发送一个字节**************************
- if(ReadACK()) //读从机应答
- AckFlag =1; //无应答
- else
- AckFlag =0; //应答
- I2cSendByte(ADDR);//发送储存单元地址字节**************************************
- if(ReadACK())
- AckFlag =1; //无应答
- else
- AckFlag =0; //应答
- I2cSendByte(DAT);//IC发送一个字节
- if(ReadACK())
- AckFlag =1; //无应答
- else
- AckFlag =0; //应答
- I2cStop(); //I2C停止信号
- }

- /*====================================
- 函数 :At24c02Read(uchar ADDR)
- 参数 :ADDR 单元地址 0-255
- 返回值 :返回指定单元的数据
- 描述 :读AT24C02指定单元内数据
- ====================================*/
- uchar AT24c02Read(uchar ADDR)
- {
- uchar DAT; //返回数据
- I2cStart();//I2C起始信号
- I2cSendByte(AT24c02ADDR +I2cWrite);//IC发送一个字节//发送器件地址加写方向位
- if(ReadACK()) //读从机应答
- AckFlag =1; //无应答
- else
- AckFlag =0; //应答
- I2cSendByte(ADDR);//IC发送一个字节
- ReadACK(); //读从机应答
- I2cStart(); //再次产生I2C起始信号
- I2cSendByte(AT24c02ADDR +I2cRead);//IC读取
- if(ReadACK()) //读从机应答
- AckFlag =1; //无应答
- else
- AckFlag =0; //应答
- DAT=I2cReadByte();//读取一个字节
- SendACK(1); //主机发送非应答
- I2cStop(); //I2C停止信号
- return(DAT); //返回读出数据
- }

- /*====================================
- 函数 :I2cStart()
- 参数 :无
- 返回值 :无
- 描述 :I2C总线起始信号
- ====================================*/
- void I2cStart()//起始信号的函数
- {
- SCL =1;
- SDA =1;
- delay5us();
- SDA =0;
- delay5us();
- }
- /*====================================
- 函数 :I2cStop()
- 参数 :无
- 返回值 :无
- 描述 :I2C总线停止信号
- ====================================*/
- void I2cStop()//停止信号的函数
- {
- SCL =0;
- SDA =0;
- SCL =1;
- delay5us();
- SDA =1;
- delay5us();
- }
- /*====================================
- 函数 :ReadACK()
- 返回值 :1非应答,0应答
- 描述 :I2C总线读从机应答信号
- ====================================*/
- bit ReadACK()//主机读从机应答
- {
- SCL =0; //拉低时钟总线,允许从机控制SDA
- SCL =1; //拉高,读SDA
- delay5us();
- if (SDA) //非应答
- {
- SCL =0;
- return(1);
- }
- else //应答
- {
- SCL =0;
- return(0);
- }
- }
- /*====================================
- 函数 :SendACK(bit i)
- 参数 :1主机发送非应答,0发送应答
- 返回值 :无
- 描述 :主机发送应答信号
- ====================================*/
- void SendACK(bit i)//主机发送应答
- {
- SCL =0; //拉低时钟总线,允许主机控制SDA
- if(i) //发送非应答 SDA=1
- SDA =1;
- else //发送应答 SDA=0
- SDA =0;
- SCL =1; //拉高总线 让从机读SDA
- delay5us(); //延时5us
- SCL =0;//拉低时钟总线,允许SDA释放
- SDA =1;//释放数据总线
- }

- /*IIC通信,AT24C02读写数据,数码管显示数据*/
- #include <REGX52.H>
- #include <intrins.h>
- #define uint unsigned int
- #define uchar unsigned char
- //宏定义
- #define AT24c02ADDR 0xA0 //AT24C02硬件地址
- #define I2cRead 1 //I2C读方向位
- #define I2cWrite 0 //I2C写方向位
-
- sbit DU =P2^6;//段选
- sbit WE =P2^7;//位选
- sbit SCL =P2^1;//时钟线
- sbit SDA =P2^0;//数据线
- uchar num;//数码管显示的值
- bit AckFlag;
- uchar ms_50,s; //记录50ms的个数 20个为1s
- //共阴极数码管0-9
- uchar code duanxuan[]= {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F,};
- //位选前4个数码管
- uchar code weixuan[] ={0xfe,0xfd,0xfb,0xf7};
- void delay(uint x) //@12.000MHz 延迟函数1毫秒
- {
- unsigned char i, j;
- while(x--)
- {
- i = 2;
- j = 239;
- do
- {
- while (--j);
- } while (--i);
- }
- }
-
- void delay5us() //@12.000MHz
- {
- _nop_();
- }
-
- void display(uchar i) //数码管显示函数
-
- {
- static uchar wei;
- uchar qian,bai, shi, ge;
- qian =i/1000;
- bai = i / 100%10;
- shi = i /10%10;
- ge = i % 10;
-
- P0 = 0XFF;//清除断码
- WE = 1; //位选打开
- P0 = weixuan[wei];
- WE = 0; //关闭位选寄存器
- switch(wei)
- {
- case 0:DU = 1;P0 = duanxuan[qian];DU = 0;break;
- case 1:DU = 1;P0 = duanxuan[bai];DU = 0;break;
- case 2:DU = 1;P0 = duanxuan[shi];DU = 0;break;
- case 3:DU = 1;P0 = duanxuan[ge];DU = 0;break;
- }
-
- wei++;
- if(wei ==4)
- wei =0;
- }
-
- void timer0Init() //定时器0初始化
- {
- EA =1; //打开总中断
- ET0 =1; //打开定时器0中断
- TR0 =1; //启动定时器0
- //TCON中的打开定时器
- TMOD |=0x01; //TMOD不能位寻址 0000 0001中 0 01表示定时器模式 16位定时
- TH0 =0xed; //(65535-46082)/256; //定时器 50ms 65536-50000/1.085/256 高8位
- TL0 =0xff; //(65535-46082)%256; //低8位
- }
- /*******************************************************************
- //IIC通信代码
- *******************************************************************/
- /*====================================
- 函数 :I2cStart()
- 参数 :无
- 返回值 :无
- 描述 :I2C总线起始信号
- ====================================*/
- void I2cStart()//起始信号的函数
- {
- SCL =1;
- SDA =1;
- delay5us();
- SDA =0;
- delay5us();
- }
- /*====================================
- 函数 :I2cStop()
- 参数 :无
- 返回值 :无
- 描述 :I2C总线停止信号
- ====================================*/
- void I2cStop()//停止信号的函数
- {
- SCL =0;
- SDA =0;
- SCL =1;
- delay5us();
- SDA =1;
- delay5us();
- }
- /*====================================
- 函数 :ReadACK()
- 返回值 :1非应答,0应答
- 描述 :I2C总线读从机应答信号
- ====================================*/
- bit ReadACK()//主机读从机应答
- {
- SCL =0; //拉低时钟总线,允许从机控制SDA
- SCL =1; //拉高,读SDA
- delay5us();
- if (SDA) //非应答
- {
- SCL =0;
- return(1);
- }
- else //应答
- {
- SCL =0;
- return(0);
- }
- }
- /*====================================
- 函数 :SendACK(bit i)
- 参数 :1主机发送非应答,0发送应答
- 返回值 :无
- 描述 :主机发送应答信号
- ====================================*/
- void SendACK(bit i)//主机发送应答
- {
- SCL =0; //拉低时钟总线,允许主机控制SDA
- if(i) //发送非应答 SDA=1
- SDA =1;
- else //发送应答 SDA=0
- SDA =0;
- SCL =1; //拉高总线 让从机读SDA
- delay5us(); //延时5us
- SCL =0;//拉低时钟总线,允许SDA释放
- SDA =1;//释放数据总线
- }
-
- //发送一个字节8位,从最高位开始***********************************************发送1个字节
- /*====================================
- 函数 :I2cSendByte(uchar DAT)
- 参数 :DAT需要发送的数据
- 返回值 :无
- 描述 :I2C发送一个字节数据
- ====================================*/
- void I2cSendByte(uchar DAT)
- {
- uchar i;
- for(i=0;i<8;i++) //分别写8次,每次写1位
- {
- SCL =0; //时钟线为0
- if(DAT & 0x80) //1011 0110&1000 0000 1为真所以发送1 否则为0则发送0
- SDA =1;
- else
- SDA =0;
- SCL =1;
- DAT =DAT<<1; //向左移位 每次移位1次 一共8次
- }
- SCL =0; //拉低时钟
- SDA = 1; //释放数据总线
- }
- /*====================================
- 函数 :At24c02Write(uchar ADDR, DAT)
- 参数 :ADDR 单元地址0-255,DAT 需要输入的数据0-255
- 返回值 :无
- 描述 :At24c02指定单元写入一个字节数据
- ====================================*/
-
- void AT24c02Write(uchar ADDR,DAT)//写进AT24c02
- {
- I2cStart(); //I2C起始信号
- I2cSendByte(AT24c02ADDR + I2cWrite);//IC发送一个字节**************************
- if(ReadACK()) //读从机应答
- AckFlag =1; //无应答
- else
- AckFlag =0; //应答
- I2cSendByte(ADDR);//发送储存单元地址字节**************************************
- if(ReadACK())
- AckFlag =1; //无应答
- else
- AckFlag =0; //应答
- I2cSendByte(DAT);//IC发送一个字节
- if(ReadACK())
- AckFlag =1; //无应答
- else
- AckFlag =0; //应答
- I2cStop(); //I2C停止信号
- }
- /*====================================
- 函数 :I2cReadByte()
- 参数 :无
- 返回值 :返回读出的一字节数据
- 描述 :I2C总线读一字节数据
- ====================================*/
- uchar I2cReadByte()//读一个字节
- {
- uchar i,DAT;
- for(i =0;i<8;i++)//分别读8次,每次读一位
- {
- DAT<<=1; //数据左移1位,准备接收一位******************************************
- SCL =0; //拉低时钟总线,允许从机控制SDA变化
- SCL =1; //拉高时钟总线,读取SDA上的数据
- if(SDA)
- DAT |=0x01; //为1则写1,否则不行执行写1,通过左移补0
- }
- return(DAT);
- }
- /* 从机要发送的值为 1010 0000
- DAT的初始值为 0000 0000
- DAT<<1 =0000 0000
- DAT|=0x01;
- 0000 0001
- DAT<<1 =0000 0010
- DAT<<1 =0000 0100
- DAT|=0x01 =0000 0101
- 最后成功发送1010 0000*/
- //读取AT24c02函数
- /*====================================
- 函数 :At24c02Read(uchar ADDR)
- 参数 :ADDR 单元地址 0-255
- 返回值 :返回指定单元的数据
- 描述 :读AT24C02指定单元内数据
- ====================================*/
- uchar AT24c02Read(uchar ADDR)
- {
- uchar DAT; //返回数据
- I2cStart();//I2C起始信号
- I2cSendByte(AT24c02ADDR +I2cWrite);//IC发送一个字节//发送器件地址加写方向位
- if(ReadACK()) //读从机应答
- AckFlag =1; //无应答
- else
- AckFlag =0; //应答
- I2cSendByte(ADDR);//IC发送一个字节
- ReadACK(); //读从机应答
- I2cStart(); //再次产生I2C起始信号
- I2cSendByte(AT24c02ADDR +I2cRead);//IC读取
- if(ReadACK()) //读从机应答
- AckFlag =1; //无应答
- else
- AckFlag =0; //应答
- DAT=I2cReadByte();//读取一个字节
- SendACK(1); //主机发送非应答
- I2cStop(); //I2C停止信号
- return(DAT); //返回读出数据
- }
-
- void timer0() interrupt 1 //定时器0中断
- {
- TH0 =0xed;
- TL0 =0xff;
- display(num);
- }
-
-
- void main()
- {
-
- timer0Init(); //定时器0初始化
- EA =0; //屏蔽中断
- AT24c02Write(55,119); //给第55单元写入数据“119”
- delay(5); //延时等待AT24C02处理*******************************************
- num =AT24c02Read(55); //读出第55单元内数据送给显示变量 返回值为DAT
- if(AckFlag) //当从机非应答
- P1 = 0; //亮P1所有灯
- else
- P1 = 0XFF; //灭P1所有灯
- EA =1; //开总中断
- while(1);
-
- }

赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。