S1-12 中断

中断

在计算机系统中,中断(Interrupt)是指某个硬件设备或软件程序发出一个信号,通知 CPU 暂停当前正在执行的任务并转而执行另一个任务。中断用于处理一些需要立即响应、优先级较高的事件,例如输入设备(例如键盘、鼠标)、输出设备(例如显示器、打印机)或者网络数据包等。
当硬件设备或软件程序需要向 CPU 发送中断请求时,它会向 CPU 发送一个中断信号,CPU 会暂停执行当前指令,并根据中断信号的类型调用相应的中断服务程序(ISR)。中断服务程序是一个预定义的程序,用于处理特定类型的中断请求,并返回到之前的任务执行状态。
在处理完中断请求后,CPU 会恢复之前被暂停的任务,继续执行之前的指令。如果存在多个中断请求,CPU 会根据事先设置的优先级来依次处理。
中断对于计算机系统的性能和可靠性至关重要。它可以提高系统的响应速度,使系统能够在同时处理多个任务时更加高效,同时也提高了系统的可靠性,可以及时处理一些关键事件,如故障处理、系统监视等。
需要注意的是,在编写中断服务程序时,需要考虑到中断与当前任务之间的上下文切换,防止出现竞态条件和死锁等问题,确保系统的稳定性和可靠性。同时,还需要合理设置中断优先级、中断屏蔽、中断嵌套等相关参数,以充分发挥中断的性能和特性。
在这里插入图片描述

ESP32的中断

ESP32 支持多种类型的中断,包括外部中断、定时器中断、任务通知中断、硬件定时器中断等。其中,外部中断是最常用的类型,它通过 GPIO 端口引脚接受外部的中断信号,在 ESP32 内部触发中断服务程序执行。
ESP32 的中断主要分为以下几类:

  1. 外部中断:当 GPIO 引脚状态发生变化时触发中断,可以通过 ESP32 内部的 GPIO 控制器进行配置和管理。外部中断常用于输入设备(如按键、触摸屏)等的响应。
  2. 定时器中断:基于 ESP32 内部的硬件定时器产生定时中断,可以通过 esp_timer_create() 函数和相关 API 进行创建和管理。定时器中断常用于周期性任务的调度或实时数据的处理。
  3. 任务通知中断:任务通知机制是 ESP32 RTOS 的一项重要功能,可以通过 xTaskNotifyFromISR() 等函数将消息传递给任务并在任务中处理。任务通知中断常用于任务之间的通信和同步。
  4. 硬件定时器中断:ESP32 还支持一些专用的硬件定时器中断,如 RMT(远程红外控制)定时器中断、LEDC(LED 控制)定时器中断、PCNT(脉冲计数器)定时器中断等。这些定时器可以在控制器内部自主运行,无需 CPU 干预。

ESP32的每个内核共有 32 个中断。每个中断都有一定的优先级,大多数(但不是全部)中断都连接到中断多路复用器。因为中断源比中断多,所以有些中断是与多个中断源共享的。

ESP32中断触发类型

在 ESP32 中,外部中断有以下几种触发类型:
上升沿触发:当 GPIO 引脚从低电平变为高电平时触发中断。
在这里插入图片描述
下降沿触发:当 GPIO 引脚从高电平变为低电平时触发中断。
在这里插入图片描述
双边沿(跳变沿)触发:当 GPIO 引脚从低电平变为高电平或从高电平变为低电平时触发中断。
在这里插入图片描述
低电平触发:当 GPIO 引脚保持低电平状态时触发中断。
在这里插入图片描述

高电平触发:当 GPIO 引脚保持高电平状态时触发中断。
在这里插入图片描述

ESP32 还提供了一些专门用于中断处理的 API 接口,例如:

  • gpio_install_isr_service():初始化 GPIO 中断服务,必须在使用 GPIO 中断前调用。
  • gpio_isr_handler_add():注册 GPIO 中断服务程序,指定 GPIO 端口和中断服务函数。
  • esp_timer_create():创建一个硬件定时器,可以用于周期性触发中断服务程序。
  • esp_intr_alloc():为特定类型的中断分配中断处理程序和同步处理器资源。
  • xQueueSendFromISR():用于从中断服务程序中向队列发送消息,可以用于与任务之间的通信。

