搜索
bottom↓
回复: 119

一个有关0.0625℃的运算想到的问题

[复制链接]

出0入0汤圆

发表于 2010-4-18 22:24:26 | 显示全部楼层 |阅读模式
发布: 2010-3-30 09:02 | 作者: cat_li | 来源: 电子爱好者社区
碰到一哥们号称挺NB的嵌入软件工程师,看了他的代码后就欧拉,事情是在一个只有4K代码的单片机接2个DS18B20测温传感器,都知道DS18B20输出数据只要乘以0.0625就是测量的温度值,这哥们说程序空间怎么也不够,实际上程序只有简单的采集两个DS18B20的数据转换成温度值,之后在1602液晶上显示,挺简单个程序,怎么也想不通为什么程序空间不够。只读了一下代码发现程序就没动脑子,真的用浮点库把DS18B20数据直接乘以0.0625了,那程序不超才怪呢,稍微动动脑子也会知道0.0625不就是1/16吗,把DS18B20的数据直接右移4位不就是了(当然要注意符号),这右移程序可十分简单还省空间,问题很好解决,空间自然也就够了。
    现在想来嵌入处理器确实是进步了,程序空间是越来越大,数据RAM空间也越来越大,导致很多人在写程序的时候真的是什么都不顾,借着C语言的灵活性真是纵横驰骋,压根也不讲个程序效率和可靠性。正如前些日子见到一孩子用ARM cortex-m3处理器给人接活写个便携表的1024点FFT算法,本身12位的AD系统,这小家伙直接到网上下载了浮点的FFT算法代码就给人加上了,结果整个程序死慢死慢的,人家用户可不买单啊,这时要动动脑子把数据直接变成乘以某个数变成整数后用定点FFT处理,之后再把数据除一下不就行了。速度自然也快了,而且也能省下空间。实际当中我们做嵌入软件很多时候犯懒都忽视程序执行效率问题,是都能实现功能,但有时候就是没法谈性能。我几次碰到这样的工程师,直接把传感器的信号放大后进嵌入处理器的AD,也不看看AD数据是否稳定有效,直接就进行FFT运算,那FFT结果真是热闹,不难看出混叠很严重,于是又机械地在FFT基础上再去衍生算法,系统程序越做越大,速度越做越慢。实际上也很简单的事,在传感器放大信号进AD之前来一级抗混叠滤波基本也就解决了,大有所谓嵌入软件高手的概念是程序几乎是万能,实在解决不了就换大程序空间更高速的处理器,整个恶性循环。
    经常听说现在流行低碳族,我想出色的嵌入软件工程师最容易成为低碳一族,只要让代码高效那处理器频率自然可以灵活降下来,自然耗电也就少了,二氧化碳排放也就少了。想想目前到处都是嵌入处理器,代码条数看来也别有效果。

阿莫论坛20周年了!感谢大家的支持与爱护!!

曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……

出0入0汤圆

发表于 2010-4-18 22:29:09 | 显示全部楼层
呵呵高人

出0入0汤圆

发表于 2010-4-19 09:59:58 | 显示全部楼层
回复【楼主位】tangwei039
-----------------------------------------------------------------------

有道理

出0入0汤圆

发表于 2010-4-19 10:07:42 | 显示全部楼层
很有道理

出0入0汤圆

发表于 2010-4-19 10:19:11 | 显示全部楼层
有道理,8位机哪里敢进行浮点计算,效率先不说,速度是不能接受的

出0入0汤圆

发表于 2010-4-19 10:35:23 | 显示全部楼层
呵呵,Mark

出0入0汤圆

发表于 2010-4-19 10:45:46 | 显示全部楼层
有道理,高人!

出0入0汤圆

 楼主| 发表于 2010-4-19 11:15:00 | 显示全部楼层
这都是技巧。呵呵,多看大家也就成高手了。

出0入0汤圆

发表于 2010-4-19 11:41:37 | 显示全部楼层
我在网上下载了一个51汇编写的18B20程序,那程序的作者牛啊,直接把16位数据乘以625再除以10000,结果代码活生生的增加了50%的长度,我看过程序之后就开始修改,就是用楼主说的办法,左移4位就得到了温度的整数部分,小数部分的使用查表得到结果。

还有一个例子就是吧16进制数转换为ASCII字符,使用查表是最简单的。

出0入0汤圆

发表于 2010-4-19 12:15:47 | 显示全部楼层
顶楼主,确实现在用C很方便,很少去考虑算法,效率确实有时很低,受教了

出0入0汤圆

发表于 2010-4-19 20:49:09 | 显示全部楼层
不错,LZ一句话很切要害,我也是纠结了很长时间的

出0入0汤圆

