51 单片机

51 单片机

参考视频:江协科技https://www.bilibili.com/video/BV1Mb411e7re

参考资料:STC官网STC单片机专业供应商 (stcmicro.com)

1. 简介

1.1 概念

什么是单片机

单片机种类

单片机应用

1.2 环境准备

驱动安装

打开普中科技给的资源包里,会有驱动的

image-20240306151115356

image-20240306151134092

image-20240306151149859

如果失败,点击安装失败解决方法

如果驱动已经安装成功了,能够检查到。只要没有黄的感叹号,都是连接成功了

image-20240306125948625

辅助软件安装stc-isp

这边能显示串口号,就说明连接成功了

image-20240307104023201

Keil5 安装

官网下载:Keil Product Downloads

Keil公司是一家业界领先的微控制器(MCU)软件开发工具的独立供应商。Keil公司由两家私人公司联合运营,分别是德国慕尼黑的Keil Elektronik GmbH和美国德克萨斯的Keil Software Inc。Keil公司制造和销售种类广泛的开发工具,包括ANSI C编译器、宏汇编程序、调试器、连接器、库管理器、固件和实时操作系统核心(real-time kernel)。有超过10万名微控制器开发人员在使用这种得到业界认可的解决方案。Keil公司在2005年被ARM公司收购。KEIL软件为适应51内核和ARM内核,KEIL版本分为KEIL C51和MDK-ARM。KEIL MDK目前最新的版本为9.61。

image-20240306151354969

随便写写,都写上就行

image-20240306151507025

Keil5破解

image-20240306144408364

image-20240306144427480

image-20240306144549623

image-20240306144621195

image-20240306144658683

1.3 开发板简介

image-20240307201724588

序号 板载资源
1 数码管模块 2个四位一体共阴数码管,可显示8位数字字符,如时钟、密码等
2 LCD1602接口 兼容LCD1602/LCD9648液晶屏,可显示数字字符等
3 LCD12864接口 兼容LCD9648/MiniLCD12864/带字库LCD12864液晶,可显示汉字/图像等
4 8*8LED点阵 可显示数字/字符/图形等
5 LED模块 8个LED,可实现流水灯等花样显示
6 矩阵按键 4*4矩阵按键,可作计算器、密码锁等应用的输入装置
7 红外接收头 NEC协议,可实现遥控
8 DS18B20温度传感器 可实现温度采集控制等
9 NRF24L01接口 可实现2.4G远程遥控通信
10 独立按键 4个按键,可作按键输入控制
11 MicroUSB接口 可作电源输入、程序下载等
12 USB转TTL模块 CH340C芯片,可作电脑USB与单片机串口下载和通信
13 3.3V电源模块 ASM1117-3.3芯片,将5V转为3.3V供用户使用
14 电源开关 系统电源控制开关
15 ADC/DAC模块 XPT2046芯片作为ADC,LM358+PWM作为DAC,可采集外部模拟信号和输出模拟电压
16 EEPROM模块 AT24C02芯片,可存储256字节数据,掉电不丢失
17 复位按键 系统复位
18 无源蜂鸣器 可作报警提示、音乐等
19 DS1302时钟模块 DS1302芯片,可作时钟发生
20 步进电机驱动模块 ULN2003芯片,可作直流电机、28BYJ48步进电机驱动
21 STC89Cxx单片机座及IO 固定单片机,并将所有I0引出,方便用户二次开发
22 TFTLCD模块接口 与3号接口组合可连接TFTLCD触摸屏,可实现酷炫GUI人机
23 74HC595 扩展I0,控制LED点阵
24 74HC245 驱动数码管段选显示
25 74HC138 驱动数码管位选显示

2. 入门-LED灯

概念

2-1 点亮一个LED灯

LED灯为啥低点位才亮

由于单片机的I/O口的结构决定了它灌电流能力较强,所以都采用低电平点亮led的方式。其实,采用低电平驱动LED,只是为了简化单片机接口的设计,如果采用接口元件,则高电平驱动和低电平驱动是同样的效果,另外,低电平驱动也简化了控制代码,避免了单片机上电复位时端口置高电平后对led的影响。

