沁恒微WCH32v003驱动ST7735S硬件spi+DMA调试小坑

        最近项目需要,要用wch32v003驱动ST7735S,用硬件spi+DMA方式可以提高屏幕刷新率,但是使用过程遇到一下问题,分享出来,有清楚的大佬可以指点指点。

        这篇文章并不是给着急移植程序使用的人看的,因为在赶进度的时候都是希望越快实现越好,不会细细琢磨,如果你有时间可以耐心看完,希望对你有所帮助。

        下面是spi+dma代码部分,屏幕部分的代码就先不放了,可以去我另外一篇文章里面移植。让你学会写ST7735s驱动LCD程序(SPI)-CSDN博客

        硬件SPI+DMA驱动0.96寸ST7735S(含代码)_st7735s 指令0x2a-CSDN博客

/********************************** (C) COPYRIGHT *******************************
 * File Name          : main.c
 * Author             : WCH
 * Version            : V1.0.0
 * Date               : 2022/08/08
 * Description        : Main program body.
 *********************************************************************************
 * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
 * Attention: This software (modified or not) and binary are used for
 * microcontroller manufactured by Nanjing Qinheng Microelectronics.
 *******************************************************************************/

/*
 *@Note
 *SPI DMA, master/slave mode transceiver routine:
 *Master:PI1_SCK(PC5)\PI1_MISO(PC7)\PI1_MOSI(PC6).
 *Slave:PI1_SCK(PC5)\PI1_MISO(PC7)\PI1_MOSI(PC6).
 *
 *This example demonstrates simultaneous full-duplex transmission and reception
 *between Master and Slave.
 *Note: The two boards download the Master and Slave programs respectively,
 *and power on at the same time.
 *     Hardware connection:
 *           PC5  -- PC5
 *           PC6 -- PC6
 *           PC7 -- PC7
 *
 */


#include "debug.h"
#include "string.h"
#include "lcd_init.h"
/* SPI Mode Definition */
#define HOST_MODE     0
#define SLAVE_MODE    1

/* SPI Communication Mode Selection */
#define SPI_MODE   HOST_MODE
//#define SPI_MODE      SLAVE_MODE

/* Global define */
#define Size          18

/* Global Variable */
u16 TxData[Size] = {0x1234, 0x5678, 0x9abc, 0xe123, 0x4567, 0x89ab,
                    0xcde0, 0x1234, 0x5678, 0x9abc, 0xe123, 0x4567,
                    0x89ab, 0xcde0, 0x1234, 0x5678, 0x9abc,0xe123};
u16 RxData[Size];



/*********************************************************************
 * @fn      SPI_FullDuplex_Init
 *
 * @brief   Configuring the SPI for full-duplex communication.
 *
 * @return  none
 */
void SPI_FullDuplex_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure = {0};
    SPI_InitTypeDef  SPI_InitStructure = {0};

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1, ENABLE);

#if(SPI_MODE == HOST_MODE)
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOC, &GPIO_InitStructure);

//    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
//    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
//    GPIO_Init(GPIOC, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOC, &GPIO_InitStructure);

#elif(SPI_MODE == SLAVE_MODE)
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOC, &GPIO_InitStructure);

//    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
//    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
//    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
//    GPIO_Init(GPIOC, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOC, &GPIO_InitStructure);

#endif

    SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;

#if(SPI_MODE == HOST_MODE)
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;

#elif(SPI_MODE == SLAVE_MODE)
    SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;

#endif

    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_InitStructure.SPI_CRCPolynomial = 0;
    SPI_Init(SPI1, &SPI_InitStructure);

    SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);
//    SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx, ENABLE);

    SPI_Cmd(SPI1, ENABLE);
}

/*********************************************************************
 * @fn      DMA_Tx_Init
 *
 * @brief   Initializes the DMAy Channelx configuration.
 *
 * @param   DMA_CHx - x can be 1 to 7.
 *          ppadr - Peripheral base address.
 *          memadr - Memory base address.
 *          bufsize - DMA channel buffer size.
 *
 * @return  none
 */
void DMA_Tx_Init(DMA_Channel_TypeDef *DMA_CHx, u32 ppadr, u32 memadr, u16 bufsize)
{
    DMA_InitTypeDef DMA_InitStructure = {0};

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    DMA_DeInit(DMA_CHx);

    DMA_InitStructure.DMA_PeripheralBaseAddr = ppadr;
    DMA_InitStructure.DMA_MemoryBaseAddr = memadr;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
    DMA_InitStructure.DMA_BufferSize = bufsize;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA_CHx, &DMA_InitStructure);
}

