微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > PIC单片机 C编程技巧

PIC单片机 C编程技巧

时间:11-13 来源:互联网 点击:
六:五的方法还是烦琐,可以用粘贴符号的形式来简化它.
#i nclude
typedef struct {
unsigned b0:1, b1:1, b2:1, b3:1, b4:1, b5:1, b6:1, b7:1;
} bits;
#define _paste(a,b) a##b
#define bitof(var,num) (((bits *)&(var))->_paste(b,num))
char myvar;
char a,b;
void main(){
a=bitof(myvar,0);
b=bitof(myvar,1);
if(bitof(myvar,7))
a=255;
else
a=100;
while(1){;}
}
有 必要说说#define _paste(a,b) a##b 的意思:
此语句是粘贴符号的意思,表示把b 符号粘贴到a 符号之后.
例子 中是
a=bitof(myvar,0);--->(((bits
*)& (myvar))->_paste(b,0))--->(((bits *)&(var))->b0)
可以看出 来,_paste(b,0)的作用是把0 粘贴到了b 后面,成了b0 符号.
总结:C语言的优势是能直接对低层硬件操作,代码可以非常非常接近 汇编,上面几个例子的位操作代码
是100%的达到汇编的程度的.另一个优势是可读性高,代码灵活.上面的几个位操作方法任由你选,
你不必 担心会产生多余的代码量出来.
6、在PICC 中使用常数指针。
常数指针使用非常灵活,可以给编程带来很多便利。我测试过,PICC 也支持常数指针,并且也会自动
分页,实在是一大喜事。
定义一个指向8 位RAM 数据的常数指针(起始为0x00):
#define DBYTE ((unsigned char volatile *) 0)
定义一个指向16 位RAM 数据的常数指针(起始为0x00):
#define CWORD ((unsigned int volatile *) 0)
((unsigned char volatile *) 0)中的0 表示指向RAM 区域的起始地址,可以灵活修改它。
DBYTE[x]中的x 表示偏移量。
下面是一段代码1:
char a1,a2,a3,a4;
#define DBYTE ((unsigned char volatile *) 0)
void main(void){
long cc=0x89abcdef;
a1=DBYTE[0x24];
a2=DBYTE[0x25];
a3=DBYTE[0x26];
a4=DBYTE[0x27];
while(1);
}
2:
char a1,a2,a3,a4;
#define DBYTE ((unsigned char volatile *) 0)
void pp(char y){
a1=DBYTE[y++];
a2=DBYTE[y++];
a3=DBYTE[y++];
a4=DBYTE[y];
}
void main(void){
long cc=0x89abcdef;
char x;
x=&cc;
pp(x);
while(1);
}
3:
char a1,a2,a3,a4;
#define DBYTE ((unsigned char volatile *) 0)
void pp(char y){
a1=DBYTE[y++];
a2=DBYTE[y++];
a3=DBYTE[y++];
a4=DBYTE[y];
}
void main(void){
bank1 static long cc=0x89abcdef;
char x;
x=&cc;
pp(x);
while(1);
}
7、 PICC 关于unsigned 和 signed 的几个关键问题!
unsigned 是表示一个变量(或常数)是无符号类型。signed 表示有符号。它们表示数值范围不一样。
PICC 默认所有变量都是unsigned 类型的,哪怕你用了signed 变量。因为有符号运算比无符号运算耗资源,
而且MCU 运算一般不涉及有符号运算。在PICC 后面加上-SIGNED_CHAR 后缀可以告诉PICC 把signed
变量当作有符号处理。
在PICC 默认的无符号运算下看这样的语句:
char i;
for(i=7;i>=0;i--){
; //中间语句
}
这样的C 代码看上去是没有丁点错误的,但编译后,问题出现了:
movlw 7
movwf i
loop
// 中间语句
decf i //只是递减,没有判断语句!!!
goto loop
原因是当i 是0 时候,条件还成立,还得循环一次,直到i 成负1 条件才不成立。而PICC 在默认参数下是
不能判断负数的,所以编译过程出现问题。那么采用这 样的语句来验证:
char i;
i=7;
while(1){
i--;
//中间语句
if(i==0)break; //告诉PICC 以判断i 是否是0 来作为条件
}
编译后代码正确:
movlw 7
movwf i
loop
// 中间语句
decfsz i //判断是否是0
goto loop
再编译这样的语句:(同样循环8 次)
for(i=8;i>0;i--){
;
}
movlw 8
movwf i
loop
decfsz i //同上编译的代码。
goto loop
再次验证了刚才的分析。
在PICC 后面加上-SIGNED_CHAR 后缀,则第一个示例就正确编译出来了,更证明了刚才的分析是正确的。
代码如下:
movlw 7
movwf i
loop
//中间语句
decf i //递减
btfss i,7 //判断i 的7 位来判断是否为负数
goto l94
总结:在PICC 无符号编译环境下,对于递减的for 语句的条件判断语句不能是>=0 的形式。
最后谈谈PICC 的小窍门:
在PICC 默认的无符号环境下,对比如下代码:
a 语句:
char i,j[8];
i=7;
while(1){
j[i]=0;
i--;
if(i==0)break;
}
b 语句:
char i,j[8];
for(i=8;i>0;i--){
j[i-1]=0;
}
表面看上去, 一般会认为下面的代码编译后要大一点点,因为多了j[i-1]中的i-1。
其实编译后代码量是一摸一样的。
原因如下:
movlw 8 或7 //a 语句是7,b 语句是8
movf i
loop
//a 语句在这里提取i 给j 数组
//i 递减判断语句
//b 语句在这里提取i 给j 数组
goto loop
可以看出只是代码位置不同而已,并没添加代码量。b 语句同样达到了从7 到0 的循环。
小总结:对于递减到0 的for 语句推荐用>0 判断语句来实现,不会出现编译错误的问题,并且不会增加代
码量,尤其对于数组操作的方面。
另:对于PICC 或CCS,在其默认的无符号编译环境下,如果出现负数运算就会出问题。
如(-100)+50 等,所以在编写代码时候要特别小心!!!
8、 用PICC 写高效的位移操作。
在许多模拟串行通信中需要用位移操作。
以1-W

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top