普冉(PUYA)单片机开发笔记(4): 配置通用定时器

概述

在前几篇开发笔记中,从 PY32F003 的一个厂家标准例程开始,实现了中断式无阻塞串口收发、对开发板 LED3 的亮/灭控制,时钟系统的初始化和时钟选择。在此基础上,今天做一下定时器的应用实验。事先考虑以下几个问题:

  • 如何使用现有例程扩展开发 MCU 的其它功能
  • 定时器的中断和 UART 的中断,在PY32F003 上如何协调
  • 使用 PY32 MCU 的定时器和使用 STM32 有什么异同

仍然使用 PUYA 的官方开发板,使用 SEGGER J-Link 仿真器,SWD 接口,四根线,3V3-DIO-CLK-GND。板子上接有 LED,连接 PB5,灌流式,外部3V3上拉,低电平点亮,高电平熄灭。外接UART2(PA0--TX,PA1--RX)。

这一次,先做一个最简单的定时器实验:当定时器 Elapse(流逝?到点了更贴切一些) 的时候,翻转板载 LED。

使用PY32F003的外部时钟

在 main(void) 函数中使用 SystemClock_Config() 函数初始化时钟系统,并选择 HSE 作为时钟源,代码如下

/********************************************************************************************************
**函数信息 :void SystemClock_Config(void)
**功能描述 :系统时钟配置
**输入参数 :
**输出参数 :
**    备注 :
********************************************************************************************************/
HAL_StatusTypeDef SystemClock_Config(void)
{HAL_StatusTypeDef conf_res= HAL_OK;RCC_OscInitTypeDef RCC_OscInitStruct = {0};RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE |RCC_OSCILLATORTYPE_HSI | RCC_OSCILLATORTYPE_LSI;              // 配置时钟源HSE/HSI/LSE/LSIRCC_OscInitStruct.HSIState = RCC_HSI_ON;                                // 开启HSIRCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;                                // 不分频//RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_8MHz;      // 配置HSI输出时钟为8MHz//RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_4MHz;      // 配置HSI输出时钟为4MHz//RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_16MHz;     // 配置HSI输出时钟为16MHz//RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_22p12MHz;  // 配置HSI输出时钟为22.12MHzRCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_24MHz;       // 配置HSI输出时钟为24MHzRCC_OscInitStruct.HSEState = RCC_HSE_ON;                                // 开启 HSERCC_OscInitStruct.HSEFreq = RCC_HSE_16_32MHz;                           // HSE工作频率范围16M~32MRCC_OscInitStruct.LSIState = RCC_LSI_OFF;                               // 关闭 LSIconf_res = HAL_RCC_OscConfig(&RCC_OscInitStruct);                       // 初始化RCC振荡器if (conf_res != HAL_OK)                                                 return conf_res;//初始化CPU,AHB,APB总线时钟RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1;      // RCC系统时钟类型RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE;  // SYSCLK的源选择为HSIRCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;      // APH时钟不分频RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;       // APB时钟不分频conf_res = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1); // 初始化RCC系统时钟// (FLASH_LATENCY_0=24M以下;// FLASH_LATENCY_1=48M)if (conf_res != HAL_OK)  return conf_res;return HAL_OK;
}

注意后面的一段中的 SYSCLKSource 指定为 RCC_SYSCLKSOURCE_HSE 选择了 HSE。AHBCLKDivider 和 APB1CLKDivider 两者决定了所有定时器的时钟频率。在我的实验环境中,这两个参数都选择“不分频”,使定时器的总线频率最高。外接晶振的频率为 24MHz,这是一个重要的基础频率,决定了在定时器配置中的 Prescaler 和 Period 的取值。

测试中,发现在初始化时钟时,即使要使用 HSE,也要设置

RCC_OscInitStruct.HSIState = RCC_HSI_ON;

如果设置成 RCC_HSI_OFF,MCU 将卡死。

由于 PY32F0003 没有 PLL,APH 和 APB 都不分频可以提高定时精度。

配置TIM16

定时周期

在 PY32F003 上,TIM16 和 TIM17 是两个通用定时器。我选用了 TIM16,配置代码如下:

