单片机原理及应用笔记:C51的运算符与项目实践

单片机原理及应用笔记

作者简介

李永康,男,银川科技学院计算机与人工智能学院,2022级计算机与科学技术9班本科生,单片机原理及应用课程第7组。

指导老师:王兴泽

电子邮件:[email protected]

个人CSDN主页:m0_65081425-CSDN博客****

前言

本篇文章是参考《单片机原理及应用(c语言版)第2版》杨居义·编著教材编写的笔记

由李永康、王宁、刘永泰、文轩同学共同完成此篇文章,其中王宁同学负责编写算术运算符、关系运算符的相关知识,文轩同学负责编写逻辑运算符、逻辑表达式的相关知识、李永康同学负责编写C51位操作及表达式的相关知识,刘永泰同学负责编写实操步骤的编写、 李永康同学负责将以上同学的内容进行整合排版。

此篇文章将实时更新,敬请期待。。。

模块三、C51程序设计与项目实践

项目11:C51的运算符与项目实践

1.算术运算符、关系表达式及优先级
1)基本算术运算符。
运算符 意义 实例(设x=11 ,y=3)
+ 加法运算符 Z=X+y; //Z=14
- 减法运算符 Z=X-y; //Z=8
* 乘法运算符 Z=X*y; //Z=33
/ 除法运算符 Z=X / y; //Z=3
% 模(求余)运算符 Z=X%y; //Z=2

在上述运算符中,加法、减法和乘法符合一般的算术运算规则。除法运算时,如果是两个整数相除,其结果为整数;如果是两个浮点数相除,其结果为浮点数。而对于模运算,则要求两个运算对象均为整型数据

除法运算时,当两个整数相除时,结果会是整数,并且会进行截断,即只保留商的整数部分,丢弃小数部分。当两个浮点数相除时,结果会是浮点数,能够保留小数部分。而对于模运算,要求两个操作数都是整数,模运算的结果是除法后得到的余数。

C语言规定了算术运算符的优先级结合性

优先级: 指当运算对象两侧都有运算符时,执行运算的先后次序。按运算符优先级别的高低顺序执行运算。
结合性 :指当一个运算对象两侧的运算符优先级别相同时的运算顺序。

算术运算符中取负运算(-x)的优先级最高,其次是乘法、除法和取余,加法和减法的优先级最低。也可以根据需要,在算术表达式中采用括号来改变优先级的顺序。

例如:

a+b/c,该表达式中,除号优先级高于加号,故先运算b/c所得结果,之后再与a相加。

(a+b)* (c-d) -e;该表达式中,括号优先级最高,其次是"*",最后是减号。故先运算(a+b)和(c-d),然后再将二者结果相乘,最后与e相减。

2)自增/减运算符

自增/减运算符的作用是使变量值自动加1或减1。

运算符 意义 实例 ( 设x=3;)
x++ 后置自增:先返回当前值,再让x加1 y=X++; //y=3,x=4
++x 前置自增:先将x的值加1,再返回增 加后的值 y=++X; //y=4, x=4
x-- 后置自减:先返回当前值,然后再将 x的值减1 y=X--; //y=3,x=2
--x 前置自减:先将x的值减1,然后再 返回减少后的值 y=--X; //y=2,x=2

++和 -- 运算符只能用于变量,不能用于常量和表达式。如++(a+1)是错误的。

例如:

++i、--i,在使用i之前,先使i值加(减)1。

i++、i--,在使用i之后,再使i值加(减)1。

粗略地看,十+i和i++的作用都相当于i=i+1,但++i和i++的不同之处在于++i先执行i=i+1,再使用i的值;而i++则是先使用i的值,再执行i=i+1。

例如:若i值原来为5,则

执行j=++i;后j的值为6,i的值也为6;执行j=i++;后j的值为5,i的值为6。

3)类型转换

运算符两侧的数据类型不同时,要转换成同种类型。转换的方法有两种:一是自动转换,编译系统在编译时自动进行类型转换,顺序是bit→char→int→long→float,signed→unsigned;二是强制类型转换,通过类型转换运算来实现。

其一般形式如下:

(类型说明符)(表达式)

功能:把表达式的运算结果强制转换成类型说明符所表示的类型。

例如:

(double)a 将a强制转换成double类型;

(int)(x+y) 将x+y值强制转换成int类型;

(float)(5%3) 将模运算5%3的值强制转换成float类型。

2.关系运算符、关系表达式及优先级
1)C51提供六种关系运算符
运算符 意义 实例(设a=2,b=3)
< 小于 a <b; //返回值1
> 大于 a >b; //返回值0
<= 小于等于 a <=b; //返回值1
>= 大于等于 a >=b; //返回值0
== 等于 a ==b; //返回值0
!= 不等于 a !=b; //返回值1
2)关系运算符的优先级

