阅读:1866回复:4
请懂i2c总线的大侠赐教
网上广泛流传的下列代码是不是有问题?其在数据发送结束的时候由发送方发送了一个Ack而将SDA拉低,而在数据接收结束的时候有接收方发送一个NoAck而将SDA留给发送方作线与,看看规范,好象是搞反了,
请做过这方面东东的大侠赐教。 下面是流行代码的程序。 51 单片机模拟I2C 总线的C 语言实现页码,1/8 http://www.21icsearch.com/pmcu/fxzl/51i2c.htm 00-10-26 51 单片机模拟I 2 C 总线的C 语言实现 1.电路原理图 EEPROM 为ATMEL 公司的AT24C01A 。单片机为ATMEL 公司的AT89C51 。 2.软件说明 C 语言为Franklin C V3.2 。将源程序另存为testi2c.c,用命令 C51 testi2c.c L51 TESTI2C.OBJ OHS51 TESTI2C 编译,连接,得到TESTI2C.HEX 文件,即可由编程器读入并进行写片,实验。 3.源程序 #include <reg51.h> #include <intrins.h> #define uchar unsigned char #define uint unsigned int #define AddWr 0xa0 /*器件地址选择及写标志*/ #define AddRd 0xa1 /*器件地址选择及读标志*/ #define Hidden 0x0e /*显示器的消隐码*/ /*有关全局变量*/ sbit Sda=P3^ 7;/*串行数据*/51 单片机模拟I2C 总线的C 语言实现页码,2/8 http://www.21icsearch.com/pmcu/fxzl/51i2c.htm 00-10-26 sbit Scl=P3^ 6;/*串行时钟*/ sbit WP=P3^ 5;/*硬件写保护*/ void mDelay(uchar j) {uint i; for(;j>0;j--) {for(i=0;i<125;i--) {;} }} /*发送起始条件*/ void Start(void)/*起始条件*/ { Sda=1; Scl=1; _nop_(); _nop_(); _nop_(); _nop_(); Sda=0; _nop_(); _nop_(); _nop_(); _nop_(); } void Stop(void)/*停止条件*/ { Sda=0; Scl=1; _nop_();51 单片机模拟I2C 总线的C 语言实现页码,3/8 http://www.21icsearch.com/pmcu/fxzl/51i2c.htm 00-10-26 _nop_(); _nop_(); _nop_(); Sda=1; _nop_(); _nop_(); _nop_(); _nop_(); } void Ack(void)/*应答位*/ { Sda=0; _nop_(); _nop_(); _nop_(); _nop_(); Scl=1; _nop_(); _nop_(); _nop_(); _nop_(); Scl=0; } void NoAck(void)/*反向应答位*/ { Sda=1;51 单片机模拟I2C 总线的C 语言实现页码,4/8 http://www.21icsearch.com/pmcu/fxzl/51i2c.htm 00-10-26 _nop_(); _nop_(); _nop_(); _nop_(); Scl=1; _nop_(); _nop_(); _nop_(); _nop_(); Scl=0; } void Send(uchar Data)/*发送数据子程序,Data 为要求发送的数据*/ { uchar BitCounter=8;/*位数控制*/ uchar temp;/*中间变量控制*/ do { temp=Data; Scl=0; _nop_(); _nop_(); _nop_(); _nop_(); if((temp&0x80)==0x80)/*如果最高位是1*/ Sda=1; else51 单片机模拟I2C 总线的C 语言实现页码,5/8 http://www.21icsearch.com/pmcu/fxzl/51i2c.htm 00-10-26 Sda=0; Scl=1; temp=Data<<1;/*RLC*/ Data=temp; BitCounter--; }while(BitCounter); Scl=0; } uchar Read(void)/*读一个字节的数据,并返回该字节值*/ { uchar temp=0; uchar temp1=0; uchar BitCounter=8; Sda=1; do{ Scl=0; _nop_(); _nop_(); _nop_(); _nop_(); Scl=1; _nop_(); _nop_(); _nop_(); _nop_(); if(Sda)/*如果Sda=1;*/51 单片机模拟I2C 总线的C 语言实现页码,6/8 http://www.21icsearch.com/pmcu/fxzl/51i2c.htm 00-10-26 temp=temp|0x01;/*temp 的最低位置1*/ else temp=temp&0xfe;/*否则temp 的最低位清0*/ if(BitCounter-1) {temp1=temp<<1; temp=temp1; } BitCounter--; }while(BitCounter); return(temp); } void WrToROM(uchar Data[ ] ,uchar Address,uchar Num) { uchar i; uchar *PData; PData=Data; for(i=0;i<Num;i++) { Start();/*发送启动信号*/ Send(0xa0);/*发送SLA+W*/ Ack(); Send(Address+i);/*发送地址*/ Ack(); Send(*(PData+i)); Ack(); Stop();51 单片机模拟I2C 总线的C 语言实现页码,7/8 http://www.21icsearch.com/pmcu/fxzl/51i2c.htm 00-10-26 mDelay(20); }} void RdFromROM(uchar Data[ ] ,uchar Address,uchar Num) { uchar i; uchar *PData; PData=Data; for(i=0;i<Num;i++) { Start(); Send(0xa0); Ack(); Send(Address+i); Ack(); Start(); Send(0xa1); Ack(); *(PData+i)=Read(); Scl=0; NoAck(); Stop(); }} void main() {51 单片机模拟I2C 总线的C 语言实现页码,8/8 http://www.21icsearch.com/pmcu/fxzl/51i2c.htm 00-10-26 uchar Number[ 4] ={1,2,3,4}; WP=1; WrToROM(Number,4,4);/*将初始化后的数值写入EEPROM*/ mDelay(20); Number[ 0] =0; Number[ 1] =0; Number[ 2] =0; Number[ 3] =0;/*将数组中的值清掉,以验证读出的数是否正确*/ RdFromROM(Number,4,4); } 问题:本程序中未采用块读写的方法,显得有点‘笨’,这是由于项目原因,现项目已完 成,程序已写好,短时不会修改,也不会花上一定的精力去做,虽然理论上已很成熟,就 这样写一下,未必不对,但与我的本栏目要求不符,所以就未做上去,如果以后我做了, 将再补上。 欢迎转载,请注明出自平凡的单片机世界 |
|
沙发#
发布于:2002-02-20 10:05
一、请你先搞清楚“线与”。
二、请再弄明白“SDA”,“SCL”控制的是单片机的什么“BIT”! 三、别忘了给我加分。 |
|
|
板凳#
发布于:2002-02-20 19:10
搞的高深莫测,不懂,能否说清楚点?,该程序应该是存在问题的.
|
|
地板#
发布于:2002-02-21 13:36
网上例子程序很多,搜“单片机”
|
|
地下室#
发布于:2002-02-21 16:00
请先搞清楚I2C的Master和Slave器件的应答协议,以下是Intel公司的关于51口线模拟I2C写的很详细,希望对你有帮助.
ftp://download.intel.com/design/mcs51/applnots/27231901.pdf |
|