TIM_HandleTypeDef TimHandle;/********************************************************************************************************
**函数信息 :void TIM16_Config(void)
**功能描述 :初始化TIM相关MSP
**输入参数 :
**输出参数 :
**    备注 :
********************************************************************************************************/
HAL_StatusTypeDef TIM16_Config(void)
{HAL_StatusTypeDef conf_res=HAL_OK;TimHandle.Instance = TIM16;                                         // 选择 TIM16TimHandle.Init.Period            = 12000 - 1;                       // 自动重装载值 500usTimHandle.Init.Prescaler         = 1000 - 1;                        // 预分频为 1000-1,两者确定定时器中断周期为500msTimHandle.Init.ClockDivision     = TIM_CLOCKDIVISION_DIV1;          // 时钟不分频TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;              // 向上计数TimHandle.Init.RepetitionCounter = 1 - 1;                           // 不重复计数TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;   // TIMx ARR 缓冲conf_res = HAL_TIM_Base_Init(&TimHandle);                           // TIMx 初始化if ( conf_res != HAL_OK)                         return conf_res;return HAL_OK;
}

这段代码实现了周期为 0.5s 的定时。参照官方说明,定时周期

T = (Period+1)*(Prescaler+1)/Fclk

其中,Fclk是总线时钟频率:24M = 24000000/秒;Period=12000-1; Prescaler=1000-1,得到定时器 Elapse 周期为

T= 12000*1000/24000000=0.5(秒)

虽然 Period 和 Prescaler 这两个值的数据类型是 uin32_t,但厂家的 HAL 库文件中说明了其取值范围从 0x0000 - 0xFFFF(65535),实际上是一个 16 位无符号整数。

  • 基于 24MHz 的总线时钟频率,理论上的最小定时周期是 1/24 us,但这个定时周期无实用价值。定时器的周期设定和定时器中断程序的处理逻辑所需的 CPU 耗费有关,同时还要考虑其它中断对定时器中断的嵌套所带来的额外时间耗费。
  • PY32F003 的 ALU 具有单周期的加减法,乘除法是否单周期的,官方文件没有说明,只是在 PY32F040 中列出了“单周期整数除法”。既然不能确定,在编写中断服务程序的时候,不能指望 ALU 执行单周期整数乘除法。
  • 寄存器操作和 GPIO 操作可以在2~6个时钟周期内完成。
  • 如果要处理业务逻辑,则需要仔细地算计中断服务程序的耗时,要确保在下一个定时中断到来之前完成所有计算。毫秒级的定时,可以完成4000条以上的汇编指令,能实现相当复杂的业务逻辑了。
  • AutoReloadPreload 是 ENABLE 还是 DISABLE 在这个实验中没有影响。

编写 HAL_TIM_Base_MspInit 函数

HAL_TIM_Base_MspInit 函数由 HAL_TIM_Base_Init 函数所调用,其函数原型是一个 __weak 类型,需要在应用代码中重写,函数代码如下,完成的功能在代码的注释中已写明。

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{__HAL_RCC_TIM16_CLK_ENABLE();           //使能TIM16时钟HAL_NVIC_SetPriority(TIM16_IRQn, 0, 3); //设置中断优先级HAL_NVIC_EnableIRQ(TIM16_IRQn);         //使能TIM1中断
}

在 PUYA 的 HAL 库中,HAL_TIM_Base_MspInit 被分离了出来,之所以分离这个函数的目的,我猜想是可以在 HAL_TIM_Base_MspInit 中对其做差异化的初始化,例如:是否使用中断,使用的中断优先级是多少,是否使用 DMA 等等。STM32CubeIDE 的 HAL 库函数也是这么组织的。

虽然可以在 py32f0xx_hal_tim.c 中直接修改 HAL_TIM_Base_MspInit 函数,但我习惯于在应用代码中重写这类函数,因为这么做可以保持 HAL 库函数的一致性,方便移植。

编写定时器中断服务程序 HAL_TIM_PeriodElapsedCallback

代码如下,很简单,就是将板载 LED 进行翻转。定时器是 0.5s 一次,观察 LED 的明灭,就是一秒钟亮一下了。

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance != TIM16) return;HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_5);
}

顺便重申一下:除非调试和其它不得不用到的场合,在中断服务程序中,尽量不使用 printf 这类全局阻塞式的语句

封装 HAL_TIM_Base_Start_IT 函数

这个封装,把 TimHandle 变量和 main 函数彻底分离:main 函数可以不关心这个 TIM 到底是哪一个定时器了。

HAL_StatusTypeDef TIM16_Start(void)
{return HAL_TIM_Base_Start_IT(&TimHandle);
}

实验结果

