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

news2025/1/11 14:55:44

目录

第一个代码:按键控制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

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

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

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

相关文章

【内存管理】页面分配机制

前言 Linux内核中是如何分配出页面的,如果我们站在CPU的角度去看这个问题,CPU能分配出来的页面是以物理页面为单位的。也就是我们计算机中常讲的分页机制。本文就看下Linux内核是如何管理,释放和分配这些物理页面的。 伙伴算法 伙伴系统的…

K8s部署高可用Jenkins

小伙伴们大家好呀!断更了近一个月,XiXi去学习了一下K8s和Jenkins的相关技术。学习内容有些庞杂,近一个月的时间里我只学会了一些皮毛,更多的内容还需要后面不断学习,不断积累。最主要的是云主机真得很贵,为…

C++ | Leetcode C++题解之第155题最小栈

题目&#xff1a; 题解&#xff1a; class MinStack {stack<int> x_stack;stack<int> min_stack; public:MinStack() {min_stack.push(INT_MAX);}void push(int x) {x_stack.push(x);min_stack.push(min(min_stack.top(), x));}void pop() {x_stack.pop();min_sta…

多物理场仿真对新能源汽车用电机优化分析 衡祖仿真

1、问题所在 为了改善空气质量&#xff0c;减少环境污染&#xff0c;减少对石油的依赖&#xff0c;降低能源安全风险&#xff0c;国家大力倡导发展新能源汽车&#xff0c;大量新能源车企应运而生&#xff0c;竞争日趋激烈。使用经济效率较高的电机对于增强企业市场竞争力非常重…

常用加密算法之 RSA 简介及应用

引言 相关博文&#xff1a; Spring Boot 开发 – 常用加密算法简介&#xff08;一&#xff09;常用加密算法之 SM4 简介及应用 一、RSA算法简介 RSA &#xff08;Rivest-Shamir-Adleman&#xff09; 算法是一种非对称加密技术&#xff0c;由Ron Rivest、Adi Shamir和Leonar…

本地离线模型搭建指南-中文大语言模型底座选择依据

搭建一个本地中文大语言模型&#xff08;LLM&#xff09;涉及多个关键步骤&#xff0c;从选择模型底座&#xff0c;到运行机器和框架&#xff0c;再到具体的架构实现和训练方式。以下是一个详细的指南&#xff0c;帮助你从零开始构建和运行一个中文大语言模型。 本地离线模型搭…

spdlog生产者消费者模式

spdlog生产者消费者模式 spdlog提供了异步模式&#xff0c;显示的创建async_logger, 配合环形队列实现的消息队列和线程池实现了异步模式。异步logger提交日志信息和自身指针&#xff0c; 任务线程从消息队列中取出消息后执行对应的sink和flush动作。 1. 环形队列 1.1 环形队…

独角兽品牌獭崎酱酒:高性价比的酱香之选

在酱香型白酒领域中&#xff0c;獭崎酱酒以其独特的品牌定位和高性价比迅速崛起&#xff0c;成为市场上备受关注的独角兽品牌。作为贵州茅台镇的一款新秀酱香酒&#xff0c;獭崎酱酒不仅传承了百年酿造工艺&#xff0c;还以创新的商业模式和亲民的价格赢得了广大消费者的青睐。…

双指针算法——部分OJ题详解

目录 关于双指针算法&#xff1a; 1&#xff0c;对撞指针 2&#xff0c;快慢指针 部分OJ题详解 283.移动零 1089.复写零 202.快乐数 11.盛水最多的容器 611.有效三角形的个数 剑指offer 57.和为s的两个数字 15.三数之和 18.四数之和 关于双指针算法&#xff1a; …

硬盘数据恢复软件,推荐5种适合你的方法来恢复硬盘数据

硬盘数据恢复软件&#xff0c;作为解决数据丢失问题的关键工具&#xff0c;帮助用户在重要文件丢失时迅速找回数据。本教程介绍5种恢复实用硬盘数据方法&#xff0c;适应不同类型和严重程度的数据损坏情况。 文章摘要&#xff1a; 一. 硬盘数据恢复软件 二. 数据恢复原理 三. …