但在本阶段的教程中,我们只使用Arduino封装好的中断函数操作,以上函数待我们学习ESP-IDF编程的时候再详细讲。

中断嵌套

ESP32 支持中断嵌套,可以在一个中断服务函数(ISR)的执行过程中,再触发另一个中断服务函数的执行。这种机制可以帮助开发者快速响应多个事件,提高系统的实时性和响应能力。
ESP32 中断嵌套的具体原理是基于 CPU 的中断向量表(Interrupt Vector Table, IVT)实现的。当 CPU 执行到一个中断服务函数时,会自动禁用当前中断,并将中断服务函数的入口地址写入 IVT 中对应的中断向量项中。如果在当前中断服务函数执行的过程中,又触发了一个新的中断请求,则会根据新中断的优先级来选择是否暂停当前中断服务函数,并转而执行新的中断服务函数。当新的中断服务函数执行完毕后,CPU 会从上一个中断服务函数的执行点继续执行程序,即回到原来的中断服务函数继续执行。
需要注意的是,在 ESP32 中,除 TIMG0_TIMER1_IRQ 和 TIMG0_TIMER2_IRQ 外,所有的中断都支持中断嵌套。此外,由于中断嵌套会增加系统复杂度和不确定性,因此在实际应用中需要谨慎使用,确保程序稳定性和可靠性。
关于 ESP32 中断嵌套的更多介绍和应用实例,可以参考 Espressif 官方文档以及社区中的相关教程和文章。

中断优先级

中断优先级是指在处理多个中断请求时,按照一定的规则确定哪个中断请求具有更高的优先级。在 ESP32 中,一个中断的优先级可以通过设置中断控制器(Interrupt Controler, INTCTL)中的相应寄存器来进行配置。
ESP32 中,每个中断通道都有一个独立的中断控制器,可以设置该中断通道的优先级、中断类型、中断触发方式等参数。具体来说,ESP32 中使用 5 位二进制数表示中断优先级,其中优先级编号越小,优先级越高。中断优先级的具体设置需要参考 ESP32 芯片手册和相关文档。
大多数情况下,开发者不需要修改中断优先级的默认设置,但在某些特殊情况下,根据需求对中断优先级进行适当配置可以提高系统的实时性和响应能力。
ESP32 中的中断嵌套和中断优先级可以帮助开发者快速响应多个事件,提高系统的实时性和响应能力。在使用这两个特性时,需要根据具体的应用场景和需求进行配置和调整,以确保系统的稳定性和可靠性。

Arduino的中断

在Arduino中,中断服务函数和其他函数的格式是一样的,但是在FreeRTOS框架中,中断如无函数有严格的格式要求,如下:

void IRAM_ATTR ISR_function() {// 中断服务程序的具体实现 
}

其中,void 表示 ISR_function() 函数没有返回值,IRAM_ATTR 表示将该函数放在 IRAM(内部 RAM)中,以提高执行速度。ISR_function() 即为中断服务函数的名称,开发者需要根据具体的中断类型和事件命名。
注意,在使用 Arduino FreeRTOS 的情况下,中断服务函数与常规任务处理函数的执行方式略有不同。在中断服务函数中,可以通过 xHigherPriorityTaskWoken 参数来指定是否唤醒更高优先级的任务。例如,如果需要在中断服务函数中唤醒一个阻塞在等待信号量的任务,可以将 xHigherPriorityTaskWoken 参数设置为 pdTRUE,并在中断服务函数结束时调用 portYIELD_FROM_ISR() 函数来切换任务上下文。

启用外部中断
void attachInterrupt(uint8_t pin, void (*ISR)(void), int mode);

该函数与用于安装中断函数,在对应的引脚上启用中断响应。

