梁山派入门指南2——滴答定时器位带操作按键输入(包括GPIO中断)

news2025/1/17 23:39:53

梁山派入门指南2——滴答定时器&位带操作&按键输入

  • 1. 滴答定时器
    • 1.1 滴答定时器简介
    • 1.2 相关寄存器
    • 1.3 固件库函数
  • 2. 位带操作
    • 2.1 位带操作介绍
    • 2.2 位带操作的优势
    • 2.3 支持位带操作的内存地址
    • 2.4 位带别名区地址的计算方式
    • 2.5 位带操作使用示例
  • 3 按键输入
    • 3.1 独立按键原理图
    • 3.2 独立按键配置流程
    • 3.3 独立按键初始化
    • 3.4 按键扫描&bsp_key文件
    • 3.5 按键输入demo

1. 滴答定时器

1.1 滴答定时器简介

SysTick 定时器可用作标准的下行计数器,是一个 24 位向下计数器,有自动重新装载能力,可屏蔽系统中断发生器。Cortex-M4 处理器内部包含了一个简单的定时器,所有基于 M4 内核的控制器都带有 SysTick 定时器,这样就方便了程序在不同的器件之间的移植。SysTick 定时器可用于操作系统,提供系统必要的时钟节拍,为操作系统的任务调度提供一个有节奏的“心跳”。正因为所有的 M4内核的芯片都有 Systick 定时器,这在移植的时候不像普通定时器那样难以移植。

GD32中的RCU 通过 AHB 时钟(HCLK)8 分频后作为 Cortex 系统定时器(SysTick)的外部时钟。通过对
SysTick 控制和状态寄存器的设置,可选择上述时钟或 AHB(HCLK)时钟作为 SysTick 时钟。

GD32F4系列的时钟概览:
在这里插入图片描述
我们来看一下滴答定时器相关的部分:
在这里插入图片描述
SysTick 定时器设定初值并使能之后,每经过 1 个系统时钟周期,计数值就减 1,减到 0 时,SysTick计数器自动重新装载初值并继续计数,同时内部的 COUNTFLAG 标志位被置位,触发中断(前提开启中断)。

  • 滴答定时器的时钟频率为30Mhz

1.2 相关寄存器

在这里插入图片描述

1.3 固件库函数

SysTick 定 时 器 的 使 用 主 要 有 SysTick_Config() 函 数 和 systick_clksource_set(uint32_t systick_clksource)函数,SysTick_Config()函数主要用来设置定时时间,systick_clksource_set()函数用来选择 SysTick 时钟源。

  1. systick_config()
/*!
    \brief    配置sysTick的时钟和中断周期
    \param[in]  none
    \param[out] none
    \retval     none
*/
void systick_config(void)
{
    /* 设置sysTick中断的频率为1000Hz,即1ms触发1次 */
    if(SysTick_Config(SystemCoreClock / 1000U)) {
        /* capture error */
        while(1) {
        }
    }
    /* 设置sysTick的优先级为0 */
    NVIC_SetPriority(SysTick_IRQn, 0x00U);
}
  1. SysTick_Handler()
/*!
    \brief    滴答定时器中断服务函数
    \param[in]  none
    \param[out] none
    \retval     none
*/
void SysTick_Handler(void)
{
	/* delay--,delay是需要延时的时间 */
    delay_decrement();
}

/*!
    \brief    delay decrement
    \param[in]  none
    \param[out] none
    \retval     none
*/
void delay_decrement(void)
{
    if(0U != delay) {
        delay--;
    }
}
  1. delay_1ms()
/*!
    \brief    延时一段时间,
    \param[in]  count: count in milliseconds
    \param[out] none
    \retval     none
*/
void delay_1ms(uint32_t count)
{
    delay = count;

    while(0U != delay) {
    }
}
  1. systick_clksource_set()

在这里插入图片描述

以上就是滴答定时器涉及到的几个函数,最主要使用的应该就是,delay_1ms()这个函数,其他的只需要了解即可。。。。

2. 位带操作

2.1 位带操作介绍

