学习笔记|矩阵按键控制原理|数值转化为键码|密码锁|STC32G单片机视频开发教程(冲哥)|第十四集:矩阵按键原理及实践

文章目录

  • 1.矩阵按键是什么
  • 2.矩阵按键的控制原理
  • 3.矩阵按键程序的编写
    • 将数值转化为键码
    • 完整代码:
      • demo.c:
      • key.c:
      • key.h:
  • 密码锁(简易版)
    • 需求分析:
  • 总结
  • 课后练习:

1.矩阵按键是什么

这个矩阵按键也是我们这个开发版上最后一个GPIO的一个应用,如果对IO回的输入跟输出还有什么问题的话,一定要回过头去看一下我们之前的程序理清楚思路。
之前的按键电路图:
在这里插入图片描述
1个按键占用一个IO口的。
在按键数量较多时,为了减少I/O口的占用,将按键排列成矩阵排列的形式的按键阵列我们称位矩阵按键。

2.矩阵按键的控制原理

电路图:
在这里插入图片描述

按键识别原理:端口默认为高电平,实时读取到引脚为低电平是表示按下。再次读取到高电平,表示松开。

第一步:现将P0.0-P0.3输出低电平,P0.6-P0.7输出高电平,如果有按键按下,按下的那一列的IO就会变成低电平,就可以判断出哪一列按下了。

第二步:现将P0.0-P0.3输出高电平,P0.6-P0.7输出低电平,如果有按键按下,按下的那一行的IO就会变成低电平,就可以判断出哪一行按下了。

第三步:行列组合一下就可以判断出是哪个按键按下了。

按键按下后导线导通,哪条线上有高电平,就会被拉低为低电平,从而检测出是哪条线路,二次检查,交叉节点就是有按键按下的按键位置。

3.矩阵按键程序的编写

先完成矩阵按键的功能编写。
复制9.TIM多任务为10.矩阵按键,用到P0端口,还是在之前的KEY模块基础上进行修改:
在key.h中定义:#define MateixKEY P0 //矩阵按键的引脚
定义函数MateixKEY_Read:
u8 MateixKEY_Read(void); //矩阵按键读取当前是哪一个按钮按下,返回值是按键序号
在key.c中实现函数MateixKEY_Read:
先增加函数头,并把实现思路复制过来作为编写依据,围绕这三步,编写矩阵按键的读取程序:
MateixKEY = 0XC0; //1100 0000 P0.6-P0.7输出高电平,
在这里插入图片描述

增加延时函数MateixKEY_delay留反应时间:
MateixKEY_delay(); //留反应时间
MateixKEY_delay的实现,并添加函数头:

void MateixKEY_delay(void)
{u8 i;i = 60; //根据之前的毫秒延时函数,可以算出此处延时的时间while(--i);
}

第一步:假设P0.7按下, 则为0100 0000,如果想实现哪路按下哪位变成1,可以采用异或运算。
即:0100 0000 ^1100 0000 = 1000 0000
则有:keystate = MateixKEY^0XC0;

第二步:第二次扫描,高位输出低电平,低位输出高电平:MateixKEY = 0X0f; //0000 1111
保存按键状态,假设P0.0按下, 则为0000 1110^0000 1111 = 0000 0001,这里要采用|=,0000 0001 | 1000 0000 = 1000 0001 = 0x81
在这里插入图片描述
keystate |= (MateixKEY^0X0f);是为了避免把之前的数值覆盖。
第三步:keystate中已经保存了行、列的状态,行列组合一下就可以判断出是哪个按键按下了。
printf(“%02x\r\n”,keystate); //强制变为2位,以16进制显示。
return keystate;
在demo.c中调用:
将10ms扫描按键的代码部分注释掉,只检测MateixKEY_Read,加入该函数,编译,运行。按动按键,串口打印对应的16进制数值。

将数值转化为键码

u8 key_val = 0; //表示按键的键码
这里采用switch关键词,直接有模板插入,编写switch函数:

	switch (keystate) //单选开关函数{case 0x41:	key_val = 1;break;case 0x42:	key_val = 2;break;case 0x44:	key_val = 3;break;case 0x48:	key_val = 4;break;case 0x81:	key_val = 5;break;case 0x82:	key_val = 6;break;case 0x84:	key_val = 7;break;case 0x88:	key_val = 8;break;default:  	key_val = 0;break;}