参数描述
pin表示外部中断触发的引脚编号,在不同开发板编号不一致,ESP32的需要对照开发板丝印确定(编号在引脚下面书写)
ISR表示中断服务函数的指针,使用函数指针是因为中断服务函数需要具有固定的格式和命名规则。在编写中断服务函数时,需要使用 void 类型作为返回值,不带任何参数
mode表示中断触发模式,可以是下列四种之一
LOW:电平低,当引脚为低电平时,触发中断
CHANGE:跳变沿,当引脚电平发生改变时,触发中断
RISING:上升沿,当引脚由低电平变为高电平时,触发中断
FALLING:下降沿,当引脚由高电平变为低电平时,触发中断
禁用中断
void detachInterrupt(uint8_t pin);

该函数用于删除绑定在引脚的中断服务,并关闭该引脚的中断,pin 表示要禁用的引脚

禁用和启用全局中断
void interrupts();    // 开启全局中断
void noInterrupts();  // 关闭全局中断

其中,interrupts() 函数用于开启全局中断,noInterrupts() 函数用于关闭全局中断。在开启了全局中断时,Arduino 系统可以响应所有外部中断请求,并会调用相应的中断服务函数;而在关闭全局中断时,Arduino 系统将无法响应任何外部中断请求,即使外部中断触发也不会执行中断服务函数。

中断的处理原则

为了保证中断服务程序的响应速度和稳定性,开发者需要遵循以下几点原则:

  1. 中断服务程序应尽可能简洁,避免复杂的计算和阻塞操作。
  2. 中断服务程序中不要调用 delay() 和其他阻塞函数,否则会影响系统的稳定性。
  3. 中断服务程序中不要修改全局变量和状态,以避免与主程序发生冲突。
  4. (在Arduino FreeRTOS编程中)中断中如果使用到信号量、消息队列、事件组、缓冲区、任务通知等通讯时,一定要使用后缀为 FromISR 的对应函数。

按键中断

在这里插入图片描述
本例中我们使用四个按键模拟四种中断触发方式:
红色按键上升沿触发,其中一个引脚连接到VCC上
绿色按键下降沿触发,其中一个引脚连接在GND上
蓝色按键跳变沿触发,其中一个引脚连接GND或者VCC都可以
黄色按钮低电平触发,其中一个引脚连接GND
黑色按键下降沿触发,这个用于删除所有中断服务程序

代码共享位置:https://wokwi.com/projects/364683897847685121