(1)<、>、<=、>=的优先级相同,==和!=的优先级相同;前4种优先级高于后

两种。

(2)关系运算符的优先级低于算术运算符

(3)关系运算符的优先级高于赋值运算符

例如:

c>a+b 等效于 c>(a+b);

a>b!=c 等效于 (a>b)!=c;

a=b>c 等效于 a=(b>c);

3)关系运算符的结合性为左结合

例如:

a=4、b=3、c=1,且{=a>b>c,则a>b的值为 1,1>c的值为0,故 f=0.

4)关系表达式

关系表达式指用关系运算符和将两个表达式(可以是算术表达式、关系表达式、逻辑表达式、字符表达式)连接起来的式子。关系表达式的结果为真和假。C51中用0表示假,用1 表示真。

3.逻辑运算符、逻辑表达式及优先级
1)C51提供3种逻辑运算符
运算符 意义 实例(设a=2,b=3)
&& 逻辑"与",非零的数值会被视为true,而0则被视为false a&&b; //返回值1。两个操作数都为true时返回true,否则返回false.
|| 逻辑"或" allb; //返回值1。只要任意一个操作数为true,结果就为true。只有在两个操作数都为false(即都为0)时,结果才为false。
! 逻辑"非",对操作数进行取反运算,逻辑非运算会将布尔值取反。 !a: //返回值o

&& 和‖是双目运算符,要求有两个运算对象;而!是单目运算符,只要求有一个运算对象。

2)逻辑运算符的优先级

在逻辑运算中,逻辑非的优先级最高,且高于算术运算符;逻辑或的优先级最低,低于关系运算符,但高于赋值运算符。

3)逻辑表达式

用逻辑运算符将关系表达式或逻辑量连接起来的式子称为逻辑表达式。其值应为逻辑量真或假,逻辑表达式与关系表达式的值相同,以0代表假,以1代表真。

4)逻辑运算符的结合性为从左到右

例如:

a=4,b=5 则:

!a 为假。因为 a=4(非 0)为真,所以!a为假(0)。

al b 为真。因为 a,b为真,所以两者相或为真。

a&&b 为真。

!a&&b 为假(0)。!优先级高于&&,先执行!a为假(0),0&&b=0,结果为假。

4.C51位操作及表达式

C51提供6种位运算符:

& 按位与;

| 按位或;

^ 按位异或;

~ 按位取反;

<< 位左移;

>> 位右移;

除按位取反运算符~,以上位操作运算符都是双目运算符,即要求运算符两各有一个运算对象

1)"按位与"运算符 &

运算规则:参与运算的两个运算对象,若两者相应的位都为1,则该位结果为1,否则为0,即0&0=0、0&1=0、1&0=0、1&1=1。

例如: a=45h=01000101b,b=0deh=11011110b,则表达式c=a&b=44h。

按位与的主要用途如下:

(1)清零。用0去和需要清零的位进行按位与运算。

(2)取指定位。

2)"按位或"运算符|

运算规则:参与运算的两个运算对象,若两者相应的位中有一位为1,则该位结果为1,否则为0,即0|0=0、0|1=1、1|0=1、1|1=1。

例如:a=30h=00110000b,b=0fh=00001111b,则表达式c=alb=3fh。

按位或的主要用途是将一个数的某些位置1,则需要将这些位与1按位或,其余的位与0进行按位或运算则不变。

3)"按位异或"运算符^

运算规则:参与运算的两个运算对象,若两者相应的位相同,则结果为0;若两者相应的位相异,结果为1,即0^0=0、0^1=1、1^0=1、1^1=0。

例如:a=0a5h,b=3dh,则表达式c=a^b=98h。

按位异或的主要用途如下:

(1)使特定位翻转(0变1,1变0)。需要翻转的位与1按位异或运算,不需要翻转的位与0按位异或运算。原数和自身按位异或后得0。

(2)不用临时变量而交换两数的值。

4)"按位取反"运算符~

~是一个单目运算符,用来对一个二进制数按位取反,即0变1,1变0。

5)位左移和位右移运算符<<和>>

位左移、位右移运算符<<和>>,用来将一个二进制数全部左移或右移若干位;移位后,空白位补0,而溢出的位舍弃。

例如:a=15h,则a=a<<2=54h;a=a>>2=05h

6)赋值运算符和复合赋值运算符

符号=称为赋值运算符,其作用是将一个数据的值赋予一个变量。赋值表达式的值就是被赋值变量的值。

在赋值运算符的前面加上其他运算符就可以构成复合赋值运算符。在C51中共有以下几种复合运算符,它们均为双目运算符。

+=、-=、*=、/=、%=、<<=、>>=、&=、|=、^=、~=

采用这种复合赋值运算的目的是简化程序、提高C程序编译效率。例如:

a+=b 相当于 a=a十b a%=b 相当于 a=a%b

