在IMX6ul中,使用GPT定时器实现高精度延时

news2024/10/21 22:44:12

        在上一节讲解过了。IMX6UL中的EPIT定时器,这一节我们讲解通用寄存器
        在STM32中,我们使用过SYSTICK来实现高精度的延时。IMX6U当中没有SYSTICK定时器,但是IMX6U有其他的定时器,前面的EPIT以及这一节我们将要使用的GPT定时器来实现高精度的延时
        官方对于GPT的描述是通用定时器(GPT)模块接口。它同样作为软件驱动程序编程的参考。GPT具有一个32位向上计数器。定时器计数值可以在外部引脚上的事件发生时被捕获到一个寄存器中。捕获触发可以被编程为上升沿或/和下降沿。GPT还可以在输出比较引脚上生成事件,并在定时器达到编程值时产生中断。GPT具有一个12位预分频器,该预分频器可以从多个时钟源提供可编程的时钟频率。

        GPT(General Purpose Timer)定时器是一个32位向上定时器(也就是从0X00000000),GPT定时器也可以和一个比较值进行比较,当计数器和这个值相等的话就发生比较事件,产生比较中断。GPT定时器有一个12位的分频器,可以对GPT定时器的shizhongyuan进行分频,它的特性如下
        ①、一个可以选择时钟源的32位向上计数器
        ②、两个输入捕获通道,可以设置触发模式
        ③、三个输出比较通道,可以设置输出模式
        ④、可以生成捕获中断、比较中断和溢出中断
        ⑤、计数器可以运行在重新启动(restart)或(自由运行)free-run模式

        我们就按照上面一个一个介绍它的特性,首先它有五个可选择的时钟源分别如下图

        分别是ipg_clk_24M、GPT_CLK(外部时钟)、ipg_clk、ipg_clk_32k和ipg_clk_highfreq。

        GPT定时器结构如下图所示

        从左上角开始,此部分位GPT为定时器的时钟源,之后我们会ipg_clk作为GPT定时器时钟源,继续往右边走,有一个12位的分频器,也就是和EPIT一样可以设置0~4095的分频,也是分别对应1~4096分频
        分频完成后,进入到Timer Counter也就是GPT定时器内部的32位计数器,通过预分频器输出的时钟信号驱动计数器递增或递减。计数器可以与外部输入同步,并能够触发中断或输出事件,然后就是两天总线,分别是Counter Value Bus(计数器值总线),Processor Data Bus(处理器数据总线)
        首先Counter Value Bus主要用于传递计数器的当前计数值。定时器的计数器在时钟脉冲下递增或者递减,计数器的值通过Counte Value Bus被实时传输到其他模块中。如比较器,用于将当前的计数值与设定的输出寄存器中的值进行比较,或者其他模块例如中断模块,以便在计数器达到某个特定值时产生中断信号或者其他事件,与计数器之间的关系是,Counter Value Bus 从计数器输出,代表计数器的状态,并通过该总线发送给框图中的其他逻辑单元(如比较器、捕获单元等)。通过这条总线,外部模块可以实时获取计数器的当前值,用于比较和逻辑判断。
        那么Processor Data Bus,向定时器发送控制命令或配置数据,例如配置定时器的初始计数值(通过Timer Input Register),设置比较寄存器中的值,用于与计数值的值相比较,读取定时器当前的计数值,以便处理器能够获知定时器的状态。与定时器的关系即是Processor Data Bus 与定时器中的输入输出寄存器交互,它可以影响定时器的工作状态,比如通过Timer Input Reg 写入初始值,或者通过设置比较值来控制定时器的行为。同时,定时器的状态(比如当前计数值)也可以通过这条总线传递回处理器。
        通俗来讲两条总线的区别就是,Timer Counter的当前计数值通过 Counter Value Bus 被实时传递到定时器内部的其他模块(例如比较器),Processor Data Bus负责处理器与定时器之间的数据通信,处理器通过这条总线配置定时器并读取定时器的计数值。计数器既向 Counter Value Bus 提供实时的计数值,也通过 Processor Data Bus 与处理器进行数据交互,处理器可以通过读写寄存器来影响计数器的工作。

        

        那么我们接着看回来,GPT_CAPTURE1和GPT_CAPTURE2,是GPT中的两个输入捕获通道,这个模块用来捕获外部输入信号的时间戳。每当捕获信号触发时,计数器对的当前值会存入对应的捕获寄存器(Timer Input Reg1 以及2),用于测量脉冲或外部事件的时间。例如两个信号之间的间隔时间。通俗来讲就是捕获通道用于获捕外部信号的特定事件(如下降沿或者下降沿),并记录下此时定时器的计数值。输入捕获一般还常用于测量PWM波形的频率、占空比、脉冲间隔等参数或者速度测量、位置检测等场合

        

        此部分为输出比较寄存器,一共有三路输出比较,因此有三个输出比较寄存器,输出比较寄存器是32位的。这些寄存器存储比较值。定时器的计数值会在这些寄存器中的值中进行比较。当计数值达到比较寄存器当中的值的时候,会触发输出事件或者中断。一般应用场景有生产一定频率和占空比的PWM波形,以及点击控制、LED调光、音频信号生成等
        实际的比较就在cmp中进行,OF1/OF2/OF3表示比较操作的输出标志,当计数器与某个输出寄存器匹配时,会触发相应的输出标志信号
        OM1,OM2,OM3这些是定时器输出比较事件的标志,当计数器与比较寄存器值相等时,触发相应的输出模块,输出信号(GPT_COMPARE1,GPT_COMPARE2,GPT_COMPARE3)。这可以用于产生定时信号或控制外设设备。
        Processor Interrupt Bus (处理器中断总线):定时器的溢出、比较匹配或者输入捕获事件都会通过中断总线通知处理器,触发相应的中断服务程序。这部分与外部事件和处理器之间的交互相关。

        那么GPT定时器的结构框图这里我们就讲解完成了,接着下一步就介绍GPT定时器有两种工作模式

        重新启动模式(restart): 当GPTx_CR(x=1 ,2)的FRR位清零的时候GPT工作在此模式。此模式下,当计数值和比较寄存器中的值相等的话计数值就会清零,然后从0X00000000开始向上重新计数,切记只有比较通道1才有此模式,向比较寄存器写入任何数据都会直接复位GPT计数器。对于其他两路比较通道(通道2和3),当发生比较事件以后不会复位计数器

        自然运行(free-run)模式:当GPTx_CR(x=1、2)寄存器的FRR位,置1的时候GPT定时器工作在此模式下,此模式适用于三个所有的比较通道,当比较事件发生以后并不会复位计数器,而是继续计数,直到计数值来到0XFFFFFFFF,然后再重新回到0X00000000

        下面就开始看一下对于GPT定时器比较重要的定时器,首先最开始的都是一个外设的配置寄存器GPTx_CR,需要用到的重比较重要的位如下

        首先是SWR(bit15)位,复位GPT定时器,向此位写1就可以复位GPT定时器,当GPT复位完成以后此为会自动清零
        这里翻译结果就是,软件复位: 这是GPT模块的软件复位。它是一个自清除位。
        当模块处于复位状态时,SWR位被置位。
        当复位过程完成时,SWR位被清除。
        设置SWR位会将所有寄存器复位为默认复位值,除了GPT控制寄存器中的EN、ENMOD、STOPEN、WAITEN和DBGEN位(此控制寄存器)。 0:GPT不处于复位状态 1:GPT处于复位状态


        FRR(bit9),运行模式的选择,在前面我们也介绍了GPT定时器有两个工作模式,位为零时比较通道1工作在重新启动模式(restart)模式。当此位为1的时候所有的三个比较通道均工作在自由运行模式(free-run)


        CLKSRC(bit8:6):GPT定时器时钟源选择位,为0的时候关闭时钟源;为1的时候选择ipg_clk作为时钟源:为2的时候选择ipg_clk_highfreq为时钟源;为3的时候选择外部时钟为时钟源;为4的时候选择ipg_clk_32k为时钟源;为5的时候选择ip_clk_24M为时钟源。这里的话我们选择ipg_clk作为GPT定时器的时钟源,因此此为设置为1,在之后的时候


        ENMOD(bit1):GPT使能模式,此位为零的时候如果关闭GPT定时器,计数器寄存器保存定时器关闭时候的计数值。此位为1的时候如果关闭GPT定时器,计数器寄存器就会清零

        EN(bit0):GPT使能位,为1的时候使能GPT定时器,为零的时候关闭GPT定时器

        下一个是GPT定时器的分频寄存器GPTx_PR,寄存器的结构图如下

        寄存器GPTx_PR我们用到的重要位就只有一个:PRESCALED(bit11:0),这就是12位分频值,可以设置0~4095,还是分别1~4096分频

        还有GPT定时器的状态寄存器GPTx_SR,此寄存器结构也是如图

        他的31:6位都是保留位,从第五位ROV(bit5),也就是回滚标志位,当计数值从0XFFFFFFFF回滚到0X00000000的时候此位置位1,一共有两路输入捕获通道,如果使用输入捕获中断的话需要在中断处理函数中清除此位
        IF2~IF1(bit4:3):输入比较中断标志位,当输出比较事件发生以后此位置1,一共有两路输入捕获通道。如果使用输入捕获中断的话需要在中断处理函数中清除此位


         OF3~OF1(bit2:0):输出比较中断标志位,当输出比较事件发生以后此位置1,一共有三路输出比较通道。如果使用输出比较中断的话需要在中断处理函数中清除此位。

        下一个是GPT定时器的计数寄存器GPTx_CNT,这个寄存器保存着GPT定时器的当前计数值。

        以及另外一个GPT定时器的输出比较寄存器GPTx_OCR,每个输出比较通道对应一个输出比较寄存器,因此一个GPT定时器有三个OCR寄存器,它们的作用都是相同的。例如输出比较通道1为例,它的输出比较寄存器为GPTx_OCR1,这是一个32位寄存器,用于存放32位的比较值。当计数值和寄存器GPTx_OCR1中的值相等就会产生比较事件,如果使能了比较中断的话就会触发相应的中断

        那么如何通过定时器去实现高精度的延时,它背后的原理是什么是我们需要去分析一下的
