单片机C语言的位操作

以下内容只有回复后才可以浏览PICC每日一贴(浅谈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 |=1<<bitno)#define bitclr(var,bitno)(var &=~(1<<bitno))则上面的操作就是: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; }; u nion 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<pic.h>它是很多头文件的集合,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<pic.h>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来做一个时钟,上面的种种缺点就可以避免,使得你可以腾出大量的时间做更有效的工作。

下面是用TMR1作时钟的C代码(RB1、RB2、RB3控制LED)示例:void set_tmr1(){TMR1L=0xdc;TMR1H=0xb; /*设定初值3036*/T1CON=0B10001; /*设定TMR1 0.125s溢出一次*/}void interrupt time(){if(TMR1IF){T1CON=0B10000; /*关闭TMR1*/TMR1L=0xdc;TMR1H=0xb; /*TMR1设初值*/T1CON=0B10001; /*从新设分频比,打开TMR1*/if(s++>8){ /*每S清0*/s=0;if(ss++>60)/*每分钟清0*/ss=0;}TMR1IF=0;return;}unsigned char s; /*每0.125S累加1*/unsigned char ss; /*每1秒累加1*/void main(){set_tmr1();........; /*设定I/O口,开TMR1中断*/while(1){if(...) /*判断闪烁方式语句,下同*/RB1=(bit)(s>4); /*每1s闪烁一次,占空比50%(调节>后面值可以改变)*/if(...)RB2=(bit)(!ss); /*每1分钟闪烁一次,亮1秒,熄59秒*/if(...)RB3=(bit)(s==0 || s==2 || s== 4 || s== 6); /*每0.25S闪烁一次*/.........; /*其它工作*/}}这样的框架对于基于要求实时性高的软件查询的程序是很有效的。

在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]; a 4=DBYTE[0x27]; while(1); }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); }关于BOOL量的一点应用。

合集下载

单片机 C语言开发 sbit使用方法

单片机 C语言开发 sbit使用方法

单片机C语音开发sbit使用方法··1.bit和sbit都是C51扩展的变量类型。

bit和int char之类的差不多,只不过char=8位, bit=1位而已。

都是变量,编译器在编译过程中分配地址。

除非你指定,否则这个地址是随机的。

这个地址是整个可寻址空间,RAM+FLASH+扩展空间。

bit只有0和1两种值,意义有点像Windows下VC中的BOOL。

sbit是对应可位寻址空间的一个位,可位寻址区:20H~2FH。

一旦用了sbi xxx = REGE^6这样的定义,这个sbit量就确定地址了。

sbit大部分是用在寄存器中的,方便对寄存器的某位进行操作的。

2.bit位标量bit位标量是C51编译器的一种扩充数据类型,利用它可定义一个位标量,但不能定义位指针,也不能定义位数组。

它的值是一个二进制位,不是0就是1,类似一些高级语言中的Boolean类型中的True和False。

3.sfr特殊功能寄存器sfr也是一种扩充数据类型,点用一个内存单元,值域为0~255。

利用它可以访问51单片机内部的所有特殊功能寄存器。

如用sfr P1 = 0x90这一句定P1为P1端口在片内的寄存器,在后面的语句中我们用以用P1 = 255(对P1端口的所有引脚置高电平)之类的语句来操作特殊功能寄存器。

sfr P1 = 0x90; //定义P1 I/O 口,其地址90Hsfr 关键定后面是一个要定义的名字,可任意选取,但要符合标识符的命名规则,名字最好有一定的含义如P1 口可以用P1 为名,这样程序会变的好读好多.等号后面必须是常数,不允许有带运算符的表达式,而且该常数必须在特殊功能寄存器的地址范围之内(80H-FFH),具体可查看附录中的相关表.sfr 是定义8 位的特殊功能寄存器而sfr16 则是用来定义16 位特殊功能寄存器,如8052 的T2 定时器,可以定义为:sfr16 T2 = 0xCC; //这里定义8052 定时器2,地址为T2L=CCH,T2H=CDH用sfr16 定义16 位特殊功能寄存器时,等号后面是它的低位地址,高位地址一定要位于物理低位地址之上.注意的是不能用于定时器0 和1 的定义.sbit 可定义可位寻址对象.如访问特殊功能寄存器中的某位.其实这样应用是经常要用的如要访问P1 口中的第2 个引脚P1.1.我们可以照以下的方法去定义:(1) sbit 位变量名=位地址sbit P1_1 = Ox91;这样是把位的绝对地址赋给位变量.同sfr 一样sbit 的位地址必须位于80H-FFH 之间. (2) sbit 位变量名=特殊功能寄存器名^位位置sft P1 = 0x90;sbit P1_1 = P1 ^ 1; //先定义一个特殊功能寄存器名再指定位变量名所在的位置,当可寻址位位于特殊功能寄存器中时可采用这种方法(3) sbit 位变量名=字节地址^位位置sbit P1_1 = 0x90 ^ 1;这种方法其实和2 是一样的,只是把特殊功能寄存器的位址直接用常数表示. 在C51存储器类型中提供有一个bdata 的存储器类型,这个是指可位寻址的数据存储器,位于单片机的可位寻址区中,可以将要求可位录址的数据定义为bdata,如:unsigned char bdata ib; //在可位录址区定义ucsigned char 类型的变量ibint bdata ab[2]; //在可位寻址区定义数组ab[2],这些也称为可寻址位对象sbit ib7=ib^7 //用关键字sbit 定义位变量来独立访问可寻址位对象的其中一位sbit ab12=ab[1]^12;操作符"^"后面的位位置的最大值取决于指定的基址类型,char0-7,int0-15,long0-31.sfr 并标准C 语言的关键字,而是Keil 为能直接访问80C51 中的SFR 而提供了一个新的关键词,其用法是:sfrt 变量名=地址值。

