为啥我不能同时使用 Systick 和 Timer1
Posted
技术标签:
【中文标题】为啥我不能同时使用 Systick 和 Timer1【英文标题】:Why can`t I use Systick and Timer1 simultaneously为什么我不能同时使用 Systick 和 Timer1 【发布时间】:2020-09-13 21:47:42 【问题描述】:我正在使用 Systick 计时器来创建延迟,systick 的处理程序每微秒 (1 µs) 发生一次。
此外,我使用的是 TIM1,它的处理程序每秒发生一次(1 秒)。 在 timer1 处理程序中,我正在切换 LED。
在 while 循环内的主函数中,我正在切换另一个 LED(与 timer1 处理程序中的不同),这里的延迟函数使用 Systick。
timer1 处理程序按预期执行,但问题是主函数中的 while 循环从未执行。
有什么帮助吗?
volatile uint32_t i=0;
void TIM1_UP_TIM10_IRQHandler(void)
NVIC_ClearPendingIRQ(TIM1_UP_TIM10_IRQn);
i ^= 1;
if(i == 1)
LED_On(0);
else
LED_Off(0);
TIM1->SR &= ~(1 << 0);
int main(void)
NVIC_SetPriority(TIM1_UP_TIM10_IRQn, 32);
NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn);
LED_Initialize();
RCC->APB2ENR |= (1 << 0); // Enable Timer1 clock
TIM1->CR1 &= ~(1 << 4); // Set the direction of timer to be upcounter
TIM1->DIER |= (1 << 0); // Enable tim1 interrupt request
TIM1->PSC = 15999; // each count takes 1 msec
TIM1->ARR = 1000; //each 1 sec an overflow update event occurs
TIM1->CR1 |= (1 << 0);
SysTick_Init(16000000/1000000);
while(1)
LED_On(1);
Delay_MS(5000);
LED_Off(1);
Delay_MS(5000);
return 0;
【问题讨论】:
您是否正确地从中断中返回?你当然可以使用 systick 和 tim1(如果你的系统有一个 systick(和一个 tim1)一起使用。 你的uC频率是多少?你应该试试 SysTick_Init(16000000/1000);对于 16000 兆赫。另外,使用您的计时器,PSC=16000 和 ARR=1000,我每 1 秒计数一次。 您没有提供 SYSTICK 处理程序或Delay_MS()
函数。这有点关键。
【参考方案1】:
如果您的时钟为 16MHz,并且您希望每 16 个时钟发生一次中断,那么它现在可以工作了。在最佳停止情况下(代码从 RAM 运行等),您需要至少 11 个时钟来进入中断处理程序,并需要 6 个时钟来退出它,这超过了中断之间的时间。
即使你跑得更快,每个人都被打断是个坏主意。 168MHz 设备在中断之间只有 168 个时钟。假设您的处理程序将运行 20 个时钟 + 11 + 6 = ~40clcks。这意味着25%的处理器时间将用于增加变量!!!不要做。在许多其他(最大时钟 72 或 80MHz)上,情况会更糟。
如果您希望我们延迟执行类似的操作(如果您重新加载计数器,则需要将其考虑在内)。代码只是为了展示思路
#define TICKSPER_uS 80
void delay_us(uint32_t uS)
uint32_t endCnt = SysTick -> VAL + uS * TICKSPER_uS;
while(SysTick -> VAL < endCNT);
【讨论】:
【参考方案2】:对于 SYSTICK 中断来说,一微秒的速度过快;尤其是在仅以 16MHz 运行时。您的系统可能几乎 100% 的时间都花在了中断处理程序计数滴答上。
即使它可以维持 1MHz 的中断率,如果 Delay_MS(5000)
是 5000 个 SYSTICK 周期的延迟,那么您将切换 LED 和 100Hz,并且不会感觉到任何闪烁,只是亮度变暗。
您似乎更可能打算一毫秒,这是一个更合理的滴答间隔:
SysTick_Init( 16000000 / 1000 ) ;
虽然我实际上会建议:
SysTick_Init( SystemCoreClock / 1000 ) ;
以便您的代码能够适应时钟频率的变化 - 因为 16MHz 是运行 STM32 的相当适中的频率。
在任何情况下,您的 SYSTICK 处理程序和Delay_MS()
实现也有可能出现错误,但如果没有看到该代码,就无法猜测。如果两者都提供了库代码,则可能性较小。
【讨论】:
【参考方案3】:这是我的 usec 延迟函数
//==============================================================================
static uint32_t timeMicroSecDivider = 0;
extern uint32_t uwTick;
//==============================================================================
// The SysTick->LOAD match the uC Speed / 1000.
// If the uC clock is 80MHz, the the LOAD is 80000
// The SysTick->VAL is the decrement counter from (LOAD-1) to 0
//==============================================================================
uint64_t getTimeMicroSec()
if ( timeMicroSecDivider == 0)
// Number of clock by micro second
timeMicroSecDivider = SysTick->LOAD / 1000;
return( (uwTick * 1000) + ((SysTick->LOAD - SysTick->VAL) / timeMicroSecDivider));
//==============================================================================
void delayTimeMicroSec(uint32_t delay)
uint64_t tickstart = getTimeMicroSec();
while ((getTimeMicroSec() - tickstart) < delay)
;
【讨论】:
以上是关于为啥我不能同时使用 Systick 和 Timer1的主要内容,如果未能解决你的问题,请参考以下文章
为啥我不能更改 Timer.scheduledTimer 函数中变量的值?
System.Threading.Timer:它为啥讨厌我?
为啥 System.Timers.Timer 能在 GC 中存活,而 System.Threading.Timer 不能?