如果设置GPT定时器的时钟源为ipg_clk = 66Mhz,设置66分频那么进入GPT的最终频率就是66MHz / 66 = 1Mhz,周期为1us,也就是每进行一次计数就表示经过了1us,也就是计数十次就经过了10us。通过读取寄存器GPTx_CNT中的值就知道计时个数
        例如现在要延时100us,那么进入延时函数以后记录下寄存器GPTx_CNT中的值为200,当GPTx_CNT中的值为300的时候就表示100us过去了,也就是延时解释。GPTx_CNT是个32位寄存器,如果时钟为1MHz的话,GPTx_CNT最多可以实现0XFFFFFFFFus = 4294967295us约等于4294s约等于72min。也就是72分钟以后GPTx_CNT寄存器就会回滚到0X00000000,也就是溢出,所以需要在延时函数中处理溢出的情况,大概的原理就是如上   

        上面对原理进行了讲解,现在开始分析具体实现的措施
        
        1.设置GPT1定时器
         首先设置GPT1_CR寄存器的SWR(bit15)位来复位寄存器GPT1.复位完成以后设置寄存器GPT1_CR寄存器的CLKSRC(bit8:6),选择GPT1的时钟源为ipg_clk,设定定时器的工作模式

        2. 设置GPT1的分频值
         设置寄存器GPT1_PR寄存器的PRESCALAR(bit11:0)位,设置分频值

        3.设置GPT1的比较值
        如果要使用GPT1的输出比较中断,那么GPT1的输出比较寄存器GPT1_OCR1的值可以根据所需要的中断时间来设置。在教程中不使用比较输出中断,所以将GPT1_OCR1设置位最大值0XFFFFFFFF

        4. 使能GPT1定时器
        设置好GPT1定时器1以后就可以使能了,设置GPT1_CR的EN(bit0)位为1来使能GPT1定时器

        5. 编写延时函数
        GPT1定时器在使能后就开始运行了,可以根据前面介绍的原理来编写延时函数,针对us和ms延时分别编写两个延时函数

        思路大致如下,然后下面我会展示之前的延时函数,然后我们直接将原来的delay函数删除掉