发表于 2010-4-20 08:43:54 | 显示全部楼层
回复【8楼】XA144F
我在网上下载了一个51汇编写的18B20程序,那程序的作者牛啊,直接把16位数据乘以625再除以10000,结果代码活生生的增加了50%的长度,我看过程序之后就开始修改,就是用楼主说的办法,左移4位就得到了温度的整数部分,小数部分的使用查表得到结果。
还有一个例子就是吧16进制数转换为ASCII字符,使用查表是最简单的。
-----------------------------------------------------------------------

把16位数据乘以40960再除以65536,直接算出1位小数,不是更简单

出0入0汤圆

发表于 2010-4-20 09:34:25 | 显示全部楼层
回复【11楼】xiaosun  
回复【8楼】XA144F
我在网上下载了一个51汇编写的18B20程序,那程序的作者牛啊,直接把16位数据乘以625再除以10000,结果代码活生生的增加了50%的长度,我看过程序之后就开始修改,就是用楼主说的办法,左移4位就得到了温度的整数部分,小数部分的使用查表得到结果。
还有一个例子就是吧16进制数转换为ASCII字符,使用查表是最简单的。
-----------------------------------------------------------------------
把16位数据乘以40960再除以65536,直接算出1位小数,不是更简单
-----------------------------------------------------------------------

你这方法没有优势啊!如果在C语言中,16位数据乘以40960,就是16-16的乘法,得到的是32位数据,运算量大不大?然后再除以65536,即做32-16的除法,运算量大不大?查表得方法可以把小数点后面4位数都计算出来,哪个更简单?虽然在C中你可以随意,但是在汇编中最好收敛些,没有那么多时间用来浪费。

出0入0汤圆

发表于 2010-4-20 16:04:11 | 显示全部楼层
一个整型变量的倒数用什么方法好啊?
   还有小数部分 怎么查表??

出0入0汤圆

发表于 2010-4-20 17:15:55 | 显示全部楼层
恩,有道理,我在wince上绘制一幅波形图,开始直接从PC移植的,使用的是浮点数,8pps,后来改为整数运算,提高了1倍左右。

出0入0汤圆

发表于 2010-4-22 22:25:22 | 显示全部楼层
麻烦LZ,DS3231的精度是0.25度,11h存放温度的高位,12h存放小数,0.25是1/4,如何移位?多谢了!!

出0入0汤圆

发表于 2010-4-23 07:29:12 | 显示全部楼层
回复【15楼】sodohe
麻烦LZ,DS3231的精度是0.25度,11h存放温度的高位,12h存放小数,0.25是1/4,如何移位?多谢了!!
-----------------------------------------------------------------------

提示4是2的2次方,16是2的4次方。之后就要动脑子了。

出0入0汤圆

发表于 2010-4-23 09:15:52 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-4-23 09:20:26 | 显示全部楼层
回复【16楼】fw190d9
回复【15楼】sodohe  
麻烦LZ,DS3231的精度是0.25度,11h存放温度的高位,12h存放小数,0.25是1/4,如何移位?多谢了!!
-----------------------------------------------------------------------
提示4是2的2次方,16是2的4次方。之后就要动脑子了。
-----------------------------------------------------------------------

谢谢,明白了!!

出0入0汤圆

发表于 2010-4-23 09:58:56 | 显示全部楼层
12位精度的时候,高字节的低四位和低字节的高四位就是温度的整数部分,低字节的低四位是温度的小数部分,这部分的处理需要一点时间。我的方法很简单,但是代码占用量比较大,即认为0x01对应0625,0x02对应1250……0x0F对应9375,这样只要查表一次就能得到温度的十进制值,这方法倒是简单,但是我想还继续改进。

出0入0汤圆

发表于 2010-4-23 12:32:10 | 显示全部楼层
mark

出10入120汤圆

发表于 2010-4-23 13:11:03 | 显示全部楼层
回复【4楼】wmm20031015  
有道理,8位机哪里敢进行浮点计算,效率先不说,速度是不能接受的
-----------------------------------------------------------------------

呵呵,未必吧
结构在程序编制中是最重要的,算法耗时速度等因素影响不大。

出0入84汤圆

发表于 2010-4-23 14:27:57 | 显示全部楼层
15L16L唱双簧的

出0入84汤圆

发表于 2010-4-23 14:32:37 | 显示全部楼层
这也是本人一直坚持用汇编的原因,人都很懒惰,用汇编后想懒也懒不起来了,很多算法只要多加演算就能变的很简单,曾花近5个小时演算一个类似A*B/C之类的算法,最终用汇编语句11条搞定

出0入0汤圆