LED具有单向导电性,当LED的正端接了高电位,负端连接了低电位,且正负端电位差超过1.8V以上时,LED就会亮起来。

image-20240307202350272

创建项目

image-20240306145440719

image-20240306145545249

选择合适的编译器

image-20240306145631963

image-20240306145712353

image-20240306145736828

创建成功如下所示

image-20240306145744892

编写代码

image-20240306145757522

image-20240306145804796

image-20240306145927039

如果你觉得字体太小,可以按照以下操作

image-20240306150033700

编写代码

#include <REGX52.h>

void main()
{
   
	P2=0xFE; //1111 1110 0表示低点位,LED在低点位的情况下才亮灯
}

解释一下P0啥意思。C51中的sfr,sbit

  • sfr (special function register)特殊功能寄存器声明

    例:sfr PO =0x80;物理地址为0x80声明P0口寄存器,

  • sbit (special bit) :特殊位声明

    例:sbit PO_1=0x81;或 sbit p0_1=POA1;

    声明PO寄存器的第1位

可位寻址/不可位寻址:在单片机系统中,操作任意寄存器或者某一位的数据时,必须给出其物理地址,又因为一个寄存器里有8位所以位的数量是寄存器数量的8倍,单片机无法对所有位进行编码故每8个寄存器中,只有一个是可以位寻址的。对不可位寻址的寄存器,若要只操作其中一位而不影响其它位时,可用“&=”、“=”“^=”的方法进行位操作

image-20240413161929215

点击编译,输出hex文件

image-20240306150335884

编译成功,

image-20240306151656087

查看是否成功输出hex文件,在文件夹的Objects下

image-20240306150359471

上传代码至单片机

image-20240306150703117

重启单片机后,会发现灯亮了

image-20240306150758001

2-2 LED闪烁

根据板子-生成延时代码

image-20240307104809609

编写代码
#include <REGX52.H>
#include <INTRINS.H>

void Delay500ms(void)	//@11.0592MHz
{
   
	unsigned char data i, j, k;

	_nop_();
	i = 4;
	j = 129;
	k = 119;
	do
	{
   
		do
		{
   
			while (--k);
		} while (--j);
	} while (--i);
}


void main()
{
   
	while(1){
   
		
		P2=0xFE;
		Delay500ms();
		P2=0xFF;
		Delay500ms();
	}
	
}

2-3 LED流水灯

#include <REGX52.H>
#include <INTRINS.H>

void Delay1ms(unsigned int xms)	//@11.0592MHz
{
   
	unsigned char data i, j;
	
	while(xms){
   
			i = 2;
			j = 199;
			do
			{
   
				while (--j);
			} while (--i);
			xms--;
	}
}



void main()
{
   
	while(1){
   
		P2=0xFE; // 1111 1110
		Delay1ms(500);
		P2=0xFD; // 1111 1101
		Delay1ms(500);
		P2=0xFB; // 1111 1011
		Delay1ms(500);
		P2=0xF7; // 1111 0111
		Delay1ms(500);
		P2=0xEF; // 1110 1111
		Delay1ms(500);
		P2=0xDF; // 1101 1111
		Delay1ms(500);
		P2=0xBF; // 1011 1111
		Delay1ms(500);
		P2=0x7F; // 0111 1111
		Delay1ms(500);
	}
	
}

3、 独立按键

3-1 独立按键控制LED亮灭

独立按键

image-20240307202410746

#include<REGX52.h>

void main()
{
   
   while(1){
   
		
		 if(P3_1==0){
    // 当第一个独立按键被按下时
			 p2_0=0; // 第一个灯就会亮
		 }else{
   
			 p2_0=1;
		 }
		 
	 }
}

简化版

#include<REGX52.h>

void main()
{
   
   P2_0=P3_1;
}

3-2 独立按键控制LED状态

注意事项

image-20240307111939335

所以需要20ms来延时抖动

#include <REGX52.H>
#include <INTRINS.H>

void Delay1ms(unsigned int xms)	//@11.0592MHz
{
   
	unsigned char data i, j;
	
	while(xms){
   
			i = 2;
			j = 199;
			do
			{
   
				while (--j);
			} while (--i);
			xms--;
	}
}