#define KEY1_PIN 4   // 红色:上升沿触发
#define KEY2_PIN 11  // 绿色:下降沿触发
#define KEY3_PIN 2   // 蓝色:跳变沿触发
#define KEY4_PIN 35  // 黄色:低电平触发
#define KEY5_PIN 19  // 黑色:退出
#define RISING_EVENT  1
#define FALLING_EVENT 2
#define CHANGE_EVENT  4
#define LOW_EVENT     8
#define CLEAR_EVENT   16
#define ALL_EVENT     31  //RISING_EVENT | FALLING_EVENT | CHANGE_EVENT | LOW_EVENT | CLEAR_EVENT
TaskHandle_t xKeyHandler = NULL;  // 按键驱动任务句柄
// 上升沿触发中断服务函数
void IRAM_ATTR ISR_RISING(){xTaskNotifyFromISR(xKeyHandler, RISING_EVENT, eSetBits, NULL);
}
// 下降沿触发中断服务函数
void IRAM_ATTR ISR_FALLING(){xTaskNotifyFromISR(xKeyHandler, FALLING_EVENT, eSetBits, NULL);
}
// 跳变沿触发中断服务函数
void IRAM_ATTR ISR_CHANGE(){xTaskNotifyFromISR(xKeyHandler, CHANGE_EVENT, eSetBits, NULL);
}
// 低电平触发中断服务函数
void IRAM_ATTR ISR_LOW(){xTaskNotifyFromISR(xKeyHandler, LOW_EVENT, eSetBits, NULL);
}
// 下降沿触发,删除所有中断
void IRAM_ATTR ISR_CLEAN(){xTaskNotifyFromISR(xKeyHandler, CLEAR_EVENT, eSetBits, NULL);
}
// 键盘驱动线程
void key_driver_entry(void *params){pinMode(KEY1_PIN, INPUT_PULLDOWN);    // 上升沿触发,所以必须下拉pinMode(KEY2_PIN, INPUT_PULLUP);      // 下降沿触发,所以必须上拉pinMode(KEY3_PIN, INPUT);             // 跳变沿触发,用哪种拉无所谓pinMode(KEY4_PIN, INPUT_PULLUP);      // 低电平触发,所以必须上拉pinMode(KEY5_PIN, INPUT_PULLUP);      // 下降沿触发,电阻上拉// 安装中断attachInterrupt(KEY1_PIN, ISR_RISING, RISING);attachInterrupt(KEY2_PIN, ISR_FALLING, FALLING);attachInterrupt(KEY3_PIN, ISR_CHANGE, CHANGE);attachInterrupt(KEY4_PIN, ISR_LOW, LOW);attachInterrupt(KEY5_PIN, ISR_CLEAN, FALLING);// 初始化按键情况printf("红色按键情况:%d\n", digitalRead(KEY1_PIN));printf("绿色按键情况:%d\n", digitalRead(KEY2_PIN));printf("蓝色按键情况:%d\n", digitalRead(KEY3_PIN));printf("黄色按键情况:%d\n", digitalRead(KEY4_PIN));uint32_t events = 0;while(1){// 接收任务通知前,先清空所有位,接收后也清空所有位if (xTaskNotifyWait(UINT32_MAX, UINT32_MAX, &events, portMAX_DELAY) == pdTRUE){if(events>0){// 当收到任务通知后,等待10ms,如果该按键在查看电平状态,则表示真的触发了,真机中可以调整这个值达到去抖目的delay(50);if((events & RISING_EVENT) > 0){// 上升沿按键可能被触发if(digitalRead(KEY1_PIN)==HIGH){printf("您按下了红色按键!\n");}}else if((events & FALLING_EVENT) > 0){if(digitalRead(KEY2_PIN)==LOW){printf("您按下了绿色按键!\n");}}else if((events & CHANGE_EVENT) > 0){printf("您按下了蓝色按键!\n");}else if((events & LOW_EVENT) > 0){if(digitalRead(KEY4_PIN)==LOW){printf("黄色按键被按下!\n");}}else if((events & CLEAR_EVENT) > 0){if(digitalRead(KEY5_PIN)==LOW){printf("终结所有按键中断!\n");//卸载中断detachInterrupt(KEY1_PIN);detachInterrupt(KEY2_PIN);detachInterrupt(KEY3_PIN);detachInterrupt(KEY4_PIN);detachInterrupt(KEY5_PIN);}}}xTaskNotifyStateClear(NULL);    // 清空所有状态}events = 0;delay(1);}vTaskDelete(NULL);
}
void setup() {// put your setup code here, to run once:Serial.begin(115200);Serial.println("Hello, ESP32-S3!");xTaskCreate(key_driver_entry, "KD", 10240, NULL, 1, &xKeyHandler);vTaskDelete(NULL);
}
void loop() {
}

代码中一共定义了5个中断服务函数,分别对用了四种中断触发类型(还有一个是KEY5,下降沿触发,用于删除所有中断的)。
五个中断服务函数中,都是使用 xTaskNotifyFromISR 发送任务通知,这个函数是 xTaskNotify 在中断中的用法,后缀是 FromISR,并且比 xTaskNotify 多了最后一个 pxHigherPriorityTaskWoken 参数,这个参数来指定是否唤醒更高优先级的任务。例如,如果需要在中断服务函数中唤醒一个阻塞在等待信号量的任务,可以将 xHigherPriorityTaskWoken 参数设置为 pdTRUE,并在中断服务函数结束时调用 portYIELD_FROM_ISR() 函数来切换任务上下文,这里我们不做任何处理,传入一个 NULL 即可。

