2024零基础入门(二)
2.1原理图
图 1 独立按键原理图 图 2 矩阵按键原理图 图 3 引脚参考图- 由原理图知,P3_4-P3_7控制独立按键、P3_0-P3_7控制矩阵按键。
- 独立按键:默认一端为低电平,当按键按下时,独立按键接通电路,对应引脚变为低电平。
- 矩阵按键,“先扫描行、再扫描列”。
2.2代码讲解
核心代码与思路:
- 核心代码1(按键状态判断,==需要记忆==):
//需记忆,写在while(1)里
Key_Val = Key_Read();//读取键码值
Key_Down = Key_Val & (Key_Val ^ Key_Old);//检测下降沿
Key_Up = ~Key_Val & (Key_Val ^ Key_Old);//检测上升沿
Key_Old = Key_Val;//扫描辅助变量
- 核心代码2,独立按键扫描:
/*按键读取函数*/
unsigned char Key_Read()
{
//独立按键
unsigned char temp=0;
if(P3_4 == 0) temp=1;
if(P3_5 == 0) temp=2;
if(P3_6 == 0) temp=3;
if(P3_7 == 0) temp=4;
return temp;
}
- 核心代码3,矩阵按键扫描:
/*按键读取函数*/
unsigned char Key_Read()
{
unsigned char temp=0;
//矩阵按键
P3_0=0;P3_1=1;P3_2=1;P3_3=1;
if(P3_4 == 0) temp=1;
if(P3_5 == 0) temp=2;
if(P3_6 == 0) temp=3;
if(P3_7 == 0) temp=4;
P3_0=1;P3_1=0;P3_2=1;P3_3=1;
if(P3_4 == 0) temp=5;
if(P3_5 == 0) temp=6;
if(P3_6 == 0) temp=7;
if(P3_7 == 0) temp=8;
P3_0=1;P3_1=1;P3_2=0;P3_3=1;
if(P3_4 == 0) temp=9;
if(P3_5 == 0) temp=10;
if(P3_6 == 0) temp=11;
if(P3_7 == 0) temp=12;
P3_0=1;P3_1=1;P3_2=1;P3_3=0;
if(P3_4 == 0) temp=13;
if(P3_5 == 0) temp=14;
if(P3_6 == 0) temp=15;
if(P3_7 == 0) temp=16;
//返回状态改变的按键标号
return temp;
}
代码示例:
示例1:
if(Key_Down==1)//按键1(P3_4)被按下的一瞬间
{
P1_0=0;
}
if(Key_Up==2)//按键2(P3_5)被松开的一瞬间
{
P1_0=1;
}
if(Key_Old==3)//按键3(P3_6)被一直按下
{
P1_1=0;
}else
{
P1_1=1;
}
- 上述代码作用:
- 当按键1被按下时,P3_4按下瞬间的电平变化被检测到,P1_0输出低电平,灯亮
- 当按键2松开时,P3_5的电平变化被检测到,P1_0输出高电平,灯灭
- 当按键3被持续按下时,P1_1输出低电平,灯亮,否则灯灭
示例2:
/*main函数前,全局变量,默认值为零*/
bit System_Flag; //定义标志
/*while(1)中*/
if(System_Flag == 1)
{
P1=ucLed;
Delayms(Time);
ucLed = _crol_(ucLed,1);
}
if(Key_Down == 1)System_Flag=1;
if(Key_Down == 2)System_Flag=0;
- 上述代码作用:
- 当标志位变为1时(即按键1被按下),执行留流水灯代码(ucLed循环左移位)
- 当标志位变为2时(即按键2被按下),流水灯暂停闪烁
- 上述按键状态判断(按键标号)还可以用
switch+break的形式执行:
示例3:
switch(Key_Down)
{
case 6:
System_Flag=1;
break;
case 12:
System_Flag=0;
break;
case 13: //减慢流水灯闪烁
Time += 100;
break;
case 14: //加快流水灯闪烁
Time -= 100;
break;
}
2.3完整程序示例
/* 头文件声明区域*/
#include <REGX52.H>
#include <intrins.h>
/*延时函数 ms*/
void Delayms(unsigned int xms) //@12.000MHz
{
unsigned char data i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
/*变量声明区域*/
//全局变量默认等于0
unsigned char ucLed = 0xfe;
unsigned char Key_Val,Key_Down,Key_Up,Key_Old;
unsigned int Time=500;
bit System_Flag; //定义标志位
/*按键读取函数*/
unsigned char Key_Read()
{
unsigned char temp=0;
/*
独立按键:
if(P3_4 == 0) temp=1;
if(P3_5 == 0) temp=2;
if(P3_6 == 0) temp=3;
if(P3_7 == 0) temp=4;
*/
//矩阵按键
P3_0=0;P3_1=1;P3_2=1;P3_3=1;
if(P3_4 == 0) temp=1;
if(P3_5 == 0) temp=2;
if(P3_6 == 0) temp=3;
if(P3_7 == 0) temp=4;
P3_0=1;P3_1=0;P3_2=1;P3_3=1;
if(P3_4 == 0) temp=5;
if(P3_5 == 0) temp=6;
if(P3_6 == 0) temp=7;
if(P3_7 == 0) temp=8;
P3_0=1;P3_1=1;P3_2=0;P3_3=1;
if(P3_4 == 0) temp=9;
if(P3_5 == 0) temp=10;
if(P3_6 == 0) temp=11;
if(P3_7 == 0) temp=12;
P3_0=1;P3_1=1;P3_2=1;P3_3=0;
if(P3_4 == 0) temp=13;
if(P3_5 == 0) temp=14;
if(P3_6 == 0) temp=15;
if(P3_7 == 0) temp=16;
return temp;
}
/* main*/
void main()
{
while(1)
{
//需要记忆,按键状态变量
Key_Val = Key_Read();//读取键码值
Key_Down = Key_Val & (Key_Val ^ Key_Old);//检测下降沿
Key_Up = ~Key_Val & (Key_Val ^ Key_Old);//检测上升沿
Key_Old = Key_Val;//扫描辅助变量
//流水灯标志位为1时,执行流水灯
if(System_Flag == 1)
{
P1=ucLed;
Delayms(Time);
ucLed = _crol_(ucLed,1);
}
//判断按钮是否按下,按下后执行对应操作
switch(Key_Down)
{
case 6:
System_Flag=1;
break;
case 12:
System_Flag=0;
break;
case 13:
Time += 100;
break;
case 14:
Time -= 100;
break;
}
}
}
2.4补充内容,变量类型
数据类型总览
| 类别 | 数据类型 | 关键字 | 长度 (字节) | 长度 (位) | 取值范围 | 备注 |
|---|---|---|---|---|---|---|
| 位变量 | 位变量 | bit |
- | 1 | 0 或 1 | C51扩展类型,用于布尔标志 |
| 特殊功能寄存器位 | sbit |
- | 1 | 0 或 1 | C51扩展,用于直接寻址SFR中的特定位 | |
| 字符型 | 有符号字符型 | signed char |
1 | 8 | -128 到 +127 | |
| 无符号字符型 | unsigned char |
1 | 8 | 0 到 255 | 最常用,处理ASCII字符或8位数据 | |
| 整型 | 有符号整型 | signed int |
2 | 16 | -32768 到 +32767 | |
| 无符号整型 | unsigned int |
2 | 16 | 0 到 65535 | 常用于循环计数、内存地址 | |
| 有符号长整型 | signed long |
4 | 32 | -2147483648 到 +2147483647 | ||
| 无符号长整型 | unsigned long |
4 | 32 | 0 到 4294967295 | ||
| 浮点型 | 单精度浮点型 | float |
4 | 32 | ±1.175494E-38 到 ±3.402823E+38 | 精度约6-7位有效数字 |
| 双精度浮点型 | double |
4 | 32 | ±1.175494E-38 到 ±3.402823E+38 | 在C51中,double与float相同 |
|
| 指针类型 | 通用指针 | * |
3 | 24 | 可指向任意存储类型 | |
| 存储区特定指针 | *(如 data *) |
1 或 2 | 8 或 16 | 指向特定存储区 | 更高效,但范围受限 | |
| 特殊功能寄存器 | 8位SFR | sfr |
1 | 8 | 0 到 255 | C51扩展,用于操作如P0、P1等寄存器 |
| 16位SFR | sfr16 |
2 | 16 | 0 到 65535 | 用于操作如定时器T0、T1等16位寄存器 |
核心概念与编程建议
-
整数范围:C51中的
int是16位,而不是现代计算机中常见的32位。 -
位变量限制:
bit变量不能定义成指针,也不存在位数组bit array[]。 -
隐式类型转换:当不同数据类型一起运算时,编译器会自动进行类型转换,优先级一般为:
bit→char→int→long→float。 -
注意这可能带来精度损失或意外结果。