关闭数码管初始化显示,main函数中新建变量:u8 KEY_NUM = 0; //保存矩阵按键的键码
读取矩阵按键的键码保存在KEY_NUM中,并在数码管最后1位显示:

			KEY_NUM = MateixKEY_Read();SEG7 = KEY_NUM; 	//在数码管最后一位显示

编译下载,按动按键就可以判断是哪个按键按下了。

完整代码:

demo.c:

#include "COMM/stc.h"		//调用头文件
#include "COMM/usb.h"
#include "seg_led.h"
#include "key.h"			//调用头文件
#include "beep.h"
#include "tim0.h"#define MAIN_Fosc 24000000UL	//定义主时钟char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";bit TIM_10MS_Flag;		//10ms标志位void sys_init();	//函数声明
void delay_ms(u16 ms);void Timer0_Isr(void);void main()					//程序开始运行的入口
{u8 KEY_NUM = 0; 		//保存矩阵按键的键码sys_init();				//USB功能+IO口初始化usb_init();				//usb库初始化Timer0_Init();EA = 1;					//CPU开放中断,打开总中断。//数码管初始化,显示0-7
//	SEG0 = 0;
//	SEG1 = 1;
//	SEG2 = 2;
//	SEG3 = 3;
//	SEG4 = 4;
//	SEG5 = 5;
//	SEG6 = 6;
//	SEG7 = 7;LED = 0x0f;	//赋初值,亮一半灭一半,可以写8位的变量.从7开始数到0while(1)		//死循环{
//		if( DeviceState != DEVSTATE_CONFIGURED ) 	//
//			continue;if( bUsbOutReady ){usb_OUT_done();}if(TIM_10MS_Flag == 1)   //将需要延时的代码部分放入{TIM_10MS_Flag = 0;		//TIM_10MS_Flag 变量清空置位
//			KEY_Deal();				//P3上所有端口都需要执行一遍BEEP_RUN();				//蜂鸣运行//			if(KEY_ReadState(KEY1)== KEY_RESS)	//判断KEY1按钮是否为单击
//			{
//				BEEP_ON(2);							//蜂鸣20ms
//				LED0 = 0;
//			}
//			else if(KEY_ReadState(KEY1)== KEY_LONGPRESS) //判断KEY1按钮是否为长按
//			{
//				BEEP_ON(2);							//蜂鸣20ms
//				LED1 = 0;
//			}
//			else if(KEY_ReadState(KEY1)== KEY_RELAX)	//判断KEY1按钮是否为松开
//			{
//				LED = 0XFF;
//			}KEY_NUM = MateixKEY_Read();SEG7 = KEY_NUM; 	//在数码管最后一位显示}}
}void sys_init()		//函数定义
{WTST = 0;  //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快EAXFR = 1; //扩展寄存器(XFR)访问使能CKCON = 0; //提高访问XRAM速度P0M1 = 0x00;   P0M0 = 0x00;   //设置为准双向口P1M1 = 0x00;   P1M0 = 0x00;   //设置为准双向口P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口P3M0 = 0x00;P3M1 = 0x00;P3M0 &= ~0x03;P3M1 |= 0x03;//设置USB使用的时钟源IRC48MCR = 0x80;    //使能内部48M高速IRCwhile (!(IRC48MCR & 0x01));  //等待时钟稳定USBCLK = 0x00;	//使用CDC功能需要使用这两行,HID功能禁用这两行。USBCON = 0x90;
}void delay_ms(u16 ms)	//unsigned int
{u16 i;do{i = MAIN_Fosc/6000;while(--i);}while(--ms);
}void Timer0_Isr(void) interrupt 1 //1ms进来执行一次,无需其他延时,重复赋值
{static timecount = 0;SEG_LED_Show();		//数码管刷新timecount++;		//1ms+1if(timecount>=10)	//如果这个变量大于等于10,说明10ms到达{timecount = 0;TIM_10MS_Flag = 1;	//10ms到了}
}