void main()
{
   
	while(1){
   
		if(P3_1==0){
   
			Delay1ms(20);
			while(P3_1==0);
			Delay1ms(20);
			P2_0=~P2_0;
		}
	}
	
}

3-3 独立按键控制LED显示二进制

#include <REGX52.H>
#include <INTRINS.H>

void Delay1ms(unsigned int xms)	//@11.0592MHz
{
   
	unsigned char data i, j;
	
	while(xms){
   
			i = 2;
			j = 199;
			do
			{
   
				while (--j);
			} while (--i);
			xms--;
	}
}


void main()
{
   
	while(1){
   
		if(P3_1==0){
   
			Delay1ms(20);
			while(P3_1==0);
			Delay1ms(20);
			P2--;
		}
	}
	
}

3-4 独立按键控制LED移位

#include <REGX52.H>
#include <INTRINS.H>

void Delay1ms(unsigned int xms)	//@11.0592MHz
{
   
	unsigned char data i, j;
	
	while(xms){
   
			i = 2;
			j = 199;
			do
			{
   
				while (--j);
			} while (--i);
			xms--;
	}
}


void main()
{
   
	
	unsigned char LEDnumber;
	
	P2=~0x01;
	
	while(1){
   
		if(P3_1==0){
   
			Delay1ms(20);
			while(P3_1==0);
			Delay1ms(20);
			LEDnumber++;
			if(LEDnumber>=8){
   
				LEDnumber=0;
			}
			P2=~(0x01<<LEDnumber);
		}
		
		if(P3_0==0){
   
			Delay1ms(20);
			while(P3_0==0);
			Delay1ms(20);
			
			if(LEDnumber==0){
   
				LEDnumber=7;
			
			}else{
   
				
				LEDnumber--;
			}
			P2=~(0x01<<LEDnumber);
		}
	}
	
	
	
}

4、数码管

概念

什么是数码管

LED数码管: 数码管是一种简单、廉价的显示器,是由多个发光二极管封装在一起组成“8”字型的器件

  • 按照发光二极管段数可以7段数码管和8段数码管,二者区别呢?就是8段数码管多了一个dp管,表示小数点。

  • 按照发光二极管连接方式,可以分为2种,第一种是,所有的阴极连在一块,叫做共阴极,还有一种是,所有的阳极连在一块,叫做共阳极

    • 共阳数码管是指将所有发光二极管的阳极接到一起形成公共阳极(COM)的数码管,共阳数码管在应用时应将公共极 COM 接到+5V
    • 共阴数码管是指将所有发光二极管的阴极接到一起形成公共阴极(COM) 的数码管,共阴数码管在应用时应将公共极 COM 接到地线GND上

image-20240307201532149

数码管引脚定义-显示原理

image-20240307203119383

电路设计

image-20240307202331685

为什么需要38译码器

image-20240307205230809

这里我们看到U5 CBA的配置。这里用来把3位数字转换成8位 比如 5 代表3位 101 转换成8位 0001 0000

CBA就表示3位 101 C表示第一位的1 B表示第二位的0 A表示第三位的1

表示选中了LED5

为什么需要74HC245

4-1 静态数码管显示6

image-20240307215230062

让数码管显示6

#include <REGX52.H>
void main()
{
   
	
	P2_4=1;
	P2_3=0;
	P2_2=1;
	P0=0x7D; // 
}

理由如下

image-20240307221243386

image-20240307220519887

  • dp表示 数码管上的小数点,因为不需要显示,所以对应的是0
  • P07对应高位,P0寄存器正确的读法是 P07-P00 。对应的数据位 0111 1101 对应的16进制位 7D
#include <REGX52.H>
#include <INTRINS.H>
unsigned char  NixmeTable[]={
   
	0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,
	0x77,0x7C,0x39,0x5E,0x79,0x71,0x00
};

void Delay1ms(unsigned int xms)	//@11.0592MHz
{
   
	unsigned char data i, j;
	
	while(xms){
   
			i = 2;
			j = 199;
			do
			{
   
				while (--j);
			} while (--i);
			xms--;
	}
}