ThinkPHP:查询数据库数据之后,更改查询数据的字段名称

一、原始查询数据 含有字段item_no&#xff0c;lot_num&#xff0c;position $data[brushed] db::table(wip_station_transaction) ->where([wip_entity_name>$wip_entity_name,line_code>$line_code,]) ->field([item_no, lot_num, position]) ->select(); …

React18中各种Hooks用法总结( 内附案例讲解)

React中各种Hooks用法总结 内附案例讲解 一、useState useState 是一个 React Hook&#xff0c;它允许你向组件添加一个 状态变量。 import React, { FC, memo, useState } from react import { MainContainer } from ./style interface IProps {children?: React.ReactNo…

上新:NFTScan 正式上线 Bitcoin-brc20 浏览器!

近日&#xff0c;NFTScan 团队正式对外发布了 Bitcoin-brc20 浏览器&#xff0c;将为 Bitcoin 生态的 NFT 开发者和用户提供简洁高效的 NFT 数据搜索查询服务。作为比特币生态中最火热的标准之一&#xff0c;brc20 也吸引着广泛的关注。洞悉其巨大潜力&#xff0c;NFTScan 对 b…

基于springboot websocket和okhttp实现消息中转

1、业务介绍 消息源服务的消息不能直接推给用户侧&#xff0c;用户与中间服务建立websocket连接&#xff0c;中间服务再与源服务建立websocket连接&#xff0c;源服务的消息推给中间服务&#xff0c;中间服务再将消息推送给用户。流程如下图&#xff1a; 此例中我们定义中间服…

Linux应急响应——知攻善防应急靶场-Linux(1)

文章目录 查看history历史指令查看开机自启动项异常连接和端口异常进程定时任务异常服务日志分析账户排查总结 靶场出处是知攻善防 Linux应急响应靶机 1 前景需要&#xff1a; 小王急匆匆地找到小张&#xff0c;小王说"李哥&#xff0c;我dev服务器被黑了",快救救我&…

【React】ref

概述 使用 ref 引用值 – React 中文文档 希望组件“记住”某些信息&#xff0c;但又不想让这些信息更新时 触发新的渲染 时&#xff0c;可以使用 ref 。 也就是说 ref 对象 包裹的值 React 追踪不到的&#xff0c;他像是用来存储组件信息的秘密“口袋”。 与 state 相同的是…

一、系统学习微服务遇到的问题集合

1、启动了nacos服务&#xff0c;没有在注册列表 应该是版本问题 Alibaba-nacos版本 nacos-文档 Spring Cloud Alibaba-中文 Spring-Cloud-Alibaba-英文 Spring-Cloud-Gateway 写的很好的一篇文章 在Spring initial上面配置 start.aliyun.com 重新下载 < 2、 No Feign…

美团携手HarmonyOS SDK,开启便捷生活新篇章

华为开发者大会&#xff08;HDC 2024&#xff09;于6月21日在东莞松山湖拉开序幕&#xff0c;通过一系列精彩纷呈的主题演讲、峰会、专题论坛和互动体验&#xff0c;为开发者们带来了一场知识与技术的盛宴。6月23日&#xff0c;《HarmonyOS开放能力&#xff0c;使能应用原生易用…

上位机图像处理和嵌入式模块部署(mcu和swd接口)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 最近学习mcu的时候&#xff0c;接触了不少调试器&#xff0c;这里面有daplink、st-link v2、j-link v9。虽然模块的形状可能不太一样&#xff0c;但…

程序人生:关于RHCE红帽认证这件事

花了两个月备考红帽&#xff0c;最终终于双满分通过。 关于考试 RHCE红帽认证总共需要考两门&#xff1a;RHCSA、RHCE。 RHCSA主要是考察基本的Linux操作&#xff1a;用户、权限、空间扩容、yum、容器等内容。 RHCE主要是考察ansible playbook 代码的开发。 通过考试没有别…