/*********************************************************************
 * @fn      DMA_Rx_Init
 *
 * @brief   Initializes the SPI1 DMA Channelx configuration.
 *
 * @param   DMA_CHx - x can be 1 to 7.
 *          ppadr - Peripheral base address.
 *          memadr - Memory base address.
 *          bufsize - DMA channel buffer size.
 *
 * @return  none
 */
void DMA_Rx_Init(DMA_Channel_TypeDef *DMA_CHx, u32 ppadr, u32 memadr, u16 bufsize)
{
    DMA_InitTypeDef DMA_InitStructure = {0};

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    DMA_DeInit(DMA_CHx);

    DMA_InitStructure.DMA_PeripheralBaseAddr = ppadr;
    DMA_InitStructure.DMA_MemoryBaseAddr = memadr;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize = bufsize;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA_CHx, &DMA_InitStructure);
}

/*********************************************************************
 * @fn      main
 *
 * @brief   Main program.
 *
 * @return  none
 */
int main(void)
{

    SystemCoreClockUpdate();
    Delay_Init();
    USART_Printf_Init(115200);
    printf("SystemClk:%d\r\n", SystemCoreClock);
    printf( "ChipID:%08x\r\n", DBGMCU_GetCHIPID() );

    SPI_FullDuplex_Init();

#if(SPI_MODE == SLAVE_MODE)
    printf("Slave Mode\r\n");
    Delay_Ms(1000);

#endif


#if(SPI_MODE == HOST_MODE)
    printf("Host Mode\r\n");
    Delay_Ms(100);
#endif
    LCD_GPIO_Init();

    LCD_RST_CLR;
    DMA_Tx_Init(DMA1_Channel3, (u32)&SPI1->DATAR, (u32)TxData, 15);
//    DMA_Rx_Init(DMA1_Channel2, (u32)&SPI1->DATAR, (u32)RxData, Size);
    DMA_Cmd(DMA1_Channel3, ENABLE);
//    DMA_Cmd(DMA1_Channel2, ENABLE);
    while(!DMA_GetFlagStatus(DMA1_FLAG_TC3));
    LCD_RST_SET;


    while(1)
    {



    }
}

        之所以没有放屏幕点亮部分是因为屏幕没有点亮,但是我用逻辑分析仪抓取spi的波形发现我数据传输都是正常的。

     

   

         但是一直驱动不了屏幕,我最近用了很多spi,说实话软件硬件spi都已经比较熟悉了,既然发送通信没有问题,我想问题可能出现在RST或者DC数据/指令这两个线上了。经过我的测试发现,问题出现在DC数据/指令这个线上,我代码里有一个测试的地方

       

        就是让一个引脚拉低,然后启用dma发送,然后等待发送完成,最后再将引脚拉高,最后看看波形。

       

        最下面的就是这个翻转的引脚,可以看到在数据并没有传输完成的时候,引脚已经被拉高了,所以在驱动屏幕的时候,会出现DC线操作和数据、指令发送不匹配的问题,当然无法驱动屏幕了。

        

        然后我又把目光放在了等待传输完成这个地方,会不会是这个用错了