void Nixie(unsigned char Location,number)
{
   
	switch(Location){
   
		case 1:P2_4=1;P2_3=1;P2_2=1;break;
		case 2:P2_4=1;P2_3=1;P2_2=0;break;
		case 3:P2_4=1;P2_3=0;P2_2=1;break;
		case 4:P2_4=1;P2_3=0;P2_2=0;break;
		case 5:P2_4=0;P2_3=1;P2_2=1;break;
		case 6:P2_4=0;P2_3=1;P2_2=0;break;
		case 7:P2_4=0;P2_3=0;P2_2=1;break;
		case 8:P2_4=0;P2_3=0;P2_2=0;break;
	}
	
	P0=NixmeTable[number];
}


void main()
{
   
	
    Nixie(7,2);
    while(1){
   
        
    }
	
}

4-2 动态数码管显示

#include <REGX52.H>
#include <INTRINS.H>
unsigned char  NixmeTable[]={
   
	0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,
	0x77,0x7C,0x39,0x5E,0x79,0x71,0x00
};

void Delay1ms(unsigned int xms)	//@11.0592MHz
{
   
	unsigned char data i, j;
	
	while(xms){
   
			i = 2;
			j = 199;
			do
			{
   
				while (--j);
			} while (--i);
			xms--;
	}
}

void Nixie(unsigned char Location,number)
{
   
	switch(Location){
   
		
		case 1:P2_4=1;P2_3=1;P2_2=1;break;
		case 2:P2_4=1;P2_3=1;P2_2=0;break;
		case 3:P2_4=1;P2_3=0;P2_2=1;break;
		case 4:P2_4=1;P2_3=0;P2_2=0;break;
		case 5:P2_4=0;P2_3=1;P2_2=1;break;
		case 6:P2_4=0;P2_3=1;P2_2=0;break;
		case 7:P2_4=0;P2_3=0;P2_2=1;break;
		case 8:P2_4=0;P2_3=0;P2_2=0;break;
	}
	
	P0=NixmeTable[number];
}


void main()
{
   
	
	while(1){
   
		Nixie(2,1);
		Nixie(3,2);
		Nixie(4,3);
	}
	
}

这种情况下会出现消影问题

位选 段选 位选 段选 位选 段选 位选 段选 位选 段选

正常情况下, 是一段位选 段选 ,一段 位选 段选 。但是程序运行太快,会出现一段的 段选 位选 ,即橘色的部分。这样子,数字就会串号了

image-20240308181759643

解决办法

位选 段选 清零 位选 段选 清零 位选 段选 清零 位选 段选 清零 位选 段选

#include <REGX52.H>
#include <INTRINS.H>
unsigned char  NixmeTable[]={
   
	0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,
	0x77,0x7C,0x39,0x5E,0x79,0x71,0x00
};

void Delay1ms(unsigned int xms)	//@11.0592MHz
{
   
	unsigned char data i, j;
	
	while(xms){
   
			i = 2;
			j = 199;
			do
			{
   
				while (--j);
			} while (--i);
			xms--;
	}
}

void Nixie(unsigned char Location,number)
{
   
	switch(Location){
   
		
		case 1:P2_4=1;P2_3=1;P2_2=1;break;
		case 2:P2_4=1;P2_3=1;P2_2=0;break;
		case 3:P2_4=1;P2_3=0;P2_2=1;break;
		case 4:P2_4=1;P2_3=0;P2_2=0;break;
		case 5:P2_4=0;P2_3=1;P2_2=1;break;
		case 6:P2_4=0;P2_3=1;P2_2=0;break;
		case 7:P2_4=0;P2_3=0;P2_2=1;break;
		case 8:P2_4=0;P2_3=0;P2_2=0;break;
	}
	
	P0=NixmeTable[number];
	Delay1ms(5);
	P0=0x00;
}


void main()
{
   

	while(1){
   
		Nixie(2,1);
		Nixie(3,2);
		Nixie(4,3);
	}	
}

单片机直接扫描:硬件设备简单,但是会耗费大量的单片机CPU时间。

专用驱动芯片,内部自带显存,扫描电路,单片机只需要告诉他显示什么即可

5、模块化

5-1 模块化编程

首先进行新建工程