#include "bsp_delay.h" //原delay.c延时函数

/*
 * @description	: 短时间延时函数
 * @param - n	: 要延时循环次数(空操作循环次数,模式延时)
 * @return 		: 无
 */
void delay_short(volatile unsigned int n)
{
	while(n--){}
}

/*
 * @description	: 延时函数,在396Mhz的主频下
 * 			  	  延时时间大约为1ms
 * @param - n	: 要延时的ms数
 * @return 		: 无
 */
void delay(volatile unsigned int n)
{
	while(n--)
	{
		delay_short(0x7ff);
	}
}

#ifndef __BSP_DELAY_H //原delay.h
#define __BSP_DELAY_H

#include "imx6ul.h"


/* 函数声明 */
void delay(volatile unsigned int n);

#endif

        先开始编写bsp_delay.c文件,第一步首先就是要初始化GPT,那么编写初始化函数

/*对GPT定时器进行初始化,并且选择时钟源*/
void delay_init()
{
	GPT1->CR = 0;					/*CR寄存器清零 */
	GPT1->CR = 1<<15;				/*定时器软复位*/
	while((GPT1->CR >> 15) & 0x01);	/*等待复位完成*/

	/*
	*GPT通用设置,bit22:bit20,输出比较1的输出功能关闭
	*bit9:  设置定时器模式为Restart模式,当CNT等于OCR1时产生中断
	*bit8:6 选择定时器时钟源ipg_clk = 66Mhz
	*/
	GPT1->CR = (1<<6);

	/*
	*GPTx_P寄存器,设置定时器分频
	*bit11:0 设置为零表示为1分频,如果要设置为最大即0XFFFF,4096分频
	*/
	GPT1->PR = 65; /*这里设置66分频*/

	/*
	*GPTx_OCR寄存器
	*GPT时钟为1Mz,计数器每次加1,就过去了1us
	*将比较值设置为最大0XFFFFFFFF
	*计时器会存在溢出的情况,0XFFFFFFFF=4294967296us=4295s=71.5min
	*/
	GPT1->CR[0] = 0XFFFFFFFF;
	GPT1->CR |= 1<<0;

}

        首先设置GPTx_CR寄存器,这也是配置寄存器首先将此定时器进行软复位,在上面也对15位的软复位进行了一段解释,设置SWR位(15位)会将所有寄存器复位为默认复位值,除了GPT控制寄存器中的EN、ENMOD、STOPEN、WAITEN和DBGEN位

        然后第二段是一个等待循坏,直到复为完成,通过右移GPT控制寄存器(CR)15位,读取SWR位的值,然后与0X01进行按位与运算,只要SWR位仍为1(即模块处于复位状态),循环将持续执行。当复位完成,SWR位被自动清除为0,循环结束,程序继续执行。
        那么为什么这里需要专门去判断复位是否完成呢,例如硬件模块可能不仅仅是简单的寄存器清零,还包括整个模块的初始化,时钟同步等,都需要一定的时间完成,这么判断可以确保所有内部逻辑都完成复位。

        分频直接控制对应的GPTx_PR寄存器然后设置65,也就是对应的66分频,这个没有上什么好讲的,在下方我们将比较值设置到最大,因为如上图OCR寄存器为32位寄存器,所以最多对应0XFFFFFFFF,最后将GPT定时器进行使能,基本的初始化配置就已经完成了   