while(!DMA_GetFlagStatus(DMA1_FLAG_TC3));

        点进去看发现这个函数就是读寄存器是否置1,我猜测是判断dma传输完成中断标志位,于是我查阅了一下寄存器使用手册。

       

        可以看到DMA_INTFR的TCIFx就是完成时候的标志位,由硬件置位,再看看具体的是第几位。

        DMA_INTFR的地址是0x40020000

         

        找到上面说的TCIF位,因为我代码里发送的使用dma的通道3,所以我们要找的是TCIF3,也就是第9位,换成十六进制就是0x00002000

        

       再看代码里的

        可以看到跟我的推断完全一样,这说明函数没有用错。

        

        但是在我总结的时候,再看一眼文字描述的时候发现了一个之前没有注意到的地方

        再看看这句话,当dma的传输字节数目减至0将会产生DMA传输完成标志

        看到这里我大概猜测是因为dma启动传输一个字节后就会减一,但是其实最后那里只是启动了传输,但是并没有真正意义上的传输完成,所以这里有一个时间差。我们可以验证一下这个猜想。(顺便提一嘴,我现在一直找问题的习惯都是提出猜想,想办法去验证它,如果不对那就继续重复,直到找到为止)

        我们先计算一下spi+dma的时钟频率,芯片的时钟频率是48M

        SPI我用的是64分频,所以就是48M/64=0.75M,也就是750kHz,一个脉冲周期就是1/75K=0.000001333s,也就是1.33us,按50%的占空比算,scl的一个高电平或者低电平持续时间大概是1.33/2=0.665us,差不多是600ns,用逻辑分析仪验证一下。(这里我提一嘴,要是有逻辑分析仪真的很有用,尤其是这种高速通信中的问题,很难找到问题所在,用传统示波器也不好分析,有条件大家可以整一个,牌子就不说了,tb上搜有挺多的,免得说我打广告)

        实际的是650ns左右,有误差很正常,周期1.3us,跟我算的一样。

        

        芯片时钟是48Mhz,一个时钟周期是1/48M=0.020833us,一个机器周期包含12个时钟周期,所以一个机器周期是12*0.020833=0.25us,简单指令运行是一个机器周期时间,大约250nm

        这里可以看出确实是在DMA开始传输后大约一个指令周期的时间引脚就被拉高了,可以验证上面的猜想应该是正确的。

        

        既然找到的问题,验证了猜想,下一步就是解决问题,我的想法是用延时函数,简单粗暴,如果大家有什么好的方法也可以提出,大家一起讨论进步。

        

        算了一下最后是剩下16位(这里还有点疑问就是为什么描述是1个字节为单位,而这里剩下2字节,这个问题还有待研究,有知道的也欢迎提出),一个周期大概是1.3us,16个就是20.8us,保险起见我们延时25us。如果库函数自带延时us函数可以直接调用,如果没有可以参考我下面的函数。(我的库里是有延迟us函数的,所以我直接调用)

        

/*
	简易的us级别的延迟函数
	我的芯片时钟是48Mhz
	一个时钟周期是1/48M=0.020833us,一个机器周期包含12个时钟周期,所以一个机器周期是12*0.020833=0.25us
	所以这里i++运行一次是0.25us,1us大概是运行4次
*/
void delay_us(uint16_t num)
{
	for(uint16_t j=0;j<num;j++)
	{
		for(uint16_t i=0;i<4;i++){}//根据不同的芯片周期修改i的数值
	}
}

        

        编译下载后再看波形,普天同庆,跟我的猜想一模一样,最后的引脚变化已经是完全在传输结束之后了,问题成功解决。

        

        

        最后总结一下,我写csdn的初衷只有两个,总结自己,帮助别人。在嵌入式领域我也是一个新手,刚接触没几年,一路上也是看其他csdn文章一步步学过来的,不能说有什么成就,但是还是有一些小小的心得,希望可以帮助到刚踏上这条路的你。

        首先我想说的是不要害怕底层!不要害怕底层!不要害怕底层!重要的事情说三遍!!

刚开始接触的时候特别讨厌底层、封装、寄存器那些,觉得特别难懂,所以一直喜欢逃避,就喜欢用别人的封装库,最好是一顿复制粘贴就可以使用的那种,但是后面我发现这样并不是学习,只是在搬运、缝合,我反问自己,这真的能学到什么呢?后面我想明白了,我要走出我自己的“舒适圈”,我下定决心要弄懂原理,慢慢接触底层知识。人最大的恐惧是源于无知,当你从未接触之前,你觉得什么都难,但是你沉下心来学习时,其实并没有想象中这么难,你只要告诉自己,别人能写,别人能看,为什么自己就不能呢?真正难的,是你踏出自己舒适圈的第一步。尝试去接触底层原理,去看寄存器手册,芯片手册。可以看看库函数封装的内容,本质其实还是操作寄存器。

        第二,不仅要踏出舒适圈,还要不断的踏出舒适圈。之前总有一种想法,就是我学这么多差不多了,够用了已经,但是后面我慢慢醒悟过来,时代在发展,技术在进步,没有人可以说自己学得已经够多了,千万不要安于现状!!!一定要不断学习,不断前进,不断提升自我,嵌入式这条道路上是没有所谓的尽头的,大家都在不断向前,如逆水行舟,不进则退。

        第三,不但要学,还要应用。应用才能体现出你的理解和存在的问题,可以查漏补缺,可以加深理解,所以多去找项目做,多去用。

        第四,学会总结,我觉得总结才是最重要的。以前的我对总结是嗤之以鼻,现在的我是逐字分析。总结也是学习的过程,像是上面提到了那句话也是我在总结的过程中发现的,不但可以加深自己的理解,整合自己的想法。学会总结,才算真正的学习。

        希望可以对大家有所帮助、有所启发。说的不对的地方也欢迎大家批评指正。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如果我要访问一个网址,那么在网络中会有哪些过程