发表于 2010-4-23 15:54:59 | 显示全部楼层
回复【19楼】XA144F
12位精度的时候,高字节的低四位和低字节的高四位就是温度的整数部分,低字节的低四位是温度的小数部分,这部分的处理需要一点时间。我的方法很简单,但是代码占用量比较大,即认为0x01对应0625,0x02对应1250……0x0F对应9375,这样只要查表一次就能得到温度的十进制值,这方法倒是简单,但是我想还继续改进。
-----------------------------------------------------------------------
D16    U V W X
0x0----0 0 0 0
0x1----0 6 2 5
0x2----1 2 5 0
0x3----1 8 7 5
0x4----2 5 0 0
0x5----3 1 2 5
0x6----3 7 5 0
0x7----4 3 7 5
0x8----5 0 0 0
0x9----5 6 2 5
0xA----6 2 5 0
0xB----6 8 7 5
0xC----7 5 0 0
0xD----8 1 2 5
0xE----8 7 5 0
0xF----9 3 7 5
仔细观察,可以发现:
table_U[]={0,0,1,1,2,3,3,4,5,5,6,6,7,8,8,9};
table_V[]={0,6,2,8,5,1,7,3};
table_W[]={0,2,5,7};
table_X[]={0,5};

U = table_U[ D16 ];
V = table_V[ D16&7 ];    // D16%8
W = table_W[ D16&3 ];    // D16%4
X = table_X[ D16&1 ];    // D16%2

这样代码量少了,但是需要查表4次。

出0入0汤圆

发表于 2010-4-23 16:00:26 | 显示全部楼层
再仔细观察,又发现:
table_V[]={0,6,2,8,5,1,7,3};
table_W[]={0,  2,  5,  7  };
table_X[]={0,      5      };

所以:
V = table_V[ D16&7 ];
W = table_V[ (D16&3)<<1 ];
X = table_V[ (D16&1)<<2 ];

出0入0汤圆

发表于 2010-4-23 20:37:41 | 显示全部楼层
回复【22楼】czzhouyun
15L16L唱双簧的
-----------------------------------------------------------------------

什么意思?唱双簧损害了你的利益了?探讨也不行?

出0入0汤圆

发表于 2010-4-24 00:31:47 | 显示全部楼层
好的算法,要学习!

出0入4汤圆

发表于 2010-4-24 01:51:15 | 显示全部楼层
写得不错!

出0入0汤圆

发表于 2010-4-24 02:13:50 | 显示全部楼层
好贴留名!标记!

出0入0汤圆

发表于 2010-4-24 02:25:07 | 显示全部楼层
【8楼】 XA144F  


我偷笑,我研究AVR优化算法好久了。

x为小数部分0-15之间的数,y为最后输出的数,为什么偷笑?因为只要10个周期。

y=(((x*5)>>2)+1)>>1;   //小数输出 10T

出0入0汤圆

发表于 2010-4-24 02:34:34 | 显示全部楼层
y=(((x*5)>>2)+1)>>1;

等效y=((x*5)/4+1)/2;

再等效y=((x*20)/16+1)/2;

实际上y=x*10/16;

由于定义的类型都是整数,单片机计算完后是取整数部份,所以要进行四舍五入
y=x*10/16+0.5;

所以y=2*(x*10/16+0.5)/2;

y=(x*20/16+1)/2;

出0入0汤圆

发表于 2010-4-24 04:35:20 | 显示全部楼层
没注意看上面的是四位都算出来,我只算小数后一位并四舍五入,因为18B20的精度就那样,后面几位没多大意义。

跟据24楼的表加上自己的处里得到下面的算式,应该算很简了吧?

U=(xx*5)>>3;              //8T
V=xx*6+(xx>>2)-U*10;      //13T
W=((xx&3)*5)>>1;          //7
X=(xx&1)*5;               //5T

共33T,比查表少周期数和代码数。不过不好理解公式。

出0入0汤圆

发表于 2010-4-24 04:54:32 | 显示全部楼层
U=(xx*5)>>3;                     //8T
V=((xx+U)*6+(xx>>2))&0xf;        //10T
W=((xx&3)*5)>>1;                 //7T
X=(xx&1)*5;                      //5T

出0入0汤圆

发表于 2010-4-24 07:01:21 | 显示全部楼层
深刻啊

出0入0汤圆

发表于 2010-4-24 07:26:02 | 显示全部楼层
学习…

出0入0汤圆

 楼主| 发表于 2010-4-24 08:12:04 | 显示全部楼层
呵呵!原来大家好得算法这么多。请那位高手说说,电机S曲线。算法

出0入85汤圆

发表于 2010-4-24 08:18:27 | 显示全部楼层
以前都是用汇编,后来懒了

出0入0汤圆

发表于 2010-4-24 09:48:19 | 显示全部楼层
DS18B20精度是 0.5度
其实 不用那么复杂的

     T = (Tadc >>3);  就可以

每一个码表示0.5度

出0入0汤圆

发表于 2010-4-24 13:24:32 | 显示全部楼层
回复【32楼】hsztc
没注意看上面的是四位都算出来,我只算小数后一位并四舍五入,因为18B20的精度就那样,后面几位没多大意义。
跟据24楼的表加上自己的处里得到下面的算式,应该算很简了吧?
U=(xx*5)&gt;&gt;3;              //8T
V=xx*6+(xx&gt;&gt;2)-U*10;      //13T
W=((xx&amp;3)*5)&gt;&gt;1;          //7
X=(xx&amp;1)*5;               //5T
共33T,比查表少周期数和代码数。不过不好理解公式。
-----------------------------------------------------------------------

