2022年PICC编程技巧 .pdf
《2022年PICC编程技巧 .pdf》由会员分享,可在线阅读,更多相关《2022年PICC编程技巧 .pdf(17页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、注:本组文章主要为网友CYPOK 的论著,由我们收集整理,特对CYPOK 表示感谢!1、和集成和集成:有自己的文本编辑器,不过是风格的,看来的工程师要专业冷到酷底了大家大可不必用它,如果你没什么癖好的话,你不会不用UltraEdit 吧?:建立你的工作目录:建议在盘根目录下建立一个以开头的文件夹做为工作目录因为你会发现它总是在你查找文件时候第一个跳入你眼中:调用(以版本为例子)启动在Project-Install Language Tool: Language Suite-hi-tech picc Tool Name -PICC Compiler (假如你的是默认安装的)选 Command-l
2、ine 最后上面这步只需要设定一次,除非你重新安装了:创建你的项目文件:(假如你实现用编辑好了一个叫的代码文件)Project-New Project-File Name-myc (假如我们把项目文件取名字叫)右边窗口当然要选择中你的工作目录然后:设定你的工作参数:Project-Edit Project 上面个栏目就用默认的,空的也就让它空着,无所谓的需要修改的是:Development Mode- 选择你的型号当然要选择Mplab SIM Simulator 让你可以用软件仿真Language Tool Suite-HI-TECH PICC 上面的步骤,你可能会遇见多个提示条,不要管它,一
3、路确定下面是编译器的选择项:双击 Project Files 窗口里面的,出现一个选择拦目命令很多,大家可以看文本编辑器里面的,里面有详细说明下面就推荐几个常用也是建议用的:Generate debug info 以及下面的项Produce assembler list file 就在它们后面打勾即可,其它的不要管,除非你有特殊要求:添加你的代码文件:当进行了前面几步后,按Add Node 找到文件就了:编译代码:最简单的一步:直接按下编译完后,会出现各种调试信息代码对应的汇编代码就是工作目录里面的,用打开可以看见详细的对比:其它,要是一切都没问题,那么你就可以调试和烧片了,和以往操作无异2、
4、如何从汇编转向PICC http:/ 电子发烧友 http:/ 电子技术论坛名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 1 页,共 17 页 - - - - - - - - - 首先要求你要有C 语言的基础。 PICC 不支持 C+,这对于习惯了C+的朋友还得翻翻C 语言的书。 C代码的头文件一定要有#include ,它是很多头文件的集合,C 编译器在pic.h 中根据你的芯片自动栽入相应的其它头文件。这点比汇编好用。载入的头文件中其实是声明芯片的寄存器和一些函数。顺便摘抄一个
5、片段:static volatile unsigned char TMR0 0 x01; static volatile unsigned char PCL 0 x02; static volatile unsigned char STATUS 0 x03; 可以看出和汇编的头文件中定义寄存器是差不多的。如下:TMR0 EQU 0X01 ;PCL EQU 0X02 ;STATUS EQU 0X03 ;都是把无聊的地址定义为大家公认的名字。一:怎么附值?如对 TMR0 附值,汇编中:MOVLW 200 ;MOVWF TMR0 ;当然得保证当前页面在0,不然会出错。C 语言:TMR0=200 ;/
6、无论在任何页面都不会出错。可以看出来C 是很直接了当的。并且最大好处是操作一个寄存器时候,不用考虑页面 的问题。一切由C 自动完成。二:怎么位操作?汇编中的位操作是很容易的。在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 者
7、是大同小异的,只是C 中不需要考虑页面的问题。三:内存分配问题:在汇编中定义一个内存是一件很小心的问题,要考虑太多的问题,稍微不注意就会出错。比如 16 位的运算等。用 C 就不需要考虑太多。下面给个例子:16位的除法( C 代码):INT X=5000 ;INT Y=1000 ;INT Z=X/Y ;而在汇编中则需要花太多精力。给一个小的 C 代码,用 RA0 控制一个 LED 闪烁:#include void main() http:/ 电子发烧友 http:/ 电子技术论坛名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名
8、师精心整理 - - - - - - - 第 2 页,共 17 页 - - - - - - - - - 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 寄存器操作都是先读取- 修改 -写入。上句的含义是程序先读 RA0 ,然后取反,最后把运算后的值重新写入RA0 ,这就实现了闪烁的功能。3、浅谈 PI
9、CC的位操作由于 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,bitno)(var &=(1bitno) 则上面的操作就是:char x;bitset(x,4) cha
10、r x;bitclr(x,5) * 但上述的方法有缺点,就是对每一位的含义不直观,最好是能在代码中能直观看出每一位代表的意思,这样就能提高编程效率,避免出错。如果我们想用X 的 0-2 位分别表示温度、电压、电流的BOOL 值可以如下:unsigned char x 0 x20; /* 象汇编那样把X 变量定义到一个固定内存中。*/ bit temperature (unsigned)&x*8+0; /*温度*/ bit voltage (unsigned)&x*8+1; /*电压*/ bit current (unsigned)&x*8+2; /* 电流 */ 这样定义后 X 的位就有一个形
11、象化的名字,不再是枯燥的1、2、3、4 等数字了。可以对X 全局修改,也可以对每一位进行操作:char=255; temperature=0; if(voltage). * 还有一个方法是用C 的 struct 结构来定义:如: struct cypok temperature:1; /*温度*/ voltage:1; /* 电压*/ current:1; /*电流*/ http:/ 电子发烧友 http:/ 电子技术论坛名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 3 页,共 1
12、7 页 - - - - - - - - - none:4; x 0 x20; 这样就可以用x.temperature=0; if(x.current). 等操作了。* 上面的方法在一些简单的设计中很有效,但对于复杂的设计中就比较吃力。如象在多路工业控制上。前端需要分别收集多路的多路信号,然后再设定控制多路的多路输出。如:有2 路控制,每一路的前端信号有温度、电压、电流。后端控制有电机、喇叭、继电器、LED 。如果用汇编来实现的话,是很头疼的事情,用 C 来实现是很轻松的事情,这里也涉及到一点C 的内存管理(其实C 的最大优点就是内存管理)。采用如下结构:union cypok struct o
13、ut motor:1; /* 电机*/ relay:1; /*继电器 */ speaker:1; /*喇叭*/ led1:1; /* 指示灯 */ led2:1; /*指示灯 */ out; struct in none:5; temperature:1; /*温度*/ voltage:1; /*电压*/ current:1; /*电流*/ in; char x; ; union cypok an1; union cypok an2; 上面的结构有什么好处呢?细分了信号的路an1 和 an2; 细分了每一路的信号的类型(是前端信号in 还是后端信号out): an1.in ; an1.out;
14、 an2.in; an2.out; 然后又细分了每一路信号的具体含义,如:an1.in.temperature; an1.out.motor; an2.in.voltage; an2.out.led2;等这样的结构很直观的在2 个内存中就表示了2 路信号。并且可以极其方便的扩充。如添加更多路的信号,只需要添加:http:/ 电子发烧友 http:/ 电子技术论坛名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 4 页,共 17 页 - - - - - - - - - union cyp
15、ok 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 100 bcf 3,5 bcf 3,6 movwf _dela
16、y l2 decfsz _delay goto l2 return 从代码可以看出总的指令是是303 个,其公式是8+3*(X-1 )。注意其中循环周期是X-1 是 99 个。这里总结的是 x 为 char 类型的循环体,当x 为 int 时候,其中受X 值的影响较大。建议设计一个char 类型的循环体,然后再用一个循环体来调用它,可以实现精确的长时间的延时。下面给出一个能精确控制延时的函数,此函数的汇编代码是最简洁、最能精确控制指令时间的:void delay(char x,char y) char z; do z=y; do;while(-z); while(-x); 其指令时间为: 7+
17、(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,则是 20003us,以此类推。有朋友不明白, 为什么不用 while(x-) 后减量, 来控制设定 X 值是多少就循环多少周期呢?现在看看编译它的汇编代码:bcf 3,5 bcf 3,6 movlw 10
18、 movwf _delay http:/ 电子发烧友 http:/ 电子技术论坛名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 5 页,共 17 页 - - - - - - - - - l2 decf _delay incfsz _delay,w goto l2 return 可以看出循环体中多了一条指令,不简洁。所以在PICC 中最好用前减量来控制循环体。再谈谈这样的语句:for(x=100;-x;);和 for(x=0;x100;x+); 从字面上看2 者意思一样,但可以通过汇编
19、查看代码。后者代码雍长,而前者就很好的汇编出了简洁的代码。所以在PICC 中最好用前者的形式来写循环体,好的C 编译器会自动把增量循环化为减量循环。因为这是由处理器硬件特性决定的。PICC 并不是一个很智能的C 编译器, 所以还是人脑才是第一的,掌握一些经验对写出高效,简洁的代码是有好处的。5、深入探讨之位操作一:用位操作来做一些标志位,也就是变量可以简单如下定义:bit a,b,c; 会自动安排一个内存,并在此内存中自动安排一位来对应a,b,c.由于我们只是用它们来简单的表示一些,信息,所以我们不需要详细的知道它们的地址位究竟是多少,只管拿来就用好了二:要是需要用一个地址固定的变量来位操作,
20、可以参照里面定义寄存器如:用内存来定义个位变量static volatile unsigned char myvar 0 x25; static volatile bit b7 (unsigned)&myvar*8+7; static volatile bit b6 (unsigned)&myvar*8+6; static volatile bit b5 (unsigned)&myvar*8+5; static volatile bit b4 (unsigned)&myvar*8+4; static volatile bit b3 (unsigned)&myvar*8+3; static vo
21、latile bit b2 (unsigned)&myvar*8+2; static volatile bit b1 (unsigned)&myvar*8+1; static volatile bit b0 (unsigned)&myvar*8+0; 这样即可以对操作,也可以对直接位操作但不好的是,此招在低档片子,如系列上可能会出问题还有就是表达起来复杂,你不觉得输入代码受累么?呵呵三:这也是一些常用手法:#define testbit(var, bit) (var) & (1 (bit)测试某一位,可以做运算#define setbit(var, bit) (var) |= (1 (bit)
22、把某一位置#define clrbit(var, bit) (var) &= (1 (bit)把某一位清付上一段代码,可以用调试观察#include #define testbit(var, bit) (var) & (1 (bit) #define setbit(var, bit) (var) |= (1 (bit) #define clrbit(var, bit) (var) &= (1 (bit) char a,b; void main() char myvar; myvar=0B10101010; http:/ 电子发烧友 http:/ 电子技术论坛名师资料总结 - - -精品资料欢迎
23、下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 6 页,共 17 页 - - - - - - - - - a=testbit(myvar,0); setbit(myvar,0); a=testbit(myvar,0); clrbit(myvar,5); b=testbit(myvar,5); if(!testbit(myvar,3) a=255; else a=100; while(1); 四:用标准的共用体来表示:#include union var unsigned char byte;struct unsigne
24、d b0:1, b1:1, b2:1, b3:1, b4:1, b5:1, b6:1, b7:1; bits; ; char a,b; void main() static union var myvar; myvar.byte=0B10101010; a=myvar.bits.b0; b=myvar.bits.b1; if(myvar.bits.b7) a=255; else a=100; while(1); 五:用指针转换来表示:#include typedef struct unsigned b0:1, b1:1, b2:1, b3:1, b4:1, b5:1, b6:1, b7:1;
25、bits;/先定义一个变量的位#define mybit0 (bits *)&myvar)-b0) /取 myvar 的地址( &myvar )强制转换成bits 类型的指针#define mybit1 (bits *)&myvar)-b1) #define mybit2 (bits *)&myvar)-b2) #define mybit3 (bits *)&myvar)-b3) #define mybit4 (bits *)&myvar)-b4) #define mybit5 (bits *)&myvar)-b5) #define mybit6 (bits *)&myvar)-b6) #de
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 2022年PICC编程技巧 2022 PICC 编程 技巧
限制150内