访问一个网址是我们日常网络使用中非常常见的操作&#xff0c;背后涉及到一系列精密而复杂的步骤。这个过程包括DNS解析、建立TCP连接、发起HTTP请求、服务器处理请求、服务器响应、浏览器渲染等环节。在这篇文章中&#xff0c;我们将深入探讨这些步骤&#xff0c;并解释它们在…

力扣hot100 跳跃游戏 II 贪心 思维

Problem: 45. 跳跃游戏 II 思路 &#x1f468;‍&#x1f3eb; 参考 每次在上次能跳到的范围&#xff08;end&#xff09;内选择一个能跳的最远的位置&#xff08;也就是能跳到max_far位置的点&#xff09;作为下次的起跳点 &#xff01; Code ⏰ 时间复杂度: O ( n ) O(n…

猫什么时候发腮?性价比高的发腮主食冻干推荐

猫什么时候发腮&#xff1f;发腮是猫咪成长过程中一个重要的体征&#xff0c;也是猫父母们非常关心的问题。想要让猫咪拥有可爱的肉嘟嘟脸型&#xff0c;主人需要在适龄的年龄段加强营养补给&#xff0c;不要错失最佳发腮期。猫什么时候发腮呢&#xff1f;应该怎样喂养才能让猫…

TypeScript实战教程(一):表单上传与后端处理

TypeScript实战教程&#xff08;一&#xff09;&#xff1a;表单上传与后端处理 文章目录 TypeScript实战教程&#xff08;一&#xff09;&#xff1a;表单上传与后端处理一、前言1、TypeScript介绍2、TypeScript的关键特性包括&#xff1a;3、使用场景4、编译过程 二、环境配置…

张维迎《博弈与社会》多重均衡与制度和文化(1)多重均衡问题

什么是多重均衡 我曾经在课堂上做过这样一个实验&#xff1a;随机选择男女两位同学参加一个选数字的游戏。游戏的基本规则为&#xff1a;每一个同学随机地从1到10十个数字中任意选择5个。如果两人选择的数字没有任何重复的话&#xff0c;则每人可以得到50元&#xff1b;如果两人…

不同核函数高斯过程回归算法与不同因子输入情况下对长江流域蒸散发量应用研究_杨梓涵_2023

不同核函数高斯过程回归算法与不同因子输入情况下对长江流域蒸散发量应用研究_杨梓涵_2023 摘要关键词 0 引言1 材料与方法1.1 数据资料1.2 参考作物腾发量( ET0 ) 计算方法1.2.1 FAO&#xff0d;56 Penman&#xff0d;Monteith 模型1.2.2 Hargreaves&#xff0d;Samani 模型1.…

apisix多节点搭建

文章目录 前言一、介绍1. 端口介绍2. APISIX节点介绍3. apisix单机安装配置教程(选看) 二、准备1. 配置集群免密登录2. 搭建etcd集群 三、安装apisix节点1. 复制脚本2. 增加执行权限3. 分发脚本4. 执行脚本5. 配置apisix的etcd集群地址 四、安装apisix-dashboard1. 复制脚本2. …

【GEE】基于GEE批量下载Landsat8 L1C数据(整幅)

之前发过一篇使用GEE下载Landsat8的文章&#xff0c;然后有很多小伙伴私信我各种问题&#xff0c;如L1C、L2数据代码怎么修改&#xff0c;如何镶嵌&#xff0c;如何去云、 如何裁剪等一系列问题。正好快过年了&#xff0c;手头的事也没有多少了&#xff0c;所以这两天整理了一下…

蜂邮EDM邮件营销平台,低至0.0041元每封!

推荐的邮件营销平台有哪些&#xff1f;邮件营销平台如何使用&#xff1f; 你是否厌倦了传统的推广方式&#xff1f;是时候尝试一种全新的、高效的传播方式了&#xff01;蜂邮EDM邮件营销平台正在掀起一场数字化风潮&#xff0c;每封邮件仅需0.0041元&#xff0c;让你的推广成本…

5款超级好用的桌面端软件推荐

​ 今天我想分享一些自己比较喜欢的桌面端软件&#xff0c;还请大家包涵指正。如果你曾搜索过 Windows效率工具推荐&#xff0c;对下文的软件或许有所了解。不过为了凑字数&#xff0c;我还是会再介绍一遍。 1.电子书阅读——Starrea ​ Starrea是一款轻量、易用而又全功能的…