创建Delay.c 文件

image-20240308202245247

#include <INTRINS.H>

void Delay1ms(unsigned int xms)	//@11.0592MHz
{
   
	unsigned char data i, j;
	
	while(xms){
   
			i = 2;
			j = 199;
			do
			{
   
				while (--j);
			} while (--i);
			xms--;
	}
}

然后创建头文件

image-20240308202400583

创建.h文件后,会发现文件里面啥都没有。所以需要添加已经存在的文件,才能显示

image-20240308202134695

image-20240308202506950

最后发现工程目录为

image-20240308202200360

main文件夹内容

#include <REGX52.h>
#include "Delay.h"

void main()
{
   
	Delay1ms(10);
}

所有函数如下

image-20240308191643714

5-2 LCD1602调试工具

模块化LCD

LCD1602.c代码

#include <REGX52.H>

//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0

//函数定义:
/**
  * @brief  LCD1602延时函数,12MHz调用可延时1ms
  * @param  无
  * @retval 无
  */
void LCD_Delay()
{
   
	unsigned char i, j;

	i = 2;
	j = 239;
	do
	{
   
		while (--j);
	} while (--i);
}

/**
  * @brief  LCD1602写命令
  * @param  Command 要写入的命令
  * @retval 无
  */
void LCD_WriteCommand(unsigned char Command)
{
   
	LCD_RS=0;
	LCD_RW=0;
	LCD_DataPort=Command;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602写数据
  * @param  Data 要写入的数据
  * @retval 无
  */
void LCD_WriteData(unsigned char Data)
{
   
	LCD_RS=1;
	LCD_RW=0;
	LCD_DataPort=Data;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602设置光标位置
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @retval 无
  */
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
   
	if(Line==1)
	{
   
		LCD_WriteCommand(0x80|(Column-1));
	}
	else if(Line==2)
	{
   
		LCD_WriteCommand(0x80|(Column-1+0x40));
	}
}

/**
  * @brief  LCD1602初始化函数
  * @param  无
  * @retval 无
  */
void LCD_Init()
{
   
	LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
	LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
	LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
	LCD_WriteCommand(0x01);//光标复位,清屏
}

/**
  * @brief  在LCD1602指定位置上显示一个字符
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的字符
  * @retval 无
  */
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
   
	LCD_SetCursor(Line,Column);
	LCD_WriteData(Char);
}

/**
  * @brief  在LCD1602指定位置开始显示所给字符串
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  String 要显示的字符串
  * @retval 无
  */
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
   
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=0;String[i]!='\0';i++)
	{
   
		LCD_WriteData(String[i]);
	}
}

/**
  * @brief  返回值=X的Y次方
  */
int LCD_Pow(int X,int Y)
{
   
	unsigned char i;
	int Result=1;
	for(i=0;i<Y;i++)
	{
   
		Result*=X;
	}
	return Result;
}

/**
  * @brief  在LCD1602指定位置开始显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~65535
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
   
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
   
		LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以有符号十进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:-32768~32767
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{
   
	unsigned char i;
	unsigned int Number1;
	LCD_SetCursor(Line,Column);
	if(Number>=0)
	{
   
		LCD_WriteData('+');
		Number1=Number;
	}
	else
	{
   
		LCD_WriteData('-');
		Number1=-Number;
	}
	for(i=Length;i>0;i--)
	{
   
		LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以十六进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~0xFFFF
  * @param  Length 要显示数字的长度,范围:1~4
  * @retval 无
  */
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
   
	unsigned char i,SingleNumber;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
   
		SingleNumber=Number/LCD_Pow(16,i-1)%16;
		if(SingleNumber<10)
		{
   
			LCD_WriteData(SingleNumber+'0');
		}
		else
		{
   
			LCD_WriteData(SingleNumber-10+'A');
		}
	}
}

/**
  * @brief  在LCD1602指定位置开始以二进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
  * @param  Length 要显示数字的长度,范围:1~16
  * @retval 无
  */
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
   
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
   
		LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
	}
}

LCD1602.h

#ifndef __LCD1602_H__
#define __LCD1602_H__

//用户调用函数:
void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);

#endif

main.c

