51单片机对I2C总线上挂接多个AT24C02的读写操作+Proteus仿真
51单片机对I2C总线上挂接多个AT24C02的读写操作+Proteus仿真
- Proteus仿真图

实例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
| //对I2C总线上挂接多个AT24C02的读写操作 #include <reg51.h> // 包含51单片机寄存器定义的头文件 #include <intrins.h> //包含\_nop\_()函数定义的头文件 #define OP\_READ1 0xa1 // 器件1地址以及读取操作,0xa1即为1010 0001B #define OP\_WRITE1 0xa0 // 器件1地址以及写入操作,0xa1即为1010 0000B #define OP\_READ2 0xaf // 器件2地址以及读取操作,0xa1即为1010 1111B #define OP\_WRITE2 0xae // 器件2地址以及写入操作,0xa1即为1010 1110B sbit SDA=P3^4; //将串行数据总线SDA位定义在为P3.4引脚 sbit SCL=P3^3; //将串行时钟总线SDA位定义在为P3.3引脚 /\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* 函数功能:延时1ms (3j+2)\*i=(3×33+2)×10=1010(微秒),可以认为是1毫秒 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/ void delay1ms() { unsigned char i,j; for(i=0;i<10;i++) for(j=0;j<33;j++) ; } /\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* 函数功能:延时若干毫秒 入口参数:n \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/ void delaynms(unsigned char n) { unsigned char i; for(i=0;i<n;i++) delay1ms(); } /\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* 函数功能:开始数据传送 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/ void start() // 开始位 { SDA = 1; //SDA初始化为高电平“1” SCL = 1; //开始数据传送时,要求SCL为高电平“1” \_nop\_(); //等待一个机器周期 \_nop\_(); //等待一个机器周期 SDA = 0; //SDA的下降沿被认为是开始信号 \_nop\_(); //等待一个机器周期 \_nop\_(); //等待一个机器周期 \_nop\_(); //等待一个机器周期 \_nop\_(); //等待一个机器周期 SCL = 0; //SCL为低电平时,SDA上数据才允许变化(即允许以后的数据传递) \_nop\_(); //等待一个机器周期 } /\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* 函数功能:结束数据传送 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/ void stop() // 停止位 { SDA = 0; //SDA初始化为低电平“0” \_nop\_(); //等待一个机器周期 \_nop\_(); //等待一个机器周期 SCL = 1; //结束数据传送时,要求SCL为高电平“1” \_nop\_(); //等待一个机器周期 \_nop\_(); //等待一个机器周期 \_nop\_(); //等待一个机器周期 \_nop\_(); //等待一个机器周期 \_nop\_(); //等待一个机器周期 \_nop\_(); //等待一个机器周期 SDA = 1; //SDA的上升沿被认为是结束信号 } /\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* 函数功能:从AT24Cxx读取数据 出口参数:x \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/ unsigned char ReadData() // 从AT24Cxx移入数据到MCU { unsigned char i; unsigned char x; //储存从AT24Cxx中读出的数据 for(i = 0; i < 8; i++) { SCL = 1; //SCL置为高电平 x<<=1; //将x中的各二进位向左移一位 x|=(unsigned char)SDA; //将SDA上的数据通过按位“或“运算存入x中 SCL = 0; //在SCL的下降沿读出数据 } return(x); //将读取的数据返回 } /\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* 函数功能:向AT24Cxx的当前地址写入数据 入口参数:y (储存待写入的数据) \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/ //在调用此数据写入函数前需首先调用开始函数start(),所以SCL=0 bit WriteCurrent(unsigned char y) { unsigned char i; bit ack_bit; //储存应答位 for(i = 0; i < 8; i++) // 循环移入8个位 { SDA = (bit)(y&0x80); //通过按位“与”运算将最高位数据送到S //因为传送时高位在前,低位在后 \_nop\_(); //等待一个机器周期 SCL = 1; //在SCL的上升沿将数据写入AT24Cxx \_nop\_(); //等待一个机器周期 \_nop\_(); //等待一个机器周期 SCL = 0; //将SCL重新置为低电平,以在SCL线形成传送数据所需的8个脉冲 y <<= 1; //将y中的各二进位向左移一位 } SDA = 1; // 发送设备(主机)应在时钟脉冲的高电平期间(SCL=1)释放SDA线, //以让SDA线转由接收设备(AT24Cxx)控制 \_nop\_(); //等待一个机器周期 \_nop\_(); //等待一个机器周期 SCL = 1; //根据上述规定,SCL应为高电平 \_nop\_(); //等待一个机器周期 \_nop\_(); //等待一个机器周期 \_nop\_(); //等待一个机器周期 \_nop\_(); //等待一个机器周期 ack_bit = SDA; //接受设备(AT24Cxx)向SDA送低电平,表示已经接收到一个字节 //若送高电平,表示没有接收到,传送异常 SCL = 0; //SCL为低电平时,SDA上数据才允许变化(即允许以后的数据传递) return ack_bit;// 返回AT24Cxx应答位 } /\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* 函数功能:向第一个AT24Cxx中的指定地址写入数据 入口参数:add (储存指定的地址);dat(储存待写入的数据) \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/ void WriteSet1(unsigned char add, unsigned char dat) // 在指定地址addr处写入数据WriteCurrent { start(); //开始数据传递 WriteCurrent(OP_WRITE1); //选择要操作的第一个AT24Cxx芯片,并告知要对其写入数据 WriteCurrent(add); //写入指定地址 WriteCurrent(dat); //向当前地址(上面指定的地址)写入数据 stop(); //停止数据传递 delaynms(4); //1个字节的写入周期为1ms, 最好延时1ms以上 } /\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* 函数功能:向第二个AT24Cxx中的指定地址写入数据 入口参数:add (储存指定的地址);dat(储存待写入的数据) \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/ void WriteSet2(unsigned char add, unsigned char dat) // 在指定地址addr处写入数据WriteCurrent { start(); //开始数据传递 WriteCurrent(OP_WRITE2); //选择要操作的AT24Cxx芯片,并告知要对其写入数据 WriteCurrent(add); //写入指定地址 WriteCurrent(dat); //向当前地址(上面指定的地址)写入数据 stop(); //停止数据传递 delaynms(4); //1个字节的写入周期为1ms, 最好延时1ms以上 } /\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* 函数功能:从第一个AT24Cxx中的当前地址读取数据 出口参数:x (储存读出的数据) \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/ unsigned char ReadCurrent1() { unsigned char x; start(); //开始数据传递 WriteCurrent(OP_READ1); //选择要操作的第一个AT24Cxx芯片,并告知要读其数据 x=ReadData(); //将读取的数据存入x stop(); //停止数据传递 return x; //返回读取的数据 }
/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* 函数功能:从第二个AT24Cxx中的当前地址读取数据 出口参数:x (储存读出的数据) \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/ unsigned char ReadCurrent2() { unsigned char x; start(); //开始数据传递 WriteCurrent(OP_READ2); //选择要操作的第二个AT24Cxx芯片,并告知要读其数据 x=ReadData(); //将读取的数据存入x stop(); //停止数据传递 return x; //返回读取的数据 } /\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* 函数功能:从第一个AT24Cxx中的指定地址读取数据 入口参数:set\_addr 出口参数:x \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/ unsigned char ReadSet1(unsigned char set_addr) // 在指定地址读取 { start(); //开始数据传递 WriteCurrent(OP_WRITE1); //选择要操作的第一个AT24Cxx芯片,并告知要对其写入数据 WriteCurrent(set_addr); //写入指定地址 return(ReadCurrent1()); //从第一个AT24Cxx芯片指定地址读出数据并返回 } /\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* 函数功能:从第二个AT24Cxx中的指定地址读取数据 入口参数:set\_addr 出口参数:x \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/ unsigned char ReadSet2(unsigned char set_addr) // 在指定地址读取 { start(); //开始数据传递 WriteCurrent(OP_WRITE2); //选择要操作的第二个AT24Cxx芯片,并告知要对其写入数据 WriteCurrent(set_addr); //写入指定地址 return(ReadCurrent2()); //从第二个AT24Cxx芯片指定地址读出数据并返回 } /\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* 函数功能:主函数 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/ main(void) { unsigned char x; SDA = 1; // SDA=1,SCL=1,使主从设备处于空闲状态 SCL = 1; WriteSet1(0x36,0xaa); //将数据"0xaa"写入第一个AT24C02的指定地址"0x36" x=ReadSet1(0x36); //从第二个AT24C02中的指定地址"0x36"读出数据 WriteSet2(0x48,x); //将读出的数据写入第二个AT24C02的指定地址"0x48" P1=ReadSet2(0x48); //将从第二个AT24C02的指定地址读出的数据送P1口显示验证 }
|
程序源码和仿真资源
1 2 3
| 链接:https://pan.baidu.com/s/1YXMgUCe_350SHGxKKX9KqQ 提取码:gep2
|
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!