I2C总线:发送字节并读取以led显示 # include # include #define uchar unsigned char #define uint unsigned int #define AT24C02_ADDR 0xa0 //将地址赋给常量 ***it SDA = P2^0; ***it SCL = P2^1; void delay(unsigned int z) { unsignedint x,y; for(x= z;x > 0;x--) for(y= 114; y > 0; y--); } void delay_5us() //5us多一点 { _nop_();//进入、退出函数,执行语句需要5个机器周期(5.43) } //I2C 初始化 void I2C_init() { SDA= 1; //初始化,使得两根总线处于闲置状态 _nop_(); SCL= 1; _nop_(); } //I2C起始信号程序 void I2C_Start() { SCL= 1; _nop_();//1.08506us SDA= 1; delay_5us(); SDA= 0; delay_5us(); } //I2C终止信号程序 void I2C_Stop() { SDA= 0; _nop_(); //执行一个机器周期稳定下来 SCL= 1; delay_5us(); SDA= 1; delay_5us(); } //I2C主机检测从机应答 返回0不应答,返回1应答 bit Test_ACK() { SCL= 1; //在时钟总线为高电平期间可以读取应答信号 delay_5us(); if(SDA) { SCL= 0; //SCL为0时才允许变化,然后发送停止信号 _nop_(); I2C_Stop(); return(0); //返回并跳出函数 } else { SCL= 0; _nop_(); return(1); } } //I2C主机发送应答 void Master_ACK(bit i) { SCL= 0; //拉低时钟总线,允许SDA数据总线变化 _nop_(); //空指令 if(i) { SDA= 0; //应答 } else { SDA= 1; //发送非应答 } _nop_(); //数据保持稳定 SCL= 1; //拉高时钟总线,让从机从SDA线上 读数据 delay_5us(); SCL= 0; //拉低时钟总线,占用总线继续通信 _nop_(); SDA= 1; //释放SDA线,交由从机控制 _nop_(); } //发送字节函数 void I2C_send_byte(uchar byte) { uchari; for(i= 0; i < 8; i++) { SCL= 0; _nop_(); if(byte& 0x80) { SDA= 1; _nop_(); } else { SDA= 0; _nop_(); } SCL= 1; _nop_(); byte<<= 1; //将byte左移一位,次高位被放在最高位 //左移1位,然后赋值给自己 } SCL= 0; _nop_(); SDA= 1; _nop_(); } //读取一个字节子函数 uchar I2C_read_byte() { uchardat,i; SCL= 0; _nop_(); SDA= 1; _nop_(); for(i= 0; i < 8; i++) { SCL= 1; //SCL置高 _nop_(); if(SDA) { dat|= 0x01;//dat = dat | 0x01; //给最低位 1 } else { dat&= 0xfe;//dat <<= 1; // == dat = dat & 0xfe; 给最低位 0 } _nop_(); SCL= 0; _nop_(); if(i< 7) { dat<<= 1; } } return(dat); } void main() { bit ACK_flag = 0; I2C_init(); I2C_Start(); I2C_send_byte(AT24C02_ADDR+0); if(!Test_ACK()) { ACK_flag= 1; } I2C_send_byte(8); if(!Test_ACK()) { ACK_flag= 1; } I2C_send_byte(0xaa); if(!Test_ACK()) { ACK_flag= 1; } I2C_Stop(); delay(5); I2C_Start(); I2C_send_byte(AT24C02_ADDR+0); if(!Test_ACK()) { ACK_flag= 1; } I2C_send_byte(8); Master_ACK(0); I2C_Start(); I2C_send_byte(AT24C02_ADDR+1); if(!Test_ACK()) { ACK_flag= 1; } P1= I2C_read_byte(); Master_ACK(0); I2C_Stop(); if(ACK_flag) { P1= 0; } while(1); } 全部以函数的方式写I2C# include # include #define uchar unsigned char #define uint unsigned int #define AT24C02_ADDR 0xa0 //将地址赋给常量 ***it SDA = P2^0; ***it SCL = P2^1; void delay(unsigned int z) { unsignedint x,y; for(x= z;x > 0;x--) for(y= 114; y > 0; y--); } void delay_5us() //5us多一点 { _nop_();//进入、退出函数,执行语句需要5个机器周期(5.43) } //I2C 初始化 void I2C_init() { SDA= 1; //初始化,使得两根总线处于闲置状态 _nop_(); SCL= 1; _nop_(); } //I2C起始信号程序 void I2C_Start() { SCL= 1; _nop_();//1.08506us SDA= 1; delay_5us(); SDA= 0; delay_5us(); } //I2C终止信号程序 void I2C_Stop() { SDA= 0; _nop_(); //执行一个机器周期稳定下来 SCL= 1; delay_5us(); SDA= 1; delay_5us(); } //I2C主机检测从机应答 返回0不应答,返回1应答 bit Test_ACK() { SCL= 1; //在时钟总线为高电平期间可以读取应答信号 delay_5us(); if(SDA) { SCL= 0; //SCL为0时才允许变化,然后发送停止信号 _nop_(); I2C_Stop(); return(0); //返回并跳出函数 } else { SCL= 0; _nop_(); return(1); } } //I2C主机发送应答 void Master_ACK(bit i) { SCL= 0; //拉低时钟总线,允许SDA数据总线变化 _nop_(); //空指令 if(i) { SDA= 0; //应答 } else { SDA= 1; //发送非应答 } _nop_(); //数据保持稳定 SCL= 1; //拉高时钟总线,让从机从SDA线上 读数据 delay_5us(); SCL= 0; //拉低时钟总线,占用总线继续通信 _nop_(); SDA= 1; //释放SDA线,交由从机控制 _nop_(); } //发送字节函数 void I2C_send_byte(uchar byte) { uchari; for(i= 0; i < 8; i++) { SCL= 0; _nop_(); if(byte& 0x80) { SDA= 1; _nop_(); } else { SDA= 0; _nop_(); } SCL= 1; _nop_(); byte<<= 1; //将byte左移一位,次高位被放在最高位 //左移1位,然后赋值给自己 } SCL= 0; _nop_(); SDA= 1; _nop_(); } //读取一个字节子函数 uchar I2C_read_byte() { uchardat,i; SCL= 0; _nop_(); SDA= 1; _nop_(); for(i= 0; i < 8; i++) { SCL= 1; //SCL置高 _nop_(); if(SDA) { dat|= 0x01;//dat = dat | 0x01; //给最低位 1 } else { dat&= 0xfe;//dat <<= 1; // == dat = dat & 0xfe; 给最低位 0 } _nop_(); SCL= 0; _nop_(); if(i< 7) { dat<<= 1; } } return(dat); } /*I2C发送数据*/ bit I2C_TransmitData(uchar ADDR, DAT) { I2C_Start(); I2C_send_byte(AT24C02_ADDR+0); if(!Test_ACK()) { return(0); } I2C_send_byte(ADDR); if(!Test_ACK()) { return(0); } I2C_send_byte(DAT); if(!Test_ACK()) { return(0); } I2C_Stop(); return(1); } /*I2C接收数据*/ uchar I2C_ReceiveData(uchar ADDR) { ucharDAT; I2C_Start(); I2C_send_byte(AT24C02_ADDR+0); if(!Test_ACK()) { return(0); } I2C_send_byte(ADDR); Master_ACK(0); I2C_Start(); I2C_send_byte(AT24C02_ADDR+1); if(!Test_ACK()) { return(0); } DAT= I2C_read_byte(); Master_ACK(0); I2C_Stop(); return(DAT); } void main() { I2C_init(); //I2C初始化 I2C_TransmitData(255,0xf0); delay(5); P1= I2C_ReceiveData(255); while(1); } 往QX-MCS51开发板的AT24C02内任意一个单元写数据,开发板上电后首先读取此单元的原有的数据,然后赋给程序中的计数变量,计数变量再以5秒的速度+1并且写入AT24C02,当计数大于99时清零再写,用数码管显示。 /*体现eeprom掉电存储功能*/ # include # include #define uchar unsigned char #define uint unsigned int #define AT24C02_ADDR 0xa0 //将地址赋给常量 ***it SDA = P2^0; ***it SCL = P2^1; ***it LED1 = P1^0; ***it wei = P2^7; ***it duan = P2^6; uchar EEPROM_DATA; //存放从AT24C02读取的值 unsigned char leddata[]={ 0x3F, //"0" 0x06, //"1" 0x5B, //"2" 0x4F, //"3" 0x66, //"4" 0x6D, //"5" 0x7D, //"6" 0x07, //"7" 0x7F, //"8" 0x6F, //"9" 0x77, //"A" 0x7C, //"B" 0x39, //"C" 0x5E, //"D" 0x79, //"E" 0x71, //"F" 0x76, //"H" 0x38, //"L" 0x37, //"n" 0x3E, //"u" 0x73, //"P" 0x5C, //"o" 0x40, //"-" 0x00, //熄灭 0x00 //自定义 }; void delay_5us() //5us多一点 { _nop_();//进入、退出函数,执行语句需要5个机器周期(5.43) } /*1ms延时函数*/ void delay(unsigned int z) { unsignedint x,y; for(x= z;x > 0;x--) for(y= 114; y > 0; y--); } void display(uchar i) { ucharshi,ge; shi= i / 10; //求模 ge= i % 10; //求余 P0= 0xff; //清除断码 wei= 1; P0= 0xfe;//点亮第1位数码管 wei= 0; duan= 1; P0= leddata[shi]; duan= 0; delay(1); P0 = 0xff; wei= 1; P0= 0xfd;//点亮第2位数码管 wei= 0; duan= 1; P0= leddata[ge]; duan= 0; delay(1); } //I2C 初始化 void I2C_init() { SDA= 1; //初始化,使得两根总线处于闲置状态 _nop_(); SCL= 1; _nop_(); } void timer0_init() //50ms定时 { TMOD|= 0x01; //定时器T0 16位计数模式 TH0= 0x4b; TL0= 0xfe; //50ms ET0= 1; //T0 中断 TR0= 1; //启动T0 EA= 1; //开总中断 } //I2C起始信号程序 void I2C_Start() { SCL= 1; _nop_();//1.08506us SDA= 1; delay_5us(); SDA= 0; delay_5us(); } //I2C终止信号程序 void I2C_Stop() { SDA= 0; _nop_(); //执行一个机器周期稳定下来 SCL= 1; delay_5us(); SDA= 1; delay_5us(); } //I2C主机检测从机应答 返回0不应答,返回1应答 bit Test_ACK() { SCL= 1; //在时钟总线为高电平期间可以读取应答信号 delay_5us(); if(SDA) { SCL= 0; //SCL为0时才允许变化,然后发送停止信号 _nop_(); I2C_Stop(); return(0); //返回并跳出函数 } else { SCL= 0; _nop_(); return(1); } } //I2C主机发送应答 void Master_ACK(bit i) { SCL= 0; //拉低时钟总线,允许SDA数据总线变化 _nop_(); //空指令 if(i) { SDA= 0; //应答 } else { SDA= 1; //发送非应答 } _nop_(); //数据保持稳定 SCL= 1; //拉高时钟总线,让从机从SDA线上 读数据 delay_5us(); SCL= 0; //拉低时钟总线,占用总线继续通信 _nop_(); SDA= 1; //释放SDA线,交由从机控制 _nop_(); } //发送字节函数 void I2C_send_byte(uchar byte) { uchari; for(i= 0; i < 8; i++) { SCL= 0; _nop_(); if(byte& 0x80) { SDA= 1; _nop_(); } else { SDA= 0; _nop_(); } SCL= 1; _nop_(); byte<<= 1; //将byte左移一位,次高位被放在最高位 //左移1位,然后赋值给自己 } SCL= 0; _nop_(); SDA= 1; _nop_(); } //读取一个字节子函数 uchar I2C_read_byte() { uchardat,i; SCL= 0; _nop_(); SDA= 1; _nop_(); for(i= 0; i < 8; i++) { SCL= 1; //SCL置高 _nop_(); if(SDA) { dat|= 0x01;//dat = dat | 0x01; //给最低位 1 } else { dat&= 0xfe;//dat <<= 1; // == dat = dat & 0xfe; 给最低位 0 } _nop_(); SCL= 0; _nop_(); if(i< 7) { dat<<= 1; } } return(dat); } /*I2C发送数据*/ bit I2C_WriteData(uchar ADDR, DAT) { I2C_Start(); I2C_send_byte(AT24C02_ADDR+0); if(!Test_ACK()) { return(0); } I2C_send_byte(ADDR); if(!Test_ACK()) { return(0); } I2C_send_byte(DAT); if(!Test_ACK()) { return(0); } I2C_Stop(); return(1); } /*I2C接收数据*/ uchar I2C_ReadData(uchar ADDR) { ucharDAT; I2C_Start(); I2C_send_byte(AT24C02_ADDR+0); if(!Test_ACK()) { return(0); } I2C_send_byte(ADDR); Master_ACK(0); I2C_Start(); I2C_send_byte(AT24C02_ADDR+1); if(!Test_ACK()) { return(0); } DAT= I2C_read_byte(); Master_ACK(0); I2C_Stop(); return(DAT); } void main() { I2C_init(); //I2C初始化 Timer0_init(); EEPROM_DATA= I2C_ReadData(255); while(1) { display(EEPROM_DATA);//数码管显示 } } /* 定时器0 中断服务程序*/ void timer0() interrupt 1 //T0内部优先级 { uchari; TH0= 0x4b; TL0= 0xfe; i++; if(i== 100) { i= 0; if(EEPROM_DATA< 99)//实现5s加1 { EEPROM_DATA++; } else { EEPROM_DATA= 0; } if(!I2C_WriteData(255,EEPROM_DATA))//判断数据是否写入 { LED1= 0; } else { LED1= 1; } } }
|