单片机c语言如何精通

Python012

单片机c语言如何精通,第1张

用过瑞萨R8C25的,和你分享一下心得:

1.C语言基础打扎实,指针这块一定要透彻,比如随便问一下,int a[3][4],请问a+2是第几号元素的地址,答案有a[0][2]和a[2][0]。很容易弄错的。

2.文件方面倒是不用看了,单片机不用C语言文件操作。

3.学一个单片机关键学的是它的说明书,像我们学的R8C25说明书是英文版的,当然后来搞到了一些中文的资料,学得很费劲,我学单片机的起步时51单片机,那个时候只用看看课本,背熟指令轻松考了个96,以为R8C25和51一样,信手拈来,后来遭受打击,我囧!51单片机不论是从功能还是指令都简单多了,而其他的商用单片机就不是那么简单,不是一本课本就可以搞定的。说这个是预防你由于以前有过单片机基础,以为就好学、简单,其实不然,作好心理准备,不简单!

4.多实践是真理,每一个说明书或者是学习资料上的例子都给它调通,不要放弃难的,越难的越不能放弃。

5.单片机挺有意思的,能做一些定时、LED、凤鸣、通信,能达到让君会心一笑,祝你学得开心哈哈!

由于单片机的性能同电脑的性能是天渊之别的,无论从空间资源上、内存资源、工作频率,都是无法

与之比较的。PC 机编程基本上不用考虑空间的占用、内存的占用的问题,最终目的就是实现功能就可以了。

对于单片机来说就截然不同了,一般的单片机的Flash 和Ram 的资源是以KB 来衡量的,可想而知,单片

机的资源是少得可怜,为此我们必须想法设法榨尽其所有资源,将它的性能发挥到最佳,程序设计时必须

遵循以下几点进行优化:

1. 使用尽量小的数据类型

能够使用字符型(char)定义的变量,就不要使用整型(int)变量来定义;能够使用整型变量定义的变

量就不要用长整型(long int),能不使用浮点型(float)变量就不要使用浮点型变量。当然,在定义变

量后不要超过变量的作用范围,如果超过变量的范围赋值,C 编译器并不报错,但程序运行结果却错了,

而且这样的错误很难发现。

2. 使用自加、自减指令

通常使用自加、自减指令和复合赋值表达式(如a-=1 及a+=1 等)都能够生成高质量的

程序代码,编译器通常都能够生成inc 和dec 之类的指令,而使用a=a+1 或a=a-1 之类

的指令,有很多C 编译器都会生成二到三个字节的指令。

3. 减少运算的强度

可以使用运算量小但功能相同的表达式替换原来复杂的的表达式。

(1) 求余运算

N= N %8 可以改为N = N &7

说明:位操作只需一个指令周期即可完成,而大部分的C 编译器的“%”运算均是调用子程序来

完成,代码长、执行速度慢。通常,只要求是求2n 方的余数,均可使用位操作的方法来代替。

(2) 平方运算

N=Pow(3,2) 可以改为N=3*3

说明:在有内置硬件乘法器的单片机中(如51 系列),乘法运算比求平方运算快得多, 因为浮点数

的求平方是通过调用子程序来实现的,乘法运算的子程序比平方运算的子程序代码短,执行速度快。

(3) 用位移代替乘法除法

N=M*8 可以改为N=M<<3

N=M/8 可以改为N=M>>3

说明:通常如果需要乘以或除以2n,都可以用移位的方法代替。如果乘以2n,都可以生成左移

的代码,而乘以其它的整数或除以任何数,均调用乘除法子程序。用移位的方法得到代码比调用乘除法子

程序生成的代码效率高。实际上,只要是乘以或除以一个整数,均可以用移位的方法得到结果。如N=M*9

可以改为N=(M<<3)+M;

(4) 自加自减的区别

例如我们平时使用的延时函数都是通过采用自加的方式来实现。

void DelayNms(UINT16 t)

{

UINT16 i,j

for(i=0i<ti++)

for(j=0i<1000j++)

}

可以改为

void DelayNms(UINT16 t)

{

UINT16 i,j

for(i=ti>=0i--)

for(j=1000i>=0j--)

}

说明:两个函数的延时效果相似,但几乎所有的C 编译对后一种函数生成的代码均比前一种代码少1~3

个字节,因为几乎所有的MCU 均有为0 转移的指令,采用后一种方式能够生成这类指令。

4. while 与do...while 的区别

void DelayNus(UINT16 t)

{

while(t--)

{

NOP()

}

}

可以改为

void DelayNus(UINT16 t)

{

do

{

NOP()

}while(--t)

}

说明:使用do…while 循环编译后生成的代码的长度短于while 循环。

5. register 关键字

void UARTPrintfString(INT8 *str)

{

while(*str &&str)

{

UARTSendByte(*str++)

}

}

可以改为

void UARTPrintfString(INT8 *str)

{

register INT8 *pstr=str

while(*pstr &&pstr)

{

UARTSendByte(*pstr++)

}

}

说明:在声明局部变量的时候可以使用register 关键字。这就使得编译器把变量放入一个多用途的寄存

器中,而不是在堆栈中,合理使用这种方法可以提高执行速度。函数调用越是频繁,越是可能提高代码的

速度,注意register 关键字只是建议编译器而已。

6. volatile 关键字

volatile 总是与优化有关,编译器有一种技术叫做数据流分析,分析程序中的变量在哪里赋值、在

哪里使用、在哪里失效,分析结果可以用于常量合并,常量传播等优化,进一步可以死代码消除。一般来

说,volatile 关键字只用在以下三种情况:

a) 中断服务函数中修改的供其它程序检测的变量需要加volatile(参考本书高级实验程序)

b) 多任务环境下各任务间共享的标志应该加volatile

c) 存储器映射的硬件寄存器通常也要加volatile 说明,因为每次对它的读写都可能由不同意义

总之,volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素

更改,比如:操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码

就不再进行优化,从而可以提供对特殊地址的稳定访问。