/*us级延时,最多延时0XFFFFFFFFus*/
void delay_us(unsigned int usdealy)
{
	unsigned long oldcnt,newcnt;
	unsigned long tcntvalue = 0;	/*定义一个变量,存放经过总时间*/

	oldcnt = GPT1->CNT;
	while(1)
	{
		newcnt = GPT1->CNT;
		if(newcnt > oldcnt)	/*计时器向上计数,并且没有溢出*/
		{
			tcntvalue +=  newcnt - oldcnt;
		}
		else
		{
			tcntvalue += 0XFFFFFFFF-oldcnt+newcnt;
		}
		oldcnt = newcnt;
		if(tcntvalue >= usdealy)
		{
			break;
		}	
	}
}

        接下来就是编写延时函数,这段代码的主要作用就是实现微妙延时级别的一个函数,使用通过不断比较定时器的当前值和之前记录的值来判断经过的时间,并且在满足延时需求后退出循环
        先定义了两个变量,oldcnt用来记录计数器之前的值,newcnt用来记录计数器当前的值,以及tcnvalue用于累加计数器经过的时间(总时间),初始值为0

        然后在循环之前我们将GPT定时器的值传入到oldcnt中,作为延时过程的初始参考点,下一步编写一个无限循环不断读取当前计数器的值(newcnt),newcnt用来获取最新的计数器状态,然后需要判断定时器是否发生溢出,如果newcnt大于oldcnt,说明计数器正常递增且没有溢出。这时两者的差值就是经过的时间,累计添加到tcnvalue这个值当中
        如果newcnt小于oldcnt说明计数器已经发生了溢出,已经从最大值返回到0,继续计数。这个时候经过的时间就是(0xFFFFFFFF-oldcnt+newcnt),即从oldcnt到最大值0XFFFFFFFF的时间,再加上从0到newcnt的时间。同样累加到tcnvalue
        oldcnt = newcnt目的是更新旧计数器值,将当前newcnt值赋给oldcnt,以便下一次循环时,能够继续计算新的时间差
        最后见擦汗是否达到目标延时。如果累计的时间tcntvalue >= usdelay,达到了目标延时usdelay突出循环,延时结束

        这个函数还需要多讲解一下,为什么这么写,和定时器的的频率有什么关系,这些都是需要思考的问题,因为我们定时器得频率被设置为了1us,每次计数器得值增加1代表经过了1us。假设usdelay为15微妙,在while循环中,初始oldcnt为某个值,比如0经过一定时间后,假设newcnt变为15,在这种情况下,newcnt - oldcnt得差值为15-0=15,这说明在这次循环中已经经过了15微妙,也就是完成15次周期,直接将15加入tcntvalue,此时tcntvalue变为15,检查tcntvalue >=usdelay,条件成立就退出循环
        定时器频率如果为2us的话,我们这里依然假设usdelay为15微妙,在while循环中,初始oldcnt为某个值,比如0经过一定时间后,假设newcnt变为7,在这种情况下,newcnt - oldcnt的差值为7 -0 =7。由于每个计数代表2us,所以实际经过的时间为7*2 =14us,再次进入循环的话,假设定时器继续递增,newcnt更新为8。此时newcnt - oldcnt = 8 - 7 =1,这代表再增加2微秒。将2加入tcnvalue,此时tcnvalue变为16,价差tcnvalue >= usdelay,条件成立,所以从这里可以看出在频率为2us的情况下,计数器的增量只能表示2us,因此实际情况中无法实现任意的微妙级别延时,只能实现2us的倍数延时(如2、4、6)

        那么再举一个具体的例子就是,假设定时器频率分别为1us和2us,先说1us,通过每次计数得到的值可以精确表示 1us 的延迟。经过 15 次循环,每次增量 1us,总计 15us,符合目标延时。
        而对于2us,每次计数值增量为 1,实际表示 2us 的时间。目标 15us 不能被 2 整除,因此需要在 8 次计数时累加 16us(8*2us),这使得实际延迟为 16us,而不是 15us

        因此,定时器的频率直接影响到代码循环中每次读取 GPT1->CNT 的值变化与实际延迟时间之间的关系。定时器频率越高,能够实现的延迟时间越精确;而频率较低时,可能会限制可实现的延迟时间为某些特定值的倍数。在设计系统时,选择合适的定时器频率是确保系统能够执行精确延迟的重要因素。

        

