C语言中的逻辑运算符与数据处理
1. 异或运算符(^)
异或运算符(Exclusive OR,简称EXOR)被认为是真正的“或”功能。只有当两个位中仅有一个为逻辑‘1’时,结果才会产生逻辑‘1’,而不是两个都为‘1’。哪个变量的对应位为逻辑‘1’并不重要。异或的真值表如下:
| B | A | F |
| — | — | — |
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
以下是使用异或运算符的代码示例:
/*
* File: logicsimulationProg.c
* Author: H. H. Ward
*
* Created on 21 November 2020, 15:56
*/
#include <xc.h>
#include <conFigInternalOscNoWDTNoLVP.h>
#include <PICSetUp.h>
//some variable
unsigned char a,b,c,d,e,f;
void main()
{
a = 0;
b = 0;
c = 0;
d = 7;
a = 0b00000101;
b = 0b11110100;
c = 13;
while (1)
{
d = ( a ^ b );
}
}
这段代码将变量‘d’加载为
0b11110001
。变量‘a’和‘b’的第2位都为逻辑‘1’,所以异或结果为逻辑‘0’。
异或运算符还可用于切换位的逻辑状态。例如:
while (1)
{
PORTBbits.RB0 ^= 1;
delay (30);
}
如果假设
PORTB
的第0位初始为逻辑‘0’,执行
PORTBbits.RB0 ^= 1;
后,该位将变为逻辑‘1’。1秒后再次执行该指令,由于此时该位为逻辑‘1’,异或结果将使其变为逻辑‘0’。这样,连接到
PORTB
第0位的LED将以1秒为周期不断闪烁。
2. 按位与赋值运算符(&=)
按位与赋值运算符
&=
会将左边第一个变量的内容与右边第二个变量的内容进行按位与操作。如果某一位的按位与结果为真,则第一个变量的对应位变为逻辑‘1’;否则变为逻辑‘0’。
以下是使用
&=
运算符的代码示例:
/*
* File: logicsimulationProg.c
* Author: H. H. Ward
*
* Created on 21 November 2020, 15:56
*/
#include <xc.h>
#include <conFigInternalOscNoWDTNoLVP.h>
#include <PICSetUp.h>
//some variable
unsigned char a,b,c,d,e,f;
void main()
{
a = 0;
b = 0;
c = 0;
d = 0;
a = 0b00000101;
b = 0b11110100;
c = 13;
while (1)
{
d &= b;
}
}
下面的表格展示了按位与操作的过程:
| Variable | Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
| — | — | — | — | — | — | — | — | — |
| Initial setting of ‘d’ | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 |
| b | 1 | 1 | 1 | 1 | 0 | 1 | 0 | 0 |
| Result d | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
可以看到,只有变量‘d’和‘b’的第2位都为逻辑‘1’,所以结果变量‘d’的第2位为逻辑‘1’,其余位为逻辑‘0’。
3. 按位或赋值运算符(|=)
按位或赋值运算符
|=
与
&=
类似,但它执行的是逻辑或操作。如果‘b’或‘d’中的任何一位为逻辑‘1’,则‘d’的对应位将被设置为逻辑‘1’。如果两个变量的对应位都为逻辑‘1’,‘d’的对应位也为逻辑‘1’,这是包含或的操作。
以下是使用
|=
运算符的代码示例:
/*
* File: logicsimulationProg.c
* Author: H. H. Ward
*
* Created on 21 November 2020, 15:56
*/
#include <xc.h>
#include <conFigInternalOscNoWDTNoLVP.h>
#include <PICSetUp.h>
//some variable
unsigned char a,b,c,d,e,f;
void main()
{
a = 0;
b = 0;
c = 0;
d = 7;
a = 0b00000101;
b = 0b11110100;
c = 13;
while (1)
{
d |= b;
}
}
下面的表格展示了按位或操作的过程:
| Variable | Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
| — | — | — | — | — | — | — | — | — |
| Initial setting of ‘d’ | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 |
| b | 1 | 1 | 1 | 1 | 0 | 1 | 0 | 0 |
| Result d | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 1 |
如果使用异或运算符
d ^= b;
,结果会有所不同。与按位或操作相比,结果中‘d’的第2位将为逻辑‘0’,因为异或会排除‘d’和‘b’第2位都为逻辑‘1’的情况。
4. 取模运算符(%)
取模运算符
%
与除法运算符
/
一起使用,用于获取除法运算的余数。例如,
8 / 3
的结果是2,余数是2。
以下是使用取模运算符的代码示例:
/*
* File: logicsimulationProg.c
* Author: H. H. Ward
*
* Created on 21 November 2020, 15:56
*/
#include <xc.h>
#include <conFigInternalOscNoWDTNoLVP.h>
#include <PICSetUp.h>
//some variable
unsigned char a,b,c,d,e,f;
void main()
{
a = 0;
b = 0;
c = 0;
d = 0;
a = 0b00001000;
b = 0b00000011;
while (1)
{
c = a/b;
d = a % b;
}
}
变量‘a’被加载为8,‘b’被加载为3。第22行将变量‘c’加载为
8 / 3
的整数部分2,第23行将变量‘d’加载为余数2。
5. 按位取反运算符(~)
按位取反运算符
~
会翻转变量中的每一位,即所有逻辑‘0’变为逻辑‘1’,所有逻辑‘1’变为逻辑‘0’。
以下是使用按位取反运算符的代码示例:
/*
* File: logicsimulationProg.c
* Author: H. H. Ward
*
* Created on 21 November 2020, 15:56
*/
#include <xc.h>
#include <conFigInternalOscNoWDTNoLVP.h>
#include <PICSetUp.h>
//some variable
unsigned char a,b,c,d,e,f;
void main()
{
a = 0;
b = 0;
c = 0;
d = 7;
b = 0b00000111;
while (1)
{
d = ~b;
}
}
下面的表格展示了按位取反操作的过程:
| Variable | Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
| — | — | — | — | — | — | — | — | — |
| Initial setting of ‘d’ | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 |
| b | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 |
| Result d | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
6. 移位运算符(< >n)
移位运算符
<<n
和
>>n
分别用于将位向左或向右移动
n
位。可以对一个变量进行移位操作,也可以将移位结果加载到另一个变量中,原变量内容保持不变。
以下是使用移位运算符的代码示例:
/*
* File: logicsimulationProg.c
* Author: H. H. Ward
*
* Created on 21 November 2020, 15:56
*/
#include <xc.h>
#include <conFigInternalOscNoWDTNoLVP.h>
#include <PICSetUp.h>
//some variable
unsigned char a,b,c,d,e;
void main()
{
a = 0;
b = 0;
c = 0;
d = 7;
e = 0;
a = 8;
b = 0b11001110;
while (1)
{
c = b >> 4;
d = b << 2;
e = (b << 4 | b >>4);
}
}
-
第23行将
0b11001110右移4位,结果为c = 0b00001100。 -
第24行将
b左移2位,结果为d = 0b00111000。 -
第25行将
b左移4位和右移4位的结果进行按位或操作,结果为e = 0b11101100。
下面的表格展示了变量‘d’在右移2位后的结果:
| Variable | Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
| — | — | — | — | — | — | — | — | — |
| Initial setting of ‘d’ | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 |
| b | 1 | 1 | 0 | 0 | 1 | 1 | 1 | 0 |
| Result d | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 |
7. 数据类型与内存
PIC微控制器有三个内存区域:
-
程序内存区域
:用于存储程序的所有指令。PIC18f4525的程序内存区域有48KB,可存储24,576条单字指令。该内存是非易失性的,断电后信息不会丢失。
-
数据RAM
:用于存储程序的临时信息。PIC18f4525有4096个内存位置,每个位置可存储8位数据(即一个字节)。该内存是易失性的,断电后所有信息丢失。
-
数据EEPROM
:用于存储程序不想因PIC断电而丢失的信息,是非易失性内存。
7.1 变量
在程序中创建变量时,编译器会在PIC的数据内存区域中为其预留一个或多个内存位置。所需的内存位置数量取决于要存储的数据所需的位数。变量与C编程中使用的不同数据类型相关联,所有数据实际上都是二进制数,我们只是给这些二进制数赋予了有意义的名称。
常见的数据类型如下表所示:
| Type | Size | Minimum Value | Maximum Value |
| — | — | — | — |
| char | 8 bits | –128 | 127 |
| unsigned char | 8 bits | 0 | 255 |
| int | 16 bits | –32,768 | 32,767 |
| unsigned int | 16 bits | 0 | 65,535 |
| short | 16 bits | –32,768 | 32,767 |
| unsigned short | 16 bits | 0 | 65,535 |
| short long | 24 bits | –8,388,608 | 8,388,607 |
| unsigned short long | 24 bits | 0 | 16,777,215 |
| long | 32 bits | –2,147,483,648 | 2,147,483,647 |
| unsigned long | 32 bits | 0 | 4,294,967,295 |
| float | 32 bits | Floating Point Numbers | |
| double | 32 bits | –126 | 128 | 2–126 | 2128 |
7.2 位运算符
| Operator | Description |
|---|---|
| & | AND each bit |
| | | OR each bit (inclusive OR) |
| ^ | EXOR each bit (exclusive OR) |
| <<n | Shift left n places |
| >>n | Shift right n places |
| ~ | One’s complement (invert each bit) |
例如,如果
x = 1111 1111
,则:
| Operation | Result |
| — | — |
| x & 0X0F | 0000 1111 |
| x | OXOF | 1111 1111 |
| x^0X0F | 1111 0000 |
| x = x<<2 | 1111 1100 |
| x = x>>4 | 0000 1111 |
| x = ~x | 0000 0000 |
7.3 数学和逻辑运算符
| Operator | Description |
|---|---|
| + | Leaves the variable as it was |
| - | Creates the negative of the variable |
| ++ | Increments the variable by 1 |
| – | Decrements the variable by 1 |
| * | Multiplies the two variables y = a × b |
| / | Divides y= a/b |
| % | Used to get the remainder of a division of two variable m = a%b |
| < | Less than: If (y < a) means y is less than a |
| <= | Less than or equal to: If (y < =a) means y is less than or equal to a |
| > | Greater than: If (y > a) means y is greater than a |
| >= | Greater than or equal to: If (y > =a) means y is greater than or equal to a |
| = | Makes the variable equal to: y = 3. After this, y takes on the value of 3 |
| ! | Not if: (!PORTBbits.RB0) if not bit 0 of portb, which means if bit 0 of portb is logic ‘0’ |
| && | Whole register AND |
| || | Whole register OR |
| ? | Test operator: y = (a>0) ? a : –1; This test to see if ‘a’ is greater than 0. If it is, then y becomes equal to ‘a’, if it’s not then y = –1 |
7.4 关键字
| Keyword | Function |
|---|---|
| typedef | Allows the programmer to define any phrase to represent an existing type |
| #ifndef | Checks to see if a label you want to use has not been defined in any include files you want to use. If it has, it does not allow you to define it now. If it hasn’t, you are allowed to define it now |
| #define | You can define what your label means here |
| #endif | Denotes the end of your definition after the #ifndef code |
| sizeof | Returns the size in number of bytes of a variable |
全局变量是一旦声明后,可在程序的任何地方进行读写操作的变量。
8. 微处理器系统中的编号系统
8.1 二进制数
微处理器系统使用二进制数系统,因为它只有两个数字‘0’和‘1’,可以用逻辑‘0’和逻辑‘1’表示,也可以用电压(0V表示逻辑‘0’,+5V表示逻辑‘1’)表示。所有逻辑操作(如AND、OR、NAND、NOR、NOT和EXOR)都使用二进制格式。
8.2 十进制转二进制
将十进制数转换为二进制数的一种简单方法是反复将十进制数除以2。例如,将66转换为二进制数:
66 / 2 = 33 ... 0
33 / 2 = 16 ... 1
16 / 2 = 8 ... 0
8 / 2 = 4 ... 0
4 / 2 = 2 ... 0
2 / 2 = 1 ... 0
1 / 2 = 0 ... 1
从下往上取余数,得到二进制数
1000010
。
8.3 二进制转十进制
将二进制数转换为十进制数,需要将二进制数中为1的位对应的十进制值相加。例如,将二进制数
1000010
转换为十进制数:
| Base No | 2^7 | 2^6 | 2^5 | 2^4 | 2^3 | 2^2 | 2^1 | 2^0 |
| — | — | — | — | — | — | — | — | — |
| Decimal equivalent | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
| Binary number | 1 | 0 | 0 | 0 | 0 | 1 | 0 | |
64 + 2 = 66
,所以二进制数
1000010
对应的十进制数是66。
8.4 示例
将127转换为二进制数并验证结果:
127 / 2 = 63 ... 1
63 / 2 = 31 ... 1
31 / 2 = 15 ... 1
15 / 2 = 7 ... 1
7 / 2 = 3 ... 1
3 / 2 = 1 ... 1
1 / 2 = 0 ... 1
得到二进制数
1111111
。验证:
64 + 32 + 16 + 8 + 4 + 2 + 1 = 127
。
通过以上内容,我们了解了C语言中一些特殊的指令和逻辑运算符,以及PIC微控制器的内存结构、数据类型、编号系统等知识。这些知识对于理解和编写微控制器程序非常重要。
9. 逻辑运算符总结与应用示例
9.1 运算符总结
前面介绍了多种逻辑运算符,下面做一个简单总结:
| 运算符 | 功能描述 |
| — | — |
| ^(异或) | 只有当两个位中仅有一个为逻辑‘1’时,结果为逻辑‘1’ |
| &=(按位与赋值) | 将左边变量与右边变量按位与,结果存于左边变量 |
| |=(按位或赋值) | 将左边变量与右边变量按位或,结果存于左边变量 |
| %(取模) | 获取除法运算的余数 |
| ~(按位取反) | 翻转变量中的每一位 |
| <
>n(右移) | 将变量的位向右移动n位 |
9.2 综合应用示例
下面是一个综合运用这些运算符的示例代码:
/*
* File: comprehensiveExample.c
* Author: Some Author
*
* Created on Some Date
*/
#include <xc.h>
#include <conFigInternalOscNoWDTNoLVP.h>
#include <PICSetUp.h>
//some variable
unsigned char a,b,c,d,e,f;
void main()
{
a = 0b00001100;
b = 0b00110011;
c = a ^ b;
d = a &= b;
e = a |= b;
f = a % b;
a = ~a;
b = b << 2;
c = c >> 1;
while (1)
{
// 可以在这里添加更多的操作
}
}
在这个示例中:
-
c = a ^ b;
计算
a
和
b
的异或结果。
-
d = a &= b;
先进行按位与操作,再将结果赋值给
a
和
d
。
-
e = a |= b;
先进行按位或操作,再将结果赋值给
a
和
e
。
-
f = a % b;
计算
a
除以
b
的余数。
-
a = ~a;
对
a
进行按位取反。
-
b = b << 2;
将
b
左移2位。
-
c = c >> 1;
将
c
右移1位。
10. 数据类型与内存的进一步理解
10.1 数据类型的选择
在编程中,正确选择数据类型非常重要。不同的数据类型占用的内存空间不同,所能表示的数值范围也不同。例如,如果需要存储一个较小的无符号整数,使用
unsigned char
就足够了,这样可以节省内存。如果需要存储一个较大的整数,可能需要使用
long
或
unsigned long
。
10.2 内存的使用优化
- 变量的生命周期 :合理控制变量的生命周期,避免不必要的内存占用。例如,在一个函数中定义的局部变量,在函数执行结束后,其占用的内存会被释放。
- 数组的使用 :如果需要存储多个相同类型的数据,可以使用数组。但要注意数组的大小,避免浪费内存。例如:
unsigned char myArray[10]; // 定义一个包含10个元素的数组
10.3 内存操作的流程图
graph TD;
A[开始] --> B[声明变量];
B --> C[分配内存];
C --> D[使用变量];
D --> E{是否需要释放内存};
E -- 是 --> F[释放内存];
E -- 否 --> G[继续使用];
F --> H[结束];
G --> D;
11. 编号系统在实际编程中的应用
11.1 二进制编号在逻辑操作中的应用
在逻辑操作中,二进制编号非常重要。例如,在使用按位与、按位或、异或等运算符时,都是基于二进制位进行操作的。通过合理运用这些运算符,可以实现一些复杂的逻辑功能。
11.2 十进制与二进制的转换在数据处理中的应用
在数据处理中,经常需要进行十进制与二进制的转换。例如,在读取传感器数据时,传感器返回的可能是二进制数据,需要将其转换为十进制数据进行显示或进一步处理。反之,在向设备发送数据时,可能需要将十进制数据转换为二进制数据。
11.3 编号系统转换的流程图
graph TD;
A[开始] --> B{选择转换类型};
B -- 十进制转二进制 --> C[反复除以2取余数];
B -- 二进制转十进制 --> D[按位计算十进制值并相加];
C --> E[得到二进制结果];
D --> F[得到十进制结果];
E --> G[结束];
F --> G;
12. 总结
通过对C语言中逻辑运算符、数据类型、内存结构以及编号系统的学习,我们可以更好地理解和编写微控制器程序。逻辑运算符可以实现各种复杂的逻辑功能,合理选择数据类型可以节省内存,了解内存结构有助于优化程序的性能,掌握编号系统的转换可以方便数据的处理。在实际编程中,要根据具体需求灵活运用这些知识,不断提高编程能力。
希望这些内容对大家有所帮助,在后续的编程实践中能够更加得心应手。
超级会员免费看
795

被折叠的 条评论
为什么被折叠?



