ImageVerifierCode 换一换
格式:DOCX , 页数:40 ,大小:34.49KB ,
资源ID:30519534      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/30519534.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(PICC 代码优化技巧.docx)为本站会员(b****8)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

PICC 代码优化技巧.docx

1、PICC 代码优化技巧常用优化技巧: 要减少bank切换,把在不同bank里的变量放到一起。 在初始化代码里,在程序的开头,注意初始化的顺序一开始所有的变量放在bank0,然后放bank1,接着bank2,bank3。 在初始化代码里可能有些变量不需要初始化。 在可能的地方,掉换操作数的顺序来使编译器避免多余使用W寄存器或临时位置。 对于数学运算,表达式里的变量尽量要在同一个bank里,以避免过多的bank切换。 如果可能,尽可能地采用字节byte运算代替字word运算。 如果可能,对于数组元素的访问尽量采用指针而不是用下标索引。注意在一个小的循环里使用指针时,管理循环多出的代码抵销了使用指针

2、节省下来的代码,所以使用两种方法差不多。 一系列的:ifelse ifelse if . 通常会比case语句产生更小的代码。 在switch case里,改变常量为有顺序的数据,不要有间隔。 依靠bank切换必需的:Depending on the bank switching required:var = value1;if (!flag)var = value2;产生更理想的代码: if (flag)var = value1;elsevar = value2;只是要确认在该代码执行时不要在中断里使用这个var。 清零,递增,以及递减一个字节byte是单指令的操作。给一个字节赋值需要两条指

3、令(value - W, and W - byte). 只要可能,尽量使用bits代替unsigned chars。置位Bit sets,清零clears,以及位测试跳转等都是单条指令。 因为不能在函数里申明位变量,你可以全局声明位变量。 调用函数会产生一些管理代码。尝试着用一些宏marcro代替你的一些小一点的函数。 如果堆栈空间允许,大块的重复代码应该由函数及函数调用来替代。 当前逻辑的优化。我还只是刚接到一个固定要求的项目,于是我尝试着把代码写得非常灵活。当我快接近项目结束时,我发现一些弹性代码不再需要了,这样可以删除它来节省代码。优化提示1:Signed vs. Unsigned变量

4、比较使用signed和unsigned变量的汇编代码,你会发现在比较有符号signed变量时会多出一些指令。结论1: 尽可能地使用unsigned的int或char。优化提示2: 基于字节Byte的循环Loops这里有两块代码,它们做的完全是同样的事情。但是其中一个要完成得快25,并且使用更小的RAM空间,你能挑出是哪一个吗?unsigned char i;for(i=0;i250;i+) do_func(); /executes do_func() 250 times, in 3.25msfor(i=250;i!=0;i-) do_func(); /executes do_func() 25

5、0 times, in 2.5ms要找出这个,我们来看一下产生的汇编代码for(i=0;i8) #define lobyte(x) (unsigned char)(x&0xff)/the optimizer takes care of using the hi/lo correct byte of integer Loops to avoid with timeouts: 320000 to 380000 cycles for 20000 iterations.for(timeout=0;timeout20000;timeout+) do_func(); /380011 cyclesfor(t

6、imeout=20000;timeout!=0;timeout-) do_func(); /320011 cycles | Best loop for a timeout: 295000 cycles for 20000 iterations./we want to execute do_func() approx. 20000 times before timing outtimeout=(20000/0x100)*0x100; /keeps lobyte(timeout)=0, which speeds up assignmentsfor(;hibyte(timeout)!=0;timeo

7、ut-) do_func(); /295704 cyclesNotice the features of the loop shown above. 1. 它在每个循环里只测试整型数的高位字节。2. 它检查这个字节是否到零,所以很快。3. 当初始化timeout变量时,它又一个好处是:汇编代码清零一个ram变量只要一条指令,而赋值则需要两条指令。结论3: 尽可能地采用递减到零的循环,因为检查ram变量是否为零更简单。 在延时循环里只查询整型数的高位字节,这要快一些。 给整型数赋值时,对ram变量清零要比赋一个数值要快一些。 优化提示4: 使用内部定时器的Timeout定时循环当然,使用芯片片内

8、定时器并检查中断的方式是最快的定时循环。它通常会比用延时循环快70左右。/set up tmr0 to set flag T0IF high when it rolls overwhile(RA0=0 & !T0IF); /wait until port goes high结论4: 尽可能地使用内建的定时器及中断标志。 优化提示5: Case 语句慢而且效率低c=getch();switch(c)case A:do something;break;case H:do something;break;case Z:do something;break; 快且高效率c=getch();switch

