stm32学习笔记---GPIO输入(代码部分)按键控制LED/光敏传感器控制蜂鸣器

目录

第一个代码:按键控制LED

模块化程序

LED驱动程序

GPIO的四个读取函数

GPIO_ReadInputDataBit

GPIO_ReadInputData

GPIO_ReadOutputDataBit

GPIO_ReadOutputData

Key驱动程序

第二个代码:光敏传感器控制蜂鸣器

蜂鸣器驱动代码

光敏传感器驱动代码

总结GPIO的使用方法


声明:本专栏是本人跟着B站江科大的视频的学习过程中记录下来的笔记,我之所以记录下来是为了方便自己日后复习。如果你也是跟着江科大的视频学习的,可以配套本专栏食用,如有问题可以QQ交流群:963138186

上一篇讲了GPIO输入部分的理论知识,接下来我们来写一下GPIO输入部分的代码。

第一个代码:按键控制LED

先看一下第一个代码的接线图

这里接了两个按键和两个 LED,其中两个按键分别接在了PB1和PB11两个口上,按键一端接GPIO口,另一端接GND,因为这是引脚上拉输入模式,就是上一篇讲到的第一种接法

两个LED分别接在了PA1和PA2两个口上。LED一端接GPIO另一端接VCC,就是低电平电量的接法。

按键、LED的数量和连接的端口都是随意的。具体接多少个,接到哪些端口,就看你的需求。

接好电路后,打开工程文件夹,复制一下之前蜂鸣器工程的代码,改个名字,叫3-4 按键控制LED。

然后点进去打开工程,接下来我们就需要在这个工程上完成LED和按键的驱动代码。

模块化程序

在本节代码演示之前演示一下程序模块化,方便我们以后直接调用或者移植。

首先我们打开工程文件夹,再建一个文件夹,叫Hardware,以后就用来存放我们所有的硬件驱动代码。

然后回到keil,还是一样的步骤,点击三个箱子的按钮,打开工程管理,新建一个组也叫hardware。挪个位置,ok。

然后再点击魔术棒按钮,打开工程选项,选择C/C++,点击这里三个点的按钮。把刚才新建的hardware文件夹添加到头文件路径列表中,ok。

这样我们就又添加了一个Hardware文件夹。

LED驱动程序

然后在Hardware这里右键添加新的文件,选择c文件,起个名字叫LED这个文件,就用来分装LED的驱动程序,

然后路径也别忘了。

选择hardware文件夹,存在这个文件夹里,add。

接着继续在Hardware处右键添加新的文件,选择h文件,起个名字也叫LED。下面的路径也是一样,选择hardware文件夹,这里可以直接在这里写,反斜杠hardware,然后Add。

这样我们就建好了LED.c和LED.h两个文件,用来分装LED的驱动程序。

这两个文件建好之后,还得添加一些必要的代码。

首先.c文件的第一行,右键,include的一个头文件

.h文件里要添加一个防止头文件重复包含的代码

最后注意这个文件要以空行结尾,这样就完成了。

接着我们就编辑一下LED的的代码

我们打开LED.c文件,首先写一个LED初始化函数。

这个函数是用来初始化LED,里面写的就是打开时钟配置端口模式这些东西,这就是我们之前学的代码,也就是RCC_APB2外设时钟控制。

我们的LED都是接在GPIOA上的,所以第一个参数是RCC_APB2Periph外设GPIOA,然后第二个参数写enable开启时钟

接着配置端口模式,先定义一个结构体变量。

首先输入GPIO_Init这里如果不显示代码提示的话,可以按一下快捷键CTRL+ALT+空格,这样就可以弹出代码提示框了。我们选择GPIO_InitTypeDef

变量名叫GPIO_InitStructure,

然后引出结构体成员并赋值,最后取结构体的地址传参和GPIO初始化函数完成端口配置。这里过程在之前几篇博客中都详细讲过了,这里不再赘述。不懂的话可以去看看之前的博客。

这样LED初始化的代码就写完了。

在.h文件中声明一下这个函数是可以被外部调用的函数

然后在main.c中包含LED模块的头文件

在主函数里直接调用LED_Init就完成了LED的初始化

编译下载可以看到两个LED都亮起来了,