#include "bsp_clk.h"

#include "bsp_delay.h"

#include "bsp_led.h"

#include "bsp_beep.h"

#include "bsp_key.h"

#include "bsp_int.h"

#include "bsp_exit.h"

#include "bsp_epittimer.h"

#include "bsp_keyfilter.h"



int main(void)

{

	unsigned char state =OFF;



	int_init();

	imx6u_clkinit();

	clk_enable();

	led_init();

	beep_init();

	filterkey_init();



	while(1)			

	{	

		state = !state;

		led_switch(LED0,state);

		delay(500);

	}

	return 0;

}

        main.c文件如上,然后Makefile文件就除了修改一下最后生成的.bin文件名字就可以了,然后最后将文件烧写进去,此次文件就完成了

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

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

相关文章

算法备案必须做吗?不做有什么风险?

算法备案是一种强制性备案制度&#xff0c;旨在保障算法技术的合法性和合规性。 《互联网信息服务算法推荐管理规定》第二十四条明确规定应当在10个工作日内备案&#xff0c;发生变更的在10个工作日内完成变更&#xff0c;注销的在20个工作日内完成注销。 ​未履行备案的&…

共筑华芯|首届“SEMiBAY湾芯展”龙华区科技创新局助力华芯邦科技携第四代半导体芯星亮相湾区半导体产业生态博览会,诚邀您莅临参观指导

