找回密码
 立即注册
查看: 144|回复: 6

这两个程序的区别在哪里?

[复制链接]
已绑定手机

6

主题

11

回帖

84

积分

注册会员

积分
84
发表于 7 天前 | 显示全部楼层 |阅读模式
程序1
#include <reg52.h>
sbit led=P2^0;
unsigned int i;
void main()
{
        led=0;
        for(i=50000;i>0;i--);
        led=1;
        for(i=50000;i>0;i--);
       
}

程序2
#include <reg52.h>
sbit led=P2^0;
unsigned int i;
void main()
{
        led=0;
        for(i=0;i<50000;i++);
        led=1;
        for(i=0;i<50000;i++);
       
}
各位大佬帮忙看一下,这两个程序写入同一块开发板,为什么小灯的亮灭时间会不一样,都是循环50000次,为什么用加的方法的程序闪烁频率慢好多

截图202610312248024831.jpg
回复

使用道具 举报 送花

已绑定手机

307

主题

582

回帖

2957

积分

金牌会员

积分
2957
发表于 6 天前 | 显示全部楼层
这两个程序都跑飞了
回复

使用道具 举报 送花

14

主题

1431

回帖

7982

积分

论坛元老

积分
7982
发表于 6 天前 | 显示全部楼层
结论
循环 50000 次的次数是一样的,差距来自 C51 对 i>0(与零比较)和 i<50000(与立即数比较)生成的指令条数不同,程序2 每次判断多耗指令,故闪得慢。

想精确控制延时,不要靠 for 空循环,它的时间随编译器版本、优化等级、变量存储区(data/idata/xdata)剧烈变化。正确做法是用定时器。

i 用 unsigned int 且初值 50000 是合法的,两个程序这里都没错;但 for(...); 结尾应改为 while(1) 包裹主循环。
回复

使用道具 举报 送花

已绑定手机

11

主题

484

回帖

1362

积分

金牌会员

积分
1362
发表于 6 天前 | 显示全部楼层
这有什么奇怪的,i++与i--本来就用时不同。用for循环做延时本来就需要反复调试。哪能这么直接比较。你的程序不规范,缺少while(1)约束。
回复

使用道具 举报 送花

18

主题

85

回帖

3524

积分

论坛元老

积分
3524
发表于 6 天前 | 显示全部楼层
     上电运行程序LED只亮(习惯用法低电平亮灯)一次就灭了,不会闪烁。main里四行语句执行完,程序结束,没有跑飞,没有(不需要?)用while(1) 包裹主循环。想要灯闪烁就加几行代码。是这样吗?
     “ i>0(与零比较)和 i<50000(与立即数比较)生成的指令条数不同” 这涉及底层知识,还不懂,不敢妄议,这次才知道有这么回事。
回复

使用道具 举报 送花

已绑定手机

2

主题

154

回帖

470

积分

中级会员

积分
470
发表于 6 天前 | 显示全部楼层
我按8位单片机编译后,看汇编对比,得出如下结论(32位结果不同):

1,main里没有while循环,跑完main后,继续跑出main外,因为flash其他的地方是nop或FF, 跑一定时间后,跑飞(重启),
   不过这里不讨论这个。
2, for(i=50000;i>0;i--);  与for(i=0;i<50000;i++);
  加法中的50000被编译器当成了有符号long, 进行long比较,8位里的long比较花费了较多时间,所以比减法慢。
如果加法改为for(i=0;i<50000u;i++); 即明确指定无符号16位。
结果与减法基本一样。

下面上汇编:
1,减法的汇编,只给出一半,下半一样。
    10:         for(i=50000;i>0;i--);
C:0x0802    7508C3   MOV      i(0x08),#0xC3    //这句与下句是i=50000(0xc350);
C:0x0805    750950   MOV      0x09,#0x50
C:0x0808    E509     MOV      A,0x09                //读取i低字节
C:0x080A    1509     DEC      0x09                   //i低字节减1
C:0x080C    7002     JNZ      C:0810                //非0跳到,下第二行
C:0x080E    1508     DEC      i(0x08)                //i高字节减1, 这句与上2句是 i--;
C:0x0810    E509     MOV      A,0x09               //读取i的低字节到a
C:0x0812    4508     ORL      A,i(0x08)            //或上 i的高字节到a
C:0x0814    70F2     JNZ      C:0808                //非0则跳转到上面(循环); 这句与上2句是判断 i>0
    11:         led=1;
C:0x0816    D2A0     SETB     led(0xA0.0)
    12:         for(i=50000;i>0;i--);  

2,加法的汇编,只给出一半,下半一样。
    20:         for(i=0;i<50000;i++);