完成上述代码后,F7->F8,把程序编译烧录到开发板上,得到如下的结果,正如预期所示,开发板上的 LED 每隔 1 秒钟亮起一下,明灭时长,看着是一半一半的样子。

串口收发的功能正常,在 LED 明灭的同时,在 XCOM 上点击以100ms间隔“定时发送”,MCU 可以连续正确地返回发送的字符串。这说明串口中断和定时器中断没有发生冲突。

实验尝试了将定时器的优先级设置为 0/1/2/3/4/5/6/7/8的时候,LED 的明灭看不出有停顿的现象。想来这个实验中,串口收发的数据量都很小,定时器中断里执行的指令也很少,产生中断嵌套的几率可以忽略不计。

Keil uVision 的工程项目文件组织优化

截止目前,例程中具备了几个功能了:时钟选择,GPIO初始化,UART初始化和定时器配置,今后还会增加功能。把这些初始化和业务逻辑操作都放在 main.c 中会有一些臃肿,这一次,对原来堆砌在 main.c 中的变量和函数进行了分类

  • 在 Application/User 组中增加了 app_uart.c,app_timer.c,app.c 三个文件。
  • main.c 中关于 UART/USART 的变量和函数都搬到了 app_uart.c 文件中,包括;
    • int fputc(int ch, FILE *f);
    • void Debug_Info(const char* msg);
    • HAL_StatusTypeDef USART_Config(void);
    • HAL_StatusTypeDef DBG_UART_Start(void);
    • void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart);
    • void HAL_UART_TxCpltCallback(UART_HandleTypeDef *pHUart);
    • void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle);
  • main.c 中关于 TIMER,TIM16 的变量和函数都搬到了 app_timer.c 文件中
    • HAL_StatusTypeDef TIM16_Config(void);
    • HAL_StatusTypeDef TIM16_Start(void);
    • void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim);
    • void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);
  • main.c 中未分类的函数搬到了 app.c 中
    • HAL_StatusTypeDef SystemClock_Config(void);
    • 其它零碎的函数

main.c 只调用封装好的函数,关注逻辑和顺序,不再关心全局变量和每一个函数的实现。分离之后,main(void) 函数简洁多了,整个 main.c 文件如下所示。如果你愿意,那么 main 函数只需要 11~12 行代码就够了。

