历史上的今天
今天是:2024年12月24日(星期二)
2021年12月24日 | 51单片机实验2——I2C通信——24C01扩展实验
2021-12-24 来源:eefocus
一、实验原理:
I2C总线是由Philips公司开发的一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传送信息。
主器件用于启动总线传送数据,并产生时钟以开放传送的器件,此时任何被寻址的器件均被认为是从器件。在总线上主和从、发和收的关系不是恒定的,而取决于此时数据传送方向。如果主机要发送数据给从器件,则主机首先寻址从器件,然后主动发送数据至从器件,最后由主机终止数据传送;如果主机要接收从器件的数据,首先由主器件寻址从器件。然后主机接收从器件发送的数据,最后由主机终止接收过程。在这种情况下,主机负责产生定时时钟和终止数据传送。
二、实验电路图

三、代码详解:
“i2c.h”
#ifndef _I2C_H_
#define _I2C_H_
#include #include /*定义关键字*/ #ifndef uchar #define uchar unsigned char #endif #ifndef uint #define uint unsigned int #endif sbit SCL = P3^0; sbit SDA = P3^1; sbit WP = P3^4; /*声明函数*/ void IIC_Start(void); // 起始信号 void IIC_Stop(void); // 停止信号 void IIC_Asked(void); // 应答信号 bit IIC_WaitAsk(void); // 等待应答 void IIC_NonAsked(void); // 非应答信号 void IIC_SendByte(unsigned char Data); // 发送一个字节 unsigned char IIC_ReceiveByte(void); // 接收一个字节 void WriteToEE(unsigned char Addr,unsigned char Data); // 写入EEPROM,24C01-08使用 unsigned char ReadFromEE(unsigned char Addr); // 从EEPROM读出,24C01-08使用 #endif “i2c.c” #include "i2c.h" #define RdAddr 0xA1 // 从地址读出 AT24C01:1010A2A1A01(1010-000-1) #define WrAddr 0xA0 // 写入从地址 AT24C01:1010A2A1A00(1010-000-0) unsigned char SystemError; // I2C系统错误字 /*开始I2C相关设置 */ void Delay_us(unsigned int m) {// 延时m (us) while(m > 0) { _nop_(); m--; } } void IIC_Start(void) {// 起始信号 EA = 0; SDA = 1; SCL = 1; Delay_us(10); SDA = 0; Delay_us(10); SCL = 0; } void IIC_Stop(void) {// 停止信号 SCL = 0; SDA = 0; Delay_us(10); SCL = 1; Delay_us(10); SDA = 1; EA = 1; } void IIC_Asked(void) {// 应答信号 SDA = 0; Delay_us(10); SCL = 1; Delay_us(10); SCL = 0; } bit IIC_WaitAsk(void) {// 等待应答 unsigned char ErrTime = 255;// 检测次数255 SDA = 1; Delay_us(10); SCL = 1; Delay_us(10); while(SDA) {// 如果非应答 ErrTime--;// 次数减1 if(!ErrTime) {// 如果次数到0 IIC_Stop();// 停止信号 SystemError = 0x11;// 置系统错误字=0x11 return 0;// 返回0 } } SCL = 0; return 1;// 如果应答,返回1 } void IIC_NonAsked(void) {// 非应答 SDA = 1; Delay_us(10); SCL = 1; Delay_us(10); SCL = 0; } void IIC_SendByte(unsigned char Data) {// 发送一个字节 unsigned char tData,i; tData = Data; i = 8; while(i > 0) { SCL = 0; _nop_(); if((tData & 0x80) == 0x80) { SDA = 1; } else { SDA = 0; } tData <<= 1; Delay_us(10); SCL = 1; Delay_us(10); i--; } SCL = 0; } unsigned char IIC_ReceiveByte(void) {// 接收一个字节 unsigned char Data,i; i = 8; Data = 0x00; SDA = 1; while(i > 0) { Data <<= 1; SCL = 0; Delay_us(10); SCL = 1; Delay_us(10); if(SDA == 1) { Data |= 0x01; } i--; } SCL = 0; return Data; } // ******* 写入EEPROM ******* // ******* 输入:Addr 地址;Data 数据 ******* void WriteToEE(unsigned char Addr,unsigned char Data) { IIC_Start(); // 发起始信号 IIC_SendByte(WrAddr); // 发写入控制字 IIC_WaitAsk(); // 等待应答 IIC_SendByte(Addr); // 发送地址 IIC_WaitAsk(); // 等待应答 IIC_SendByte(Data); // 发送数据 IIC_WaitAsk(); // 等待应答 IIC_Stop(); // 发停止信号 } // ******* 从EEPROM读出 ******* // ******* 输入:Addr 地址;返回数据 ******* unsigned char ReadFromEE(unsigned char Addr) { unsigned char Data; IIC_Start(); // 发起始信号 IIC_SendByte(WrAddr); // 发写入控制字 IIC_WaitAsk(); // 等待应答 IIC_SendByte(Addr); // 发送地址 IIC_WaitAsk(); // 等待应答 IIC_Start(); // 发重复起始信号 IIC_SendByte(RdAddr); // 发读出控制字 IIC_WaitAsk(); // 等待应答 Data = IIC_ReceiveByte(); // 接收一个字节到Data IIC_NonAsked(); // 非应答信号 IIC_Stop(); // 发停止信号 return Data; // 返回Data } **注意:**这个工程项目中去掉应答信号函数void IIC_Asked(void)也行,因为没用上。写的目的是提供大家以后参考使用。 也因为多余了这个应答函数,因此编译时,编译器会报一个warning: SEGMENT: ?PR?IIC_ASKED?I2C。意思是有个函数声明了却未使用。但不影响实验结果。 “main.c” #include #include "i2c.h" unsigned char code seg[16]= {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71}; unsigned char code pos[4]= {0xfe,0xfd,0xfb,0xf7}; unsigned char disbuf[4]={0,0,0,0}; unsigned char counter = 0;//定时器中断计数器 unsigned char index = 0;//地址索引 void delay(unsigned int x) { unsigned char i; while(x--) { for(i=0;i<125;i++) ; } } void display(void){ unsigned char i; for(i=0;i<4;i++){ P0 = seg[disbuf[i]]; //段码 P1 = pos[i]; //位选码 delay(2); P1=0xff; //消隐 } } void main(void){ TMOD=0x01; TH0=(65536-10000)/256; TL0=(65536-10000)%256; EA=1; ET0=1; TR0=1; WP=0; for(index=0;index<=0x1f;index++){// 连续写入24C01 WriteToEE(index,index);// index地址写入index delay(9);//必须等待写周期结束 } index=0; WP=1; while(1){ display(); } } void timer0() interrupt 1{ unsigned char Data=0; TH0=(65536-10000)/256; TL0=(65536-10000)%256; counter++; if (counter==100){ counter=0; Data= ReadFromEE(index);// 读出index地址数据 disbuf[3]=index/0x10; //地址、数据写入显示缓冲器 disbuf[2]=index%0x10; disbuf[1]=Data/0x10; disbuf[0]=Data%0x10; index++; if(index==0x2f){index=0;} } } 仿真结果: 实验结果:单片机成功将0到15这十六个数写入AT24C01的存储区中,并通过I2C总线的读取方式,将存放在AT24C01存储区的这十六个数依次读取出来并在数码管上显示出来。 上图为单片机成功写入16个数进入AT24C01存储区并依次读取数据并在数码管上显示的图片。 
史海拾趣
|
CANopen主节点的设计方案 - 基于IXXAT公司 CANopen Master API for Windows CANopen主节点除具备CANopen设备的基本条件外,还需具备NMT Master的功能,即对CANopen网络进行管理。对CANopen主节点的实现提出三种方案: ?? 方案1:在CANopen-Chip ...… 查看全部问答> |
|
先说说我的: NOKIA 3310 像板砖一样的家伙 呵呵 不过在01年的时候也算稀罕物。 经过多次高空坠落试验,都完好无损, 后来从一个酒瓶高的容器上坠落,液晶屏里的蓝色液体流出,彻底退休了。当时在工资还不高的情况下,流的不是液晶, ...… 查看全部问答> |
|
初次搞485的多机通信(一主多从),现在遇到的问题令我很困惑。 我的通信思路是,从机逐个与主机通信,即主机发送一帧数据(8字节,包含数据信息),呼叫从 ...… 查看全部问答> |
|
我大学里是学软件的,对C#之类的比较熟,C/C++也还行,汇编了解一些,电气电路和硬件几乎一点不懂。 现在有个工作是从事激光仪器里的单片机开发,请问需要学习多少电气知识?线路应该有人设计好的,我写程序要看懂电路吗?有哪里方面是要与设计电 ...… 查看全部问答> |
|
ce5.0 evc4.2. 我要在对话框中加个最小化按钮,用ShowWindow(SW_MINIMIZE)来实现,但对话框最小化就不见了.而在xp系统中就行。 感觉是任务栏没有显示,造成最小化后程序不能回到任务栏,所以不见了。 … 查看全部问答> |
|
一个简短程序放在AT89C55WD中好象不工作了,是否与程序有关? 问题1: 全部程序如下: #include sbit Fscx = P3^4; sbit CW = P3^5; void main() { int i; CW = 0; while(1) { Fscx = 1; ...… 查看全部问答> |
|
CE里默认为64M,IMGRAM128=1设置后对128M支持没有问题,但是设置IMGRAM256=1之后,就不能进入系统了 所以想问一下CE里怎么添加对256M的支持,多谢!… 查看全部问答> |
|
上周周一(6月13号)开始为一块电路板做定位工作,由于自己没有详细考虑PCB设计时的显示位置与实际模具的接口的位置关系,导致周二、三、四的布局布线工作全都白做了,实在是悲惨,只能怪自己前期考虑的不周,这也算是一次学习的机会吧 ...… 查看全部问答> |
|
这套电源管理方案指南中提供了线电源和移动设备电源的全套解决方案,而且设计目前TI最新的产品系列,对于电源方案的制定非常有参考意义。 [ 本帖最后由 wstt 于 2012-6-16 00:43 编辑 ]… 查看全部问答> |
|
今天早上刚到公司打卡看到EEWORLD寄来的快递 估计就是蓝牙板 迫不及待拆开看一下 比想象中小不少 这样可能看不出来 这样就能感觉出mini了吧 简单上个电 看下功耗 2.367mA 应该主要是有源晶振的功耗 晚 ...… 查看全部问答> |