C:0x0802    E4       CLR      A
C:0x0803    F508     MOV      i(0x08),A            //这句与下句: i=0;
C:0x0805    F509     MOV      0x09,A
C:0x0807    AE08     MOV      R6,i(0x08)        //这句与下4句: R4~R7=i;
C:0x0809    AF09     MOV      R7,0x09               
C:0x080B    E4       CLR      A
C:0x080C    FC       MOV      R4,A                 //高2字节=0;
C:0x080D    FD       MOV      R5,A
C:0x080E    7B50     MOV      R3,#0x50        //这句与下4句: R0~R3=50000;
C:0x0810    7AC3     MOV      R2,#0xC3
C:0x0812    F9       MOV      R1,A
C:0x0813    F8       MOV      R0,A                //高2字节=0;
C:0x0814    D3       SETB     C                     //c=1
C:0x0815    120849   LCALL    C?SLCMP(C:0849) //调用SLCMP(), 有符号long比较,比较R0~R3与R4~R7, 见下面,时间比较耗时;
C:0x0818    400A     JC       C:0824                    //i-50000为负,则结束循环。
C:0x081A    0509     INC      0x09                     //i低字节加1  (这句与下面是i加1);
C:0x081C    E509     MOV      A,0x09                //读取i低字节到a
C:0x081E    70E7     JNZ      C:0807                 //a非0,跳到循环开头。
C:0x0820    0508     INC      i(0x08)                 //i高字节加1(低字节进位了)
C:0x0822    80E3     SJMP     C:0807                //跳到循环开头。
    21:         led=1;
C:0x0824    D2A0     SETB     led(0xA0.0)
    22:         for(i=0;i<50000;i++);   

有符号long比较, (R0~R3) - (R4~R7);
                 C?SLCMP:                        
C:0x0849    EB       MOV      A,R3
C:0x084A    9F       SUBB     A,R7                  //R3 - R7
C:0x084B    F5F0     MOV      B(0xF0),A        //结果存B
C:0x084D    EA       MOV      A,R2
C:0x084E    9E       SUBB     A,R6                 //R2 - R6
C:0x084F    42F0     ORL      B(0xF0),A         //结果或存到B
C:0x0851    E9       MOV      A,R1
C:0x0852    9D       SUBB     A,R5                //R1 - R5
C:0x0853    42F0     ORL      B(0xF0),A         //结果或存到B
C:0x0855    EC       MOV      A,R4
C:0x0856    6480     XRL      A,#P0(0x80)     //A=R4, A去掉符号位
C:0x0858    C8       XCH      A,R0                 //A与R0交换
C:0x0859    6480     XRL      A,#P0(0x80)     //A=R0, A去掉符号位
C:0x085B    98       SUBB     A,R0                //A-R0 == 原R0-原R4(去掉符号位的)
C:0x085C    45F0     ORL      A,B(0xF0)       //A或上B
C:0x085E    22       RET                            //返回


3,加法的汇编-加"u"指定无符号16位,只给出一半,下半一样。
    20:         for(i=0;i<50000u;i++);
C:0x0802    E4       CLR      A
C:0x0803    F508     MOV      i(0x08),A                 //这句与下句: i=0
C:0x0805    F509     MOV      0x09,A
C:0x0807    0509     INC      0x09                       //i低字节加1, (这句与下3句是 i加1)
C:0x0809    E509     MOV      A,0x09                  //i低字节读进A
C:0x080B    7002     JNZ      C:080F                   //A非0则跳到下第二句
C:0x080D    0508     INC      i(0x08)                  //i高字节加1(低字节进位)
C:0x080F    B450F5   CJNE     A,#0x50,C:0807   //比较A-0x50(50000的低字节),不等则跳转到循环开头。
C:0x0812    E508     MOV      A,i(0x08)              //i高字节读进A
C:0x0814    B4C3F0   CJNE     A,#0xC3,C:0807  //比较A-0xC3(50000的高字节),不等则跳转到循环开头。
    21:         led=1;
C:0x0817    D2A0     SETB     led(0xA0.0)



回复

使用道具 举报 送花

已绑定手机

2

主题

41

回帖

310

积分

中级会员

积分
310
发表于 6 天前
看来是数据类型以及i++、i--对应的汇编不同造成的,学习了。

送花

已绑定手机

24

主题

701

回帖

2731

积分

金牌会员

积分
2731
发表于 5 天前 | 显示全部楼层
编译成最后的指令不一样,所以执行时间不一样
回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2026-11-7 14:12 , Processed in 0.076997 second(s), 93 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表