9、(c)case 0:do something;break;case 1:do something;break;case 2:do something;break;Hi-Tech C的优化器会尽可能地把switch语句变成计算偏移的goto。结论5: 尽可能地在case语句里使用连续的数字。 优化提示6: Hi-Tech C里的除法如果你使用Hi-Tech C,在你程序的任何位置有任何数学除法的运算,就将会使用到bank0里13到23个字节的空间,以及一些EPROM/Flash程序空间。尽管变量不在bank0,这一样会发生。OccurrenceAny mathematical division

10、at all in the entire program using a variable of type long, even if all variables do not reside in bank0.RAM usage23 bytes in bank0ROM/flash usagelarge, it has to include ldiv routinesFix/ExplanationUse combinations of bit shifts ie: x=x*6 is replaced by x1=x;x2=x;x=x12 + x2Install Language Tool:Lan

11、guage Suite-hi-tech piccTool Name -PICC CompilerExecutable -c:hi-picinpicc.exe (假如你的是默认安装的)选Command-line最后上面这步只需要设定一次,除非你重新安装了:创建你的项目文件:(假如你实现用编辑好了一个叫的代码文件)Project-New Project-File Name-myc (假如我们把项目文件取名字叫)右边窗口当然要选择中你的工作目录然后:设定你的工作参数:Project-Edit Project上面个栏目就用默认的,空的也就让它空着,无所谓的需要修改的是:Development Mode

12、-选择你的型号当然要选择Mplab SIM Simulator让你可以用软件仿真Language Tool Suite-HI-TECH PICC上面的步骤,你可能会遇见多个提示条,不要管它,一路确定下面是编译器的选择项:双击Project Files 窗口里面的,出现一个选择拦目命令很多,大家可以看文本编辑器里面的,里面有详细说明下面就推荐几个常用也是建议用的:Generate debug info 以及下面的项Produce assembler list file就在它们后面打勾即可,其它的不要管,除非你有特殊要求:添加你的代码文件:当进行了前面几步后,按Add Node 找到文件就了:编译

13、代码:最简单的一步:直接按下编译完后,会出现各种调试信息代码对应的汇编代码就是工作目录里面的,用打开可以看见详细的对比:其它,要是一切都没问题,那么你就可以调试和烧片了,和以往操作无异2、如何从汇编转向PICC首先要求你要有C 语言的基础。PICC 不支持C+,这对于习惯了C+的朋友还得翻翻C 语言的书。C代码的头文件一定要有#include,它是很多头文件的集合,C 编译器在pic.h 中根据你的芯片自动栽入相应的其它头文件。这点比汇编好用。载入的头文件中其实是声明芯片的寄存器和一些函数。顺便摘抄一个片段:static volatile unsigned char TMR0 0x01;sta

14、tic volatile unsigned char PCL 0x02;static volatile unsigned char STATUS 0x03;可以看出和汇编的头文件中定义寄存器是差不多的。如下:TMR0 EQU 0X01;PCL EQU 0X02;STATUS EQU 0X03;都是把无聊的地址定义为大家公认的名字。一:怎么附值?如对TMR0 附值,汇编中:MOVLW 200;MOVWF TMR0;当然得保证当前页面在0,不然会出错。C 语言:TMR0=200;/无论在任何页面都不会出错。可以看出来C 是很直接了当的。并且最大好处是操作一个寄存器时候,不用考虑页面的问题。一切由C

15、 自动完成。二:怎么位操作?汇编中的位操作是很容易的。在C 中更简单。C 的头文件中已经对所有可能需要位操作的寄存器的每一位都有定义名称:如:PORTA 的每一个I/O 口定义为:RA0、RA1、RA2。RA7。OPTION 的每一位定义为:PS0、PS1、PS2 、PSA 、T0SE、T0CS、INTEDG 、RBPU。可以对其直接进行运算和附值。如:RA0=0;RA2=1;在汇编中是:BCF PORTA,0;BSF PORTA,2;可以看出2 者是大同小异的,只是C 中不需要考虑页面的问题。三:内存分配问题:在汇编中定义一个内存是一件很小心的问题,要考虑太多的问题,稍微不注意就会出错。比如

16、16 位的运算等。用C 就不需要考虑太多。下面给个例子:16 位的除法(C 代码):INT X=5000;INT Y=1000;INT Z=X/Y;而在汇编中则需要花太多精力。给一个小的C 代码,用RA0 控制一个LED 闪烁:#includevoid main()int x;CMCON=0B111; /掉A 口比较器,要是有比较器功能的话。ADCON1=0B110; /掉A/D 功能,要是有A/D 功能的话。TRISA=0; /RA 口全为输出。loop:RA0=!RA0;for(x=60000;-x;); /延时goto loop;说说RA0=!RA0 的意思:PIC 对PORT 寄存器操