这说明我们的端口配置和模块化编程是没有问题的。

这里因为GPIO配置好了之后,默认就是低电平,所以我们还没操作LED,LED就亮起来了。我们可以在LED_Init函数的最后写上一行代码:

这样初始化之后,如果不操作LED就是熄灭的了。

重新编译下载,LED默认是关闭状态的。

GPIO的四个读取函数

接下来的程序我们需要用到读取GPIO端口的功能,先找一下GPIO的库函数文件,这四个就是GPIO的读取函数

GPIO_ReadInputDataBit

第一个函数是用来读取输入数据寄存器某一个端口的输入值。它的参数是指定外设和某一个端口。返回值代表这个端口的高低电平。读取按键,我们就需要用到这个函数。

GPIO_ReadInputData

第二个函数比上一函数少了个bit,它是用来读取整个输入数据寄存,参数只有一个GPIOx,用来指定外设。返回值是是一个16位的数据,每一位代表一个端口值。

GPIO_ReadOutputDataBit

第三个函数是用来读取输出数据寄存的某一个位。所以原则上来说,它并不是用来读取端口的输入数据的,这个函数一般用于输出模式下,用来看一下自己输出的是什么。

GPIO_ReadOutputData

最后一个函数也是少了一个bit,意思也是一样,是用来读取整个输出寄存器的

对照一下这个图,应该就好理解了。

GPIO_ReadInputDataBit就是读取这里输入数据寄存器的某一位。

GPIO_ReadInputData就是读取整个输入数据寄存器。

GPIO_ReadOutputDataBit就是读取这里输出数据寄存器的某一位。

GPIO_ReadOutputData就是读取这整个输出数据寄存器。

所以如果你想读取GPIO口的话,需要用read input的两个函数。如果在输出模式下,想要看一下现在输出了什么才需要用到read output的两个函数。

接着我们还得完善一下LED驱动程序模块,除了初始化,我们还需要点亮和熄灭LED的函数和按下按键后LED状态取反的函数

LED.c

#include "stm32f10x.h"                  // Device header

/**
  * 函    数:LED初始化
  * 参    数:无
  * 返 回 值:无
  */
void LED_Init(void)
{
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);		//开启GPIOA的时钟
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);						//将PA1和PA2引脚初始化为推挽输出
	
	/*设置GPIO初始化后的默认电平*/
	GPIO_SetBits(GPIOA, GPIO_Pin_1 | GPIO_Pin_2);				//设置PA1和PA2引脚为高电平
}

/**
  * 函    数:LED1开启
  * 参    数:无
  * 返 回 值:无
  */
void LED1_ON(void)
{
	GPIO_ResetBits(GPIOA, GPIO_Pin_1);		//设置PA1引脚为低电平
}

/**
  * 函    数:LED1关闭
  * 参    数:无
  * 返 回 值:无
  */
void LED1_OFF(void)
{
	GPIO_SetBits(GPIOA, GPIO_Pin_1);		//设置PA1引脚为高电平
}

/**
  * 函    数:LED1状态翻转
  * 参    数:无
  * 返 回 值:无
  */
void LED1_Turn(void)
{
	if (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_1) == 0)		//获取输出寄存器的状态,如果当前引脚输出低电平
	{
		GPIO_SetBits(GPIOA, GPIO_Pin_1);					//则设置PA1引脚为高电平
	}
	else													//否则,即当前引脚输出高电平
	{
		GPIO_ResetBits(GPIOA, GPIO_Pin_1);					//则设置PA1引脚为低电平
	}
}

/**
  * 函    数:LED2开启
  * 参    数:无
  * 返 回 值:无
  */
void LED2_ON(void)
{
	GPIO_ResetBits(GPIOA, GPIO_Pin_2);		//设置PA2引脚为低电平
}

/**
  * 函    数:LED2关闭
  * 参    数:无
  * 返 回 值:无
  */
void LED2_OFF(void)
{
	GPIO_SetBits(GPIOA, GPIO_Pin_2);		//设置PA2引脚为高电平
}

/**
  * 函    数:LED2状态翻转
  * 参    数:无
  * 返 回 值:无
  */
