把定时操作当作带循环的函数

本文深入探讨了如何将定时操作视为带循环的函数,通过实例解释了这一概念,帮助开发者更清晰地理解定时操作的工作原理及其实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在之前有很长一段时间里,虽然知道定时函数是干什么的,有些什么作用,但是在理解上总感觉有点不自然,不那么顺畅。在思考了一段时间后,终于发现,可以把定时操作当作带循环的函数来理解,这样在使用定时操作的时候,想法就比较自然了。

函数几乎是所有编程语言都会提供的一种抽象,它把一段代码当作一个整体,给它一个名字,这样,也就赋予了这段代码语义。比如printf();在讨论问题的求解、方案的设计时,我们可以直接用“打印某某字符串”来描述,而不需要说“获得某个字符串,然后调用系统的IO...”。这样思路会更加清晰,才不会使设计人员迷失在如何实现的细节当中。总的来说,一个函数的名称说明了它能做什么,而函数的代码体则说明了怎么做

带循环的函数样式如下:


void function(Parameter par)
{
	int flag = 1 ;
	while(flag)
	{
		//Some statements to do the real work
		if(SomeCondition())
			flag = 0 ;
	}
}


首先,函数需要接收一些参数Parameters,这些参数将告诉函数需要对哪些数据进行处理。接着,将flag设置为1,这样循环体就开始了一遍一遍的循环,在检测到某个条件(SomeCondition)满足时,将flag0,在flag0时会结束循环。

接着,我们看一下定时操作。所谓定时操作就是在相隔一定的时间段后重复执行一段代码(SomeWork),而往往定时都会在达到某些条件时停止这段代码的执行。比如很多的动画效果就是定时操作。

所以,定时操作可以理解为一个循环操作,只不过相对于我们所熟悉的while循环来说,定时操作是每隔一定时间循环一次,而while循环则是一次马上接连一次

定时器函数可以设计如下:

int flag[] ;
Parameter par[] ;
void OnTimer()
{
	for(int i=0; i<len(flag); i++
	{
		if(flag[i]==1)
		{
			SomeFunction(par[i]) ;
			if(SomeCondition)
			{
				flag[i] = 0 ;
			}
		}
	}
}


开启一个定时操作可以理解为调用一个带循环的函数。函数的调用可以分两步:先准备好参数,接着调用函数。对于定时操作来说,准备好参数就是填充某个par[i](见代码);而调用函数则可以看作是将flag[i]的值设为1

举一个实际的例子。在网页中经常会有一些动画,比如,菜单的缓缓下落,在全部显示菜单后就停止下落。这里,菜单的下落就可以看作是执行一个循环函数,比如菜单的高度从0一直变到50,等间隔1采样,就可以得到0~50的连续整数。每一次循环显示其中一个高度,当高度达到50之后就结束了循环。所不同的是,在一定的时间间隔后才执行一次循环。

重要的是将定时操作看作是一个循环函数这种思考方式。

<think>嗯,用户想要修改HAL库中的HAL_Delay函数,以实现秒级的延时。首先,我需要理解HAL_Delay原本的工作原理。根据引用[3],HAL_Delay是基于HAL_GetTick()函数,它获取的是系统滴答计数器的当前值。默认情况下,系统滴答定时器(SysTick)的中断频率通常是1kHz,也就是每1毫秒增加一次计数器。所以,HAL_Delay的参数是以毫秒为单位的,比如HAL_Delay(1000)就是延时1秒。 用户想要让HAL_Delay的参数代表秒而不是毫秒,这就需要调整SysTick的配置,让计数器每秒钟增加一次,而不是每毫秒。这时候需要参考引用[2]中的内容,那里提到可以通过修改滴答时钟的配置来改变HAL_Delay的基准时间。例如,将SysTick的定时周期设置为1秒,这样每次中断时计数器加1,HAL_Delay的参数就变成了秒。 接下来,我需要确定如何修改SysTick的配置。通常,SysTick的时钟源是系统时钟(比如72MHz),通过分频来产生所需的中断频率。原来的配置是1ms中断一次,所以分频系数可能是系统时钟除以1000。如果要改成1秒中断一次,分频系数需要调整为系统时钟除以1。例如,系统时钟为72MHz的话,分频后的频率应该是1Hz,这样每1秒触发一次中断。 然后,需要找到SysTick的初始化代码。在STM32CubeMX生成的代码中,SysTick的初始化通常在HAL_Init()函数里调用,具体实现可能在stm32f1xx_hal.c中的HAL_InitTick函数。用户需要修改这里的分频系数,将原来的分频值从系统时钟/1000改为系统时钟/1。不过,这样可能会导致分频系数过大,超出寄存器的范围,因为SysTick的LOAD寄存器是24位的,最大值为0xFFFFFF。例如,如果系统时钟是72MHz,那么分频后的周期是72MHz / 1 = 72MHz,这显然超过了SysTick的LOAD寄存器的最大值,会导致无法正确设置。所以这种方法可能不可行。 这时候可能需要另一种方法,比如不修改SysTick的配置,而是改变uwTickFreq的值。在HAL库中,uwTickFreq变量表示每秒的滴答数,默认是1kHz(即1000 ticks每秒)。如果将其改为1,那么HAL_GetTick()返回的数值就代表秒数,而不是毫秒数。因此,在HAL_InitTick函数中,需要设置uwTickFreq = 1,并且调整SysTick的中断周期为1秒。不过,同样面临分频系数的问题,SysTick的LOAD寄存器可能无法容纳这么大的值,导致溢出。 另一个可能的解决方案是保持SysTick的配置不变(即每1ms中断一次),但修改HAL_GetTick()的返回值。例如,原本每1ms增加一次计数器,现在让HAL_GetTick()返回的是当前计数值除以1000,这样得到的就是秒数。不过,这样做可能会影响其他依赖HAL_GetTick()的模块,比如超时检测等,因为原来的代码可能期望的是毫秒级的时间。但用户的目的是仅修改HAL_Delay的参数为秒,所以如果只调整HAL_GetTick()的返回值,可能更灵活。 例如,可以覆盖HAL_GetTick()函数,让它返回秒数。或者,在HAL_Delay函数内部,将传入的参数乘以1000,转换为毫秒。但用户想要的是直接修改HAL_Delay的源码,使其参数代表秒。所以更直接的方法是将传入的Delay参数乘以1000,然后再进行比较。不过,原来的HAL_Delay函数已经有处理,比如添加uwTickFreq来保证最小等待时间。所以需要调整这部分逻辑,让传入的参数乘以1000,同时可能修改uwTickFreq的值。 综合来看,最可靠的方法可能是修改SysTick的中断周期为1秒,并调整uwTickFreq为1。不过需要确保SysTick的LOAD寄存器可以容纳所需的计数值。例如,系统时钟为72MHz,如果SysTick的时钟源是HCLK/8(即9MHz),那么LOAD值设置为9,000,000-1就可以实现1秒的中断。这样LOAD值0x895440,这在24位范围内是允许的,因为0x895440等于8,976,960,而9,000,000超过了24位的最大值(16,777,215),所以可能需要调整系统时钟的分频或者使用不同的时钟源。 假设系统时钟为较低频率,比如8MHz,使用HCLK/8作为SysTick时钟源,那么SysTick时钟是1MHz,LOAD值设为1,000,000-1即可,这刚好在24位范围内(0xF423F)。这种情况下,可以实现1秒的中断。 所以,步骤应该是: 1. 在SystemClock_Config函数中,配置SysTick的时钟源和分频,使得SysTick的中断周期为1秒。 2. 修改HAL库中的uwTickFreq变量为1,表示每秒一个tick。 3. 修改HAL_Delay函数,确保传入的参数被当作秒来处理,可能需要调整等待循环的条件。 不过,实际操作中可能会遇到问题,比如系统时钟配置的限制,或者LOAD值超出范围。这时候可能需要调整系统时钟的分频,或者使用其他定时器作为时基。 另外,用户提到网上常用的方法是修改HAL_Delay的时间基准,或者使用额外的定时器。根据引用[1],用户希望找到更方便移植的方法。所以,可能更推荐修改SysTick的配置,并调整uwTickFreq,而不是使用其他定时器。 总结修改步骤: - 修改SysTick的重新加载值,使其每1秒触发一次中断。 - 更新uwTickFreq为1。 - 检查HAL_Delay的代码,确保等待循环正确比较tick差值与Delay参数。 需要注意的是,修改SysTick的周期会影响整个系统的时基,所有依赖HAL_GetTick()的功能都会受到影响,比如超时处理、任务调度等。因此,用户需要确保这种修改不会对其他模块造成问题。 此外,如果用户只是想让HAL_Delay的参数以秒为单位,而不改变其他部分的毫秒处理,可能需要另一种方法,比如在调用HAL_Delay时传入秒数乘以1000,或者创建一个新的函数HAL_DelaySeconds,内部调用HAL_Delay(seconds * 1000)。但用户明确要求修改HAL_Delay的源码,所以必须直接调整其内部实现。 最后,需要测试修改后的代码,确保延时准确,并且系统其他功能正常。</think>### 修改HAL_Delay实现秒级延时的步骤 #### 1. 理解HAL_Delay的默认行为 HAL_Delay默认基于SysTick定时器实现毫秒级延时,其核心依赖`HAL_GetTick()`函数获取系统时间戳[^3]。SysTick默认配置为1kHz频率(每1ms触发一次中断),`uwTickFreq`变量值为`1`(表示每秒1000个tick)[^2]。 #### 2. 修改SysTick时钟配置 需调整SysTick中断频率为1Hz(每秒触发一次): ```c // 在SystemClock_Config()或HAL_InitTick()中修改 HAL_SYSTICK_Config(SystemCoreClock / 1); // 原为SystemCoreClock/1000 ``` #### 3. 更新uwTickFreq参数 在`stm32f1xx_hal.c`中修改`uwTickFreq`的定义,使其表示每秒1个tick: ```c // 修改HAL_InitTick()中的赋值 uwTickFreq = 1; // 原为1000 ``` #### 4. 重HAL_Delay函数逻辑 调整等待循环中的时间计算,直接使用秒级单位: ```c __weak void HAL_Delay(uint32_t Delay) { uint32_t tickstart = HAL_GetTick(); uint32_t wait = Delay; while ((HAL_GetTick() - tickstart) < wait) { // 可添加低功耗模式代码(如__WFI()) } } ``` #### 5. 验证与应用 调用`HAL_Delay(2)`即可实现2秒延时。需注意: - 系统其他依赖`HAL_GetTick()`的模块(如超时检测)会同步变为秒级单位 - 若需保留毫秒级延时,建议新建独立函数而非修改原函数 ```c // 新建毫秒级延时函数(需额外定时器) void HAL_Delay_ms(uint32_t ms) { HAL_TIM_Base_Start(&htim2); __HAL_TIM_SET_COUNTER(&htim2, 0); while (__HAL_TIM_GET_COUNTER(&htim2) < ms); HAL_TIM_Base_Stop(&htim2); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值