单片机C语言编程学习

单片机C语言编程学习

单片机C 语言编程学习一、概述在一个集成电路芯片上集成微处理器、存储器、I/0接口电路,从而构成了单片机。

Intel公司推出了MCS-51系列单片机:集成8位CPU、4K字节ROM、128字节的RAM、4个8位并口、一个全双工串行口、2个16位定时器/计数器。

寻址范围64K,并有控制功能较强的布尔处理器。

二、预备知识<一>、电平特性1、数字电路中只有两种电平:高和低(本课程中)定义单片机为TTL电平:高+5V 低0V2、RS232电平:计算机的串口(-9V~15V) 高-12V 低+12V (+3V~+15V)所以计算机与单片机之间通讯时需要加电平转换芯片max232。

<二>、二进制与十六进制的表示及转换1、二进制:数字电路中的两种电平特性决定了它:0 0 6 110 12 11001 1 7 111 13 11012 10 8 1000 14 11103 11 9 1001 15 11114 100 10 1010 16 100005 101 11 10112、十六进:是二进制的简短表示形式。

十进制中的0-15分别表示为十六进制的0、1、2、3、4、5、6、7、8、9、A、B、C、D、E、F3、熟练掌握二进制与十六进制之间的转换。

规律:一般把四个二进制数放在一起转换成一个十六进制数,转换时先把二进制数转换成十进制数,再把十进制数转换成十六进制数。

如:0001B -> 1 -> 1HB表示为二进制,H为十六进制1001B -> 9 -> 9H1010B -> 10 -> AH0010 1100 -> 44 -> 2CH4、二进制各种对制关系:<三>、二进制数的逻辑运算1. “与”运算“与”运算是实现“必须都有,否则就没有”这种逻辑关系的一种运算。

运算符为“· ”, 其运算规则如下:0·0=0, 0·1=1·0=0, 1·1=12. “或”运算“或”运算是实现“只要其中之一有,就有”这种逻辑关系的一种运算, 其运算符为“+”。

单片机的C语言中位操作用法

单片机的C语言中位操作用法

单片机的C语言中位操作用法作者:郭天祥来源:转自更新时间:2008-12-4 21:50:22 在对单处机进行编程的过程中,对位的操作是经常遇到的。

C51对位的操控能力是非常强大的。

从这一点上,就可以看出C不光具有高级语言的灵活性,又有低级语言贴近硬件的特点。

这也是在各个领域中都可以看到C的重要原因。

在这一节中将详细讲解C51中的位操作及其应用。

1、位运算符C51提供了几种位操作符,如下表所示:运算符含义运算符含义& 按位与~ 取反| 按位或<< 左移^ 按位异或>> 右移1)“按位与”运算符(&)参加运算的两个数据,按二进位进行“与”运算。

原则是全1为1,有0为0,即:0&0=0; 0&1=0; 1&0=0; 1&1=1;如下例:a=5&3; //a=(0b 0101) & (0b 0011) =0b 0001 =1那么如果参加运算的两个数为负数,又该如何算呢?会以其补码形式表示的二进制数来进行与运算。

a=-5&-3; //a=(0b 1011) & (0b1101) =0b 1001 =-7在实际的应用中与操作经常被用于实现特定的功能:1.清零“按位与”通常被用来使变量中的某一位清零。