void LED2_Turn(void)
{
	if (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_2) == 0)		//获取输出寄存器的状态,如果当前引脚输出低电平
	{                                                  
		GPIO_SetBits(GPIOA, GPIO_Pin_2);               		//则设置PA2引脚为高电平
	}                                                  
	else                                               		//否则,即当前引脚输出高电平
	{                                                  
		GPIO_ResetBits(GPIOA, GPIO_Pin_2);             		//则设置PA2引脚为低电平
	}
}

调用六个函数来实现两个灯的打开和关闭以及状态取反。

当然这里定义4个函数比较繁琐了一点,我们后面还会讲如果用一个函数还实现关和开的操作,这里LED还是比较少,就直接这样写了。

最后在头文件里面声明一下这几个函数。

LED.h

#ifndef __LED_H
#define __LED_H

void LED_Init(void);
void LED1_ON(void);
void LED1_OFF(void);
void LED1_Turn(void);
void LED2_ON(void);
void LED2_OFF(void);
void LED2_Turn(void);

#endif

这样LED的驱动函数模块就分装好了。

Key驱动程序

现在开始写按键部分的代码,同样封装在一个驱动函数模块里。一样的过程就省略了,直接看写好的结果:

Key.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"

/**
  * 函    数:按键初始化
  * 参    数:无
  * 返 回 值:无
  */
void Key_Init(void)
{
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);		//开启GPIOB的时钟
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);						//将PB1和PB11引脚初始化为上拉输入
}

/**
  * 函    数:按键获取键码
  * 参    数:无
  * 返 回 值:按下按键的键码值,范围:0~2,返回0代表没有按键按下
  * 注意事项:此函数是阻塞式操作,当按键按住不放时,函数会卡住,直到按键松手
  */
uint8_t Key_GetNum(void)
{
	uint8_t KeyNum = 0;		//定义变量,默认键码值为0
	
	if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)			//读PB1输入寄存器的状态,如果为0,则代表按键1按下
	{
		Delay_ms(20);											//延时消抖
		while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0);	//等待按键松手
		Delay_ms(20);											//延时消抖
		KeyNum = 1;												//置键码为1
	}
	
	if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0)			//读PB11输入寄存器的状态,如果为0,则代表按键2按下
	{
		Delay_ms(20);											//延时消抖
		while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0);	//等待按键松手
		Delay_ms(20);											//延时消抖
		KeyNum = 2;												//置键码为2
	}
	
	return KeyNum;			//返回键码值,如果没有按键按下,所有if都不成立,则键码为默认值0
}

别忘了在头文件中声明一下这两个函数

Key.h

#ifndef __KEY_H
#define __KEY_H

void Key_Init(void);
uint8_t Key_GetNum(void);

#endif

然后在主函数中调用这些函数来实现按键控制LED的亮灭逻辑

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "LED.h"
#include "Key.h"

uint8_t KeyNum;		//定义用于接收按键键码的变量

int main(void)
{
	/*模块初始化*/
	LED_Init();		//LED初始化
	Key_Init();		//按键初始化
	
	while (1)
	{
		KeyNum = Key_GetNum();		//获取按键键码
		
		if (KeyNum == 1)			//按键1按下
		{
			LED1_Turn();			//LED1翻转
		}
		
		if (KeyNum == 2)			//按键2按下
		{
			LED2_Turn();			//LED2翻转
		}
	}
}

运行效果:

STM32-按键控制LED

第二个代码:光敏传感器控制蜂鸣器

接着我们来写一下第二个代码:光敏传感器控制蜂鸣器

先看一下接线图

接好线后上电可以看到光敏传感器的灯亮了,当我们遮住光线时,输出指示灯灭,代表输出高电平,松手时,输出指示灯亮,代表输出低电平。

这个传感器上面的电位器可以调节高低电平的判断阈值。

接着我们复制上一个工程改名,然后打开工程。

我们的主要步骤还是驱动程序的封装,给各模块封装好的程序都放在这个我们的hardware文件夹中

说明:关于程序的文件建立,添加路径步骤我前面的博文都写得很清楚了,以后不再赘述。

蜂鸣器的代码逻辑和LED的代码逻辑很相似就不再赘述了,接下来的代码逻辑可以看我的注释,如果看不懂可以在评论区留言或者后台私信,私信时请带问题处的截图。

