单片机程序之高效的位移操作

时间:13-07-07 栏目:单片机, 编程之美 作者:JH单片机 评论:0 点击: 3,577 次


文章目录

近来,在制作一些家用的小电器,又在收集、学习智能家居和物联网方面的知识。紧接着网站又搬了一个新家,将近一个月没有码字了。这些好像都跟阿浩的做事效率有关,而这篇文章也是说效率的,但并不是说阿浩的效率如何的低,而是怎样让单片机执行更高效的代码。

说到这里,有人或许会反驳我:用汇编不就行了嘛?答案是肯定的。用汇编写程序,产生的代码精短,执行效率高,无可置疑。但是当你要写一个大型的程序,而对执行效率要求要高的话,选择C语言来写,具有优势。这种优势,就不在这大费口舌了。而下面介绍的几个方法,对你写出高效的C程序有一些帮助。

高效代码

首先,必须知道的,一个C语言程序,最终是要编译成机器码给单片机执行的。也就是说,C语言将被编译器,“翻译”成汇编代码,然后编译成单片机最终的代码。以上理解了就好办,我们只需要让C语言写的代码,“翻译”成汇编代码会,代码行减少了,就说这种写法更高效。

高效的位移操作

我们在许多模拟串行通信中需要用到移位操作。
例如,IIC、SPI,1-Wire总线等等

这里以1-Wire总线读一个字节为例

unsigned char read_byte(void)
{
unsigned char i;
unsigned char value = 0;
for (i = 0; i < 8; i++)
{
   if(read_bit())
   value| = 0 x 01< delay(10); //等待总线时隙
}
return(value);
}

这段代码是正确的,但编译后执行效率并不高。
而其实只要深入了解C和汇编之间的关系,写出高效的C代码,既有C的便利,又有汇编的效率。

下面对代码进行修改剖析:
1.for(i=0;i 解释一下:因为CPU判断一个数是否为0,只需要一条指令。比判断一个数多大要执行得快(需要3个指令)。

2.value|=0x01<>=1; //先右移一位,value最高位一定是0

if(read_bit()){
  value|=0x80; //判断总线状态,如果是高,就把value的最高位置1
}

这样写出来的代码变得极其高效,编译后基本就是汇编级的代码了。

位移操作,让计算也高效

使用单片机AD采集信号方面,通常做法是连续采集N次,然后求平均值。
一般为了MCU计算更为“方便”,采集次数推荐用8,16,32,64,128,256等次数,你懂的,这些数比较特殊。
这里以采样128次,然后求平均值为例。注:sampling()为外部采样函数。

unsigned int total;
unsigned char i,val;
for(i=0;i<128;i++)
{
  total+=sampling();
}
val=total/128;

以上代码是通常的写法,但是效率并不高,浪费资源。

改造进行
1.首先分析128这个数是0B10000000,发现其实第7位是1,其他位都为0,所以我们就可以判断第7位的状态来判断128次采样是否到了。
2.val=total/128 运用了除法运算,浪费资源,完全可以用右移的方法来代替(虽然有些编译器会将此类运算转换为位移运算,但写成移位的铁定没错)。
val=total/128等同于 val=(unsigned char)(total>>7);
但这并不完全高效,还再优化一下:
total>>7 还可以变通成(total<<1)>>8,先左移动一位,再右移动8位,不就成了右移7位了么? 因为位移1,4,8位的操作只需要一个指令。

unsigned int total;
unsigned char i=0
unsigned char val;
while(!(i&0x80)){  //判断 i 第7位,只需要一个指令。
  total+=sampling();
  i++;
}
val=(unsigned char)((total<<1)>>8);  //几个指令就代替了几十个指令的除法运算

编译后的代码量居然可以减少一半,而运算速度可以提高几倍,再回头,就可以理解为什么采用次数要用推荐的一些特殊值了。

 
关于本文作者

爱数电,爱模电;爱单片机,爱嵌入式;爱EDA,也爱DSP; 爱Altium Designer,也爱PCB;爱生活,同时也爱微博…… 一个自动化专业的学生,与志同道合者学习交流!!!

QQ 号码:594420349
腾讯微博:http://t.qq.com/kevin_753

项目合作