/********************************************************************************* @file    main.c* @brief   Main program entry.******************************************************************************* @attention** Copyright (c) 2023 CuteModem Intelligence.* All rights reserved.** This software is licensed under terms that can be found in the LICENSE file* in the root directory of this software component.* If no LICENSE file comes with this software, it is provided AS-IS.********************************************************************************//* Private includes*/
#include "main.h"
#include <stdio.h>
/* Private define ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private user code ---------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*//**
* -------------------------------------------------------------------------
* @file   : int main(void)
* @brief  : main函数
* @param  : 无
* @retval : 无限循环,无返回值
* @remark : 
* -------------------------------------------------------------------------
*/
int main(void)
{HAL_Init();             // systick初始化SystemClock_Config();   // 配置系统时钟if(USART_Config() != HAL_OK) Error_Handler();         printf("[SYS_INIT] Debug port initilaized.\r\n");if(GPIO_Config() != HAL_OK) Error_Handler();          printf("[SYS_INIT] Board LED initilaized.\r\n");if(TIM16_Config() != HAL_OK) Error_Handler();printf("[SYS_INIT] Timer initialized.\r\n");if (TIM16_Start() != HAL_OK) Error_Handler();printf("[SYS_INIT] Timer started.\r\n");printf("\r\n+---------------------------------------+""\r\n|        PY32F003 MCU is ready.         |""\r\n+---------------------------------------+""\r\n");if (DBG_UART_Start() != HAL_OK) Error_Handler();while (1){/***  For testing GPIO output*  2023-11-24*  Hard coder Luoyuan*/
#if(0)// Toggle LED3 in TIM16 IT service procedure instead.HAL_Delay(1000);HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_5);
#endif}
}/**
* -------------------------------------------------------------------------
* @brief  : void Error_Handler(void)
* @detail : 错误陷阱函数,提示错误,然后死循环
* @param  : 无
* @retval : 无
* @remark : 
* -------------------------------------------------------------------------
*/
void Error_Handler(void)
{Debug_Info("[__ERROR_] System halt.");while (1) {}
}#ifdef USE_FULL_ASSERT
/*** @brief  Reports the name of the source file and the source line number*         where the assert_param error has occurred.* @param  file: pointer to the source file name* @param  line: assert_param error line source number* @retval None*/
void assert_failed(uint8_t *file, uint32_t line)
{/* User can add his own implementation to report the file name and line number,tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
}
#endif /* USE_FULL_ASSERT */

这里所调用的函数,要在 main.h 文件中定义好。实验所用的 main.h 代码如下,除了众多的注释以外,可运行代码也就30行的样子。

/********************************************************************************* @file    main.h* @author  MCU Application Team* @Version V1.0.0* @Date* @brief   Header for main.c file.*          This file contains the common defines of the application.*******************************************************************************//* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __MAIN_H
#define __MAIN_H#ifdef __cplusplus
extern "C"
{
#endif/* Includes ------------------------------------------------------------------*/
#include "py32f0xx_hal.h"
#include "py32f003xx_Start_Kit.h"
#include <stdbool.h>/* Exported functions prototypes ---------------------------------------------*/
HAL_StatusTypeDef SystemClock_Config(void);
HAL_StatusTypeDef GPIO_Config(void);
HAL_StatusTypeDef USART_Config(void);
HAL_StatusTypeDef DBG_UART_Start(void);
HAL_StatusTypeDef TIM16_Config(void);
HAL_StatusTypeDef TIM16_Start(void);void Debug_Info(const char* msg);void MX_DMA_Init(void);
void MX_ADC1_Init(void);
void Error_Handler(void);#define TEST_PORT USART2     // USART1
#define DEFAULT_UART_CFG (4) // 115200
// #define DEF_OVERSAMPLING_8
// #define IDLE_TEST// USART1
#define USARTx USART1
#define USARTx_CLK_ENABLE()         __HAL_RCC_USART1_CLK_ENABLE()
#define USARTx_RX_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()
#define USARTx_TX_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()#define USARTx_FORCE_RESET()        __HAL_RCC_USART1_FORCE_RESET()
#define USARTx_RELEASE_RESET()      __HAL_RCC_USART1_RELEASE_RESET()/* Definition for USARTx Pins */
#define USARTx_TX_PIN           GPIO_PIN_2
#define USARTx_TX_GPIO_PORT     GPIOA
#define USARTx_TX_AF            GPIO_AF1_USART1
#define USARTx_RX_PIN           GPIO_PIN_3
#define USARTx_RX_GPIO_PORT     GPIOA
#define USARTx_RX_AF            GPIO_AF1_USART1/* Definition for USARTx's NVIC */
#define USARTx_IRQn         USART1_IRQn
#define USARTx_IRQHandler   USART1_IRQHandler//#define TIMx                           TIM16
//#define TIMx_CLK_ENABLE()              __HAL_RCC_TIM16_CLK_ENABLE()
//#define TIMx_IRQn                      TIM16_IRQn/* Size of Trasmission buffer */
#define TXBUFFERSIZE (COUNTOF(aTxBuffer) - 1)
/* Size of Reception buffer */
#define RXBUFFERSIZE TXBUFFERSIZE/* Exported macro ------------------------------------------------------------*//* Private defines -----------------------------------------------------------*/#ifdef __cplusplus
}
#endif#endif /* __MAIN_H */

按照酱紫的方法,在不改变项目文件组织框架的基础上,可以将更多的功能集成到这个项目中,main.c 和 main() 函数体保持简洁的结构和越来越明晰的业务逻辑。

总结(踩坑记)

PY32F0xx 的厂家例程包的设计是每一个例程“独立”的,这给我的实验中增加功能带来了一些困惑。每一个例程中,在 Application/User 组里的 py32f0xx_hal_msp.c 的内容都是不同的,在这个文件中定义了例程所需要的 HAL_xxx_MspInit(),例如 HAL_MspInit(),HAL_TIM_Base_MspInit() 函数等等,反正是例程所需要的 MspInit 都在 py32f0xx_hal_msp.c 文件中。这种文件组织让我好顿困惑,经过从 main() 函数的 HAL_Init,HAL_TIM_Base_Init 函数中无数的 F12,终于明白了厂家例程的这种做法。这个小坑耗费了我不少的时间去寻找解决之道。这里分享给各位码神,勿要再次入坑。

如果要用到中断的话,一定要在 py32f0xx_it.c 的 xxx_IRQHandler 函数中重定向 HAL_xxx_IRQHandler(&handler),就像我的实验中用到了 UART 中断,就要将 USART1_IRQHandler 函数重定向到 HAL_UART_Handler(&UartHandler);还用到了 TIM16 中断,就要将  TIM16_IRQHandler 重定向到 HAL_TIM_IRQHandler&TimHandler)。如果没有这些重定向,中断的Enable将会卡死。

