一、怎么从汇编转向PICC
首先要求你要有C言语的根底。C代码的头文件必定要有#include,它是许多头文件的调集,C编译器在pic.h 中依据你的芯片主动载入相应的其它头文件。这点比汇编好用。载入的头文件中其实是声明芯片的寄存器和一些函数。
staTIc volaTIle unsigned char TMR0 @ 0x01;
staTIc volaTIle unsigned char PCL @ 0x02;
static volatile unsigned char STATUS @ 0x03;
能够看出和汇编的头文件中界说寄存器是差不多的。如下:
TMR0 EQU 0X01;
PCL EQU 0X02;
STATUS EQU 0X03;
都是把无聊的地址界说为咱们公认的姓名。
1、怎么赋值?
如对TMR0 附值,汇编中:
MOVLW 200;
MOVWF TMR0;
当然得确保当时页面在0,否则会犯错。
C言语:
TMR0=200;//不管在任何页面都不会犯错。
能够看出来C是很直接了当的。而且最大长处是操作一个寄存器时分,不必考虑页面的问题。全部由
C主动完结。
2、怎么位操作?
汇编中的位操作是很简略的。在C中更简略。C的头文件中现已对一切或许需求位操作的寄存器的每
一位都有界说称号:
PS1、PS2 、PSA 、T0SE、T0CS、INTEDG 、RBPU。能够对其直接进行运算和附值。
如:
RA0=0;
RA2=1;
在汇编中是:
BCF PORTA,0;
BSF PORTA,2;
能够看出2 者是迥然不同的,仅仅C 中不需求考虑页面的问题。
3、内存分配问题
在汇编中界说一个内存是一件很当心的问题,要考虑太多的问题,略微不留意就会犯错。比方16 位的
运算等。用C 就不需求考虑太多。下面给个比如:
16 位的除法(C 代码):
INT X=5000;
INT Y=1000;
INT Z=X/Y;
而在汇编中则需求花太多精力。
给一个小的C 代码,用RA0 操控一个LED 闪耀:
#include
void 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 寄存器操作都是先读取—-修正—-写入。上句的意义是程序先
读RA0,然后取反,最终把运算后的值从头写入RA0,这就完成了闪耀的功用。
二、浅谈PICC 的位操作
因为PIC 处理器对位操作是最高效的,所以把一些BOOL 变量放在一个内存的位中,既能够到达运算
速度快,又能够到达最大极限节约空间的意图。在C 中的位操作有多种挑选。
*********************************************
如:char x;x=x|0B00001000;
char x;x=x & 0B11011111;
把上面的变成公式则是:
#define bitset(var,bitno)(var |=1《#define bitclr(var,bitno)(var &=~(1《则上面的操作便是:
char x;bitset(x,4);
char x;bitclr (x,5);
*************************************************
但上述的办法有缺点,便是对每一位的意义不直观,最好是能在代码中能直观看出每一位代表的意思,
这样就能进步编程功率,防止犯错。假如咱们想用X 的0-2 位别离表明温度、电压、电流的BOOL 值能够如下:
unsigned char x @ 0x20;
bit temperature@ (unsigned)&x*8+0;
bit voltage@ (unsigned)&x*8+1;
bit current@ (unsigned)&x*8+2;
这样界说后X的位就有一个形象化的姓名,不再是单调的1、2、3、4 等数字了。能够对X 大局修正,也能够对每一位进行操作:
char=255;
temperature=0;
if(voltage)。。.。。.
*****************************************************************
还有一个办法是用C 的struct 结构来界说,如:
struct cypok{
temperature:1;
voltage:1;
current:1;
none:4;
}x @ 0x20;
这样就能够用
x.temperature=0;
if(x.current)。。.。
等操作了。
**********************************************************
上面的办法在一些简略的规划中很有用,但关于杂乱的规划中就比较费劲。如象在多路工业操控上。
前端需求别离搜集多路的多路信号,然后再设定操控多路的多路输出。如:有2 路操控,每一路的前端信
号有温度、电压、电流。后端操控有电机、喇叭、继电器、LED。假如用汇编来完成的话,是很头疼的事
情,用C 来完成是很轻松的工作,这儿也涉及到一点C 的内存办理(其实C 的最大长处便是内存办理)。
选用如下结构:
union cypok{
struct out{
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;
an2.in;
an2.out;
然后又细分了每一路信号的具体意义,如:
an1.in.temperature;
an1.out.motor;
an2.in.voltage;
an2.out.led2;等
这样的结构很直观的在2 个内存中就表明了2 路信号。而且能够极端便利的扩大。
如增加更多路的信号,只需求增加:
union cypok an3;
union cypok an4;
从上面就能够看出用C 的巨大长处。
三、PICC 之延时函数和循环体优化。
许多朋友说C 中不能准确操控延时时刻,不能象汇编那样直观。其实否则,对延时函数深化了解一下
就能规划出一个抱负的结构出来。一般的咱们都用for(x=100;–x;){;}此句同等与x=100;while(–x){;};
或for(x=0;x《100;x++){;}。
来写一个延时函数。
在这儿要特别留意:X=100,并不表明只运转100 个指令时刻就跳出循环。
能够看看编译后的汇编:
x=100;while(–x){;}
汇编后:
movlw 100
bcf 3,5
bcf 3,6
movwf _delay
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+(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
movwf _delay
l2
decf _delay
incfsz _delay,w
goto l2
return
能够看出循环体中多了一条指令,不简练。所以在PICC 中最好用前减量来操控循环体。
再谈谈这样的句子:
for(x=100;–x;){;}和for(x=0;x《100;x++){;}
从字面上看2 者意思相同,但能够经过汇编检查代码。后者代码雍长,而前者就很好的汇编出了简练的代
码。所以在PICC 中最好用前者的方式来写循环体,好的C 编译器会主动把增量循环化为减量循环。因为
这是由处理器硬件特性决议的。PICC 并不是一个很智能的C 编译器,所以仍是人脑才是榜首的,把握一些
经历对写出高效,简练的代码是有长处的。
四、深化探讨PICC之位操作
1、用位操作来做一些标志位,也便是BOOL变量.能够简略如下界说:
bit a,b,c;
PICC会主动组织一个内存,并在此内存中主动组织一位来对应a,b,c.因为咱们仅仅用它们来简略的
表明一些0,1信息,所以咱们不需求具体的知道它们的地址\位终究是多少,只管拿来就用好了。
2、要是需求用一个地址固定的变量来位操作,能够参照PIC.H里边界说寄存器。
如:用25H内存来界说8个位变量.
static volatile unsigned char myvar @ 0x25;
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 volatile bit b2 @ (unsigned)&myvar*8+2;
static volatile bit b1 @ (unsigned)&myvar*8+1;
static volatile bit b0 @ (unsigned)&myvar*8+0;
这样即能够对myvar操作,也能够对B0--B7直接位操作.
但欠好的是,此招在等级低片子,如C5X系列上或许会出问题.
还有便是表达起来杂乱,你不觉得输入代码累么?呵呵
3、这也是一些常用方法
#definetestbit(var, bit)((var) & (1 《《(bit)))
//测验某一位,能够做BOOL运算
#definesetbit(var, bit)((var) |= (1 《《 (bit)))//把某一方位1
#defineclrbit(var, bit)((var) &= ~(1 《《 (bit)))//把某一位清0
附上一段代码,能够用MPLAB调试调查
#i nclude “pic.h”
#definetestbit(var, bit)((var) & (1 《《(bit)))
#definesetbit(var, bit)((var) |= (1 《《 (bit)))
#defineclrbit(var, bit)((var) &= ~(1 《《 (bit)))
char a,b;
void main()