key.c:

#include "key.h"			//调用头文件
u16 Count[8] = {0,0,0,0,0,0,0,0};	//按键的时间状态变量初始化8位
u8 LastState = 0;					//8位变量,b0=1 则表示key0上一次按下过//========================================================================
// 函数名称:KEY_Deal
// 函数功能:按键状态的获取
// 入口参数:无
// 函数返回:无
// 当前版本: VER1.0
// 修改日期: 2023-1-1
// 当前作者:
// 其他备注:循环读取8个端口的状态,并将按下的时间赋值给Count数组,然后按下的状态赋值给变量LastState
//========================================================================
void KEY_Deal(void) 			//检查所有的按键状态,10ms执行一次
{u8 i = 0;for(i=0;i<8;i++)			//for循环变量 循环8次,i取值为0-7,代表P30-P37的状态查询{if(~KEY & (1<<i) )					//如果持续按下,变量加1{if(Count[i] < 60000)			// Count是u16类型,最大值小于65535,故增加限定条件。Count[i] ++;					//如果持续按下,这个变量加1}else					//如果按键松开,变量清0{if(Count[i] > 0 )	//如果这个按键是按下过的,{LastState |= (1<<i);	//这个变量相应的标志位置1,单独写对应位}else{LastState &= ~(1<<i);	//仅操作这个变量相应的标志位清0}Count[i] = 0;					//如果松开,计数变量清0}}}
//========================================================================
// 函数名称:KEY_ReadState
// 函数功能:读取指定的按钮的状态
// 入口参数: @keynum; 按钮的端口号,例如P32的端口号是2,
// 函数返回:见KEY的返回值的各种状态,看其他备注
// 当前版本: VER1.0
// 修改日期: 2023-1-1
// 当前作者:
// 其他备注: 函数返回值如下:
状态	功能
//#define KEY_NOPRESS 0 	//按键未按下	0
//#define KEY_FLCKER 1 		//消抖	1
//#define KEY_RESS 2		//单击	2
//#define KEY_PRESSOVER 3 	//单击结束	3
//#define KEY_LONGPRESS 4 	//长按3s	4
//#define KEY_LONGOVER 5 	//长按结束	5
//#define KEY_RELAX 6 		//按键松开	6
//========================================================================u8  KEY_ReadState(u8 keynum) 	//读取指定按键的状态,10ms执行1次
{if(Count[keynum] > 0)			//判断按键是按下的{if(Count[keynum] < 3)		//按下小于30ms,返回消抖状态{return KEY_FLCKER;}else if(Count[keynum] == 3)	//按正好等于30ms,返回单击状态{return KEY_RESS;}else if(Count[keynum] < 300 ) //按下小于3000ms,返回单击结束{return KEY_PRESSOVER;}else if(Count[keynum] == 300 ) //按下正好等于3000ms,返回长按{return KEY_LONGPRESS;}else					//长按结束{return KEY_LONGOVER;}}else						//按键已经松开了,返回KEY_RELAX状态{if(LastState &(1<<keynum))			//按键之前按下过,要判断上1s是不是高电平,如果上1s是低电平,说明是按键按下//例如,要判断P32,P30,31,32,左移2位,//按键已经松开了{return KEY_RELAX;}else			//按键之前没有按下过,返回未按下{return KEY_NOPRESS;}}
}
//========================================================================
// 函数名称:MateixKEY_delay
// 函数功能:矩阵按键读取专用延时函数
// 入口参数:无
// 函数返回:无
// 当前版本: VER1.0
// 修改日期: 2023
// 当前作者:
// 其他备注:
//========================================================================
void MateixKEY_delay(void)
{u8 i;i = 60; //根据之前的ms延时的函数,可以算出此处延时的时间while(--i);
}
//========================================================================
// 函数名称:MateixKEY_Read
// 函数功能:矩阵按键读取当前是哪一个按钮按下
// 入口参数:无
// 函数返回:0表示没有按键按下,1-8表示当前是第几个按键按下
// 当前版本: VER1.0
// 修改日期: 2023-1-1
// 当前作者:
// 其他备注:
//========================================================================
u8 MateixKEY_Read(void) 	//矩阵按键读取当前是哪一个按钮按下,返回值是按键序号
{u8 keystate;				//表示当前的按钮状态值u8 key_val = 0;				//表示按键的键码
//	第一步:现将P0.0-P0.3输出低电平,P0.6-P0.7输出高电平,如果有按键按下,按下的那一列的IO就会变成低电平,就可以判断出哪一列按下了。MateixKEY = 0XC0;			//1100 0000  P0.6-P0.7输出高电平,MateixKEY_delay();			//留反应时间keystate = (MateixKEY^0XC0);	//保存按键状态,假设P0.7按下, 则为0100 0000,如果想实现变成哪路按下变成1,用异或//	第二步:现将P0.0-P0.3输出高电平,P0.6-P0.7输出低电平,如果有按键按下,按下的那一行的IO就会变成低电平,就可以判断出哪一行按下了。MateixKEY = 0X0f;			//0000 1111  高位输出低电平,低位输出高电平MateixKEY_delay();			//留反应时间keystate |= (MateixKEY^0X0f);	//保存按键状态,假设P0.0按下, 则为0000 1110^0000 1111 = 0000 0001,这里要采用|=,为了避免把之前的数值覆盖。//	第三步:行列组合一下就可以判断出是哪个按键按下了。
//	printf("%02x\r\n",keystate); //强制变为2位,以16进制显示。switch (keystate) //单选开关函数{case 0x41:	key_val = 1;break;case 0x42:	key_val = 2;break;case 0x44:	key_val = 3;break;case 0x48:	key_val = 4;break;case 0x81:	key_val = 5;break;case 0x82:	key_val = 6;break;case 0x84:	key_val = 7;break;case 0x88:	key_val = 8;break;default:  	key_val = 0;break;}return key_val;}

key.h:

#ifndef __KEY_H
#define __KEY_H#include "COMM/stc.h"			//调用头文件
#include "COMM/usb.h"//------------------------引脚定义------------------------//
#define KEY P3 			//定义一个按键 引脚选择P32-P36#define KEY1 2			//按键1
#define KEY2 3			//按键2
#define KEY3 4			//按键3
#define KEY4 5			//按键4#define MateixKEY P0    //矩阵按键的引脚//------------------------变量声明------------------------//
//状态	功能
#define KEY_NOPRESS 0 		//按键未按下	0
#define KEY_FLCKER 1 		//消抖	1
#define KEY_RESS 2			//单击	2
#define KEY_PRESSOVER 3 	//单击结束	3
#define KEY_LONGPRESS 4 	//长按3s	4
#define KEY_LONGOVER 5 		//长按结束	5
#define KEY_RELAX 6 		//按键松开	6//------------------------函数声明-----------------------//
void KEY_Deal(void);			//检查所有的按键状态
u8  KEY_ReadState(u8 keynum);	//读取指定按键的状态u8 MateixKEY_Read(void);		//矩阵按键读取当前是哪一个按钮按下,返回值是按键序号#endif

密码锁(简易版)

在这里插入图片描述

由于KEY_NUM = MateixKEY_Read();执行后,会持续输出1,需要修改,3s内只输出1次即可,让它符合今天的主题。
先定义一个静态变量,这是一个很常见的用法,static u8 keystate_Last; //表示当前的按钮上一次的状态值
增加判断条件:

	if(keystate_Last != keystate)	//如果本次获取到的按键状态值和之前的不一样{keystate_Last = keystate;   //把本次的按键状态值写入进去switch (keystate) //单选开关函数{case 0x41:	key_val = 1;break;case 0x42:	key_val = 2;break;case 0x44:	key_val = 3;break;case 0x48:	key_val = 4;break;case 0x81:	key_val = 5;break;case 0x82:	key_val = 6;break;case 0x84:	key_val = 7;break;case 0x88:	key_val = 8;break;default:  	key_val = 0;break;}printf("%d\r\n",(int)key_val);  //强制转化为整形变量}

需求分析:

1.通过LED0模拟门锁状态,LED点亮表示门锁打开,熄灭表示门锁锁上;
增加横线显示值,SEG_Tab[22]=
默认显示横线:u8 Show_Tab[8] = {21,21,21,21,21,21,21,21};
新增变量:u8 KEY_Str = 0; //表示当前输入了几个密码
2.增加8位数码管,可以动态显示8位的密码,无密码时显示 “- - - - - - - -”;
3.通过矩阵按键可以输入1-8的数字表示密码,并依次显示在数码管上;
4.每输入一个数字,蜂鸣器响20ms表示有数字按下;
5.密码正确打开LED0,密码错误蜂鸣响2秒;
根据条件,修改demo.c中的main函数代码如下:

void main()					//程序开始运行的入口
{u8 KEY_NUM = 0; 		//保存矩阵按键的键码u8 KEY_Str = 0; 		//表示当前输入了几个密码位sys_init();				//USB功能+IO口初始化usb_init();				//usb库初始化Timer0_Init();EA = 1;					//CPU开放中断,打开总中断。//数码管初始化,显示0-7
//	SEG0 = 0;
//	SEG1 = 1;
//	SEG2 = 2;
//	SEG3 = 3;
//	SEG4 = 4;
//	SEG5 = 5;
//	SEG6 = 6;
//	SEG7 = 7;//LED = 0x0f;	//赋初值,亮一半灭一半,可以写8位的变量.从7开始数到0LED = 0xff;	//赋初值,密码锁应用初始状态熄灭所有LEDwhile(1)		//死循环{
//		if( DeviceState != DEVSTATE_CONFIGURED ) 	//
//			continue;if( bUsbOutReady ){usb_OUT_done();}if(TIM_10MS_Flag == 1)   //将需要延时的代码部分放入{TIM_10MS_Flag = 0;		//TIM_10MS_Flag 变量清空置位
//			KEY_Deal();				//P3上所有端口都需要执行一遍BEEP_RUN();				//蜂鸣运行//			if(KEY_ReadState(KEY1)== KEY_RESS)	//判断KEY1按钮是否为单击
//			{
//				BEEP_ON(2);							//蜂鸣20ms
//				LED0 = 0;
//			}
//			else if(KEY_ReadState(KEY1)== KEY_LONGPRESS) //判断KEY1按钮是否为长按
//			{
//				BEEP_ON(2);							//蜂鸣20ms
//				LED1 = 0;
//			}
//			else if(KEY_ReadState(KEY1)== KEY_RELAX)	//判断KEY1按钮是否为松开
//			{
//				LED = 0XFF;
//			}KEY_NUM = MateixKEY_Read();		//当前矩阵按键的键值//SEG7 = KEY_NUM; 	//在数码管最后一位显示if( KEY_NUM > 0)				//如果有按键按下{KEY_NUM = 0;						//键值先清空,清空按键BEEP_ON(2);							//蜂鸣20msShow_Tab[KEY_Str] = KEY_NUM; 		//表示当前输入了几个密码 = KEY_NUM;		//将当前的按键状态保存到数组KEY_Str++;							//输入的密码位数+1if(KEY_Str ==8)		//如果密码已经等于8位,{if((Show_Tab[0]==1)&&(Show_Tab[1]==1)&&(Show_Tab[2]==1)&&(Show_Tab[3]==1)&&(Show_Tab[4]==1)&&(Show_Tab[5]==1)&&(Show_Tab[6]==1)&&(Show_Tab[7]==1)){LED0 = 0;			//如果密码正确,LED0点亮}else{BEEP_ON(200);	//密码错误,蜂鸣2s。单位是10ms,2000ms=2s}}}}}
}

编译下载,发现按键后均显示0:KEY_NUM = 0;位置有误,应该放在调用以后再置0.
重新测试,8位输入后不能自动清空,应该添加代码,到达长度后回到初始值显示横杠:SEG0 = SEG1 = SEG2 = SEG3 = SEG4 = SEG5 = SEG6 = SEG7 = 21;
重新测试,输入错误后,复位,再按键输入,显示有问题:KEY_Str ==8后忘记归0了。
经过修改,功能已正常实现。
完整代码请参考:《STC单片机原理-教学视频配套附件-20230731.zip

总结

1.了解矩阵按键的工作原理和代码编写的过程

课后练习:

给今天的门锁增加如下功能:
1.LED0(门锁)打开后,5秒后自动关闭;
2.增加门内的手动开门按钮,按下按钮门锁打开;
3.10秒内没有输入密码自动数码管熄灭省电;有按键按下时再显示。
4.用for去改写一下密码判断的地方。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/79865.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Shell 正则表达式及综合案例及文本处理工具

目录 一、常规匹配 二、常用特殊字符 三、匹配手机号 四、案例之归档文件 五、案例之定时归档文件 六、Shell文本处理工具 1. cut工具 2. awk工具 一、常规匹配 一串不包含特殊字符的正则表达式匹配它自己 例子&#xff0c;比如说想要查看密码包含root字符串的&#x…

Vue3路由

文章目录 Vue3路由1. 载入vue-router 库2. 实例2.1 Vue.js vue-router 实现单页应用2.2 router-link创建链接2.3 router-view显示与url对应组件2.4 <router-link> 相关属性 Vue3路由 1. 载入vue-router 库 Vue.js 路由需要载入vue-router 库 安装直接下载地址&#xf…

Redis模块一:缓存简介

目录 缓存的定义 应用 生活案例 程序中的缓存 缓存优点 缓存的定义 缓存是⼀个高速数据交换的存储器&#xff0c;使用它可以快速的访问和操作数据。 应用 1.CPU缓存&#xff1a;CPU缓存是位于CPU和内存之间的临时存储器&#xff0c;它的容量通常远小于内存&#xff0…

linux安装常见的中间件和数据库

文章目录 一、数据库二、redis三、tomcat四、nginx五、mq六、es七、nacos八、neo4j&#xff08;图数据库&#xff09;九、fastdfs其他 一、数据库 linux环境上使用压缩包安装mysql【数据库】Mysql 创建用户与授权 二、redis redis是没有账号的&#xff0c;只能设置密码Linux…

学信息系统项目管理师第4版系列07_项目管理知识体系

1. 项目管理原则 1.1. 勤勉、尊重和关心他人 1.1.1. 关键点 1.1.1.1. 关注组织内部和外部的职责 1.1.1.2. 坚持诚信、关心、可信、合规原则 1.1.1.3. 秉持整体观 1.1.2. 职责 1.1.2.1. 诚信 1.1.2.2. 关心 1.1.2.3. 可信 1.1.2.4. 合规 1.2. 营造协作的项目管理团队…

Pytorch从零开始实战02

Pytorch从零开始实战——彩色图像识别 本系列来源于365天深度学习训练营 原作者K同学 文章目录 Pytorch从零开始实战——彩色图像识别环境准备数据集模型选择模型训练数据可视化 环境准备 本文基于Jupyter notebook&#xff0c;使用Python3.8&#xff0c;Pytorch2.0.1cu118…

IDM(Internet Download Manager)下载器2024最新版本如何下载?

IDM&#xff08;Internet Download Manager&#xff09;下载器能够兼容支持多种浏览器进行文件下载&#xff0c;很多时候只要复制一个地址IDM的下载弹窗就自动弹出来&#xff0c;有时候不需要下载的时候也会弹&#xff0c;时间久了就会感觉很烦&#xff0c;不过这个问题其实可以…

Python stomp 发送消息无法显示文本

我们向消息服务器通过 stomp 发送的是文本消息。 当消息服务器发送成功后&#xff0c;消息服务器上的文本没有显示&#xff0c;显示的是 2 进制的数据。 如上图&#xff0c;消息没有作为文本来显示。 问题和解决 消息服务器是如何判断发送的小时是文本还是二进制的。 根据官…

go-GC垃圾回收

GC GC是自动化内存管理回收机制 虚拟内存函数栈的数据是会根据函数返回而自动销毁的&#xff0c;而堆上的数据是不会随着函数自动销毁的&#xff0c;堆内数据会随着程序运行而逐渐变大&#xff0c;从而导致内存OOM&#xff0c;Go语言就用了GC来清理堆上的内存数据。 如何区分…

tomcat架构概览

https://blog.csdn.net/ldw201510803006/article/details/119880100 前言 Tomcat 要实现 2 个核心功能&#xff1a; 处理 Socket 连接&#xff0c;负责网络字节流与 Request 和 Response 对象的转化。加载和管理 Servlet&#xff0c;以及具体处理 Request 请求。 因此 Tomc…

CSS盒子模型

盒子模型的组成 CSS会把所有的HTML元素都看成一个盒子&#xff0c;所有的样式也都是基于这个盒子 content&#xff08;内容&#xff09;&#xff1a;盒子的内容padding&#xff08;内边距&#xff09;&#xff1a;用于控制元素内部与边框之间的距离border&#xff08;边框&…

让NPU跑起来迅为RK3588开发板设置交叉编译器

让NPU跑起来迅为RK3588开发板设置交叉编译器 编译器下载地址是网盘资料“iTOP-3588 开发板\02_【iTOP-RK3588 开发板】开发资料 \12_NPU 使用配套资料\03_编译所需工具\Linux”。 拷贝 gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu.tar.gz 到 Ubuntu 的/opt/tool_ch…

分类预测 | MATLAB实现PCA-GRU(主成分门控循环单元)分类预测

分类预测 | MATLAB实现PCA-GRU(主成分门控循环单元)分类预测 目录 分类预测 | MATLAB实现PCA-GRU(主成分门控循环单元)分类预测预测效果基本介绍程序设计参考资料致谢 预测效果 基本介绍 Matlab实现基于PCA-GRU主成分分析-门控循环单元多输入分类预测&#xff08;完整程序和数据…

八股文学习三(jvm+线程池+锁)

1. jvm (1)概念 JVM是可运行 Java 代码的假想计算机 &#xff0c;包括一套字节码指令集、一组寄存器、一个栈、一个垃圾回收&#xff0c;堆 和 一个存储方法域。JVM 是运行在操作系统之上的&#xff0c;它与硬件没有直接的交互。 java运行过程&#xff1a; 我们都知道 Java…

C#,数值计算——Hashfn1的计算方法与源程序

1 文本格式 using System; using System.Collections; using System.Collections.Generic; namespace Legalsoft.Truffer { public class Hashfn1 { private Ranhash hasher { get; set; } new Ranhash(); private int n { get; set; } public Hash…

TCP IP网络编程(六) 基于UDP的服务器端、客户端

文章目录 一、理解UDP1.UDP套接字的特点2.UDP内部工作原理3.UDP的高效使用 二、实现基于UDP的服务器端、客户端1.UDP中的服务端和客户端没有连接2.UDP服务器端和客户端均只需要一个套接字3.基于UDP的数据I/O函数4.基于UDP的回声服务器端、客户端5.UDP客户端套接字的地址分配 三…

IDEA中创建Java Web项目1

一、File-> New -> Project... 1. 项目类型中选择 Java Enterprise 项目 2. Name&#xff1a;填写自己的项目名称 3. Project template&#xff1a;选择项目的模板&#xff0c;Web application。支持JSP和Servlet的项目 4. Application server&#xff1a;选择应用服务…

【C++11保姆级教程】列表初始化(Literal types)和委派构造函数(delegating))

文章目录 前言一、列表初始化 (List Initialization)1.1数组初始化1.2结构体初始化1.3容器初始化1.4列表初始化的优势 二、委派构造函数 (Delegating Constructors)2.1委派构造函数是什么&#xff1f;2.2委派构造函数示例代码2.3调用顺序2.3委派构造函数优势 总结 前言 C11引入…

MySQL基础运维知识点大全

一. MySQL基本知识 1. 目录的功能 通用 Unix/Linux 二进制包的 MySQL 安装下目录的相关功能 目录目录目录binMySQLd服务器&#xff0c;客户端和实用程序docs信息格式的 MySQL 手册manUnix 手册页include包括&#xff08;头&#xff09;文件lib图书馆share用于数据库安装的错…

数据结构-leetcode-数组形式的整数加法

解题图解&#xff1a; 下面是代码&#xff1a; /*** Note: The returned array must be malloced, assume caller calls free().*/ int* addToArrayForm(int* num, int numSize, int k, int* returnSize){int k_tem k;int klen0;while(k_tem){//看看k有几位k_tem /10;klen;}i…