key_driver_entry 中,开始对引脚进行初始化,因为触发中断的方式不同,所以我们初始化引脚的上下拉电阻方式也不同原则如下:
上升沿触发,使用下拉电阻方式初始化引脚(INPUT_PULLDOWN),确保初始化为低电平,另一个引脚接VCC
下降沿触发,使用上拉电阻方式初始化引脚(INPUT_PULLUP),确保初始化为高电平,另一个引脚接GND
跳变沿触发,使用哪种方式都行,但必须是INPUT方式,如果使用上拉初始化,另一个引脚接GND,如果使用下拉初始化,另一个引脚接VCC
低电平触发,使用上拉电阻方式初始化引脚(INPUT_PULLUP),确保初始化为高电平,另一个引脚接GND。
通过初始化后的电平状态输出,我们可以看到上下拉的作用。
在这里插入图片描述

大循环中,使用 xTaskNotifyWait 等待通知事件的到达,在接收前后都进行数据位的清空,处理后再次把所有状态位清空。
在之前的例程中,以及实验中得知,物理按键有抖动的情况,为了消除这些抖动,因为在按键的过程中,引脚电平可能会出现多次的高低翻转,也就意味着可能出现多次中断,这是我们不希望看到的,所以我们采用很多种方式协助去抖动:

  1. 接收任务通知前后将数据位清空,配合 delay 函数,当中断服务函数多次发送通知的时候,驱动函数还在 delay 中,虽然修改了数据位,但下次接手前(这时候已经完成了按键操作)就会把数据清空。
  2. 收到通知后进行50ms的 delay (这个数字可以根据实际硬件情况调整,尽量短,需要自己测试),如果50ms之后按键状态仍然是想要的状态(高或者低),那就认为是已经触发了事件(注意,这里不能说是正确触发了中断,因为中断这时候其实已经多次触发,但有可能是不正确的)。这个数字如果太大,造成的后果是键松开了,但 delay 还没结束,就会触发失败。
  3. 事件处理完之后使用 xTaskNotifyStateClear 清空直接任务通知状态,因为在 xTaskNotifyWait 中我们虽然清空了数据位,但状态仍然是被激发状态,容易造成混乱,这句卸载 xTaskNotifyWait 之前或者处理程序最后都可以,根据实际情况决定。

这段程序有个BUG,LOW 方式的中断始终无法触发,不知道是模拟器问题还是程序问题,大家可以真机测试一下看。

程序运行后,红色按键和绿色按键每次按下的会后都会触发一次,松开不触发,而蓝色按键不管是按下还是松开都会被触发,因为他是跳变沿触发,只要电平状态改变就会触发。

定时器对按键中断的优化

用 delay 延时检测电平状态的形式是比常用的,也是比较偷懒和影响效率的方式,在不惜成本的情况下尽量还是用硬件去抖,如果非得用软件去抖,大家还可以使用定时器辅助完成。
代码共享位置:https://wokwi.com/projects/364697074528877569