为了减少“读-改-写”操作的次数,Cortex ® -M4 处理器提供了一个可以执行单原子比特操作的位带功能。存储器映射包含了两个支持位带操作的区域。其中一个是 SRAM 区的最低 1MB 范围,第二个是片内外设区的最低 1MB 范围。这两个区域中的地址除了普通应用外,还有自己的“位带别名区”。位带别名区把每个比特扩展成一个 32 位的字。当用户访问位带别名区时,就可以达到访问原始比特的目的。总结就是 CPU 不能直接对位带区中的单个数据位位寻址,只能通过对位带别名区的访问(或读/写)实现对位带区单个数据位的访问(或读/写),这种操作被称为位带操作

2.2 位带操作的优势

  • 更高效:避免了 ” 读-改-写 “ 的繁琐步骤
  • 读取更简单:只需要直接读取位带别名区的内容,就可以直接对某个bit位寻址
  • 访问速度更快:位带操作由于是属于硬件完成的,只需要CPU直接对位带别名区进行读写即可。
  • 相对安全:在带有操作系统的开发中,多任务并发运行的时候就有可能在任务切换的过程中发生不可预料的问题,而位带操作由于是属于硬件完成的不可被异常打断的操作(原子操作),相对于读-写-改的操作模式会更安全。
  • 提高运行效率和节省代码空间。简单的程序直接使用库函数或者寄存器操作,对于比较复杂的程序建议尽量使用位带操作来实现

2.3 支持位带操作的内存地址