#include <REGX52.h>
#include "LCD1602.h"

void main()
{
   
	
	LCD_Init();
	LCD_ShowString(1,1,"A");
	while(1)
	{
   
		
	}
}

注意事项

  1. LCD板子没有插进入,千万别返回来擦进入
  2. 延时函数,LCD1602.h里面的函数得写对
  3. 变阻器,需要自己调节,调整亮度
  4. 程序需要重新下载,才能显示

image-20240308213918955

下面是我的错误尝试。引以为戒

image-20240308214306857

6、矩阵键盘

基本概念

  • 在键盘中按键数量较多时,为了减少I/0口的用,通常将按键排列成矩阵形式
  • 采用逐行或逐列的“扫描”,就可以读出任何位置按键的状态

image-20240309110909498

6-1 矩阵键盘显示

项目目录结构如下

image-20240310152719108

MatrixKey.c

#include <REGX52.h>
#include "Delay.h"

unsigned char MatrixKey()
{
   
	
	unsigned char KeyNumber=0;
	
	P1=0xFF;
	P1_3=0;
	if(P1_7==0){
   Delay1ms(20);while(P1_7==0);Delay1ms(20);KeyNumber=1;}
	if(P1_6==0){
   Delay1ms(20);while(P1_6==0);Delay1ms(20);KeyNumber=5;}
	if(P1_5==0){
   Delay1ms(20);while(P1_5==0);Delay1ms(20);KeyNumber=9;}
	if(P1_4==0){
   Delay1ms(20);while(P1_4==0);Delay1ms(20);KeyNumber=13;}
	
	// 
	P1=0xFF;
	P1_2=0;
	if(P1_7==0){
   Delay1ms(20);while(P1_7==0);Delay1ms(20);KeyNumber=2;}
	if(P1_6==0){
   Delay1ms(20);while(P1_6==0);Delay1ms(20);KeyNumber=6;}
	if(P1_5==0){
   Delay1ms(20);while(P1_5==0);Delay1ms(20);KeyNumber=10;}
	if(P1_4==0){
   Delay1ms(20);while(P1_4==0);Delay1ms(20);KeyNumber=14;}
	
	P1=0xFF;
	P1_1=0;
	if(P1_7==0){
   Delay1ms(20);while(P1_7==0);Delay1ms(20);KeyNumber=3;}
	if(P1_6==0){
   Delay1ms(20);while(P1_6==0);Delay1ms(20);KeyNumber=7;}
	if(P1_5==0){
   Delay1ms(20);while(P1_5==0);Delay1ms(20);KeyNumber=11;}
	if(P1_4==0){
   Delay1ms(20);while(P1_4==0);Delay1ms(20);KeyNumber=15;}
	
	P1=0xFF;
	P1_0=0;
	if(P1_7==0){
   Delay1ms(20);while(P1_7==0);Delay1ms(20);KeyNumber=4;}
	if(P1_6==0){
   Delay1ms(20);while(P1_6==0);Delay1ms(20);KeyNumber=8;}
	if(P1_5==0){
   Delay1ms(20);while(P1_5==0);Delay1ms(20);KeyNumber=12;}
	if(P1_4==0){
   Delay1ms(20);while(P1_4==0);Delay1ms(20);KeyNumber=16;}
	
	
	return KeyNumber;
	
}

matrixKey.h

#ifndef __MATRIXKEY_H__
#define __MATRIXKEY_H__


unsigned char MatrixKey();

#endif

main.c

#include <REGX52.h>
#include "LCD1602.h"
#include "MatrixKey.h"

unsigned char KeyNum;
void main()
{
   
	
	LCD_Init();
	LCD_ShowString(1,1,"A");
	while(1)
	{
   
		KeyNum=MatrixKey();
		if(KeyNum){
   
			LCD_ShowNum(2,1,KeyNum,2);
		}
	}
}

6-2 矩阵键盘密码锁

image-20240311144518457

main.c代码如下

#include <REGX52.h>
#include "LCD1602.h"
#include "MatrixKey.h"

unsigned char KeyNum;
unsigned int Password,Count;
void main()
{
   
	
	LCD_Init();
	LCD_ShowString(1,1,"Password")
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值