单片机练习 - I2C总线协议-转载
时间:10-02
整理:3721RD
点击:
这次利用单片机通过软件模拟I2C总线协议, 并对基于I2C协议的AT24C02 EEPROM进行读写操作, 具体说明与功能见代码注释.
转载MK2大神博客
AT24C02与单片机的连接电路图如下:
单片机利用P2.0模拟SDA, P2.1模拟SCL.
程序代码:
- //用软件方法模拟I2C总线协议来读写AT24C02 EEPROM
- //每次上电后, 继续按照上次的计数结果计数, 每半秒计数一次
- #include <reg52.H>
- #include <intrins.H>
- #define uchar unsigned char
- sbit SDA = P2^0;
- sbit SCL = P2^1;
- //仿真延时5.43us
- void delay5us()
- {
- _nop_();
- }
- //延时10ms, 仿真约11ms
- //实际测试中, 对于写一个字节, 只须2ms
- void delay10Ms()
- {
- uchar a,b;
- for(a=50;a>0;a--)
- for(b=100;b>0;b--);
- }
- //延时2ms
- void delay2Ms()
- {
- uchar a,b;
- for(a=10;a>0;a--)
- for(b=100;b>0;b--);
- }
- /***************************** I2C总线协议 ************************************/
- //起始信号
- void start()
- {
- SDA = 1; //启动I2C总线
- SCL = 1;
- delay5us(); //延时
- SDA = 0; //起始信号
- delay5us(); //SDA拉低时间至少4us后, 才能拉低SCL
- SCL = 0;
- }
- //终止信号
- void stop()
- {
- SDA = 0;
- SCL = 1; //SCL拉高至少4us后, 才能拉高SDA, 产生终止信号
- delay5us();
- SDA = 1;
- delay5us(); //保持SDA拉高4.7us以上
- //终止后, 总线处于空闲状态
- }
- //发送应答
- void ack()
- {
- SDA = 0;
- SCL = 1;
- delay5us();
- SCL = 0;
- SDA = 1;
- }
- //发送非应答
- void nack()
- {
- SDA = 1;
- SCL = 1;
- delay5us();
- SCL = 0;
- }
- //获取应答, 有应答返回0, 非应答返回1
- bit getAck()
- {
- bit flag;
- SDA = 1;
- SCL = 1;
- flag = SDA;
- SCL = 0;
- return flag;
- }
- //发送一字节数据, 有应答返回0, 非应答返回1
- bit sendByte(uchar dat)
- {
- uchar i;
- for(i = 0; i < 8; i++)
- {
- dat = dat << 1; //左移, 最高位将移到CY中
- SDA = CY;
- SCL = 1;
- delay5us();
- SCL = 0;
- }
- return getAck();
- }
- //接收一字节数据
- uchar recvByte()
- {
- uchar i, tmp, dat;
- for(i = 0; i < 8; i++)
- {
- SCL = 1;
- delay5us();
- if(SDA == 1)
- {
- tmp = 1;
- }
- else
- tmp = 0;
- dat = (dat << 1) | tmp;
- SCL = 0;
- delay5us();
- }
- return dat;
- }
- /***************************** I2C总线协议 ************************************/
- /***************************** AT24C02 EEPROM的读写操作 ************************************/
- //AT24C02 EEPROM 在TX1-B实验板上的地址是 1010 000B
- //向EEPROM指定地址写一字节数据
- void writeByte(uchar dat, uchar add)
- {
- start();
- sendByte(0xa0); //找出EEPROM芯片, 写数据
- sendByte(add); //先写地址
- sendByte(dat); //读数据
- stop(); //释放总线
- delay2Ms(); //发送完写数据, stop()后, 需要延时10ms让芯片完成内部写周期
- //实际测试中, 写一字节, 只须2ms
- }
- //连续写指定长度的字节流(Page Write)
- void writeBytes(uchar * dats, uchar length, uchar add)
- {
- uchar i;
- start();
- sendByte(0xa0);
- sendByte(add);
- for(i = 0; i < length; i++)
- {
- sendByte(dats[i]);
- }
- stop();
- delay10Ms();
- }
- //读取EEPROM指定地址的一字节数据(Random Read)
- uchar readByte(uchar add)
- {
- uchar dat;
- start();
- sendByte(0xa0); //找出EEPROM芯片, 写数据
- sendByte(add); //先写地址
- start();
- sendByte(0xa1); //读数据
- dat = recvByte();
- nack(); //非响应
- stop(); //释放总线
- return dat;
- }
- //连续读指定大小的字节数(Sequential Read)
- void readBytes(uchar * buffer, uchar size, uchar add)
- {
- uchar i, count = size - 1;
- start();
- sendByte(0xa0);
- sendByte(add);
- start();
- sendByte(0xa1);
- for(i = 0; i < count; i++)
- {
- buffer[i] = recvByte();
- ack(); //应答
- }
- buffer[count] = recvByte();
- nack(); //非应答, 结束
- stop();
- }
- /***************************** AT24C02 EEPROM的读写操作 ************************************/
- sbit wela = P2^7; //数码管位选
- sbit dula = P2^6; //数码管段选
- //0-F数码管的编码(共阴极)
- unsigned char code table[]={0x3f,0x06,0x5b,0x4f,0x66,
- 0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
- void display(uchar v)
- {
- unsigned char count;
- unsigned char datas[] = {0, 0, 0};
- datas[0] = v / 100;
- datas[1] = v % 100 / 10;
- datas[2] = v % 10;
- for(count = 0; count != 3; count++)
- {
- //关位选, 去除对上一位的影响
- P0 = 0xff;
- wela = 1; //打开锁存, 给它一个下降沿量
- wela = 0;
- //段选
- P0 = table[datas[count]];
- dula = 1; //打开锁存, 给它一个下降沿量
- dula = 0;
- //位选
- P0 = _crol_(0xfe, count); //选择第(count + 1) 个数码管
- wela = 1; //打开锁存, 给它一个下降沿量
- wela = 0;
- delay2Ms();
- }
- }
- uchar value, th, tl, tCount;
- void main()
- {
- value = readByte(0); //向EEPROM地址0读一字节数据
- tCount = 0;
- EA = 1; //开中断
- ET1 = 1; //允许T1中断
- TMOD = 0x10; //工作方式1
- TH1 = th = 0x4b;//(65536 - 50000/1.085) / 256; //定时50ms
- TL1 = tl = 0xfd;//(65536 - 50000/1.085) - th * 256;
- TR1 = 1; //T1开始计时
- while(1)
- {
- if(tCount > 10) //满500ms, 加1
- {
- value++;
- writeByte(value, 0); //将当前值保存在EEPROM地址0中
- tCount = 0;
- }
- display(value);
- }
- }
- void time1() interrupt 3
- {
- TH1 = th;
- TL1 = tl;
- tCount++;
- }
利用单片机通过软件模拟I2C总线协议, 并对基于I2C协议的AT24C02 EEPROM进行读写操作
谢谢
感谢分享
真心感谢分享
学习学习啊
貌似是郭天祥的原理图……
今天刚好看到这,学习了
正好遇到这个问题
有更贱答的方法看计算机测控
真心感谢分享
小编用的是什么单片机啊?
确实挺好的,