并不是所有的区域都支持位带操作,下面是两个支持位带操作的区域:

  1. SRAM 区的最低 1MB: 0x2000_0000-0x200F_FFFF(对应位带别名区的地址:0x2200 0000)
    在这里插入图片描述
  2. 片上外设区的最低 1MB:0x4000_0000-0x400F_FFFF(对应位带别名区的地址:0x4200 0000)
    在这里插入图片描述
    在这里插入图片描述](https://i-blog.csdnimg.cn/direct/c58d512bdca64756a4b3efce6c274e7f.png)
![在这里插入图片描述

2.4 位带别名区地址的计算方式

上面介绍了位带操作的地址和优势,那怎么去查找目标比特对应的位带别名区的地址呢?

下面的公式表明了位带别名区中的每个字如何对应位带区的相应比特或目标比特:

				     	 bit_word_addr =bit_band_base +(byte_offset×32)+(bit_number×4)

其中:

  • bit_word_addr指的是位带区目标比特对应在位带别名区的地址
  • bit_band_base指的是位带别名区的起始地址
  • byte_offset指的是位带区目标比特所在的字节的字节地址偏移量
  • bit_number指的是目标比特在对应字节中的位置(0-7)

在这里插入图片描述

2.5 位带操作使用示例

#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "bsp_led.h"
#include "sys.h"

#define BIT_ADDR(byte_offset,bit_number) (volatile unsigned long*)(0x42000000 +(byte_offset << 5)+(bit_number << 2))   // 位带别名区的地址
	
#define GPIOD_OCTL_OFFSET ((GPIOD + 0x14) - 0x40000000) 	// 偏移量

#define PDout(n)  *(BIT_ADDR(GPIOD_OCTL_OFFSET,n))   		  // PD口输出

/************************************************
函数名称 : main
功    能 : 主函数
参    数 : 无
返 回 值 : 无
作    者 : LC
*************************************************/
int main(void)
{

    systick_config();    // 滴答定时器初始化
	led_gpio_config();   // led初始化

	// gpio_bit_set(GPIOD,GPIO_PIN_7);     // PD7输出高电平
	// gpio_bit_reset(GPIOD,GPIO_PIN_7);   // PD7输出低电平
 
    while(1) {
			//gpio_bit_write(PORT_LED2,PIN_LED2,SET);     // LED2输出高电平
			PDout(7) = 1;                                 // PD7输出高电平
			delay_1ms(1000);                           		// 延时1s
			//gpio_bit_write(PORT_LED2,PIN_LED2,RESET);   // LED2输出低电平
			PDout(7) = 0;                                 // PD7输出低电平
			delay_1ms(1000);                              // 延时1s
    }
}

3 按键输入

3.1 独立按键原理图

我们打开梁山派提供的原理图,可以看到有三个按键,但是我们能使用的只有唤醒按键:
在这里插入图片描述

在这里插入图片描述

3.2 独立按键配置流程

打开梁山派开发指南,查看GPIO的输入配置流程如下:
在这里插入图片描述

3.3 独立按键初始化

根据配置流程,结合固件库手册中提供的库函数使用说明,开始编写初始化代码:
【注】:GPIO相关的库函数上一章有提到,可以查看:梁山派入门指南1——初窥门径梁山派

#define BSP_KEYUP_RCU   RCU_GPIOA   // 按键端口时钟
#define BSP_KEYUP_PORT  GPIOA       // 按键端口
#define BSP_KEYUP_PIN   GPIO_PIN_0  // 按键引脚
/************************************************
函数名称 : key_gpio_config
功    能 : 按键引脚初始化,默认配置为输入模式,下拉
参    数 : 需要初始化的引脚
返 回 值 : 无
作    者 : 不想写代码的我
*************************************************/
void key_gpio_config(void)
{
	/* 开启时钟 */
	rcu_periph_clock_enable(BSP_KEYUP_RCU);
	/* 配置为输入模式,下拉 */
	gpio_mode_set(BSP_KEYUP_PORT,GPIO_MODE_INPUT,GPIO_PUPD_PULLDOWN,BSP_KEYUP_PIN);
}

当然,我们也可以引入GPIO的中断,那么随之按键的初始化也发生改变:

#define BSP_KEYUP_RCU   RCU_GPIOA   // 按键端口时钟
#define BSP_KEYUP_PORT  GPIOA       // 按键端口
#define BSP_KEYUP_PIN   GPIO_PIN_0  // 按键引脚

/* 中断类型 */
#define BSP_KEY_EXTI_IRQn EXTI0_IRQn 

/* EXTI中断源 */
#define BSP_KEY_EXTI_PORT_SOURCE EXTI_SOURCE_GPIOA
#define BSP_KEY_EXTI_PIN_SOURCE EXTI_SOURCE_PIN0

/* 中断的EXTI线 */
#define BSP_KEY_EXTI_LINE EXTI_0 

/* 中断服务函数名 */
#define BSP_KEY_EXTI_IRQHandler EXTI0_IRQHandler 
/************************************************
函数名称 : key_gpio_config
功    能 : 按键引脚初始化,默认配置为输入模式,下拉
参    数 : 需要初始化的引脚
返 回 值 : 无
作    者 : 不想写代码的我
*************************************************/
void key_gpio_config(void)
{
	/* 开启时钟 */
	rcu_periph_clock_enable(BSP_KEYUP_RCU);
	/* 配置为输入模式,下拉 */
	gpio_mode_set(BSP_KEYUP_PORT,GPIO_MODE_INPUT,GPIO_PUPD_PULLDOWN,BSP_KEYUP_PIN);

	/* 使能GPIO中断,需要配置SYSCFG中的EXTI寄存器,要先开启时钟 */
	rcu_periph_clock_enable(RCU_SYSCFG); 
	
	/* 配置中断优先级 */
	nvic_irq_enable(BSP_KEY_EXTI_IRQn,3,0); 
	
	/* 连接中断到EXTI线 */
	syscfg_exti_line_config(BSP_KEY_EXTI_PORT_SOURCE,BSP_KEY_EXTI_PIN_SOURCE);
	
	/* 初始化中断线 */
	exti_init(BSP_KEY_EXTI_LINE,EXTI_INTERRUPT,EXTI_TRIG_BOTH);
	
	/* 使能中断 */
	exti_interrupt_enable(BSP_KEY_EXTI_LINE);

}

相应的,需要编写中断服务函数:

/************************************************
函数名称 : BSP_KEY_EXTI_IRQHandler
功    能 : 按键中断处理函数
参    数 : 无
返 回 值 : 无
作    者 : 不想写代码的我
*************************************************/
void BSP_KEY_EXTI_IRQHandler(void)
{
	/* 查询中断标志位 */
	if(exti_interrupt_flag_get(BSP_KEY_EXTI_LINE) == SET) 
	{
		/* 获取按键的状态 */
		if(gpio_input_bit_get(BSP_KEYUP_PORT,BSP_KEYUP_PIN) == SET) // 按键按下
		{
			/* 需要执行的操作 */
			gpio_bit_toggle(PORT_LED2,PIN_LED2);
		}
		
		/* 清除中断标志位 */
		exti_interrupt_flag_clear(BSP_KEY_EXTI_LINE); // 清中断标志位
		
	}
}

3.4 按键扫描&bsp_key文件

为了节省篇幅,在这里我直接展示我写好的bsp_key文件,不介绍具体原理

  1. bsp_key.c
#include "bsp_key.h"

/************************************************
函数名称 : key_gpio_config
功    能 : 按键引脚初始化,默认配置为输入模式,下拉
参    数 : 需要初始化的引脚
返 回 值 : 无
作    者 : 不想写代码的我
*************************************************/
void key_gpio_config(void)
{
	/* 开启时钟 */
	rcu_periph_clock_enable(BSP_KEYUP_RCU);
	/* 配置为输入模式,下拉 */
	gpio_mode_set(BSP_KEYUP_PORT,GPIO_MODE_INPUT,GPIO_PUPD_PULLDOWN,BSP_KEYUP_PIN);
	
	/* 判断是否使能中断GPIO中断 */
	#if KEY_INTERRUPT
	
	/* 使能GPIO中断,需要配置SYSCFG中的EXTI寄存器,要先开启时钟 */
	rcu_periph_clock_enable(RCU_SYSCFG); 
	
	/* 配置中断优先级 */
	nvic_irq_enable(BSP_KEY_EXTI_IRQn,3,0); 
	
	/* 连接中断到EXTI线 */
	syscfg_exti_line_config(BSP_KEY_EXTI_PORT_SOURCE,BSP_KEY_EXTI_PIN_SOURCE);
	
	/* 初始化中断线 */
	exti_init(BSP_KEY_EXTI_LINE,EXTI_INTERRUPT,EXTI_TRIG_BOTH);
	
	/* 使能中断 */
	exti_interrupt_enable(BSP_KEY_EXTI_LINE);
	
	#endif
}


/************************************************
函数名称 : WKUP_Down_Task
功    能 : KEY_UP按键按下时调用的函数
参    数 : 需要初始化的引脚
返 回 值 : 无
作    者 : 不想写代码的我
*************************************************/
void WKUP_Down_Task(void)
{
   
}

/************************************************
函数名称 : WWKUP_Up_Task
功    能 : KEY_UP按键弹起时调用的函数
参    数 : 需要初始化的引脚
返 回 值 : 无
作    者 : 不想写代码的我
*************************************************/
void WWKUP_Up_Task(void)
{
   
}

/************************************************
函数名称 : Key_One_Scan
功    能 : 按键扫描函数,。这里只能扫描KEY_UP按键
参    数 : 需要初始化的引脚
返 回 值 : 无
作    者 : 不想写代码的我
*************************************************/
void Key_One_Scan(uint8_t KeyName ,void(*OnKeyOneUp)(void), void(*OnKeyOneDown)(void))
{
   static uint8_t Key_Val[Key_Name_Max];    //按键值的存放位置
   static uint8_t Key_Flag[Key_Name_Max];   //KEY0~2为0时表示按下,为1表示松开,WKUP反之
    
   Key_Val[KeyName] = Key_Val[KeyName] <<1;  //每次扫描完,将上一次扫描的结果左移保存
   
    switch(KeyName)
    {
        case Key_Name_WKUP:  Key_Val[KeyName] = Key_Val[KeyName] | (gpio_input_bit_get(BSP_KEYUP_PORT,BSP_KEYUP_PIN));   //读取WKUP按键值
            break; 
        default:
            break;
    }
    if(KeyName == Key_Name_WKUP)     //WKUP的电路图与其他按键不同,所以需要特殊处理
    {
        //WKUP特殊情况
        //当按键标志为1(松开)是,判断是否按下,WKUP按下时为0xff
        if(Key_Val[KeyName] == 0xff && Key_Flag[KeyName] == 1)
        {
            (*OnKeyOneDown)();
           Key_Flag[KeyName] = 0;
        }
        //当按键标志位为0(按下),判断按键是否松开,WKUP松开时为0x00
        if(Key_Val[KeyName] == 0x00 && Key_Flag[KeyName] == 0)
        {
            (*OnKeyOneUp)();
           Key_Flag[KeyName] = 1;
        } 
    }
   
}

#if KEY_INTERRUPT

/************************************************
函数名称 : BSP_KEY_EXTI_IRQHandler
功    能 : 按键中断处理函数
参    数 : 无
返 回 值 : 无
作    者 : 不想写代码的我
*************************************************/
void BSP_KEY_EXTI_IRQHandler(void)
{
	/* 查询中断标志位 */
	if(exti_interrupt_flag_get(BSP_KEY_EXTI_LINE) == SET) 
	{
		/* 获取按键的状态 */
		if(gpio_input_bit_get(BSP_KEYUP_PORT,BSP_KEYUP_PIN) == SET) // 按键按下
		{
			/* 需要执行的操作 */
			gpio_bit_toggle(PORT_LED2,PIN_LED2);
		}
		
		/* 清除中断标志位 */
		exti_interrupt_flag_clear(BSP_KEY_EXTI_LINE); // 清中断标志位
		
	}
}

#endif


  1. bsp_key.h
#ifndef _BSP_KEY_H
#define _BSP_KEY_H

#include "gd32f4xx.h"
#include "systick.h"
#include "bsp_led.h"

/* 配置为1开启中断,为0关闭中断 */
#define KEY_INTERRUPT  0

#define BSP_KEYUP_RCU   RCU_GPIOA   // 按键端口时钟
#define BSP_KEYUP_PORT  GPIOA       // 按键端口
#define BSP_KEYUP_PIN   GPIO_PIN_0  // 按键引脚

#if KEY_INTERRUPT

/* 中断类型 */
#define BSP_KEY_EXTI_IRQn EXTI0_IRQn 

/* EXTI中断源 */
#define BSP_KEY_EXTI_PORT_SOURCE EXTI_SOURCE_GPIOA
#define BSP_KEY_EXTI_PIN_SOURCE EXTI_SOURCE_PIN0

/* 中断的EXTI线 */
#define BSP_KEY_EXTI_LINE EXTI_0 

/* 中断服务函数名 */
#define BSP_KEY_EXTI_IRQHandler EXTI0_IRQHandler 

#endif	/* KEY_INTERRUPT */


/* 按键引脚名字,目前可用的只有 Key_Name_WKUP */
typedef enum
{
 Key_Name_WKUP = 0,
 Key_Name_Max
}EnumKeyOneName;

/* 按键引脚初始化,默认配置为输入模式,下拉 */
void key_gpio_config(void); 	  

/*  KEY_UP按键按下按下和弹起时调用的函数*/
void WKUP_Down_Task(void);

void WWKUP_Up_Task(void);

/* 按键扫描函数 */
void Key_One_Scan(uint8_t KeyName ,void(*OnKeyOneUp)(void), void(*OnKeyOneDown)(void)); 

#endif /* _BSP_KEY_H */


3.5 按键输入demo

结合上面的bsp_key文件,就可以编写出一个按键扫描的demo,代码如下:

#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"

#include "bsp_led.h"
#include "bsp_key.h"

/*!
    \brief    main function
    \param[in]  none
    \param[out] none
    \retval     none
*/
int main(void)
{
	uint16_t i=0;
	
	/* 配置sysTick的时钟和中断周期*/
    systick_config();
	
	/* led初始化 */
	led_gpio_config(Led_Name_Led1);
	led_gpio_config(Led_Name_Led2);
	key_gpio_config();

    while(1) 
	{
		if(++i >= 50)
		{
			/* 500ms翻转一次led的状态 */
			gpio_bit_toggle(PORT_LED1,PIN_LED1);
			i = 0;
		}
		
		Key_One_Scan(Key_Name_WKUP,WWKUP_Up_Task,WKUP_Down_Task);
		delay_1ms(10);

    }
}

【注】:这里的按键输入是采用GPIO输入的方式实现的,后续中断中还会对bsp_key文件进行进一步封装。
关于按键扫描的原理,可以参照:夜深人静学32系列9——GPIO驱动数码管/蜂鸣器/按键/LED 和 STM32框架之按键扫描新思路

以上就是本期的所有内容,创造不易,点个关注再走呗。

在这里插入图片描述

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

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

相关文章

安全类脚本:拒绝ssh暴力破解

要求如下&#xff1a; 一个小时内&#xff0c;连续密码错误4次。 Linux lastb 命令用于列出登入系统失败的用户相关信息。 实验过程如下&#xff1a; 1. 创建两个IP地址不同的干净环境&#xff0c;分别是&#xff1a;192.168.46.101 Rocky 2 和 192.168.46.120 openEuler 2. 2.…

HugeGraph集群部署

部署HugeGraph集群 最近工作中&#xff0c;需要部署一个HugeGraph的多副本集群&#xff0c;要求一个主节点&#xff0c;两个从节点。由于HugeGraph官网并没有完整的搭建集群实例&#xff0c;所以这里写一篇文章记录自己搭建集群的过程&#xff0c;供自己和大家学习和参考。 注…

SqlSugar连接达梦数据库集群超时或异常缓慢

《SqlSugar配置连接达梦数据库集群》文章中介绍SqlSugar连接达梦数据库集群&#xff0c;只需按下图所示位置添加dm_svc.conf文件&#xff0c;并在SqlSugar的连接字符串中指定服务名即可。   但在使用过程中发现&#xff0c;基于.net 6开发的WebApi&#xff0c;编译为ANYCPU&…

Qt/C++进程间通信:QSharedMemory 使用详解(附演示Demo)

在开发跨进程应用程序时&#xff0c;进程间通信&#xff08;IPC&#xff09;是一个关键问题。Qt 框架提供了多种 IPC 技术&#xff0c;其中 QSharedMemory 是一种高效的共享内存方式&#xff0c;可以实现多个进程之间快速交换数据。本文将详细讲解 QSharedMemory 的概念、用法及…

STM32的集成开发环境STM32CubeIDE安装

STM32CubeIDE - STM32的集成开发环境 - 意法半导体STMicroelectronics

NanoKVM简单开箱测评和拆解,让普通电脑实现BMC/IPMI远程管理功能

Sipeed推出了NanoKVM&#xff0c;简直是没有BMC的台式机和工作站的福音。有了这个就可以轻松实现以往服务器才有的远程管理功能。 NanoKVM 简介 Lichee NanoKVM 是基于 LicheeRV Nano 的 IP-KVM 产品&#xff0c;继承了 LicheeRV Nano 的极致体积 和 强大功能。 NanoKVM 包含…

唐刘:TiDB 的 2024 - Cloud、SaaS 与 AI

2024 年已经过去&#xff0c;在去年我也写过两篇类似的文章&#xff0c;TiDB in 2023 - 一次简单的回顾和 TiDB Cloud in 2023 - 一次简单的回顾&#xff0c;这一次&#xff0c;我准备将 TiDB 和 cloud 一起写&#xff0c;一方面原因是我懒了&#xff0c;另外一个更重要的原因在…

Web端实时播放RTSP视频流(监控)

一、安装ffmpeg: 1、官网下载FFmpeg: Download FFmpeg 2、点击Windows图标,选第一个:Windows builds from gyan.dev 3、跳转到下载页面: 4、下载后放到合适的位置,不用安装,解压即可: 5、配置path 复制解压后的\bin路径,配置环境变量如图: <

Excel 技巧10 - 如何检查输入重复数据(★★)

本文讲了如何在Excel中通过COUNTIF来检查输入重复数据。 当输入重复数据时&#xff0c;显示错误提示。 1&#xff0c;通过COUNTIF来检查输入重复数据 比如下面是想检查不要输入重复的学号。 选中C列&#xff0c;点 Menu > 数据 > 数据验证 在数据验证页面&#xff0c…

IEC103 转 ModbusTCP 网关

一、产品概述 IEC103 转 ModbusTCP 网关型号 SG-TCP-IEC103 &#xff0c;是三格电子推出的工业级网关&#xff08;以下简 称网关&#xff09;&#xff0c;主要用于 IEC103 数据采集、 DLT645-1997/2007 数据采集&#xff0c; IEC103 支持遥测和遥 信&#xff0c;可接…

Unity3d 实时天气系统基于UniStorm插件和xx天气API实现(含源码)

前言 实时天气在Unity3d三维数字沙盘中的作用非常重要&#xff0c;它能够增强虚拟环境的真实感和互动性&#xff0c;实时天气数据的应用可以提供更为精准和直观的天气信息支持&#xff0c;如果真实的数据加上特效、声音和模型反馈会提高产品档次&#xff0c;提高真实感。 目前…

Linux命令行工具-使用方法

参考资料 Linux网络命令&#xff1a;网络工具socat详解-CSDN博客 arm-linux-gnueabihf、aarch64-linux-gnu等ARM交叉编译GCC的区别_aarch64-elf-gcc aarch64-linux-gnu-CSDN博客 解决Linux内核问题实用技巧之-dev/mem的新玩法-腾讯云开发者社区-腾讯云 热爱学习地派大星-CS…

【Flink系列】9. Flink容错机制

9. 容错机制 在Flink中&#xff0c;有一套完整的容错机制来保证故障后的恢复&#xff0c;其中最重要的就是检查点。 9.1 检查点&#xff08;Checkpoint&#xff09; 9.1.1 检查点的保存 1&#xff09;周期性的触发保存 “随时存档”确实恢复起来方便&#xff0c;可是需要我…

【深度学习】关键技术-激活函数(Activation Functions)

激活函数&#xff08;Activation Functions&#xff09; 激活函数是神经网络的重要组成部分&#xff0c;它的作用是将神经元的输入信号映射到输出信号&#xff0c;同时引入非线性特性&#xff0c;使神经网络能够处理复杂问题。以下是常见激活函数的种类、公式、图形特点及其应…

20.<Spring图书管理系统①(登录+添加图书)>

PS&#xff1a;关于接口定义 接口定义&#xff0c;通常由服务器提供方来定义。 1.路径&#xff1a;自己定义 2.参数&#xff1a;根据需求考虑&#xff0c;我们这个接口功能完成需要哪些信息。 3.返回结果&#xff1a;考虑我们能为对方提供什么。站在对方角度考虑。 我们使用到的…

【Sql递归查询】Mysql、Oracle、SQL Server、PostgreSQL 实现递归查询的区别与案例(详解)

文章目录 Mysql 5.7 递归查询Mysql 8 实现递归查询Oracle递归示例SQL Server 递归查询示例PostgreSQL 递归查询示例 更多相关内容可查看 Mysql 5.7 递归查询 MySQL 5.7 本身不直接支持标准 SQL 中的递归查询语法&#xff08;如 WITH RECURSIVE 这种常见的递归查询方式&#xf…

vue2修改表单只提交被修改的数据的字段传给后端接口

效果&#xff1a; 步骤一、 vue2修改表单提交的时候&#xff0c;只将修改的数据的字段传给后端接口&#xff0c;没有修改得数据不传参给接口。 在 data 对象中添加一个新的属性&#xff0c;用于存储初始表单数据的副本&#xff0c;与当前表单数据进行比较&#xff0c;找出哪些…

「刘一哥GIS」系列专栏《GRASS GIS零基础入门实验教程(配套案例数据)》专栏上线了

「刘一哥GIS」系列专栏《GRASS GIS零基础入门实验教程》全新上线了&#xff0c;欢迎广大GISer朋友关注&#xff0c;一起探索GIS奥秘&#xff0c;分享GIS价值&#xff01; 本专栏以实战案例的形式&#xff0c;深入浅出地介绍了GRASS GIS的基本使用方法&#xff0c;用一个个实例讲…

纯命令 git使用

首先我们到一个新的公司 要添加一个新的git仓库的权限 我们应该现拉去代码 配置git的仓库信息 第一 先添加权限 第二 如果不是自己电脑 需要配置信息 配置基础信息 查看本地git账号git config --global user.name git config --global user.email修改本地账号git co…

Linux系统编程:深入理解计算机软硬件体系和架构

一、硬件体系 首先我们要知道&#xff0c;我们最常见的计算机&#xff08;笔记本&#xff09;以及我们不常见的计算机&#xff08;服务器&#xff09;其实本质上都是一堆硬件的结合&#xff1a;cpu、网卡、显卡、内存、磁盘、显示器、键盘…… 但他们并不是毫无章法地放在一起…