在深圳市政府指导和深圳市发展改革委支持下&#xff0c;深圳市半导体与集成电路产业联盟携手深圳市重大产业投资集团有限公司共同主办的首届“SEMiBAY湾芯展”——湾区半导体产业生态博览会&#xff0c;将于今年10月16日至18日盛大举行。 本次展会以“芯动未来&#xff0c;共创…

MYSQL8.0.24数据库登录时 报错 ERROR 1045 (28000) / MYSQL8.0.24数据库多次修改密码无效

文章目录 前提:失败方案一:修改密码失败方案二:失败方案三:最终解决方案:前提: 在没有使用电脑上的mysql一段时间之后,忘记了mysql的root账号密码。然后登录怎么登录都登录不上,在重置了密码之后。发现一直报这个错误 ERROR 1045 (28000) : Access denied for user ‘…

ChatTTS在Windows电脑的本地部署与远程生成音频详细实战指南

文章目录 前言1. 下载运行ChatTTS模型2. 安装Cpolar工具3. 实现公网访问4. 配置ChatTTS固定公网地址 前言 本篇文章主要介绍如何快速地在Windows系统电脑中本地部署ChatTTS开源文本转语音项目&#xff0c;并且我们还可以结合Cpolar内网穿透工具创建公网地址&#xff0c;随时随…

深入计算机语言之C++:类与对象(上)

&#x1f511;&#x1f511;博客主页&#xff1a;阿客不是客 &#x1f353;&#x1f353;系列专栏&#xff1a;从C语言到C语言的渐深学习 欢迎来到泊舟小课堂 &#x1f618;博客制作不易欢迎各位&#x1f44d;点赞⭐收藏➕关注 前面我们学习了关于c语言的一些基础知识&#xff…

Go语言gRPC快速入门

文章目录 前言gRPC是什么Go语言的gRPC技术栈准备工作接口定义代码生成服务端代码编写客户端代码编写效果演示完整代码链接最后 前言 你好&#xff0c;我是醉墨居士&#xff0c;这篇博客想帮助初学者能够快速入门gRPC&#xff0c;希望能够为你节省宝贵的时间&#xff0c;让时间…

无线网络基础

文章目录 无线组网胖AP瘦AP胖瘦AP的区别组网方式连接方式CAPWAP概念 无线组网 WLAN&#xff1a;无线局域网 蜂窝网络&#xff1a;无线广域网 802.11&#xff0c;无线网络封装的报文头部 WLAN是一种基于IEEE 802.11标准的无线局域网技术 802.11标准聚焦在TCP/IP对等模型的下两层…

算力提升10倍,特斯拉Cybercab预示了半导体行业哪些方向?

北京时间10月11日上午&#xff0c;备受世界瞩目的“We&#xff0c;Robot”发布会成功举行。现场&#xff0c;特斯拉正式发布了被命名为Cybercab的特斯拉Robotaxi&#xff08;无人驾驶出租车&#xff09;&#xff0c;以及Robovan&#xff08;无人驾驶厢式货车&#xff09;。 这次…

Harmony OS原生端渲染RTMP流功能实现

前段时间公司收到鸿蒙的邀请&#xff0c;希望我们加入鸿蒙的生态应用。领导要求我们将原先安卓SDK实现的功能在鸿蒙生态上1&#xff1a;1还原。相信这也是当前很多公司在做的事情。 我们项目原先有获取硬件实时视频流展示的需求&#xff0c;这块功能也耗费了两周的时间才打通测…

springboot 整合 快手 移动应用 授权 发布视频 小黄车