a-=b 相当于 a=a-b a<<=3 相当于 a=a<<3

a*=b 相当于 a=a*b a>>=2 相当于 a=a>>2

a/=b 相当于 a=a/b ......

7)其他运算符

\] 数组的下标; () 括号; . 结构/联合变量指针成员; \& 取内容; ? 三目运算符; , 逗号运算符; sizeof sizeof运算符,用于在程序中测试某一数据类型占用多少字节。 ##### 任务11-2-1:分别用P2、P3口显示"加减"运算的结果 ###### 1.任务要求 (1)了解"加"运算及编程。 (2)了解"减"运算及编程。 (3)掌握十进制数、十六进制数、二进制数转换。 (4)掌握无符号字符型定义,即"unsigned char a,b;"。 (5)掌握无限循环编程。 ###### 2.任务描述 分别用P2、P3口显示"加减"运算结果。把两个数进行"加减"运算,即设52+48和52-48,把"加"运算结果传送至P2口显示出来,把"减"运算结果传送至P3口显示出来。 ###### 3.任务实现 1)分析 定义两个无符号字符型变量a、b,并分别赋值为十进制数52、48,然后进行a+b、a-b运算,并把运算结果分别传送至P2、P3口显示。 2)程序设计 先建立文件夹XM11-2-1,然后建立工程项目XM11-2-1,最后建立源程序文件XM11-2-1.c,输人如下源程序。 #include\l/包含单片机寄存器的头文件 /\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* 函数功能:主函数(C语言规定必须有1个主函数) \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/ void main(void) { unsigned char a,b; //定义无符号字符型,qu'shi取值范围位0\~255 a = 52; //a赋值为52 b = 48; //b赋值为48 P2=a+b; /\*P2=52+48=100=64H=01100100B,结果为P2.7、P2.4、P2.3、P2.1、P2.0接的LED灯亮\*/ P3=a-b; /\*P3=52-48=4=00000100B,结果为P3.7、P3.6、P3.5、P3.4、P3.3、P3.1、P3.0接的LED灯亮\*/ While ( 1); //无限循环 ; //空操作 } 3)用Proteus软件仿真 经过Keil软件编译通过后,在ProteuslSIS编辑环境中绘制仿真电路图,将编译好的"XM11-1.hex"文件加载到AT89C51里,然后启动仿真,就可以看到分别用P2、P3口显示"加减"运算结果,效果图如下图所示。 ![](https://i-blog.csdnimg.cn/direct/8b7652405f70430390fc57c81bfeae54.png) ##### 任务11-2-2:用P1口显示逻辑"与或"运算的结果 ###### 1.任务要求 1)掌握"与"运算及编程。 2)掌握"或"运算及编程。 ###### 2.任务描述 用P1口显示逻辑"与或"运算结果。把(6\>0x0f)\&\&(8\<0xa)和(6\>0x0f) \|\|(8\<0xa)运算结果传送至P1口显示出来。 ###### 3.任务实现 **1)分析** 把(6\>0x0f)\&\&(8\<0xa)进行"与"运算,即(6\>0x0f)\&\&(8\<0xa)=0\&\&1=0结果传送至 P1 口使得8只LED 全亮,然后调延时;再把(6\>Ox0f) \|(8\<0xa)进行"或"运算即(6\>0xOf)1(8\0x0f)\|\| (8\<0xa)进行"或"运算,即"(6\>0x0f)\|\| (8\<0xa) =0 \|\| 1=1,最终结果送P1口使得8只LED全灭,然后调延时。 **2)程序设计** 先建立文件夹"XM11-2,然后建立"XM11-2"工程项目,最后建立源程序文件"XM11-2.c",输入如下源程序: 门: #include\ //包含单片机寄存器的头文件/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* 函数功能:用整型数据延时时间 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/ void delay(void) /\*两个void意思分别为无需返回值,没有参数传递\*/ { unsigned int i; /\*定义无符号整数,最大取值范围65535\*/ for(i=0;i\<50000;i++) //做50000次空循环 ; //什么也不做,等待一个机器周期 } /\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* 函数功能:主函数 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/ void main(void) { while(1) //无限循环{ P1= ((6\>0xOf)\&\& (8\ //包含单片机寄存器的头文件 /\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* 函数功能:主函数(C语言规定必须有1个主函数) \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/ void main(void){ P2=0x52\&0x48; /\*P2=01010010\&01001000=01000000B,结果为P2.7、P2.5、P2.4、P2.3、P2.2、P2.1、P2.0接的LED灯亮\*/ P3=0x52\|0x48; /\*P3=01010010\&01001000=01011010B,结果为P3.7、P3.5、P3.2、P3.0、接的LED灯亮\*/ While ( 1);/无限循环 ; //空操作 } 3)用Proteus软件仿真 经过Keil软件编译通过后,在ProteuslSIS编辑环境中绘制仿真电路图,将编译好的"XM11-3.hex"文件加载到AT89C51里,然后启动仿真,就可以看到分别用P2、P3口显示位"与或"运算结果,效果图如下图所示。 ![](https://i-blog.csdnimg.cn/direct/4c2760f264104c7d8fc4bb9098cfbf3d.png) ##### 任务11-2-4:用P1口显示"位左右移"运算结果 ###### 1.任务要求 1)掌握"右移"、"左移"运算及编程; 2)掌握二进制数移位; 3)掌握无限循环编程。 ###### 2.任务描述 用P1口显示"左右移"运算结果。把数"0xaa"进行"\<\<"左移1位运算,即"0xaa\<\<1",把运算结果送P1口显示出来,调延时,再把P1左移1位运算送显示;然后再把刚刚左移2位的数进行右移2位运算,分别把运算结果送P1口显示出来。 ###### 3.任务实现 **1)分析** 设一个十六进制数"0xaa",展开为二进制数为10101010B,进行左移1位运算 "10101010B→01010100",规则为高位丢掉,低位添0,把运算结果送P1口显示,再进行左移1位运算"01010100→10101000",把运算结果送P1口显示即LED6、LED4、LED2、LED1、LEDO亮,其他LED7、LED5、LED3灭。 **2)程序设计** 先建立文件夹"XM11-4",然后建立"XM11-4"工程项目,最后建立源程序文件"XM11-4.c",输入如下源程序: 然后再把这个数据进行右移2位运算,即"10101000→01010100---00101010",再把运算结果送P1口显示即LED7、LED6、LED4、LED2、LEDO亮,其他LED5、LED3、LED1灭。 #include\ //包含单片机寄存器的头文件 /\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* 函数功能:用整型数据延时时间 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/ void delay(void) /\*两个void意思分别为无需迟回值,没有参数传递\*/ { unsigned int i; //定义无符号整数,最大取值范围65535; for(i=0;i\<50000;i++) //做50000次空循环 ; //什么也不做,等待一个机器周期 } /\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* 函数功能:主函数 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/ void main(void) { while(1) //无限循环{ P1=0xaa\<\<1; /\*运算结果送P1=01010100B,LED7、LED5、LED3、LED1、LED0亮,其他LED6、LED4、LED2灭\* delay(); //延时 P1= P1\<\<1; /\*运算结果送P1=10101000B,LED6、LED4、LED2、LED1、LED0亮,其他LED7、LED5、LED3灭\* delay(); //延时 P1=P1\>\>1; /\*运算结果送P1=01010100B,再把运算结果送P1口显示即LED7、LED5、LED3、LED1、LED0亮,其他LED6、LED4、LED2灭\*I delay(); //延时 P1=P1\>\>1; /\*运算结果送P1=00101010B,再把运算结果送P1口显示即LED7、LED6、LED4、LED2、LED0亮,其他LED5、LED3、LED1灭\*l delay(); //延时 } } **3)用Proteus软件仿真** 经过Keil软件编译通过后,在ProteusISIS编辑环境中绘制仿真电路图,将编译好的"XM11-4.hex"文件加载到AT89C51里,然后启动仿真,就可以看到用P1口显示"左右移"运算结果,效果图如下图所示。 ![](https://i-blog.csdnimg.cn/direct/25fe9680fca740369ddf480794b2c0b0.png) #### 总结 以上就是关于c51的运算符与项目实践的相关知识了,后续内容持续更新

