普冉(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架构中,我们测试最常接触的,就是接口。本课程的重点是接口自动化测试,那同学们真的了解什么是接口吗?首先,我们从通俗的角度来看什么是接口。在计算机中,接口是计算机系统中两个独立的部件进行信息交换的共享边界。这种交换可以发…

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

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

HarmonyOS—实现UserDataAbility

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

简单使用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 回顾 管道符 | 把前一个指令的输出作…

用python打印出菱形图案

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

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

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

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

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

计网Lesson10 - 网络层之IP协议分析

文章目录 网络层协议IPv4 数据报格式IPv4 数据报首部格式版本&#xff08;Version&#xff09;首部长度&#xff08;Header Length&#xff09;区分服务&#xff08;Differentiated Services Field&#xff09;可选字段填充总长度&#xff08;Total Length&#xff09;标识、标…

记录 | vscode无法在这个大型工作区中监视文件更改,请按照说明链接解决问题

在 VSCode 上打开一个项目时&#xff0c;突然弹出以下错误&#xff1a; 无法在这个大型工作区中监视文件更改。请按照说明链接解决问题。 原因&#xff1a; 由于工作区太大包含太多文件导致vs code监视文件达到上限而因此这个错误。在 Linux 上执行以下命令&#xff1a; cat …

spingboot项目实战之若依框架创建新模块

前言 目前的脚手架系统很多&#xff0c;比较早接触诺依框架&#xff0c;以若依框架为参考如何创建新模块 步骤 1. 下载诺依框架&#xff0c;依照参考说明一步步&#xff0c;能做到系统运行起来。 2. 准备好mysql文件&#xff0c;创建新数据库表 3. 数据库管理工具navicat…

操作系统原理-作业三-存储器

某页式虚拟存储管理系统中&#xff0c;页面大小为 2KB &#xff0c;某一进程分配到的内存块数为 3 &#xff0c;并按下列地址顺序引用内存单元&#xff1a; 2531 、 6632 、 4140 、 3584 、 2892 、 5743 、 1700 、 2148 、 6940、 4345 、 3209 、 0732 、 6202 、 4541 。…

[MySQL] MySQL中的索引

文章目录 一、初识索引 1、1 索引的概念 1、2 索引案例 二、认识磁盘 2、1 磁盘结构 2、2 操作系统与磁盘的数据交互 2、3 磁盘随机访问与连续访问 2、4 MySQL与磁盘的数据交互 三、索引的理解 3、1 建立测试表 3、2 为何MySQL与磁盘IO交互是 Page 3、3 理解Page 3、3、1 页目录…

在线教育培训系统搭建,打造方便快捷的学习模式

教育在我国是一件重中之重的事业发展&#xff0c;所谓“活到老学到老”&#xff0c;人们都离不开教育。 而在当下互联网的发展下&#xff0c;教育、职业培训的方式也变得越来越多样&#xff0c;在线教育模式成为了不少高校的选择&#xff0c;也成为了不少学生的选择。 在线教…

Flutter 上了 Apple 第三方重大列表,2024 春季 iOS 的隐私清单究竟是什么?

这个话题的起因来自 2023 年 WWDC 之后苹果发布的「App Store 提交隐私更新」政策&#xff0c;政策主要提出了两点&#xff1a;第三方 SDK 隐私清单和签名和需要提供必要理由的 API 流程。 其实先简单总结&#xff0c;就是 Apple 想通过隐私清单来进一步提升用户数据收集和使用…