夜猫子啊……
:-)

如果我24楼的表都是放在RAM中呢?应该是最快的了吧?

出0入0汤圆

发表于 2010-4-24 18:09:06 | 显示全部楼层
CAL_FLO:
                MOV        A,7BH
                MOV        B,#04H
                MUL        AB
                MOV        B,A
                MOV        DPTR,#TMPX0

                MOVC        A,@A+DPTR
                MOV        73H,A

                MOV        A,B
                INC        DPTR
                MOVC        A,@A+DPTR
                MOV        74H,A

                MOV        A,B
                INC        DPTR
                MOVC        A,@A+DPTR
                MOV        75H,A

                MOV        A,B
                INC        DPTR
                MOVC        A,@A+DPTR
                MOV        76H,A
       
                RET

TMP00:        DB        '0000'
TMP01:        DB        '0625'
TMP02:        DB        '1250'
TMP03:        DB        '1875'
TMP04:        DB        '2500'
TMP05:        DB        '3125'
TMP06:        DB        '3750'
TMP07:        DB        '4375'
TMP08:        DB        '5000'
TMP09:        DB        '5625'
TMP0A:        DB        '6250'
TMP0B:        DB        '6875'
TMP0C:        DB        '7500'
TMP0D:        DB        '8125'
TMP0E:        DB        '8750'
TMP0F:        DB        '9375'

正好,也是33个周期。

出0入0汤圆

发表于 2010-4-24 18:43:40 | 显示全部楼层
【39楼】 eduhf_123 经历

51查表快,AVR查表慢,不管放在RAM还是FLASH。




【40楼】 XA144F

哈哈,我是AVR的33个周期,后来改进后的是30个周期,改进后的程序在33楼。

我喜欢用30楼的 y=(((x*5)>>2)+1)>>1; 十个周期

测量的18B20保留一位小数(0-9),是四舍五入的,比较实用。

出0入0汤圆

发表于 2010-4-24 19:14:17 | 显示全部楼层
将我写的AVR C直接转成相应的51汇编,要53T,因为51和AVR结构不同,所以如果用51的方法写应该会更少写,不用查表。

CAL_FLO:MOV     A,7BH        ;U
        MOV     B,#5
        MUL     AB
        MOV     B,#8
        DIV     AB
        MOV     73H,A
        
        MOV     A,7BH        ;V
        ADD     A,73H
        MOV     B,#6
        MUL     AB
        MOV     B,A
        MOV     A,7BH
        RR      A
        RR      A
        ADD     A,B
        ANL     A,#0FH
        MOV     74H,A
        
        MOV     A,7BH         ;W
        ANL     A,#3
        MOV     B,#5
        MUL     AB
        CLR     C
        RRC     A
        MOV     75H,A
        
        MOV     A,7BH          ;X
        ANL     A,#1
        MOV     B,#5
        MUL     AB
        MOV     76H,A

        RET

出0入0汤圆

发表于 2010-4-24 19:29:37 | 显示全部楼层
CAL_FLO:MOV     A,7BH      
        MOV     B,#6
        MUL     AB
        MOV     B,A
        MOV     A,7BH
        RRC     A
        CLR     C
        RRC     A
        ADD     A,B
        MOV     B,#10
        DIV     AB
        MOV     73H,A      ;U
        MOV     74H,B      ;V
        
        MOV     A,7BH
        ANL     A,#3
        MOV     B,#25
        MUL     AB
        MOV     B,#10
        DIV     AB
        MOV     75H,A       ;W
        MOV     76H,B       ;X                 
        
        RET

43T

出0入0汤圆

发表于 2010-4-24 23:18:40 | 显示全部楼层
回复【41楼】hsztc
【39楼】 eduhf_123 经历
  
51查表快,AVR查表慢,不管放在RAM还是FLASH。
-----------------------------------------------------------------------

AVR查RAM中的表也慢?
对AVR不很熟悉的我表示不太能理解。

出0入0汤圆

发表于 2010-4-24 23:36:02 | 显示全部楼层
AVR使用LPM指令,具体为:
LPM  Rd,Z+

所以只要将Z刚开始装入表格的首地址,然后重复4次

LDI ZL,LOW(TAB)
LDI ZH,HIGH(TAB)

LPM R1,Z+
LPM R2,Z+
LPM R3,Z+
LPM R4,Z+

出0入0汤圆

发表于 2010-4-25 00:11:05 | 显示全部楼层
有意思,高人很多,学习了!

出0入0汤圆

发表于 2010-4-25 01:26:23 | 显示全部楼层
我指的是AVR的C,不是汇编。就算是汇编Z的值是要计算的,C在复位的时候会把表格放在RAM中。