相关推荐
明明真系叻1 小时前
2025.4.20机器学习笔记:文献阅读
人工智能·笔记·机器学习
螺丝钉的扭矩一瞬间产生高能蛋白2 小时前
基于FreeRTOS和STM32的微波炉
stm32·单片机·嵌入式硬件
Aspiring Q2 小时前
vscode+keil嵌入式软件开发全流程
vscode·stm32·单片机
程序员JerrySUN2 小时前
驱动开发硬核特训 · Day 11(下篇):从 virtio_blk 看虚拟总线驱动模型的真实落地
linux·驱动开发·嵌入式硬件
努力创造奇迹2 小时前
STM32 HAL库 内部传感器驱动实现
stm32·单片机·嵌入式硬件
kfepiza2 小时前
HttpSessionListener 的用法笔记250417
java·笔记·servlet·tomcat
omnibots3 小时前
ESP-ADF外设子系统深度解析:esp_peripherals组件架构与核心设计(输入类外设之触摸屏 Touch)
嵌入式硬件·架构·iot
铭阳(●´∇`●)3 小时前
Python内置函数---anext()
笔记·python·学习
路上^_^3 小时前
CSS核心笔记001
前端·css·笔记
十年之少3 小时前
网络请求——微信小程序学习笔记
笔记·学习·微信小程序