阅读:880回复:3
Franklin的陷井
问题的提出:
让我们先看一段程序: 这是一段摸拟I2C总路线写的程序, #define Byte unsigned char sbit SCL = 0x80; sbit SDA = 0x81; void WaitForACK(void); void I2CWrite(Byte _Data) { char i; for(i = 0; i < 8; i++){ if(_Data & 0x80) SDA = 1; else SDA = 0; SCL = 1; SCL = 0; _Data <<= 1; } WaitForACK(); } 你认为它能正确的把的所给的数传送出去吗? 在将它烧到IC上之前,我一直以为这不会有任何问题。 可是,系统就是不能正常工作。 拿示波器一量,在SCL的前8个脉冲期间,SDA从来就没变化,要么高,要么低。也不能等到任何ACK。 又把程序检查了N遍,没办法,只能检查LIST文件了。 一看,豁然开朗: stmt level source 1 #define Byte unsigned char 2 3 sbit SCL = 0x80; 4 sbit SDA = 0x81; 5 6 void WaitForACK(void); 7 8 void I2CWrite(Byte _Data) 9 { 10 1 char i; 11 1 for(i = 0; i < 8; i++){ 12 2 if(_Data & 0x80) 13 2 SDA = 1; 14 2 else 15 2 SDA = 0; 16 2 SCL = 1; 17 2 SCL = 0; 18 2 _Data <<= 1; 19 2 } 20 1 WaitForACK(); 21 1 } 22 C51 COMPILER V6.11.28, I2C 11/02/102 19:10:55 PAGE 2 ASSEMBLY LISTING OF GENERATED OBJECT CODE ; FUNCTION _I2CWrite (BEGIN) ; Register R7 is assigned to parameter _Data ; R6 is assigned to i ; SOURCE LINE # 11 0000 7E00 MOV R6,#000H 0002 ?FOR1: ; SOURCE LINE # 12 0002 EF MOV A,R7 0003 30E704 JNB ACC.7,?ELSE1 ; SOURCE LINE # 13 0006 D281 SETB SDA 0008 8002 SJMP ?NXT5 000A ?ELSE1: ; SOURCE LINE # 15 000A C281 CLR SDA 000C ?NXT5: ; SOURCE LINE # 16 000C D280 SETB SCL ; SOURCE LINE # 17 000E C280 CLR SCL ; SOURCE LINE # 18 0010 EF MOV A,R7 0011 C3 CLR C 0012 33 RLC A ; SOURCE LINE # 11 0013 0E INC R6 0014 BE08EB CJNE R6,#008H,?FOR1 ; SOURCE LINE # 20 0017 120000 R LCALL WaitForACK 001A 22 RET 且看: ; SOURCE LINE # 18 0010 EF MOV A,R7 0011 C3 CLR C 0012 33 RLC A 少了一行 MOV R7,A 也就是说 _Data <<= 1; 被翻成了 _Data << 1; 解决方法: 方法一: 选择菜单Options->Project,打开C51->Optimizer选项,将Optimizer level改为2以下即可。 优点:间单,对于文件别处类似问题一样有效。 缺点:牺牲代码质量,影响代码运行速度。 修改后生成代码如下: ; FUNCTION _I2CWrite (BEGIN) ; Register R7 is assigned to parameter _Data ; R6 is assigned to i ; SOURCE LINE # 11 0000 7E00 MOV R6,#000H 0002 ?FOR1: ; SOURCE LINE # 12 0002 EF MOV A,R7 0003 30E704 JNB ACC.7,?ELSE1 ; SOURCE LINE # 13 0006 D281 SETB SDA 0008 8002 SJMP ?NXT5 000A ?ELSE1: ; SOURCE LINE # 15 000A C281 CLR SDA 000C ?NXT5: ; SOURCE LINE # 16 000C D280 SETB SCL ; SOURCE LINE # 17 000E C280 CLR SCL ; SOURCE LINE # 18 0010 EF MOV A,R7 0011 C3 CLR C 0012 33 RLC A 0013 FF MOV R7,A 0014 ?NXT4: ; SOURCE LINE # 11 0014 0E INC R6 0015 EE MOV A,R6 0016 6480 XRL A,#080H 0018 B48800 CJNE A,#088H,?LAB3 001B ?LAB3: 001B 40E5 JC ?FOR1 001D ?NXT3: ; SOURCE LINE # 20 001D 120000 R LCALL WaitForACK 0020 22 RET ; FUNCTION _I2CWrite (END) 方法二: 增加一临时变量: 优缺点与方法一刚好相反。 修改后原代码: #define Byte unsigned char sbit SCL = 0x80; sbit SDA = 0x81; void WaitForACK(void); void I2CWrite(Byte _Data) { char i; Byte temp = _Data; for(i = 0; i < 8; i++){ if(temp & 0x80) SDA = 1; else SDA = 0; SCL = 1; SCL = 0; temp <<= 1; } WaitForACK(); } 生成代码: stmt level source 1 #define Byte unsigned char 2 3 sbit SCL = 0x80; 4 sbit SDA = 0x81; 5 6 void WaitForACK(void); 7 8 void I2CWrite(Byte _Data) 9 { 10 1 char i; 11 1 Byte temp = _Data; 12 1 13 1 for(i = 0; i < 8; i++){ 14 2 if(temp & 0x80) 15 2 SDA = 1; 16 2 else 17 2 SDA = 0; 18 2 SCL = 1; 19 2 SCL = 0; 20 2 temp <<= 1; 21 2 } 22 1 WaitForACK(); 23 1 } 24 25 C51 COMPILER V6.11.28, I2C 11/03/102 20:06:43 PAGE 2 ASSEMBLY LISTING OF GENERATED OBJECT CODE ; FUNCTION _I2CWrite (BEGIN) ; Register R7 is assigned to parameter _Data ; SOURCE LINE # 11 0000 8F00 R MOV temp,R7 ; R6 is assigned to i ; SOURCE LINE # 13 0002 7E00 MOV R6,#000H 0004 ?FOR1: ; SOURCE LINE # 14 0004 E500 R MOV A,temp 0006 30E704 JNB ACC.7,?ELSE1 ; SOURCE LINE # 15 0009 D281 SETB SDA 000B 8002 SJMP ?NXT5 000D ?ELSE1: ; SOURCE LINE # 17 000D C281 CLR SDA 000F ?NXT5: ; SOURCE LINE # 18 000F D280 SETB SCL ; SOURCE LINE # 19 0011 C280 CLR SCL ; SOURCE LINE # 20 0013 E500 R MOV A,temp 0015 C3 CLR C 0016 33 RLC A 0017 F500 R MOV temp,A ; SOURCE LINE # 13 0019 0E INC R6 001A BE08E7 CJNE R6,#008H,?FOR1 ; SOURCE LINE # 22 001D 120000 R LCALL WaitForACK 0020 22 RET ; FUNCTION _I2CWrite (END) 注意,原代码第11行: Byte temp = _Data; 不可写成: Byte temp; temp = _Data; 否则无效. |
|
|
沙发#
发布于:2002-11-04 04:08
也不找个好点的compiler。
|
|
|
板凳#
发布于:2002-11-04 23:45
也不找个好点的compiler。谢谢,我还以为没人看呢。 我也没办法,底层用的是Franklin。接口被定死了. |
|
|
地板#
发布于:2002-11-05 14:24
等管道最下边,兴趣没了
|
|
|