目前单片机的编程中,C51语言可以说是十分盛行,这种语言我也用过,但基本上都是用汇编语言.
C51语言的好处是可读性强、移植性好、浮点运算,除此之外没有别的好处了.我们不妨将两种语言作一个比较:
1、效率方面:我曾对编译后的C51语言分析过,可以发现由它生成的代码数量,至少是汇编语言的两倍以上,有的甚至高达十倍以上.占用空间大了,效率自然低.
2、移植性:C51的可移植性是比汇编好一些,但是单片机程序不同于微机控件程序那样通用,几乎没有一个程序是可以到处移植的.单片机中最常用的移植程序大概就是运算子程序了,在这方面,汇编格式的运算子程序移植起来一个也不比C51逊色.
3、浮点运算:以我的感觉,单片机不适合采用浮点运算,我曾经做过试验,编译了一个1.2+2.3的浮点运算,编译后代码长达2K多,完成这个运算所需要的时间就不用说了.我从八四年就开始研究单片机,到现在做过的系统中,含有单片机的超过五十项,所有系统中的运算,全部都采用定点运算,几个定点子程序成了法宝,代码效率非常高,请看下面的一段:
;W = W130 * (130 / Dia) * (130 / Dia) = W130 * 16900 / (Dia * Dia)
CalAndMem: MOV R5, SetPie130War1H
MOV R4, SetPie130War1L
MOV R3, #HIGH 16900
MOV R2, #LOW 16900
CALL QKMUL ;W130 * 16900
;双字节乘法子程QKMUL
;(R3、R2)*(R5、R4)=R7、R6、R5、R4
;R3、R5、R7为高字节
MOV A, SetDiamt
MOV B, A
MUL AB
MOV R3, B
MOV R2, A
CALL NDIV ; /(Dia * Dia)
;二进制除法子程:NDIV
;入口:R7654=被除数,R7高字节,R32=除数,R3高字节
;出口:R76=余数,R7高字节,R54=商,R5高字节
;R765432用于参数传递,不用保护
MOV SetPieWar1H, R5 ;当前缸径下的压力报警点
MOV SetPieWar1L, R4
--------
其中的子程序都是网上的成品,非常精简.
4、实时性:用汇编编程序的人都知道,单片机的实时性要求很高,经常需要计算这段程序需要多长时间,什么时间来中断,中断后执行多长时间,对原程序有没有妨碍,等等,这都是C51程序难以做到的.
5、节省内存:当然,这和代码效率是成反比的,同样的内存所能完成的功能也就大大提高.
永远记住:高性能的代码是用汇编语言编写出来的,而不是用高级语言生成的,高质量的PCB是有经验的工程技术人员用手工排出来的,而不是软件自动布线出来的.
谈谈我对C51语言的看法
全部回复(21)
正序查看
倒序查看
现在还没有回复呢,说说你的想法
使用C51可以写出跟asm51毫不逊色的程序,这要看编程者的水平了,看下面的例子:
// ============================================================
// 功能:计算斜率
// 说明:被除数必须小于除数,返回(n1*256)/n2的商
// 编程:臧德运
unsigned char Div(unsigned char n1, unsigned char n2)
{
union {unsigned int w; struct {unsigned char h, l;}bytes;}i;
unsigned char n;
if(n1==0){return(0);} // 被除数等于零返回
i.bytes.h=n1; i.bytes.l=0; // 使用公用体变量便于字节操作
for(n=8;n>0;n--)
{
i.w=i.w<<1;
if(CY==0)
{
if(ACC }
else ACC=ACC-n2;
i.bytes.h=ACC; i.bytes.l++;
}
return(i.bytes.l);
}
// ============================================================
// 功能:画直线
// 编程:臧德运
void PLine(unsigned char x1, unsigned char y1, unsigned char x2, unsigned char y2, bit mode)
{
unsigned char n, k;
unsigned char x, y, x0, y0;
// 修正坐标原点为左下角
y1=y1^0x7f;
y2=y2^0x7f;
// 求X坐标偏移量的绝对值
if(x2 {
ACC=~ACC;ACC++; // 求绝对值
n=x1; x1=x2; x2=n; n=y1; y1=y2; y2=n; // 校正画线方向提高效率
}
x0=ACC;
// 求Y坐标偏移量的绝对值
// 避免使用ABS函数提高效率
if(y2 y0=ACC;
x=x1; y=y1;
if(x0==y0) // 斜率等于1时画正斜线
{
for(n=x0;n>0;n--)
{
Pixel(x, y, mode); x++;
if(y2>y1)y++;
else y--;
}
}
else
{
if(x0>y0) // 小于45度的斜线
{
k=Div(y0,x0);
for(n=0;n<=x0;n++)
{
ACC=k;B=n;ACC=ACC*B; y0=B;
if(ACC_7)y0++;
if(y2>y1){y=y1+y0;}else{y=y1-y0;}
Pixel(x1+n, y, mode);x++;
}
}
else // 大于45度的斜线
{
k=Div(x0,y0);
for(n=0;n<=y0;n++)
{
ACC=k;B=n;ACC=ACC*B;
if(ACC_7)B++;
x=B+x1;
Pixel(x, y, mode);if(y2>y1){y++;}else{y--;}
}
}
}
return;
}
// ============================================================
// 二(十六)进制转换为十进制
// 返回:低四位十进制编码+B(万位)
// 格式:C51
// 编程:臧德运
unsigned int bin2dec(unsigned char bl, unsigned char bh)
{
union{unsigned int i; struct{unsigned char h, l;}bytes;}d;
d.bytes.l=bl; d.bytes.h=bh;
B=0;bh=0;
// 逐次d.i-10000,不够减退出循环,循环次数就是万位值
while(1)
{
d.i+=0xd8f0;if(!CY)break;
B++;
}
d.i+=10000;
// 把减10000的余数转化为100进制
// bh=100进制高位
// d.bytes.l=余数,也就是100进制低位
for(bl=8;bl!=0;bl--)
{
bh+=bh; // 100进制高位同步左移
d.i=d.i<<1; // 8次位移逐次求100进位
if(d.bytes.h>=100) // 编译器在编译d.bytes.h>=100时,会有减100操作.
{
d.bytes.h=ACC; // 比较时刻运算结果送100进制低位
bh++; // 100进制进位
}
}
bl=B; // 保护B内容
// 100进制转换为10进制
d.bytes.l=(d.bytes.h/10)<<4;
d.bytes.l=d.bytes.l|B;
d.bytes.h=(bh/10)<<4;
d.bytes.h=d.bytes.h|B;
B=bl; // 恢复B内容
return(d.i);
}
// ============================================================
// 功能:计算斜率
// 说明:被除数必须小于除数,返回(n1*256)/n2的商
// 编程:臧德运
unsigned char Div(unsigned char n1, unsigned char n2)
{
union {unsigned int w; struct {unsigned char h, l;}bytes;}i;
unsigned char n;
if(n1==0){return(0);} // 被除数等于零返回
i.bytes.h=n1; i.bytes.l=0; // 使用公用体变量便于字节操作
for(n=8;n>0;n--)
{
i.w=i.w<<1;
if(CY==0)
{
if(ACC
else ACC=ACC-n2;
i.bytes.h=ACC; i.bytes.l++;
}
return(i.bytes.l);
}
// ============================================================
// 功能:画直线
// 编程:臧德运
void PLine(unsigned char x1, unsigned char y1, unsigned char x2, unsigned char y2, bit mode)
{
unsigned char n, k;
unsigned char x, y, x0, y0;
// 修正坐标原点为左下角
y1=y1^0x7f;
y2=y2^0x7f;
// 求X坐标偏移量的绝对值
if(x2
ACC=~ACC;ACC++; // 求绝对值
n=x1; x1=x2; x2=n; n=y1; y1=y2; y2=n; // 校正画线方向提高效率
}
x0=ACC;
// 求Y坐标偏移量的绝对值
// 避免使用ABS函数提高效率
if(y2
x=x1; y=y1;
if(x0==y0) // 斜率等于1时画正斜线
{
for(n=x0;n>0;n--)
{
Pixel(x, y, mode); x++;
if(y2>y1)y++;
else y--;
}
}
else
{
if(x0>y0) // 小于45度的斜线
{
k=Div(y0,x0);
for(n=0;n<=x0;n++)
{
ACC=k;B=n;ACC=ACC*B; y0=B;
if(ACC_7)y0++;
if(y2>y1){y=y1+y0;}else{y=y1-y0;}
Pixel(x1+n, y, mode);x++;
}
}
else // 大于45度的斜线
{
k=Div(x0,y0);
for(n=0;n<=y0;n++)
{
ACC=k;B=n;ACC=ACC*B;
if(ACC_7)B++;
x=B+x1;
Pixel(x, y, mode);if(y2>y1){y++;}else{y--;}
}
}
}
return;
}
// ============================================================
// 二(十六)进制转换为十进制
// 返回:低四位十进制编码+B(万位)
// 格式:C51
// 编程:臧德运
unsigned int bin2dec(unsigned char bl, unsigned char bh)
{
union{unsigned int i; struct{unsigned char h, l;}bytes;}d;
d.bytes.l=bl; d.bytes.h=bh;
B=0;bh=0;
// 逐次d.i-10000,不够减退出循环,循环次数就是万位值
while(1)
{
d.i+=0xd8f0;if(!CY)break;
B++;
}
d.i+=10000;
// 把减10000的余数转化为100进制
// bh=100进制高位
// d.bytes.l=余数,也就是100进制低位
for(bl=8;bl!=0;bl--)
{
bh+=bh; // 100进制高位同步左移
d.i=d.i<<1; // 8次位移逐次求100进位
if(d.bytes.h>=100) // 编译器在编译d.bytes.h>=100时,会有减100操作.
{
d.bytes.h=ACC; // 比较时刻运算结果送100进制低位
bh++; // 100进制进位
}
}
bl=B; // 保护B内容
// 100进制转换为10进制
d.bytes.l=(d.bytes.h/10)<<4;
d.bytes.l=d.bytes.l|B;
d.bytes.h=(bh/10)<<4;
d.bytes.h=d.bytes.h|B;
B=bl; // 恢复B内容
return(d.i);
}
0
回复
提示
我想来到这里的人,大多数都是这方面的高手,上面有这么多人发表了自己的看法,不管怎么说,真正的是非我想大家都有数.
有人感觉还是用C编写单片机程序精炼,效率也不低,甚至和汇编语言差不多.
是,用高级语言编写的程序看上去是很精简,当然这也是个优点,源程序上看不出什么问题来,但不知道他分析过编译软件生成的代码没有,有一个事实,在我们用手工编写的程序中,Ri寄存器都当成工作寄存器来使用,可是用高级语言生成的程序中,他们都成了辅助寄存器,或者说是局部变量,一个很简单的功能,本来利用几个寄存器和几条指令本地就可以处理,编译器会把有关参数装入Ri,然后调用相应的子程序,这些数据在Ri中的频繁装载,对整个程序的效率有什么样的影响,大家一想就会明白.
有的人,说起话来他就不负责任,还想拿什么车来压我,甚至举出ARM单片机来说明问题,大家知道这种单片机是一种什么样的器件啊,它是带有流水线结构的32位机,有的甚至带有协处理器,如果程序执行状遇到错误,系统会立即转入异常状态,性能直追80486.请问这些功能是最普通、最常见的哪种单片机具备的?他还不如告诉我们不能直接用汇编语言编写windows呢.
我的意思并不是否认用高级语言编写软件,我对C/VB用的都很熟练,很清楚高级语言的优点,对于高档高速器件,不应该局限于汇编上,但是对于绝大多数的使用环境,普通低档单片机是足够胜任的.是否采用高档单片机,这不光是一个器件价格的问题,器件技术是否容易掌握也是一个不可忽视的因素.对于大多数工作人员使用最多的常规器件,采用汇编语言,可以最大限度的发挥器件的性能,不论是速度还是程序空间,都是高级语言无法相比的.我想这一点是谁也不能否认的.
有人感觉还是用C编写单片机程序精炼,效率也不低,甚至和汇编语言差不多.
是,用高级语言编写的程序看上去是很精简,当然这也是个优点,源程序上看不出什么问题来,但不知道他分析过编译软件生成的代码没有,有一个事实,在我们用手工编写的程序中,Ri寄存器都当成工作寄存器来使用,可是用高级语言生成的程序中,他们都成了辅助寄存器,或者说是局部变量,一个很简单的功能,本来利用几个寄存器和几条指令本地就可以处理,编译器会把有关参数装入Ri,然后调用相应的子程序,这些数据在Ri中的频繁装载,对整个程序的效率有什么样的影响,大家一想就会明白.
有的人,说起话来他就不负责任,还想拿什么车来压我,甚至举出ARM单片机来说明问题,大家知道这种单片机是一种什么样的器件啊,它是带有流水线结构的32位机,有的甚至带有协处理器,如果程序执行状遇到错误,系统会立即转入异常状态,性能直追80486.请问这些功能是最普通、最常见的哪种单片机具备的?他还不如告诉我们不能直接用汇编语言编写windows呢.
我的意思并不是否认用高级语言编写软件,我对C/VB用的都很熟练,很清楚高级语言的优点,对于高档高速器件,不应该局限于汇编上,但是对于绝大多数的使用环境,普通低档单片机是足够胜任的.是否采用高档单片机,这不光是一个器件价格的问题,器件技术是否容易掌握也是一个不可忽视的因素.对于大多数工作人员使用最多的常规器件,采用汇编语言,可以最大限度的发挥器件的性能,不论是速度还是程序空间,都是高级语言无法相比的.我想这一点是谁也不能否认的.
0
回复
提示
@deyun
使用C51可以写出跟asm51毫不逊色的程序,这要看编程者的水平了,看下面的例子://============================================================//功能:计算斜率//说明:被除数必须小于除数,返回(n1*256)/n2的商//编程:臧德运unsignedcharDiv(unsignedcharn1,unsignedcharn2){union{unsignedintw;struct{unsignedcharh,l;}bytes;}i;unsignedcharn;if(n1==0){return(0);} //被除数等于零返回i.bytes.h=n1;i.bytes.l=0; //使用公用体变量便于字节操作for(n=8;n>0;n--){ i.w=i.w
结构体用的不错.
0
回复
提示
@sdjufeng
我想来到这里的人,大多数都是这方面的高手,上面有这么多人发表了自己的看法,不管怎么说,真正的是非我想大家都有数.有人感觉还是用C编写单片机程序精炼,效率也不低,甚至和汇编语言差不多.是,用高级语言编写的程序看上去是很精简,当然这也是个优点,源程序上看不出什么问题来,但不知道他分析过编译软件生成的代码没有,有一个事实,在我们用手工编写的程序中,Ri寄存器都当成工作寄存器来使用,可是用高级语言生成的程序中,他们都成了辅助寄存器,或者说是局部变量,一个很简单的功能,本来利用几个寄存器和几条指令本地就可以处理,编译器会把有关参数装入Ri,然后调用相应的子程序,这些数据在Ri中的频繁装载,对整个程序的效率有什么样的影响,大家一想就会明白.有的人,说起话来他就不负责任,还想拿什么车来压我,甚至举出ARM单片机来说明问题,大家知道这种单片机是一种什么样的器件啊,它是带有流水线结构的32位机,有的甚至带有协处理器,如果程序执行状遇到错误,系统会立即转入异常状态,性能直追80486.请问这些功能是最普通、最常见的哪种单片机具备的?他还不如告诉我们不能直接用汇编语言编写windows呢.我的意思并不是否认用高级语言编写软件,我对C/VB用的都很熟练,很清楚高级语言的优点,对于高档高速器件,不应该局限于汇编上,但是对于绝大多数的使用环境,普通低档单片机是足够胜任的.是否采用高档单片机,这不光是一个器件价格的问题,器件技术是否容易掌握也是一个不可忽视的因素.对于大多数工作人员使用最多的常规器件,采用汇编语言,可以最大限度的发挥器件的性能,不论是速度还是程序空间,都是高级语言无法相比的.我想这一点是谁也不能否认的.
是的,汇编语言的优点是代码简练,C的优点是变量跟结构清晰.
使用高级语言完全能知道编译器生成的代码方法,甚至能直接利用Ri寄存器,还甚至人为的不使用R寄存器传递变量,看下面的例子:
// =================================================
// 写数据到SPROM数据线
// 返回: ACK状态
// 编程: 臧德运
bit w24XX(unsigned char c)
{
ACC=c; // 参数传递给A寄存器提高代码效率
for(c=8;c>0;c--) // DJNZ R7, xxxx作循环提高效率
{
SDA24XX=0x80 & ACC; // 让编译器使用循环左移实现数据高位送SDA?
SCK24XX=1; _nop_(); // 插入控操作使高脉冲持续一段时间
SCK24XX=0; _nop_();
} // 这里是DJNZ R7, xxxx代码
SDA24XX=1; _nop_();
SCK24XX=1; CY=SDA24XX;
_nop_(); SCK24XX=0;
Sdelay();
return(CY);
}
建议C和ASM混合使用.
使用高级语言完全能知道编译器生成的代码方法,甚至能直接利用Ri寄存器,还甚至人为的不使用R寄存器传递变量,看下面的例子:
// =================================================
// 写数据到SPROM数据线
// 返回: ACK状态
// 编程: 臧德运
bit w24XX(unsigned char c)
{
ACC=c; // 参数传递给A寄存器提高代码效率
for(c=8;c>0;c--) // DJNZ R7, xxxx作循环提高效率
{
SDA24XX=0x80 & ACC; // 让编译器使用循环左移实现数据高位送SDA?
SCK24XX=1; _nop_(); // 插入控操作使高脉冲持续一段时间
SCK24XX=0; _nop_();
} // 这里是DJNZ R7, xxxx代码
SDA24XX=1; _nop_();
SCK24XX=1; CY=SDA24XX;
_nop_(); SCK24XX=0;
Sdelay();
return(CY);
}
建议C和ASM混合使用.
0
回复
提示
看了这么多,说C好或者汇编好时应该有个基调.那就是需要我们的设计的系统.有的系统资源充足,实时性要求又不高,用C写好读易懂,何乐而不为?有的系统要求效率高,需要用汇编,也很好.其实汇编和C的优势劣势都显而易见.一个3000行的C语言程序,你若硬要用汇编写,也是可以的,不过打印出来只怕就是一本书了,而且如果过三个月谁让你改改软件怕也是个难事,汗啊~!但是无论你C用的多好,要与汇编比效率,总也是比不过的.感觉现在特别需要效率的地方也不是太多的,我比较喜欢的是大部分用C,特别需要效率的地方就嵌部分汇编进去.正所谓:60分万岁,多一分浪费,凡事够用就好,达到系统设计要求就是王道!!!
0
回复
提示
说句老实话,我觉得您没有体现出一个20余年单片机经历的工程师应有的见地.hotpower的话大体合乎情理您却听不进去,令人遗憾.
我想问一下,您做过的50几个含有MCU的项目中,性能最佳的是什么型号?项目中程序代码量最大的共计多少行?使用过RTOS吗?含有TCP/IP栈吗?语言之争在缺乏应用背景的条件下是毫无意义的.网上争论Java与C++,VC和Delphi的也是屡见不鲜,甚至有人好Java恶C,简直是关公战秦琼,为什么国人总是乐于争论这些不是问题的问题呢?C语言和汇编语言本不是一个层次,您的汇编子程序虽好,不过是在51汇编上可以调用罢了,其他架构的呢?我想是需要全盘改写吧.C编译器正是C高层次抽象和底层汇编的转换接口.如果还一味沉浸在51系列的汇编之中,我觉得您再无进步的可能.如果您看过开放源代码的操作系统如uC/OSII会有更深的体会,如果您对编译原理有了解也不会从您所用的C51编译器的代码效率来得出一些不正确的观点.
以上观点,就事论事,不当之处,请指教.
我想问一下,您做过的50几个含有MCU的项目中,性能最佳的是什么型号?项目中程序代码量最大的共计多少行?使用过RTOS吗?含有TCP/IP栈吗?语言之争在缺乏应用背景的条件下是毫无意义的.网上争论Java与C++,VC和Delphi的也是屡见不鲜,甚至有人好Java恶C,简直是关公战秦琼,为什么国人总是乐于争论这些不是问题的问题呢?C语言和汇编语言本不是一个层次,您的汇编子程序虽好,不过是在51汇编上可以调用罢了,其他架构的呢?我想是需要全盘改写吧.C编译器正是C高层次抽象和底层汇编的转换接口.如果还一味沉浸在51系列的汇编之中,我觉得您再无进步的可能.如果您看过开放源代码的操作系统如uC/OSII会有更深的体会,如果您对编译原理有了解也不会从您所用的C51编译器的代码效率来得出一些不正确的观点.
以上观点,就事论事,不当之处,请指教.
0
回复
提示
@whatcall
说句老实话,我觉得您没有体现出一个20余年单片机经历的工程师应有的见地.hotpower的话大体合乎情理您却听不进去,令人遗憾.我想问一下,您做过的50几个含有MCU的项目中,性能最佳的是什么型号?项目中程序代码量最大的共计多少行?使用过RTOS吗?含有TCP/IP栈吗?语言之争在缺乏应用背景的条件下是毫无意义的.网上争论Java与C++,VC和Delphi的也是屡见不鲜,甚至有人好Java恶C,简直是关公战秦琼,为什么国人总是乐于争论这些不是问题的问题呢?C语言和汇编语言本不是一个层次,您的汇编子程序虽好,不过是在51汇编上可以调用罢了,其他架构的呢?我想是需要全盘改写吧.C编译器正是C高层次抽象和底层汇编的转换接口.如果还一味沉浸在51系列的汇编之中,我觉得您再无进步的可能.如果您看过开放源代码的操作系统如uC/OSII会有更深的体会,如果您对编译原理有了解也不会从您所用的C51编译器的代码效率来得出一些不正确的观点.以上观点,就事论事,不当之处,请指教.
谢谢,关于你说的问题,我基本是赞同的.
讨论汇编与c的问题,确实不可能得出一个绝对的结论,这一点我在工作中也感觉到了.不可否认,C程序,按照大路性的编写方式,其效率确实是个问题,但是对于超大的程序,汇编也是难以支持的.
我最近的一个项目,用的c51,程序行数达到了3500行,单片机是ADuC841,显示器件为240128点阵液晶屏,用来显示参数和波形曲线.
在反复的应用研究中,我琢磨出了一套变通的c语言,当然在c的支持范围之内.这套变通的c语言,连乘除法运算都用自己的专用子程序,它更加贴近汇编,虽然程序行数增加了,甚至是明显增加,但是编译后的代码量却大大减小,速度也很高,在必要的时候插入汇编混合编程,查看代码,和汇编的效果基本一样.
少举几例:
-----------------------------------------
部分宏:
#define I2(v) HIGH_BYTE_OF_INT(v)
#define I1(v) LOW_BYTE_OF_INT(v)
#define L4(v) HH_BYTE_OF_LONG(v)
#define L3(v) HL_BYTE_OF_LONG(v)
#define L2(v) LH_BYTE_OF_LONG(v)
#define L1(v) LL_BYTE_OF_LONG(v)
#define L43(v) HIGH_INT_OF_LONG(v)
#define L21(v) LOW_INT_OF_LONG(v)
#define L32(v) MID_INT_OF_LONG(v)
#define DIV42(u, v) Ndivide(LOW_INT_OF_LONG(u), HIGH_INT_OF_LONG(u), v)
-----------------------------------------
//显示累计参数
//s=0,显示6位,s=1,显示8位
void DisLong(ulong alng, uchar s)
{
uchar sh = 0;
alng = DIV42(alng, 10000);
L21(alng) = Ndiv21(L21(alng), 100);
if (s)
{
sh = DisDigit(L1(alng) / 10, sh);
sh = DisDigit(L1(alng) % 10, sh);
}
sh = DisDigit(L2(alng) / 10, sh);
sh = DisDigit(L2(alng) % 10, sh);
L21(alng) = Ndiv21(L43(alng), 100);
sh = DisDigit(L1(alng) / 10, sh);
DisDigit(L1(alng) % 10, sh);
PutEngChar(L2(alng) / 10);
if (dDecNums == 1)
PutEngChar(CODE_POINT);
PutEngChar(L2(alng) % 10);
}
上面这段分位程序,执行速度比用/100000,/10000…,/10的方式快五倍以上
------------------------------------------------
//参数加
void ParaUp1()
{
if (!FlagParaWord) //单字节
{
if (i2Pointer == &iStartPhase) //参考相位循环加减
(*(uchar *)(i2Pointer))++;
else if (*(uchar *)(i2Pointer) < LOW_BYTE_OF_INT(i2ParaLimH))
if (i2Pointer == &iPumpDiaA || i2Pointer == &iPumpDiaB)
HIGH_BYTE_OF_INT(*i2Pointer) += 10;
else
HIGH_BYTE_OF_INT(*i2Pointer)++;
} //这个大括号不能少略,以示下面else的对应关系
else //双字节
if (*i2Pointer < i2ParaLimH)
(*i2Pointer)++;
FlagParaChanged = 1;
DisSetPara(); //参数更改后立即显示更新
}
------------------------------------------------
讨论汇编与c的问题,确实不可能得出一个绝对的结论,这一点我在工作中也感觉到了.不可否认,C程序,按照大路性的编写方式,其效率确实是个问题,但是对于超大的程序,汇编也是难以支持的.
我最近的一个项目,用的c51,程序行数达到了3500行,单片机是ADuC841,显示器件为240128点阵液晶屏,用来显示参数和波形曲线.
在反复的应用研究中,我琢磨出了一套变通的c语言,当然在c的支持范围之内.这套变通的c语言,连乘除法运算都用自己的专用子程序,它更加贴近汇编,虽然程序行数增加了,甚至是明显增加,但是编译后的代码量却大大减小,速度也很高,在必要的时候插入汇编混合编程,查看代码,和汇编的效果基本一样.
少举几例:
-----------------------------------------
部分宏:
#define I2(v) HIGH_BYTE_OF_INT(v)
#define I1(v) LOW_BYTE_OF_INT(v)
#define L4(v) HH_BYTE_OF_LONG(v)
#define L3(v) HL_BYTE_OF_LONG(v)
#define L2(v) LH_BYTE_OF_LONG(v)
#define L1(v) LL_BYTE_OF_LONG(v)
#define L43(v) HIGH_INT_OF_LONG(v)
#define L21(v) LOW_INT_OF_LONG(v)
#define L32(v) MID_INT_OF_LONG(v)
#define DIV42(u, v) Ndivide(LOW_INT_OF_LONG(u), HIGH_INT_OF_LONG(u), v)
-----------------------------------------
//显示累计参数
//s=0,显示6位,s=1,显示8位
void DisLong(ulong alng, uchar s)
{
uchar sh = 0;
alng = DIV42(alng, 10000);
L21(alng) = Ndiv21(L21(alng), 100);
if (s)
{
sh = DisDigit(L1(alng) / 10, sh);
sh = DisDigit(L1(alng) % 10, sh);
}
sh = DisDigit(L2(alng) / 10, sh);
sh = DisDigit(L2(alng) % 10, sh);
L21(alng) = Ndiv21(L43(alng), 100);
sh = DisDigit(L1(alng) / 10, sh);
DisDigit(L1(alng) % 10, sh);
PutEngChar(L2(alng) / 10);
if (dDecNums == 1)
PutEngChar(CODE_POINT);
PutEngChar(L2(alng) % 10);
}
上面这段分位程序,执行速度比用/100000,/10000…,/10的方式快五倍以上
------------------------------------------------
//参数加
void ParaUp1()
{
if (!FlagParaWord) //单字节
{
if (i2Pointer == &iStartPhase) //参考相位循环加减
(*(uchar *)(i2Pointer))++;
else if (*(uchar *)(i2Pointer) < LOW_BYTE_OF_INT(i2ParaLimH))
if (i2Pointer == &iPumpDiaA || i2Pointer == &iPumpDiaB)
HIGH_BYTE_OF_INT(*i2Pointer) += 10;
else
HIGH_BYTE_OF_INT(*i2Pointer)++;
} //这个大括号不能少略,以示下面else的对应关系
else //双字节
if (*i2Pointer < i2ParaLimH)
(*i2Pointer)++;
FlagParaChanged = 1;
DisSetPara(); //参数更改后立即显示更新
}
------------------------------------------------
0
回复
提示
@sdjufeng
谢谢,关于你说的问题,我基本是赞同的.讨论汇编与c的问题,确实不可能得出一个绝对的结论,这一点我在工作中也感觉到了.不可否认,C程序,按照大路性的编写方式,其效率确实是个问题,但是对于超大的程序,汇编也是难以支持的.我最近的一个项目,用的c51,程序行数达到了3500行,单片机是ADuC841,显示器件为240128点阵液晶屏,用来显示参数和波形曲线.在反复的应用研究中,我琢磨出了一套变通的c语言,当然在c的支持范围之内.这套变通的c语言,连乘除法运算都用自己的专用子程序,它更加贴近汇编,虽然程序行数增加了,甚至是明显增加,但是编译后的代码量却大大减小,速度也很高,在必要的时候插入汇编混合编程,查看代码,和汇编的效果基本一样.少举几例:-----------------------------------------部分宏:#defineI2(v)HIGH_BYTE_OF_INT(v)#defineI1(v)LOW_BYTE_OF_INT(v)#defineL4(v)HH_BYTE_OF_LONG(v)#defineL3(v)HL_BYTE_OF_LONG(v)#defineL2(v)LH_BYTE_OF_LONG(v)#defineL1(v)LL_BYTE_OF_LONG(v)#defineL43(v)HIGH_INT_OF_LONG(v)#defineL21(v)LOW_INT_OF_LONG(v)#defineL32(v)MID_INT_OF_LONG(v)#defineDIV42(u,v)Ndivide(LOW_INT_OF_LONG(u),HIGH_INT_OF_LONG(u),v)-----------------------------------------//显示累计参数//s=0,显示6位,s=1,显示8位voidDisLong(ulongalng,uchars){ ucharsh=0; alng=DIV42(alng,10000); L21(alng)=Ndiv21(L21(alng),100); if(s) { sh=DisDigit(L1(alng)/10,sh); sh=DisDigit(L1(alng)%10,sh); } sh=DisDigit(L2(alng)/10,sh); sh=DisDigit(L2(alng)%10,sh); L21(alng)=Ndiv21(L43(alng),100); sh=DisDigit(L1(alng)/10,sh); DisDigit(L1(alng)%10,sh); PutEngChar(L2(alng)/10); if(dDecNums==1) PutEngChar(CODE_POINT); PutEngChar(L2(alng)%10);}上面这段分位程序,执行速度比用/100000,/10000…,/10的方式快五倍以上------------------------------------------------//参数加voidParaUp1(){ if(!FlagParaWord) //单字节 { if(i2Pointer==&iStartPhase) //参考相位循环加减 (*(uchar*)(i2Pointer))++; elseif(*(uchar*)(i2Pointer)
支持
0
回复
提示