如下例:a=0xfe; //a=0b 11111110a=a&0x55;//使变量a的第1位、第3位、第5位、第7位清零a= 0b 010101002.检测位要知道一个变量中某一位是‘1’还是‘0’,可以使用与操作来实现。

a=0xf5; //a=0b 11110101result=a&0x08; //检测a的第三位,result=03.保留变量的某一位要屏蔽某一个变量的其它位,而保留某些位,也可以使用与操作来实现。

a=0x55; //a=0b 01010101a=a&0x0f; //将高四位清零,而保留低四位a=0x052)“按位或”运算符(|)参与或操作的两个位,只要有一个为‘1’,则结果为‘1’。

单片机应用技术c语言版

单片机应用技术c语言版

单片机应用技术c语言版
单片机应用技术是电子信息领域的一项重要技术。

它将计算机技术、通信技术和控制技术集成在一起,广泛应用于工业自动化、家电
控制、智能电子产品等领域。

其中,C语言是单片机编程的重要工具。

C语言是一种高级编程语言,具有结构化、规范化、高效等特点,被广泛应用于操作系统、软件开发、嵌入式系统等领域。

在单片机应
用技术中,C语言也是最常用的编程语言。

C语言为单片机提供了底层驱动、数据处理和逻辑控制等功能,
同时也提供了简单易用、高效稳定的编程方法。

通过C语言编写程序,可以实现单片机的各种功能,如控制LED灯、读取传感器数据、控制
步进电机等。

单片机应用技术中的C语言编程,需要具备一定的基础知识和技能。

首先需要了解单片机的硬件结构和操作方法,包括芯片型号、引
脚连接、输入输出设置等。

其次需要掌握C语言的基本语法和数据类型,包括变量、数组、条件语句、循环语句等。

最后需要掌握C语言
与单片机硬件的交互方法,包括端口地址、寄存器设置、中断处理等。

在应用C语言编写单片机程序时,需要注意一些编程技巧。

首先
是优化代码结构,减少程序执行时间,提高程序效率。

其次是增加程
序调试功能,方便程序的调试和优化。

最后是注意程序的稳定性和安
全性,避免程序异常崩溃或硬件损坏。

总之,C语言是单片机应用技术的重要组成部分,掌握它对于从
事单片机应用技术的学习和实践具有重要意义。

通过对C语言的深入
学习和应用,可以实现单片机的各种功能,为智能化生产和生活奠定
基础。

第4章单片机C语言1

第4章单片机C语言1