然后调用,每次都是一排程序(八行)。

(0003) const unsigned char tabled[]=
(0004) {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xbf,0xff,0xff,0xff,0xff,0xff};
(0005) //0,1,2,3,4,5,6,7,8,9,-, , , , , ;"depcgbfa"共阳
(0006)
(0007) void main(void)
(0008) {
(0009)  unsigned char x;
(0010)  
(0011) x=5;
_main:
  x                    --> R16
    00044 E005      LDI        R16,5
(0012)
(0013) PORTB=tabled[x];
    00045 E080      LDI        R24,0
    00046 E091      LDI        R25,1
    00047 2FE0      MOV        R30,R16
    00048 27FF      CLR        R31
    00049 0FE8      ADD        R30,R24
    0004A 1FF9      ADC        R31,R25
    0004B 8020      LD        R2,Z
    0004C B825      OUT        0x05,R2
(0014) PORTC=tabled[x+1];
    0004D E081      LDI        R24,1
    0004E E091      LDI        R25,1
    0004F 2FE0      MOV        R30,R16
    00050 27FF      CLR        R31
    00051 0FE8      ADD        R30,R24
    00052 1FF9      ADC        R31,R25
    00053 8020      LD        R2,Z
    00054 B828      OUT        0x08,R2
(0015)
(0016) while(1);
FILE: <library>
    00055 CFFF      RJMP        0x0055
    00056 9508      RET

出0入0汤圆

发表于 2010-4-30 19:21:02 | 显示全部楼层
直接转换方便,顶一下

出0入0汤圆

发表于 2010-4-30 20:25:31 | 显示全部楼层
有意思

出0入0汤圆

发表于 2010-4-30 20:33:25 | 显示全部楼层
从LZ的文章可以看出
这都是软件不懂硬件给害的。
特别是从PC转嵌入式的人,以为在PC上OK了,到嵌入式板只是移植问题。
其实这里头受很多硬件资源的制约。

橘生淮南则为桔,生于淮北则为枳。

出0入0汤圆

发表于 2010-4-30 21:53:55 | 显示全部楼层
当然,还有的人叫嚣说C语言是王道,汇编可以完全抛弃。

出10入120汤圆

发表于 2010-4-30 23:52:20 | 显示全部楼层
回复【51楼】XA144F  
当然,还有的人叫嚣说c语言是王道,汇编可以完全抛弃。
-----------------------------------------------------------------------

我一直就这么主张,认为假如项目一定需要使用汇编,就是两个原因:
1、程序结构垃圾。
2、该换用速度更快容量更大的CPU。

90%的原因是第一条。

出0入0汤圆

发表于 2010-5-1 09:40:02 | 显示全部楼层
52L:不尽然。

1.程序结构垃圾——如何定义“垃圾”?是编程者的算法不好还是C编译器的编译结果不好?

2.该换用速度更快容量更大的CPU——对我来说,接受客户要求定制仪器时,成本是不用考虑的,所以使用更快更大的CPU无所谓,靠的是高速优势来弥补因为代码冗长造成的效率低。但是对于批量生产的产品而言,成本是老板最关心的问题,即保证性能的同时要成本最低。

对单片机而言,现在的编译器可以做到很高的代码效率。简单的说,你用C写出一段代码,然后以你想象的方式翻译为最精简的汇编代码,然后将编译器输出的结果与之比较,看看有多大差别……

使用C语言的好处就是让编译器给你生成运算的代码,而不用自己去设计,比如让8位单片机完成16-16的乘除法运算,如果让用户用汇编来写,绝对的会让人头大。但并不是说C语言是万能的,比如这样一段C语言代码,在51单片机中编译的:

main()
        {
                char a,b,c,d;
                a=255;
                b=16;
                c=a/b;
                d=a%b;
        }

所有变量都是8位的字符型,所以对于51单片机而言是最好处理的,但是keil编译器如何应对的这个8-8除法运算?这是编译器生成的函数,可以直接得到商和余数:

                 C?SCDIV:
C:0x0003    C2D5     CLR      F0(0xD0.5)
C:0x0005    30F707   JNB      0xF0.7,C:000F
C:0x0008    B2D5     CPL      F0(0xD0.5)
C:0x000A    63F0FF   XRL      B(0xF0),#0xFF
C:0x000D    05F0     INC      B(0xF0)
C:0x000F    30E70C   JNB      0xE0.7,C:001E
C:0x0012    B2D5     CPL      F0(0xD0.5)
C:0x0014    F4       CPL      A
C:0x0015    04       INC      A
C:0x0016    84       DIV      AB
C:0x0017    63F0FF   XRL      B(0xF0),#0xFF
C:0x001A    05F0     INC      B(0xF0)
C:0x001C    8001     SJMP     C:001F
C:0x001E    84       DIV      AB
C:0x001F    30D502   JNB      F0(0xD0.5),C:0024
C:0x0022    F4       CPL      A
C:0x0023    04       INC      A
C:0x0024    22       RET      

如果照汇编来写,那只有几条指令(a在R6,b在R7,c在0x08,d在0x09):

MOV A,R6
MOV B R7
DIV AB
MOV 0x08,A
MOV 0x09,B

哪个更快?

我没有说要一定使用汇编或C语言,而是根据自己的需要来决定,或者说在C中加入汇编也是很不错的。

PS:对黑客而言,汇编语言中几条指令的效果如同催化剂,比调用几个API函数简单有效的多——比如“缓冲区溢出攻击”,只要找到缓冲区的溢出点,就将汇编指令对应的机器代码注入,那就可以控制别人的计算机了。所以汇编语言是黑客的必修课,只是知道用现成的软件的都不能称为黑客。

出0入0汤圆

发表于 2010-5-1 10:55:28 | 显示全部楼层
lz:这事你别说的太细

出0入0汤圆

发表于 2010-5-1 21:43:48 | 显示全部楼层
【53楼】 XA144F

用C得这么写:

void main(void)
{
  char a,c,d;
  a=255;
  c=a>>4;
  d=a&0x0f;

while(1);
}


(0011) void main(void)
(0012) {
(0013)   char a,c,d;
(0014)   a=255;
_main:
  d                    --> R16
  c                    --> R18
  a                    --> R16
    0003D EF0F      LDI        R16,0xFF
(0015)   c=a>>4;
    0003E 2F20      MOV        R18,R16
    0003F 9522      SWAP        R18
    00040 702F      ANDI        R18,0xF
(0016)   d=a&0x0f;
    00041 700F      ANDI        R16,0xF
(0017)
(0018) while(1);
FILE: <library>
    00042 CFFF      RJMP        0x0042
    00043 9508      RET

出0入0汤圆

发表于 2010-5-2 19:54:22 | 显示全部楼层
55L:如果b=17呢?你举的例子可把我的意思都改变了啊。

出0入0汤圆

发表于 2010-5-2 21:12:53 | 显示全部楼层
【56楼】 XA144F

哈哈,17就没办法了

出0入0汤圆

发表于 2010-5-2 21:18:28 | 显示全部楼层
【56楼】 XA144F  

你的变量改成unsigned char 看看,我生成的跟汇编是一样的


(原文件名:1111.PNG)

出0入0汤圆

发表于 2010-5-2 21:45:21 | 显示全部楼层
除的过程中直接获得余数的方法。


(原文件名:1111.PNG)

不过我也觉得汇编很重要,两个都不能少。

出0入0汤圆

发表于 2010-5-2 23:38:14 | 显示全部楼层
大懒来了!
  X=0000~1111转换为1位十进制小数:
      MOV  A,X
      SWAP A
      MOV  B,#10
      MUL  AB ;1位十进制小数在B中


  X=0000~1111转换为2位十进制小数:
      MOV  A,X
      SWAP A
      MOV  B,#10
      MUL  AB ;1位十进制小数在B中
      PUSH B
      MOV  B,#10
      MUL  AB ;1位十进制小数在B中
      POP  A
      2位十进制小数:高位在A,低位在B

   不是俺笑话一些高人,就是这么一道题;想当年研究生复试的时候很多人写的乱七八糟,更不用说调试情况了。

出0入0汤圆

发表于 2010-5-3 00:59:26 | 显示全部楼层
y = (x * 50) >> 3; /* 保留2两位小数 */

出0入0汤圆

发表于 2010-5-3 23:35:44 | 显示全部楼层
hehe,楼上看一下你的代码对应的ASM程序:
                       MOV     A,x
0003 75F032            MOV     B,#032H
0006 A4                MUL     AB
0007 AEF0              MOV     R6,B
0009 7803              MOV     R0,#03H
000B         ?C0004:
000B CE                XCH     A,R6
000C A2E7              MOV     C,ACC.7
000E 13                RRC     A
000F CE                XCH     A,R6
0010 13                RRC     A
0011 D8F8              DJNZ    R0,?C0004
0013 F500        R     MOV     y,A
建议写嵌入式软件的多看一下C和ASM的对应关系:
Converting from C to Asm (from Shawn Bullock).ourdev_551312.rar(文件大小:14K) (原文件名:C_TO_ASM.rar)

出0入0汤圆

发表于 2010-5-4 01:11:01 | 显示全部楼层
【62楼】 yxw_bob

能发一份中文版的看看吗? 我不懂E文啊。

还有
【61楼】 hhrfjz --- y = (x * 50) >> 3; /* 保留2两位小数 */  

和我的【30楼】【33楼】 的都是为AVR而优化的,内核不一样没有可比性啊,51有除法指令,代码基本不用考虑,

但AVR没有除法指令,一条8位/8位的除法都要一百多个周期,所以得想办法优化。

如果要比的话,AVR和51在同时钟下【61楼】【33楼】的程序执行时间小于51的一条MUL AB

【30楼】的在51还没执行完一条MOV  A,x就执行完了。

出0入0汤圆

发表于 2010-5-4 12:49:50 | 显示全部楼层
楼上,我从没想过翻译,看一看哪位大虾帮忙翻译下?

AVR的汇编子程序有一本书,我用过还可以.
AVR单片机实用程序设计(附光盘)(张克彦,北京航空航天大学出版社)

出0入0汤圆

发表于 2010-5-4 14:28:15 | 显示全部楼层
关于软件上提高效率的方法,我这里有个文档非常好。

好像也是这个论坛下的,记不清楚了。

我这里再发一次吧。


点击此处下载 ourdev_551370.pdf(文件大小:602K) (原文件名:让你的软件飞起来.pdf)

出0入0汤圆

发表于 2010-5-4 14:46:57 | 显示全部楼层
算法很重要啊!

65L,有没有使用计算机的MMX指令?那应该会更快的。

出0入0汤圆

发表于 2010-5-4 18:33:29 | 显示全部楼层
65楼 的pdf写的不错啊。

出0入0汤圆

发表于 2010-5-5 10:55:42 | 显示全部楼层
学习一下

出0入0汤圆

发表于 2010-5-8 21:50:29 | 显示全部楼层
气氛真好,mark

出10入120汤圆

发表于 2010-5-9 10:18:06 | 显示全部楼层
回复【53楼】XA144F  
52l:不尽然。
1.程序结构垃圾——如何定义“垃圾”?是编程者的算法不好还是c编译器的编译结果不好?
2.该换用速度更快容量更大的cpu——对我来说,接受客户要求定制仪器时,成本是不用考虑的,所以使用更快更大的cpu无所谓,靠的是高速优势来弥补因为代码冗长造成的效率低。但是对于批量生产的产品而言,成本是老板最关心的问题,即保证性能的同时要成本最低。
对单片机而言,现在的编译器可以做到很高的代码效率。简单的说,你用c写出一段代码,然后以你想象的方式翻译为最精简的汇编代码,然后将编译器输出的结果与之比较,看看有多大差别……
使用c语言的好处就是让编译器给你生成运算的代码,而不用自己去设计,比如让8位单片机完成16-16的乘除法运算,如果让用户用汇编来写,绝对的会让人头大。但并不是说c语言是万能的,比如这样一段c语言代码,在51单片机中编译的:
main()
        {
                char a,b,c,d......
-----------------------------------------------------------------------

就楼主这里例子而言,单片机做一个浮点数运算也就是几个毫秒的事情,我们做一个极端的假使,计算温度需要0.5S可以了吧?

对于温度而言,本来就是一个惰性变化的物理量,在程序中你只要做到采集计算分离,0.5S~1S计算一次温度又如何?

出0入0汤圆

发表于 2010-5-9 15:21:59 | 显示全部楼层
【70楼】 makesoft


一片单片机只为了测一个温度,其它都不用干了?

出0入0汤圆

发表于 2010-5-10 10:08:16 | 显示全部楼层
是啊,虽然使用DS18B20方便,但是这是以牺牲时间为基础的……转换的时间很长,计算的时间多一样又怎样呢?所以要速度快,还是用模拟传感器加ADC吧,哈哈!

出0入0汤圆

发表于 2010-5-10 18:18:16 | 显示全部楼层
【72楼】 XA144F

18B20还算可以啊,不需要多少时间的,只不过要分成两部份。

先启动转换,这个动作可以在瞬间完成,然后单片机可以做其它事,过了一秒以后再去读转换值,这个也是在瞬间完成。

出10入120汤圆

发表于 2010-5-12 19:18:28 | 显示全部楼层
回复【71楼】hsztc  
【70楼】 makesoft

一片单片机只为了测一个温度,其它都不用干了?
-----------------------------------------------------------------------

那要看到底多少任务是强实时的,以我的经验敢断定CPU速度和浮点数运算都不是一个项目中的瓶颈,只要你的项目不是足够大。

出0入0汤圆

发表于 2010-5-13 10:05:12 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-8-9 21:41:55 | 显示全部楼层
回复【楼主位】tangwei039
-----------------------------------------------------------------------

受教了

出0入0汤圆

发表于 2010-10-8 16:44:56 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-10-8 22:36:39 | 显示全部楼层
mark!

出0入0汤圆

发表于 2010-10-9 13:30:31 | 显示全部楼层
再发个好理解又快速的。

///////////////////////////////得到四位小数 最大28T/////////////////////////////
unsigned char x,y1,y2,y3,y4;

  x=PINB;  //测试用,输入值
  
  y1=y2=y3=y4=0;      //18B20 得到四位小数  0 . y1 y2 y3 y4
  if(x&(1<<3)) {y1=5;}   //条件成立+5000
  if(x&(1<<2)) {y1+=2; y2=5;}  //条件成立+2500
  if(x&(1<<1)) {y1+=1; y2+=2; y3=5;}  //条件成立+1250
  if(x&(1<<0)) {if(y2>=5){y2-=4; y1++;} else y2+=6;  y3+=2; y4=5;}  //条件成立+625
   
  PORTC=y1;   //得到第1位小数
  DDRC=y2;    //得到第2位小数
  PORTB=y3;   //得到第3位小数
  DDRB=y4;    //得到第4位小数
/////////////////////////////////////////////////////////////////////////////

////////////////////////////////保留一位小数(四舍五入)/////////////////////

z=((unsigned char)(((unsigned char)(x*10u))+8u))>>4; //IAR 9T



z=(((unsigned char)(x*10u))+8u)>>4;  //ICC 8T

//////////////////////////////////////////////////////////////////////

出0入0汤圆

发表于 2010-12-11 10:22:49 | 显示全部楼层
那些人都是傻× 你不用管它 会编程的都会>>  <<

出0入0汤圆

发表于 2010-12-11 12:59:39 | 显示全部楼层
占位,学习!

出0入0汤圆

发表于 2010-12-11 13:19:14 | 显示全部楼层
jh

出0入0汤圆

发表于 2010-12-11 13:36:41 | 显示全部楼层
这么多好算法。

出10入10汤圆

发表于 2010-12-11 14:13:19 | 显示全部楼层
mark!

出0入0汤圆

发表于 2010-12-11 14:33:47 | 显示全部楼层
写C代码的同时,脑袋里浮现的是汇编,这样程序的效率会比较高。

出0入0汤圆

发表于 2010-12-11 15:12:08 | 显示全部楼层
没看完

以前用汇编

我们的年代不必和当年开发仙剑的时候

少用一个RAM就开心的要死了

但是也要考虑MCU的负荷

我一般能左右移数据差不多的绝不使用乘除

出0入0汤圆

发表于 2010-12-12 15:54:45 | 显示全部楼层
学习了, 用DS18B20都是抄来的代码, 还没仔细看过,汗

出0入0汤圆

发表于 2010-12-12 22:49:46 | 显示全部楼层
回复【87楼】aahui  
学习了, 用ds18b20都是抄来的代码, 还没仔细看过,汗
-----------------------------------------------------------------------

这习惯不好哦!抄来的程序或多或少的,一定要仔细看看啊!

出0入0汤圆

发表于 2010-12-14 17:17:57 | 显示全部楼层
记号

出0入0汤圆

发表于 2010-12-14 22:06:51 | 显示全部楼层
记号

出0入0汤圆

发表于 2010-12-14 22:21:45 | 显示全部楼层
楼主说的好,我也是从这个0.0625开始注意到用移位来解决乘法除法的妙处了,当初这个芯片的设计者,其实就已经想到了位移问题,否则不会弄出个0.0625,只是我们手里的书本,往往只讲到0.0625,没有讲明白这个东西实际上市1/16,可以用移位来换算---至少我手里的书籍没有介绍这个重要问题!

出0入0汤圆

发表于 2010-12-14 22:56:06 | 显示全部楼层
回复【91楼】wandy2010  老铁
楼主说的好,我也是从这个0.0625开始注意到用移位来解决乘法除法的妙处了,当初这个芯片的设计者,其实就已经想到了位移问题,否则不会弄出个0.0625,只是我们手里的书本,往往只讲到0.0625,没有讲明白这个东西实际上市1/16,可以用移位来换算---至少我手里的书籍没有介绍这个重要问题!

-----------------------------------------------------------------------

关键是定势思维捣鬼,一看到0.0625就充血……哈哈,如果写成1/16或许好些,大家一看就知道用移位最简单。

出0入0汤圆

发表于 2010-12-15 00:40:03 | 显示全部楼层
气氛真好,mark

出0入0汤圆

发表于 2010-12-15 15:07:19 | 显示全部楼层
回复【86楼】format
没看完
以前用汇编
我们的年代不必和当年开发仙剑的时候
少用一个ram就开心的要死了
但是也要考虑mcu的负荷
我一般能左右移数据差不多的绝不使用乘除

-----------------------------------------------------------------------

确实如此,可惜新手很多不注意,我也是傻乎乎的用浮点乘法很长时间,呵呵

出0入0汤圆

发表于 2011-8-20 21:26:22 | 显示全部楼层
现在是浪费的年代。

出0入0汤圆

发表于 2011-8-20 21:37:37 | 显示全部楼层
强大的处理器后面只会产生更多憋足的工程师。

出0入0汤圆

发表于 2011-8-20 21:55:02 | 显示全部楼层
受益匪浅

出0入0汤圆

发表于 2011-8-20 22:11:08 | 显示全部楼层
好方法

出0入0汤圆

发表于 2011-8-20 23:36:43 | 显示全部楼层
以此告诫自己
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-8-26 20:19

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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