蓝桥杯单片机第2阶段-2

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补充内容,变量类型:star:

:books: 数据类型总览

类别 数据类型 关键字 长度 (字节) 长度 (位) 取值范围 备注
位变量 位变量 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中,doublefloat相同
指针类型 通用指针 * 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位寄存器

:light_bulb: 核心概念与编程建议

  • 整数范围:C51中的 int是16位,而不是现代计算机中常见的32位。

  • 位变量限制bit变量不能定义成指针,也不存在位数组 bit array[]

  • 隐式类型转换:当不同数据类型一起运算时,编译器会自动进行类型转换,优先级一般为:bitcharintlongfloat

  • 注意这可能带来精度损失或意外结果。