变量:在程序运行中其值可以改变的量。
定义一个变量,编译系统就会自动为它安排一个存贮区,具体的 地址值 ,用户不必在意。一个变量由变量名和变量值构成. 变量名:存贮单元地址的符号表示。 变量的值:变量所在地址单元存放的内容。
Microcontroller 单片机的C语言 05
数据类型:数据的长度。 无论哪种数据都是存放在存贮单元中的,每一个数据究竟要占用几 个单元,都要提供给编译系统,正如汇编语言中存放数据的单元要用DB、 DW、DD伪指令进行定义一样。
Microcontroller 单片机的C语言
10
4.3.2
在固定的存贮器地址进行变量参数传递是C51的一个标准特征,定 义了变量、参数传递区的存贮器模式,也就是默认了变量和参数传递 区存贮器类型、无需再对变量和参数传递区的存贮器类型进行说明。 存贮器模式决定了变量的默认存贮器类型、参数传递区和无明确存 贮区类型的说明。有三种存贮器模式:SMALL、LARGE 和 COMPACT。
Microcontroller 单片机的C语言
14
下面表格表示两种语言将m单元的内容送n单元的对照语句: 直接寻址
汇编语言 MOV n,m 传送语句 C 语言 n=m; 赋值语句 汇编语言 MOV R1,#m ; m的地址送R1 MOV n,@R1 ; m单片机的C语言
04
4.2 C51的数据类型
C51的数据有常量和变量之分。 常量:在程序运行中其值不变的量。 数值型常量:可以为十进制数、 十六进制数( 用0x表示)和字符 (用‘ ’ 引号括起)。 符号型常量:用符号表示常量,此符号需用宏定义指令(#define)对 其进行定义(相当于汇编的‚EQU‛伪指令)。 如:#define PI 3.1415那么程序中只要出现PI的地方,编译 程序都译为3.1415。

单片机C语言快速精度除法方案

单片机C语言快速精度除法方案

单片机C语言快速精度除法方案单片机中进行除法操作时,可以采用多种方法来提高运算速度和精度。

下面介绍一种利用查表法来实现快速精度除法的方案。

在单片机中,由于乘法运算相对于除法来说速度更快,我们可以通过将除数乘以一些系数,将除法转换为乘法来实现快速运算。

假设要进行a/b的除法运算,其中a为被除数,b为除数。

首先确定一个系数k,将除数b乘以k,得到乘积c=k*b,然后再进行a/c的除法运算。

为了提高运算精度,我们可以利用查表法来获得除数的系数k。

假设查表法已经得到了一个包含n个元素的查找表,每个元素的索引值为i,对应的值为ki。

查找表中的元素可以通过预先计算或使用数学方法获得。

下面介绍利用查表法进行快速精度除法的步骤:1.根据所需精度选择或生成一个包含n个元素的查找表。

2. 将除数b拆分为整数部分和小数部分,例如b = b_int + b_frac。

3. 根据整数部分b_int在查找表中查找对应的系数ki,记为ki_int。

4. 将小数部分b_frac乘以系数ki_int得到乘积c_frac = b_frac* ki_int。

5. 将被除数a拆分为整数部分和小数部分,例如a = a_int +a_frac。

6. 将整数部分a_int进行正常除法运算,得到商q_int。

7. 将小数部分a_frac和c_frac进行除法运算,得到商q_frac。

8. 将商q_int和q_frac合并得到最终结果q。

通过将除法转换为乘法和查表操作,可以实现快速且精度较高的除法运算。

这种方法在处理对除法运算精度要求较高的场景中特别有效,可以大大提高单片机的计算效率。

需要注意的是,在选择或生成查找表时,应该根据具体的应用需求来确定表的大小和精度级别。

过小的查找表可能导致运算精度不够,而过大的查找表则会占用过多的存储空间。

因此,在设计中需要权衡计算速度和存储空间的使用。

此外,还可以通过并行计算、硬件加速等方法来进一步提高除法运算的速度和精度。

编写单片机C语言代码的技巧和经验

编写单片机C语言代码的技巧和经验编写单片机C语言代码的技巧和经验C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。

那么编写单片机C语言代码的技巧和经验都有哪些呢。

以下仅供参考!具体如下:1、如果可以的话少用库函数,便于不同的mcu和编译器间的移植2、选择合适的算法和数据结构应该熟悉算法语言,知道各种算法的优缺点,具体资料请参见相应的参考资料,有很多计算机书籍上都有介绍。

将比较慢的顺序查找法用较快的二分查找或乱序查找法代替,插入排序或冒泡排序法用快速排序、合并排序或根排序代替,都可以大大提高程序执行的效率。

选择一种合适的数据结构也很重要,比如你在一堆随机存放的数中使用了大量的插入和删除指令,那使用链表要快得多。

数组与指针语句具有十分密码的关系,一般来说,指针比较灵活简洁,而数组则比较直观,容易理解。

对于大部分的编译器,使用指针比使用数组生成的代码更短,执行效率更高。

但是在Keil中则相反,使用数组比使用的指针生成的代码更短。

3、使用尽量小的数据类型能够使用字符型(char)定义的变量,就不要使用整型(int)变量来定义;能够使用整型变量定义的变量就不要用长整型(long int),能不使用浮点型(float)变量就不要使用浮点型变量。

当然,在定义变量后不要超过变量的作用范围,如果超过变量的范围赋值,C编译器并不报错,但程序运行结果却错了,而且这样的错误很难发现。

在ICCAVR中,可以在Options中设定使用printf参数,尽量使用基本型参数(%c、%d、%x、%X、%u和%s格式说明符),少用长整型参数(%ld、%lu、%lx和%lX格式说明符),至于浮点型的参数(%f)则尽量不要使用,其它C编译器也一样。

在其它条件不变的情况下,使用%f 参数,会使生成的代码的数量增加很多,执行速度降低。

4、使用自加、自减指令通常使用自加、自减指令和复合赋值表达式(如a-=1及a+=1等)都能够生成高质量的程序代码,编译器通常都能够生成inc和dec之类的指令,而使用a=a+1或a=a-1之类的指令,有很多C编译器都会生成二到三个字节的指令。

单片机c语言的结构体实现字节、位操作

单片机c语言的结构体实现字节、位操作结构体是C语言中一种数据类型,它可以包含不同类型的数据成员。

结构体可以通过位操作和字节操作来进行操作。

1. 字节操作:字节操作主要是针对结构体中的整型数据成员。

可以使用位与(&)和位或()操作来读取或设置结构体中某个字节的值。

示例代码:c#include <stdio.h>定义一个结构体typedef struct {unsigned char byte1;unsigned char byte2;unsigned char byte3;unsigned char byte4;} MyStruct;int main() {MyStruct myStruct;读取第二个字节的值unsigned char secondByte = myStruct.byte2;printf("Second byte: %d\n", secondByte);设置第三个字节的值为10myStruct.byte3 = 10;return 0;}2. 位操作:位操作主要是针对结构体中的位字段数据成员。

可以使用位操作符(<<,>>,&,)来对位字段进行读取和设置。

示例代码:c#include <stdio.h>定义一个结构体typedef struct {unsigned char flag1 : 1;unsigned char flag2 : 1;unsigned char flag3 : 1;unsigned char flag4 : 1;} MyStruct;int main() {MyStruct myStruct;设置第一个位字段为1myStruct.flag1 = 1;读取第二个位字段的值unsigned char secondFlag = myStruct.flag2;printf("Second flag: %d\n", secondFlag);return 0;}通过结构体的字节操作和位操作,可以对结构体中的字节和位字段进行精确的操作。

STC89c52单片机 计算器C语言程序

STC89c52单片机计算器C语言程序STC89C52单片机计算器C语言程序下面是STC89C52单片机计算器的C语言程序,适用于P2位选P0段选时钟12MHZ。

程序代码如下:includedefine uchar unsigned chardefine uint unsigned intuchar Led[17] = {0x3f。

0x06.0x5b。

0x4f。

0x66.0x6d。

0x7d。

0x07.0x7f。

0x6f。

0x77.0x7c。

0x39.0x5e。

0x79.0x71.0x00};long float Number[]={0,0,0,0};uchar A[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};long int D[] = {0,0,0,0,0,0,0,0};uchar code C[] = {0x0.0xFE。

0xFD。

0xFB。

0xF7.0xEF。

0xDF。

0xBF。

0x7F};uchar k=16;uchar b;long float Out_put;uchar e=0;uchar g=0;uchar L=0;uchar g1=0;uchar g2=0;uchar g3=0;uchar g4=0;char j=-1;uchar m=0;uchar n=0;uchar x=0;程序中包含了头文件和宏定义,以及数码管段选、数码管显示位控制寄存器、数码管显示内容寄存器、数码管位选、按键控制变量等各种变量。

其中,Led数组存储了数码管的段选值,Number数组存储了数字,A数组存储了数码管的位选值,D数组存储了数码管的显示内容,C数组存储了数码管的位选值,k、b、Out_put、e、g、L、g1、g2、g3、g4、j、m、n、x 等变量用于按键控制和运算。

代码中没有明显的格式错误,可以直接使用。

下面是已经修改过的文章:uchar xo = 0./*控制开始计数小数点的变量*/long int result;void Delay(uint o) {uint i。

单片机c语音自定义标志位用法bit

单片机C语言编程中“位”(bit)的保存方案引言在现有的教课书及相关文章中,都难得提到在单片机C语言编程中对于自定义“位”的状态进行保存的理念。

当单片机C语言编程中提及“位”的概念时,人们自然会想到状态字PSW 中PSW.5的F0与PSW.1的F1两个用户通用标志位。

这两个标志位均可参与布尔运算、“位”控操作,也可随状态字PSW一起保存。

但是,往往会忽视这一点:在一些特定的情况下,如在C语言编程的中断服务程序中,对状态字PSW中PSW.5的F0与PSW.1的F1这两个用户标志位的操作可能是无效的。

如:void EX1_ISR() interrupt 2 {//外部中断1static unsigned int tempaddr;//定义接收地址缓存static unsigned int tempkey;//定义接收数据缓存unsigned int timecnt;timecnt=TH1*256+TL1;TH1=0;TL1=0;TR1=1;//定时器1启动F0=~F0;//取反F0if(F0) {tempaddr=tempaddr<<1;}else {tempkey=tempkey<<1;}}以上是一段单片机外部中断1的中断服务程序,乍看似乎没什么问题,仿真调试时也能通过“编辑”。

但实际上这是一段错误的程序——其中对“F0”用户标志位的“取反”操作是达不到其预期效果的。

因为对“F0”用户标志位的“取反”操作是在中断服务程序中进行的。

在进入中断时,C语言自动会保护“中断现场”——将程序指针PC、累加器ACC、状态字PSW等压入堆栈保护起来……直到中断返回时弹出堆栈并覆盖了中断服务时的变值,恢复到压入堆栈之前的原样。

因此,状态字PSW中的F0也不例外,如果压入堆栈之前F0是处于逻辑“0”状态,中断返回后还是复原成逻辑“0”状态——不管中断服务程序中怎么取反改变——也就是说,在中断服务程序中试图改变F0之值的操作是有失偏颇的。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
相关文档
最新文档