通过这些功能的集成("堆砌"而已,稍稍给自个儿整的高大上一丢丢 ;),发现 PY32F0xx 的 HAL 库函数和 STM32F0xx 系列的还是有一些差异的。好在通过学习厂家例程,其中绝大多数的指令是兼容的,而对寄存器、USART 和定时器的底层控制方法是“几乎”完全相同的,我想这是因为都是采用相同的 Cortex M0+ 内核的缘故吧,内核一样,底层控制肯定都一样的。

随着对 PUYA HAL 库文件的熟悉,还会继续集(堆)成(砌)更多的功能。希望这些实验能给各位码神一些参考。谬误之处,恳请指正。

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

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

相关文章

【C语言】函数调用及创建,并将数组传参到函数

&#x1f3a5; 岁月失语唯石能言的个人主页 &#x1f525;个人栏专&#xff1a;秒懂C语言 ⭐若在许我少年时&#xff0c;一两黄金一两风 目录 前言 一、函数的概念 二、库函数 2.1 标准库和头文件 2.2库函数的使用方法 2.2.1功能 2.2.2库函数的头文件 2…

一些程序源码及教程的网站合集~

很多时候我们需要一个快速上手的code demo及教程&#xff0c;除了最常用的【github】&#xff0c;一些中文网站可能会帮助我们更好上手~ 这里提供几个中文网站参考&#xff1a; 【51CTO】&#xff1a; Python 动态手势识别系统hmm 手势识别opencv_mob64ca140d96d9的技术博客…

19、WEB攻防——.NET项目DLL反编译未授权访问配置调试报错

文章目录 一、.NET项目——DLL文件反编译指向—代码特性二、.NET项目——Web.config错误调试—信息泄露三、.NET项目——身份验证未授权访问—安全漏洞 web搭配&#xff1a; windowsiisaspaccesswindowsiisaspxsqlserver 一、.NET项目——DLL文件反编译指向—代码特性 bin目…

【Linux】探索Linux进程优先级 | 环境变量 |本地变量 | 内建命令

最近&#xff0c;我发现了一个超级强大的人工智能学习网站。它以通俗易懂的方式呈现复杂的概念&#xff0c;而且内容风趣幽默。我觉得它对大家可能会有所帮助&#xff0c;所以我在此分享。点击这里跳转到网站。 目录 一、进程优先级1.1优先级VS权限1.2为什么要有进程优先级&am…

《YOLOv8改进系列》专栏目录介绍

YOLOv8改进系列 &#x1f680; 专栏目录介绍 本专栏内容是紧跟最新、最前沿的改进方法&#xff0c;不仅适用检测任务&#xff0c;分类任务&#xff0c;分割任务&#xff0c;关键点任务同样适用。文章适用于多种场景&#xff0c;包括但不限于小目标、工业缺陷、轻量化等领域。 …

1.3 什么是接口?什么是接口测试?

上一小节我们认识了C/S和B/S架构,那在B/S架构中,我们测试最常接触的,就是接口。本课程的重点是接口自动化测试,那同学们真的了解什么是接口吗?首先,我们从通俗的角度来看什么是接口。在计算机中,接口是计算机系统中两个独立的部件进行信息交换的共享边界。这种交换可以发…

YOLOv8-pose关键点检测:模型轻量化创新 | 轻量化自研设计双卷积,修改backbone和neck,完成涨点且计算量和参数量显著下降

💡💡💡本文解决什么问题:双卷积由组卷积和异构卷积组成,执行 33 和 11 卷积运算代替其他卷积核仅执行 11 卷积,加入YOLOv8 backbone和ncek DualConv | GFLOPs从9.6降低至9.1,参数量6842kb降低至6393 ,mAP50从0.921提升至0.931,mAP50-95从0.697提升至0.726 Yolo…

防火墙访问控制、安全审计、网络设备防护检查表

1、访问控制类检查 2、安全审计类检查 3、网络设备防护类检查 原件&#xff1a; 防火墙标准检查表 分类 测评项 预期结果 访问控制 应在网络边界部署访问控制设备&#xff0c;启用访问控制功能 启用了访问控制规则 应能根据会话状态信息为数据流提供明确的允许/拒绝访…

HarmonyOS—实现UserDataAbility