蜂鸣器驱动代码

Buzzer.c

#include "stm32f10x.h"                  // Device header

/**
  * 函    数:蜂鸣器初始化
  * 参    数:无
  * 返 回 值:无
  */
void Buzzer_Init(void)
{
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);		//开启GPIOB的时钟
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);						//将PB12引脚初始化为推挽输出
	
	/*设置GPIO初始化后的默认电平*/
	GPIO_SetBits(GPIOB, GPIO_Pin_12);							//设置PB12引脚为高电平
}

/**
  * 函    数:蜂鸣器开启
  * 参    数:无
  * 返 回 值:无
  */
void Buzzer_ON(void)
{
	GPIO_ResetBits(GPIOB, GPIO_Pin_12);		//设置PB12引脚为低电平
}

/**
  * 函    数:蜂鸣器关闭
  * 参    数:无
  * 返 回 值:无
  */
void Buzzer_OFF(void)
{
	GPIO_SetBits(GPIOB, GPIO_Pin_12);		//设置PB12引脚为高电平
}

/**
  * 函    数:蜂鸣器状态翻转
  * 参    数:无
  * 返 回 值:无
  */
void Buzzer_Turn(void)
{
	if (GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_12) == 0)		//获取输出寄存器的状态,如果当前引脚输出低电平
	{
		GPIO_SetBits(GPIOB, GPIO_Pin_12);						//则设置PB12引脚为高电平
	}
	else														//否则,即当前引脚输出高电平
	{
		GPIO_ResetBits(GPIOB, GPIO_Pin_12);						//则设置PB12引脚为低电平
	}
}

Buzzer.h

#ifndef __BUZZER_H
#define __BUZZER_H

void Buzzer_Init(void);
void Buzzer_ON(void);
void Buzzer_OFF(void);
void Buzzer_Turn(void);

#endif

接着我们封装一下光敏传感器的程序

光敏传感器驱动代码

LightSensor.c

#include "stm32f10x.h"                  // Device header

/**
  * 函    数:光敏传感器初始化
  * 参    数:无
  * 返 回 值:无
  */
void LightSensor_Init(void)
{
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);		//开启GPIOB的时钟
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入模式,如果这个模块始终都连接在端口上,也可以选择浮空输入,只要保证引脚不会悬空即可
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);						//将PB13引脚初始化为上拉输入
}

/**
  * 函    数:获取当前光敏传感器输出的高低电平
  * 参    数:无
  * 返 回 值:光敏传感器输出的高低电平,范围:0/1
  */
uint8_t LightSensor_Get(void)
{
	//这里直接写一个返回端口值的函数即可
	return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13);			//返回PB13输入寄存器的状态
}

LightSensor.h

#ifndef __LIGHT_SENSOR_H
#define __LIGHT_SENSOR_H

void LightSensor_Init(void);
uint8_t LightSensor_Get(void);

#endif

最后我们在主函数中实现一下

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "Buzzer.h"
#include "LightSensor.h"

int main(void)
{
	/*模块初始化*/
	Buzzer_Init();			//蜂鸣器初始化
	LightSensor_Init();		//光敏传感器初始化
	
	while (1)
	{
		if (LightSensor_Get() == 1)		
		//如果当前光敏输出1,就是光线比较暗的情况。
		//光敏传感器就是当光线比较暗时,阻值大,那么就上拉为高电平
		{
			Buzzer_ON();				//蜂鸣器开启
		}
		else							//否则
		{
			Buzzer_OFF();				//蜂鸣器关闭
		}
	}
}

运行效果:

STM32-光敏传感器控制蜂鸣器

本节课的程序演示到这里就差不多了。

总结GPIO的使用方法

最后我们来总结一下GPIO的使用方法。

总体上来说还是比较简单的:

首先初始化时钟;

然后定义结构体,赋值结构体,GPIO_Mode可以选择我们讲的八种输入输出模式;GPIO_Pin选择引脚可以用按位或的方式,同时选中多个引脚;

GPIO_Speed选择输出速度这个不是很重要,要求不高的话,直接选50MHz就行了;

最后使用GPIO_Init函数将指定的GPIO外设初始化好.

然后这里有八个读取和写入的函数,我们读写GPIO口主要就用这些函数就行了

