×
单片机 > 单片机程序设计 > 详情

单片机C语言的位操作

发布时间:2020-06-18 发布时间:
|

由于PIC处理器对位操作是最高效的,所以把一些BOOL变量放在一个内存的位中,既可以达到运算速度快,又可以达到最大限度节省空间的目的。
在C中的位操作有多种选择。

*********************************************

如:char x;x=x|0B00001000;         /*对X的4位置1。*/

char x;x=x&0B11011111;               /*对X的5位清0。*/
把上面的变成公式则是:
#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;                           /*象汇编那样把X变量定义到一个固定内存中。*/
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每日一贴。(初谈如何从汇编转向PICC)  
  
小弟不才,特抛砖引玉,与大家共勉。
聊聊如何从汇编转向PICC。
因为HIDE-TECH PICC破解版很多,所以HIDE PICC有比其它PICC有更多的用户,虽然它的编译效率不是最好。最好的是CCS,但没破戒版。。。,不过用HIDE PICC精心安排函数一样可以获得很高的编译效率,还是人脑是第一的。


当然要求你要有C语言的基础。PICC不支持C++,这对于习惯了C++的朋友还得翻翻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;
都是把无聊的地址定义为大家公认的名字。


一:怎么附值?
如对TMR0附值:
汇编中:MOVLW 200;
MOVWF TMR0;当然得保证当前页面在0,不然会出错。
C语言:TMR0=200;//无论在任何页面都不会出错。
可以看出来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者是大同小异的,只是C中不需要考虑页面的问题。


三:内存分配问题:
在汇编中定义一个内存是一件很小心的问题,要考虑太多的问题,稍微不注意就会出错。比如16位的运算等。用C就不需要考虑太多。
下面给个例子:
16位的除法(C代码):
INT X=5000;
INT Y=1000;
INT Z=X/Y;
而在汇编中则需要花太多精力。
给一个小的C代码,用RA0控制一个LED闪烁:
#include
void main(){
int x;  
CMCON=0B111;   file://关掉A口比较器,要是有比较器功能的话。
ADCON1=0B110;          file://关掉A/D功能,要是有A/D功能的话。
TRISA=0;              file://A口全为输出。
loop:RA0=!RA0;           
for(x=60000;--x;){;}           file://延时
goto loop;
}
说说RA0=!RA0的意思:PIC对PORT寄存器操作都是先读取----修改----写入。

上句的含义是程序先读RA0,然后取反,最后把运算后的值重新写入RA0,这就实现了闪烁的功能。

(一点经验)如何有效的实时控制LED闪烁。  
  
在很多设计中需要有精彩而实用的LED闪烁来表示设备工作正常与否和工作状态。


在一些实时性要求不高的设计中可以用插入延时来控制LED闪烁。


它的缺点现而易见:1:LED闪烁方式反映慢。2:在延时过程不能干其它工作(中断除外),浪费了资源。3:代码雍长,真正控制LED就几个个指令,其它的延时代码占了99%的空间。


如果用TMR1或TMR2来做一个时钟,上面的种种缺点就可以避免,使得你可以腾出大量的时间做更有效的工作。



『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
8051单片机的函数发生器的设计