UserDataAbility接收其他应用发送的请求&#xff0c;提供外部程序访问的入口&#xff0c;从而实现应用间的数据访问。Data提供了文件存储和数据库存储两组接口供用户使用。 文件存储 开发者需要在Data中重写FileDescriptoropenFile(Uriuri,Stringmode)方法来操作文件&#xf…

socket是如何进行通信的

Socket通信的原理大致分为以下几个步骤&#xff1a; 服务器端建立Socket&#xff0c;开始侦听整个网络中的连接请求。当检测到来自客户端的连接请求时&#xff0c;向客户端发送收到连接请求的信息&#xff0c;并建立与客户端之间的连接。当完成通信后&#xff0c;服务器关闭与…

bash命令: logrotate的使用

1. 概述 Linux服务器上运行的程序都会通过日志来告知外部自己的运行过程、结果以及遇到的问题&#xff0c;随着日志的不断累计&#xff0c;它会变的越来越大&#xff0c;所以常见的方案是根据时间或者日志文件的大小&#xff0c;对日志文件进行轮转&#xff0c;比如Java程序里…

简单使用selenium抓取微博热搜话题存储进Excel表格中

#test.pyimport requests from selenium import webdriver import time from write import write#首先打开浏览器 drive webdriver.Chrome()#设置隐式等待&#xff1a;等待元素找到&#xff0c;如果找到元素则马上继续执行语句&#xff0c;如果找不到元素&#xff0c;会在设定…

【PWN】学习笔记(三)【返回导向编程】(下)

目录 课程回顾动态链接过程 课程 课程链接&#xff1a;https://www.bilibili.com/video/BV1854y1y7Ro/?vd_source7b06bd7a9dd90c45c5c9c44d12e7b4e6 课程附件&#xff1a; https://pan.baidu.com/s/1vRCd4bMkqnqqY1nT2uhSYw 提取码: 5rx6 回顾 管道符 | 把前一个指令的输出作…

动物疾控中心污水处理设备工艺特点

诸城市鑫淼环保小编带大家了解一下动物疾控中心污水处理设备工艺特点 1、采用中和沉淀、复合式消毒、UV紫外线光波灭菌、臭氧氧化、多介质过滤等技术处理废水中的各类污染物; 2、利用pH计和进口计量泵控制投药量,并设有液位控制、水位报警等装置; 3、操作方便,运行稳定,使用寿命…

Jira 中如何修改时间为绝对时间

问题描述 在使用Jira的时候&#xff0c;有一些时间显示的是相对时间&#xff0c;如&#xff1a;2天前&#xff0c;3个小时前等&#xff0c;有些用户不习惯这样的显示方式&#xff0c;希望使用绝对的时间格式&#xff0c;如&#xff1a;2022年2月22日 22:22 应该怎样修改 解…

用python打印出菱形图案

你可以使用Python编写一个简单的函数来打印菱形图案。下面是一个例子&#xff0c;这个函数接受一个参数n&#xff0c;表示菱形的高度&#xff0c;然后打印出一个菱形图案&#xff1a; def print_diamond(n): # 上半部分 for i in range(n): print(" " …

python 多进程

python 多进程 多进程和多线程什么是进程什么是线程多进程和多线程的区别与联系优缺点多线程的优点多线程的缺点多进程的优点多进程的缺点 选择多线程还是多进程&#xff1f; 多进程使用multiprocessing.Process创建多进程通过multiprocessing.Process模块创建继承Process类来创…

springboot098基于web的网上摄影工作室的开发与实现

springboot098基于web的网上摄影工作室的开发与实现 源码获取&#xff1a; https://docs.qq.com/doc/DUXdsVlhIdVlsemdX

Java Applet 基础

标题&#xff1a;Java Applet 基础 介绍&#xff1a; Java Applet是Java语言提供的一种用于在网页中嵌入小型程序的技术。通过使用Java Applet&#xff0c;开发者可以在网页中添加交互性和动态性。本文将介绍Java Applet的基本概念和使用方法&#xff0c;并提供相应的示例代码…

微搭低代码实现登录注册功能

目录 1 创建用户数据源2 实现登录逻辑3 搭建登录页面4 设置登录框5 实现登录的逻辑6 用户注册总结 原来产品在创建应用的时候可以创建模型应用&#xff0c;模型应用对应我们小程序的后端。最新的更新已经将模型应用的能力下线&#xff0c;那我们不得不自己实现一下后端的逻辑。…