C#/.NET/.NET Core优秀项目和框架2024年1月简报

前言 公众号每月定期推广和分享的C#/.NET/.NET Core优秀项目和框架&#xff08;每周至少会推荐两个优秀的项目和框架当然节假日除外&#xff09;&#xff0c;公众号推文中有项目和框架的介绍、功能特点、使用方式以及部分功能截图等&#xff08;打不开或者打开GitHub很慢的同学…

[Python-闫式DP]

闫式DP分析法 闫老师是将DP问题归结为了有限集合中的最值问题。 动态规划有两个阶段&#xff0c;一是状态表示&#xff0c;二是状态计算。 状态表示 f(i,j) 状态表示是一个化零为整的过程&#xff0c;动态规划的做题思路不是暴力法的每一个物品都去枚举&#xff0c;而是将相…

异步解耦之RabbitMQ(二)__RabbitMQ架构及交换机

异步解耦之RabbitMQ(一) RabbitMQ架构 RabbitMQ是一个基于AMQP&#xff08;Advanced Message Queuing Protocol&#xff09;协议的消息代理中间件&#xff0c;它通过交换机和队列实现消息的路由和分发。以下是RabbitMQ的架构图&#xff1a; Producer&#xff08;生产者&#…

Java设计模式-组合模式(13)

大家好,我是馆长!今天开始我们讲的是结构型模式中的组合模式。老规矩,讲解之前再次熟悉下结构型模式包含:代理模式、适配器模式、桥接模式、装饰器模式、外观模式、享元模式、组合模式,共7种设计模式。 组合模式(Composite Pattern) 定义 组合(Composite)模式:又叫…

深度学习与神经网络Pytorch版 3.2 线性回归从零开始实现 1.生成数据集

3.2 线性回归从零开始实现 目录 3.2 线性回归从零开始实现 一 &#xff0c;简介 1. 原理 2. 步骤 3. 优缺点 4. 应用场景 二 &#xff0c;代码展现 1. 生成数据集(完整代码) 2. 各个函数解析 2.1 torch.normal()函数 2.2 torch.matmul()函数 2.3 d2l.plt.scatter(…

【教学类-44-54】20240201 德彪钢笔行书(实线字体)制作的数字描字帖

作品展示 背景需求&#xff1a; 找到了两款适合做数字描字贴的字体 【教学类-44-03】20240111阿拉伯数字字帖的字体&#xff08;三&#xff09;——德彪钢笔行书&#xff08;实线字体&#xff09;和print dashed&#xff08;虚线字体&#xff09;-CSDN博客文章浏览阅读1.1k次…

【HarmonyOS】鸿蒙开发之HTTP网络请求——第5章

HTTP网络请求封装 network/request.ets import { configInterface } from ./type import http from ohos.net.http import { getToken } from ../utils/storage//网络请求封装 export const request (config:configInterface)>{let httpRequest:http.HttpRequest http.c…

༺༽༾ཊ—Unity之-01-工厂方法模式—ཏ༿༼༻

首先创建一个项目&#xff0c; 在这个初始界面我们需要做一些准备工作&#xff0c; 建基础通用文件夹&#xff0c; 创建一个Plane 重置后 缩放100倍 加一个颜色&#xff0c; 任务&#xff1a;使用工厂方法模式 创建 飞船模型&#xff0c; 首先资源商店下载飞船模型&#xff0c…

二进制安全虚拟机Protostar靶场(5)堆的简单介绍以及实战 heap0

前言 这是一个系列文章&#xff0c;之前已经介绍过一些二进制安全的基础知识&#xff0c;这里就不过多重复提及&#xff0c;不熟悉的同学可以去看看我之前写的文章 什么是堆 堆是动态内存分配的区域&#xff0c;程序在运行时用来分配内存。它与栈不同&#xff0c;栈用于静态…

【Vue3+Vite】Vue3视图渲染技术 快速学习 第二期

文章目录 一、模版语法1.1 插值表达式和文本渲染1.1.1 插值表达式 语法1.1.2 文本渲染 语法 1.2 Attribute属性渲染1.3 事件的绑定 二、响应式基础2.1 响应式需求案例2.2 响应式实现关键字ref2.3 响应式实现关键字reactive2.4 扩展响应式关键字toRefs 和 toRef 三、条件和列表渲…