17、作都是先读取-修改-写入。上句的含义是程序先读RA0,然后取反,最后把运算后的值重新写入RA0,这就实现了闪烁的功能。3、浅谈PICC 的位操作由于PIC 处理器对位操作是最高效的,所以把一些BOOL 变量放在一个内存的位中,既可以达到运算速度快,又可以达到最大限度节省空间的目的。在C 中的位操作有多种选择。*如:char x;x=x|0B00001000; /*对X 的4 位置1。*/char x;x=x&0B11011111; /*对X 的5 位清0。*/把上面的变成公式则是:#define bitset(var,bitno)(var |=1bitno)#define bitclr(var

18、,bitno)(var &=(1bitno)则上面的操作就是:char x;bitset(x,4)char x;bitclr(x,5)*但上述的方法有缺点,就是对每一位的含义不直观,最好是能在代码中能直观看出每一位代表的意思,这样就能提高编程效率,避免出错。如果我们想用X 的0-2 位分别表示温度、电压、电流的BOOL 值可以如下:unsigned char x 0x20; /*象汇编那样把X 变量定义到一个固定内存中。*/bit temperature (unsigned)&x*8+0; /*温度*/bit voltage (unsigned)&x*8+1; /*电压*/bit curren

19、t (unsigned)&x*8+2; /*电流 */这样定义后X 的位就有一个形象化的名字,不再是枯燥的1、2、3、4 等数字了。可以对X 全局修改,也可以对每一位进行操作:char=255;temperature=0;if(voltage).*还有一个方法是用C 的struct 结构来定义:如:struct cypoktemperature:1; /*温度*/voltage:1; /*电压*/current:1; /*电流*/none:4;x 0x20;这样就可以用x.temperature=0;if(x.current).等操作了。*上面的方法在一些简单的设计中很有效,但对于复杂的设计中

20、就比较吃力。如象在多路工业控制上。前端需要分别收集多路的多路信号,然后再设定控制多路的多路输出。如:有2 路控制,每一路的前端信号有温度、电压、电流。后端控制有电机、喇叭、继电器、LED。如果用汇编来实现的话,是很头疼的事情,用C 来实现是很轻松的事情,这里也涉及到一点C 的内存管理(其实C 的最大优点就是内存管理)。采用如下结构:union cypokstruct outmotor:1; /*电机*/relay:1; /*继电器*/speaker:1; /*喇叭*/led1:1; /*指示灯*/led2:1; /*指示灯*/out;struct innone:5;temperature:1;

21、 /*温度*/voltage:1; /*电压*/current:1; /*电流*/in;char x;union cypok an1;union cypok an2;上面的结构有什么好处呢?细分了信号的路an1 和an2;细分了每一路的信号的类型(是前端信号in 还是后端信号out):an1.in ;an1.out;an2.in;an2.out;然后又细分了每一路信号的具体含义,如:an1.in.temperature;an1.out.motor;an2.in.voltage;an2.out.led2;等这样的结构很直观的在2 个内存中就表示了2 路信号。并且可以极其方便的扩充。如添加更多路的

22、信号,只需要添加:union cypok an3;union cypok an4;从上面就可以看出用C 的巨大好处4、PICC 之延时函数和循环体优化。很多朋友说C 中不能精确控制延时时间,不能象汇编那样直观。其实不然,对延时函数深入了解一下就能设计出一个理想的框价出来。一般的我们都用for(x=100;-x;);此句等同与x=100;while(-x);或for(x=0;x100;x+);。来写一个延时函数。在这里要特别注意:X=100,并不表示只运行100 个指令时间就跳出循环。可以看看编译后的汇编:x=100;while(-x);汇编后:movlw 100bcf 3,5bcf 3,6mo

23、vwf _delayl2 decfsz _delaygoto l2return从代码可以看出总的指令是是303 个,其公式是8+3*(X-1)。注意其中循环周期是X-1 是99 个。这里总结的是x 为char 类型的循环体,当x 为int 时候,其中受X 值的影响较大。建议设计一个char 类型的循环体,然后再用一个循环体来调用它,可以实现精确的长时间的延时。下面给出一个能精确控制延时的函数,此函数的汇编代码是最简洁、最能精确控制指令时间的:void delay(char x,char y)char z;doz=y;do;while(-z);while(-x);其指令时间为:7+(3*(Y-1)+7)*(X-1)如果再加上函数调用的call 指令、页面设定、传递参数花掉的7 个指令。则是:14+(3*(Y-1)+7)*(X-1)。如果要求不是特别严格的延时,可以用这个函数:void delay()unsigned int d=1000;while(-d);此函数在4M 晶体下产生10003us 的延时,也就是10MS。如果把D 改成2000,则是20003u

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1