#define KEY1_PIN 4   // 红色:上升沿触发
#define RISING_EVENT  1
TaskHandle_t xKeyHandler = NULL;  // 按键驱动任务句柄
TimerHandle_t xKeyTimer = NULL;   // 去抖定时器
void key_timer(TimerHandle_t xTimer){if(digitalRead(KEY1_PIN)==HIGH){xTaskNotify(xKeyHandler, RISING_EVENT, eSetBits); // 发送通知}
}
// 上升沿触发中断服务函数
void IRAM_ATTR ISR_RISING(){xTimerStartFromISR(xKeyTimer, NULL);    // 启动定时器,可能多次启动
}
// 键盘驱动线程
void key_driver_entry(void *params){// 初始化按键去抖定时器xKeyTimer = xTimerCreate("KEY1_TIMER", 50, pdFALSE, NULL, key_timer);pinMode(KEY1_PIN, INPUT_PULLDOWN);// 安装中断attachInterrupt(KEY1_PIN, ISR_RISING, RISING);uint32_t events = 0;while(1){// 接收任务通知前,先清空所有位,接收后也清空所有位if (xTaskNotifyWait(UINT32_MAX, UINT32_MAX, &events, portMAX_DELAY) == pdTRUE){if((events & RISING_EVENT) > 0){printf("按键被触发了!\n");}xTaskNotifyStateClear(NULL);    // 清空所有状态}events = 0;delay(1);}vTaskDelete(NULL);
}
void setup() {// put your setup code here, to run once:Serial.begin(115200);Serial.println("Hello, ESP32-S3!");xTaskCreate(key_driver_entry, "KD", 10240, NULL, 1, &xKeyHandler);vTaskDelete(NULL);
}
void loop() {
}

代码 key_event_task_entry 首先初始化了一个按键的定时器,这个定时器在 Start 后50ms执行一次(这个就是去抖时间,根据实际硬件情况修改),函数中判断如果该引脚仍然是高电平,则说明确实按下了键,而不是抖动,这时候向任务发送一个通知,表示按键被按下了。而 xTimerStartFromISR 是可以重复调用的,如果第二次调用在,则会reset之后重新计时,不会重复启动多个定时器,这正好符合我们的要求。

注意: 在实际开发中,应该还对按键的抬起进行去抖动,尤其是跳变沿触发方式上,上面两段代码仅仅是在模拟器上运行,问题不大,但真机测试的时候可能会存在抬起扰动的风险。
抬起抖动可能不会超过 50ms ,所以如果抬起发生扰动的时候,第二次判断按键状态的时候一定是低电平(如果去抖时间短就不好说了),比较保守的做法是在按键抬起后,第一次出现低电平在进行一个定时器的判断进行去抖。

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

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

相关文章

苹果手机怎么连接电脑?看这里,答案揭晓!

通过连接苹果手机和电脑,用户可以将手机上的照片、视频、音乐、文件等数据传输到电脑中,也可以将电脑中的文件传输到手机中。 这样可以方便地备份手机数据,也可以在电脑中编辑、处理手机中的文件。那么,苹果手机怎么连接电脑呢&a…

Promise面试题合集(问题+答案)

event loop它的执行顺序: 一开始整个脚本作为一个宏任务执行执行过程中同步代码直接执行,宏任务进入宏任务队列,微任务进入微任务队列当前宏任务执行完出队,检查微任务列表,有则依次执行,直到全部执行完执…

使用Nginx作为反向代理服务器在Linux中的最佳实践

在Linux环境下,Nginx因其高效性能、稳定性以及丰富的功能集而广泛用于作为反向代理服务器。以下是在Linux中使用Nginx作为反向代理服务器的最佳实践: 1. 安装与配置 首先,确保你的Linux发行版已经安装了Nginx。大多数Linux发行版都提供了Ng…

什么是OV证书?

OV证书是一种经过严格身份验证的SSL/TLS证书,相较于基础的域名验证(DV)证书,它的验证过程更为深入和全面。在颁发OV证书前,证书颁发机构(CA)不仅会验证申请者对域名的所有权,还会对企业或组织的身份进行严格的审查,包括…

rime中州韵小狼毫 日期/农历 时间 事件 节气 滤镜

教程目录:rime中州韵小狼毫须鼠管安装配置教程 保姆级教程 100增强功能配置教程 网络上但凡提到 rime中州韵小狼毫须鼠管输入法,总少不了智能时间,日期等炫技,可见这个便捷时间/日期输入功能是多么的受欢迎。作者也不落窠臼&…

[我的rust付费栏目]rust跟我学(一)已上线

大家好,我是开源库get_local_info的作者带剑书生,get_local_info诞生半个月,现在已经获得500的下载量,并获社区日更前五名,后被西安城市开发者社区收录(【我的Rust库】get_local_info 0.1.5发布_rust_科比布…

【SpringBoot3】Spring Boot 3.0 介绍以及新特性

文章目录 一、Spring Boot 3.01、介绍2、Spring Boot 核心概念3、Spring Boot 3.0 新特性 二、Spring Boot Starter1、介绍2、Starter 命名规则3、官方提供了哪些Starter 三、spring-boot-starter-parent 说明四、示例:创建web项目参考 一、Spring Boot 3.0 1、介绍…

科研绘图(八)线性热图

线性热图(Linear Heat Map)是一种数据可视化技术,用于展示数值在一维线性空间上的分布情况。它通常用于展示沿着一条线(例如时间线或任何一维序列)的数据密度或强度变化。线性热图与传统的二维热图不同,后者…

Vue中的v-model

聚沙成塔每天进步一点点 本文内容 ⭐ 专栏简介基本用法文本输入框复选框下拉框 原理解析文本输入框的原理复选框和下拉框的原理 ⭐ 写在最后 ⭐ 专栏简介 Vue学习之旅的奇妙世界 欢迎大家来到 Vue 技能树参考资料专栏!创建这个专栏的初衷是为了帮助大家更好地应对 V…

UE5 UE4 打包报错Failed to compile material 解决

参考:https://forums.unrealengine.com/t/failed-to-compile-material-for-pcd3d_sm5-warning/385087 https://forums.unrealengine.com/t/failed-to-compile-material-for-platform-pcd3d-sm4/436176 报错:Failed to compile Material for platform PC…

运算符重载函数

C为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。 函数名字为:关键字operator后面接需要重载的运算符符…

django rest_framework 部署doc文档

1.背景 在实际开发过程中,前后端分离的项目,是需要将一份完整的接口文档交付给前端开发人员,这样有利于开发速度和开发质量,以及有可能减少协同时间。 2.内容 本项目是以Pythondjangorest_framework作为技术框架,在这…

设计模式之里氏代换原则:打破常规,让代码更灵活

在软件开发的世界中,设计模式是解决常见问题的最佳实践。其中,里氏代换原则(Liskov Substitution Principle,LSP)是面向对象设计的基本原则之一,它强调了在软件中子类型必须能够替换其基类型,而…

Zabbix监控(2)

目录 一.自动发现 配置自动发现:(被动模式) 修改三台服务器的hosts文件: 修改agent02的配置文件: 访问页面,删除客服端主机配置: 在配置的自动发现中添加规则: 我们重启的zab…

基于springboot的疫情物资捐赠和分配系统

🍅点赞收藏关注 → 私信领取本源代码、数据库🍅 本人在Java毕业设计领域有多年的经验,陆续会更新更多优质的Java实战项目希望你能有所收获,少走一些弯路。🍅关注我不迷路🍅一 、设计说明 1.1 课题背景 二…

网站引导页源码带视频背景源码系统:HTML5开发的引导页 附带完整的搭建教程

随着互联网技术的飞速发展,网站引导页作为用户体验的重要环节,越来越受到开发者的关注。传统的静态图片引导页已经无法满足用户对于新鲜感和互动性的需求。小编给大家分享一款基于HTML5的带视频背景的源码系统,旨在为用户提供更加丰富、动态的…

细说JavaScript内置对象(JavaScript内置对象详解)

一、String对象 1、简单上手 2、构造方法 3、其他方法 3.1、charAt() 3.2、indexOf() 3.3、split() 3.4、substring() 3.5、substr() 4、实际操作 二、Math对象 1、简单上手 2、对象属性 3、对象方法 4、实际操作 三、Date对象 1、简单上手 2、构造方法 3、实…

【网络安全】【密码学】【北京航空航天大学】实验四、古典密码(上)【C语言实现】

实验四、古典密码(上) 一、实验目的 1、 通过本次实验,了解古典加密算法的主要思想,掌握常见的古典密码。 2、 学会应用古典密码,掌握针对部分古典密码的破译方法。 二、原理简介 古典密码的编码方法主要有两种&am…

第一个 OpenGL 程序:旋转的立方体(VS2022 / MFC)

文章目录 OpenGL API开发环境在 MFC 中使用 OpenGL初始化 OpenGL绘制图形重置视口大小 创建 MFC 对话框项目添加 OpenGL 头文件和库文件初始化 OpenGL画一个正方形OpenGL 坐标系改变默认颜色 重置视口大小绘制立方体使用箭头按键旋转立方体深度测试添加纹理应用纹理换一个纹理 …

【电商API接口】挖掘电商数据常用的方法

电子商务模式是一个连接线上用户和线下商家的多边平台商业模式。O2O 商业模式将实体经济与线上资源融合在一起,使网络成为实体经济延伸到虚拟世界的渠道; 线下商业可以到线上挖掘和吸引客源,而消费者可以在线上筛选商品和服务并完成支付,再到…