之后我们学习了模块化编程的方法,一般我们自己做一个产品的话,外围硬件比较多。这时候就要尽量把每个硬件的驱动函数单独提取出来,封装在.c和点h文件里,这样有利于简化主函数的逻辑。在主函数中,我们还有更重要的任务要完成,不要让这些驱动函数混在主函数里影响我们。另外把硬件驱动提取出来,也有利于我们移植程序,还有利于我们进行分工合作。

比如让别人来写驱动函数,你的主要精力就可以集中在主程序的逻辑上了。最后既然要做分装,函数的注释就需要写清楚,这样可以方便使用你这个模块的人快速上手这些函数。

以上就是本节的全部内容了,下篇继续。

QQ交流群:963138186

本篇就到这里,下篇继续!欢迎点击下方订阅本专栏↓↓↓

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[C++][设计模式][模板方法]详细讲解

目录 1.动机2.理解1.设计流程对比1.结构化软件设计流程2.面向对象软件设计流程 2.早绑定与晚绑定 3.模式定义4.要点总结5.代码感受1.代码一 -- 结构化1.lib.cpp2.app.cpp 2.代码二 -- 面向对象1.lib.cpp2.app.cpp 1.动机 在软件构建过程中,对于某一项任务&#xff…

“实习情报官”上万月薪!量化私募发力学界

选拔要求有“门道” 量化私募的招聘又有新花样! 顶尖高校的数理人才一直是量化机构紧盯的“资源”,包括各类奥赛奖牌得主、理科状元。 最头部的量化机构,也一直是高校学霸们流向的去处。 但是,当业内已有近30家百亿量化私募机…

LLVM——安装多版本LLVM和Clang并切换使用(Ubuntu)

1、描述 本机(Ubuntu22)已经安装了LLVM-14,但是需要使用LLVM-12。安装LLVM-12和Clang-12并切换使用。 2、过程 安装LLVM-12和Clang-12。 sudo apt-get install llvm-12 sudo apt-get install clang-12 【注】运行 sudo apt-get install ll…

Inpaint软件最新版下载【安装详细图文教程】

​根据使用者情况表明在今天的数字时代,我们经常会遇到需要处理图形的情况,然而,当我们遇到水印在图形上,我们就需要寻找一个有效的方式来去除它,Inpaint软件就是一个非常实用的工具,它能够帮助我们去除水印…

6月21日训练 (东北林业大学)(个人题解)(待补全)

前言: 这次训练是大一大二一起参加的训练,总体来说难度是有的,我和队友在比赛时间内就写出了四道题,之后陆陆续续又补了了三道题,还有一道题看了学长题解后感觉有点超出我的能力范围了,就留给以后的自己吧。…

带百分比的进度条控件(ProgressBar)源码

带百分比的进度条控件(ProgressBar): 源码下载地址:https://download.csdn.net/download/wgxds/89472915

淘酒屋荣获2024中法贸易杰出服务商称号暨夏季窖主大会圆满召开

淘酒屋荣获中法贸易杰出服务商称号,暨闪光的创始人2024夏季窖主大会圆满召开 2024年,作为中法建交60周年的重要节点,同时迎来了中法文化旅游年,这为两国文化交流与合作开启了新的篇章。在庆祝中法贸易交流的重要时刻,…

[SAP ABAP] 追加内表数据

向内表中逐条追加数据记录 语法格式 APPEND <wa> TO <itab>. <wa>&#xff1a;代表工作区 <itab>&#xff1a;代表内表 示例1 结果显示&#xff1a; 将一个内表中的所有数据记录添加到另一个内表中 语法格式 APPEND LINES OF <itab1> TO <…

Android焦点机制结合WMS

文章前提&#xff1a; 了解WMS基本作用了解window的概念&#xff0c;phoneWindow&#xff0c;rootViewImpl了解view的事件分发 开始&#xff1a; 讲三件事情&#xff1a; window的创建&#xff0c;更新焦点的更新事件的分发 Window的创建&#xff0c;更新&#xff1a; wi…

赵丽颖纯白茉莉绽放温柔之美

