普冉(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.hqwc.cn/news/265110.html

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

相关文章

使用Git进行版本控制

参考&#xff1a;《Python编程从入门到实践》 前言1、安装、配置 Git1.1 在Linux系统中安装Git1.2 在OS X系统中安装Git1.3 在Windows系统中安装Git1.4 配置Git 2、创建项目3、忽略文件4、初始化仓库5、检查状态6、将文件加入到仓库中7、执行提交8、查看提交历史 前言 版本控制…

回顾【数学基础】找出断层,继续前进, 使用chatGPT学习并解决实际问题:微积分

已经学过的算术、代数、几何。跳过。 从微积分开始 想象一下&#xff0c;你在画一条曲线&#xff0c;或者在一个大草地上奔跑。微积分就是一种数学工具&#xff0c;帮助我们了解这条曲线的形状&#xff0c;或者你奔跑的方式。 微分&#xff08;就像研究曲线上的每一小点&…

基于SSM超市订单管理系统(Java毕业设计)

大家好&#xff0c;我是DeBug&#xff0c;很高兴你能来阅读&#xff01;作为一名热爱编程的程序员&#xff0c;我希望通过这些教学笔记与大家分享我的编程经验和知识。在这里&#xff0c;我将会结合实际项目经验&#xff0c;分享编程技巧、最佳实践以及解决问题的方法。无论你是…

16ASM 数据传送指令 算数运算指令

目录 指令种类 数据传送指令 通用传送指令 堆栈操作指令 标志寄存器进出堆栈指令 地址传送指令 算术运算指令 加法减法指令 乘法除法指令 指令种类 数据传送类指令 通用数据传送指令&#xff1a;MOV &#xff0c;XCHG&#xff0c;XLAT堆栈传送指令&#xff1a;PUSH&a…

嵌入式开发按怎样的路线学习较好?

嵌入式开发按怎样的路线学习较好&#xff1f; 在开始前我有一些资料&#xff0c;是我根据自己从业十年经验&#xff0c;熬夜搞了几个通宵&#xff0c;精心整理了一份「嵌入式从专业入门到高级教程工具包」&#xff0c;点个关注&#xff0c;全部无偿共享给大家&#xff01;&…

甄知燕千云与汉得智能制造深度集成,革新智能化提单服务

当今&#xff0c;以数字技术为代表的新一轮科技革命和产业变革加速推进&#xff0c;全球正迈向数字化新时代。在数字化转型浪潮下&#xff0c;企业必须主动顺应时代潮流&#xff0c;抓住机遇&#xff0c;迎接挑战。在数字技术和解决方案的驱动下&#xff0c;推动企业提升效率、…

超级实用的防止商品超卖的 7 种实现方式,非常好用!

高并发场景在现场的日常工作中很常见&#xff0c;特别是在互联网公司中&#xff0c;这篇文章就来通过秒杀商品来模拟高并发的场景。 本文环境&#xff1a; SpringBoot 2.5.7 MySQL 8.0 X MybatisPlus Swagger2.9.2 模拟工具&#xff1a; Jmeter 模拟场景&#xff1a; 减库…

【华为鸿蒙系统学习】- HarmonyOS4.0开发|自学篇

​ &#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 &#x1f4ab;个人格言:"没有罗马,那就自己创造罗马~" 目录 HarmonyOS 4.0 技术介绍&#xff1a; HarmonyOS三大特征&#xff1a; 1.实现硬件互助&#…

离散型随机变量的分布律(也称概率质量函数:probability mass function, PMF)

设是一个离散型随机变量&#xff0c;可能的取值为&#xff0c;取各个值的概率记为&#xff1a; &#xff08;1&#xff09; 其中 并且&#xff0c; 公式&#xff08;1&#xff09;就称为离散型随机变量的分布律&#xff0c;也称概率质量函数&#xff1a;probability ma…

【带头学C++】----- 九、类和对象 ---- 9.8 动态对象创建

目录 9.8 动态对象创建 9.8.1 动态创建对象基础概念 9.8.2 C语言创建动态对象的 9.8.3 new创建动态对象 9.8.4 delete释放动态对象 9.8.5 动态对象数组 9.8 动态对象创建 9.8.1 动态创建对象基础概念 在创建数组时&#xff0c;我们通常需要预先指定数组的长度&#xff0…

Unity中的ShaderToy

文章目录 前言一、ShaderToy网站二、ShaderToy基本框架1、我们可以在ShaderToy网站中&#xff0c;这样看用到的GLSL文档2、void mainImage 是我们的程序入口&#xff0c;类似于片断着色器3、fragColor作为输出变量&#xff0c;为屏幕每一像素的颜色&#xff0c;alpha一般赋值为…

最简单的pixel刷机和安装面具、lsposed

一 下载手机对应的系统 1&#xff0c;手机usb连接然后重启进入Fastboot模式&#xff1a;adb reboot bootloader2&#xff0c;找到你下载的系统&#xff0c;Windows 系统 直接运行 flash-all.bat上图 &#xff1a;左边就是安卓11和12的系统&#xff0c;右边是对应的手机型号 下…