前言&#xff1a; 因快手文档混乱&#xff0c;官方社区技术交流仍有很多未解之谜&#xff0c;下面3种文档的定义先区分。 代码中的JSON相关工具均用hutool工具包 1.快手 移动双端 原生SDK 文档https://mp.kuaishou.com/platformDocs/develop/mobile-app/ios.html 2.快手 Api 开…

每日OJ题_牛客_chika和蜜柑_TopK_C++_Java

目录 牛客_chika和蜜柑_TopK 题目解析 C代码 Java代码 牛客_chika和蜜柑_TopK chika和蜜柑 (nowcoder.com) 描述&#xff1a; chika很喜欢吃蜜柑。每个蜜柑有一定的酸度和甜度&#xff0c;chika喜欢吃甜的&#xff0c;但不喜欢吃酸的。 一共有n个蜜柑&am…

万物皆可浮雕,comfyui一键图片转浮雕

一键生成图片浮雕效果&#xff1a;ComfyUI工作流指南 在图像处理和艺术创作领域&#xff0c;生成浮雕效果的图片是一种既独特又吸引人的表现手法。使用ComfyUI工作流&#xff0c;可以一键生成灰度图、深度图和浮雕图&#xff0c;大大简化了复杂的图像处理过程。本文将详细介绍…

嵌入式C语言之结构体封装函数

嵌入式C语言之结构体封装函数 Chapter1 嵌入式C语言之结构体封装函数结构体封装函数的作用结构体封装函数的应用结构体封装函数的好处举例1举例2举例3 Chapter1 嵌入式C语言之结构体封装函数 原文链接&#xff1a;https://blog.csdn.net/qq_43416206/article/details/13140531…

spring:Springboot3使用模版引擎thymeleaf

文章目录 介绍语法1、文本替换2、属性替换3、条件判断4. 列表循环5. 表单处理 基本示例视图解析机制视图解析器的默认配置为什么用Controller可以&#xff0c;用RestController就只是返回字符串 介绍 Thymeleaf 是一个现代的服务器端 Java 模板引擎&#xff0c;用于在服务器端…

掌握这几款在线音频剪辑工具,轻松成为音频处理达人!

在数字时代&#xff0c;音频剪辑已经成为一项必备技能。无论是制作短视频、播客&#xff0c;还是进行音乐创作&#xff0c;一款好用的音频剪辑工具都能助你事半功倍。今天&#xff0c;我们就来为大家推荐几款实用的在线音频剪辑工具&#xff0c;让你轻松成为音频处理达人&#…

救命!后悔没早点读,自学Python,这本书永远的神,经典又好懂!

这是一本对新手来说很友好的入门书&#xff0c;这本是今年才出的新版&#xff0c;之前的两个版本在某瓣都是9分以上了。专为初学者设计&#xff0c;同时也适合有编程经验的读者。该书由Eric Matthes编写&#xff0c;内容涵盖Python基础语法、编程概念以及丰富的实践项目。 全书…

【工具变量】文明城市评选DID(2000-2023年)

数据简介&#xff1a; 随着城市化的不断推进和全球城际竞争的日益激烈&#xff0c;城市品牌成为争夺优质资源、推动城市可持续发展的重要战略工具。通过关注城市品牌建设&#xff0c;不仅可以刺激本地企业家更多地进行创新活动&#xff0c;为企业家创新活动提供更好的营商环境…

自回溯天线:实现波束自动跟踪的智能天线系统

自回溯天线:实现波束自动跟踪的智能天线系统 1. 引言 自回溯天线是一种能够自动将接收到的信号发射回信号源方向的智能天线系统。它基于相位共轭原理,无需复杂的信号处理和控制系统,就能实现波束的自动跟踪。 自回溯天线技术依靠纯模拟方式实现&#xff0c;通过共轭模块对入射…

vue3中如何更改当前类的文件名称

首先&#xff0c;使用script指定文件名称 <template><div class"person"><h2>姓名&#xff1a;{{ name }}</h2><h2>年龄&#xff1a;{{ age }}</h2><button click"showTel">查看联系方式</button><bu…

【含文档】基于Springboot+Vue的招投标管理系统(含源码+数据库+lw)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 系统定…