赵丽颖纯白茉莉&#xff0c;绽放温柔之美在这个繁忙喧嚣的娱乐圈&#xff0c;赵丽颖以其独特的魅力&#xff0c;成为了无数人心中的白月光。近日&#xff0c;赵丽颖工作室发布了一组live图&#xff0c;她身着一袭温柔白裙&#xff0c;宛如一朵盛开的纯白茉莉花&#xff0c;美得…

论文阅读03(基于人类偏好微调语言模型)

1.主题 基于人类偏好微调语言模型&#xff08;Fine-Tuning Language Models from Human Preferences&#xff09; 出处&#xff1a; Fine-Tuning Language Models from Human Preferences、 2.摘要 奖励学习使得强化学习&#xff08;RL&#xff09;可以应用于那些通过人类判断…

深度学习windows环境配置

1 下载CUDA和cudnn 详见文章 CUDA与CUDNN在Windows下的安装与配置&#xff08;超级详细版&#xff09;_windows cudnn安装-CSDN博客 我电脑的CUDA下载链接如下 ​​​​​https://developer.nvidia.com/cuda-12-1-0-download-archive?target_osWindows&target_archx86…

Validation校验

文章目录 Validation校验作用依赖坐标UserController接收客户端注册用户请求的方法请求参数封装实体User的结构校验分组 Validation校验 作用 服务端接收前端传递的请求从参数的时候&#xff0c;可以对请求参数进行自动校验。 场景&#xff1a;通过postman向服务端发送一个注…

指纹浏览器与虚拟机的区别及在跨境电商中的应用

在如今数字化世界中&#xff0c;隐私和安全变得愈发重要。许多人在网络上进行敏感操作&#xff0c;如网上购物、在线银行、社交媒体管理等。为了保护自己的隐私&#xff0c;人们常常会寻求一些额外的工具&#xff0c;比如指纹浏览器和虚拟机。这两种工具在保护个人隐私方面都有…

东郊到家类型小程序APP软件基于SpringBoot开发的系统源码

项目背景 在快节奏的现代生活中&#xff0c;人们越来越追求高效、便捷的生活方式。上门服务作为一种新型的服务模式&#xff0c;正逐渐受到广大用户的青睐。而这一切的背后&#xff0c;离不开技术的强大支撑。今天&#xff0c;我们就来探讨一下上门服务类型软件的技术魅力&…

4. DSL入门_01

1. 常见的DSL (1) 查询所有: 查询出所有数据&#xff0c;一般测试的时候使用&#xff0c;例如&#xff1a; match_all .但是受分页限制&#xff0c;一般返回10条数据 (2) 全文检索(full text)查询&#xff1a;利用分词器对用户输入内容分词&#xff0c;然后去倒排索引中匹配&a…

数据结构和算法(2)---- Stack 的原理和实现

Stack 的定义和结构 栈(Stack)是仅限于在表尾进行插入和删除的线性表 我们把允许插入和删除的一端称为栈顶(top)&#xff0c;另一端称为栈底(bottom)&#xff0c;不含任何元素的栈称为空栈&#xff0c;栈也被称为先进后出(Last In First Out)的线性表&#xff0c;简称LIFO结构…

为什么能通过文本分析情感?

通过文本分析情感&#xff0c;通常称为情感分析&#xff08;Sentiment Analysis&#xff09;或意见挖掘&#xff08;Opinion Mining&#xff09;&#xff0c;是自然语言处理&#xff08;NLP&#xff09;的一个分支。这项技术能够识别和提取文本中的主观信息&#xff08;对呀&am…

Linux操作系统处理器调度基本准则和实现

1&#xff0c;基本概念 在多道程序系统中&#xff0c;进程的数量往往多于处理机的个数&#xff0c;进程争用处理机的情况就在所难免。处理机调度是对处理机进行分配&#xff0c;就是从就绪队列中&#xff0c;按照一定的算法&#xff08;公平、低效&#xff09;选择一个进程并将…

windows端口被占用问题,杀死进程

描述&#xff1a;端口被占用 在使用IntelliJ IDEA运行程序时&#xff0c;可能会遇到端口占用的情况&#xff0c;这通常由以下几个原因引起&#xff1a; 1、同一程序多次启动&#xff1a;如果你没有正确关闭之前运行的程序实例&#xff0c;再次尝试运行相同的程序时&#xff0c;…