我正在使用stm8l-发现,并且我已经创建了一个代码,用于使用计时器(TIM1)每1秒切换一次led,但这无法正常工作。我的配置中缺少这里的东西
我可以第一次进入中断功能,但此后它不再进入中断功能。有人请调查并帮助我
enter code here
#include <iostm8l.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "defs.h"
unsigned int count = 0;
@svlreg @interrupt void TIM1(void)
{
count += 1;
TIM1_SR1 &= ~(0x01);
}
main()
{
CLK_DIVR = 0x00; // Set the frequency to 16Mhz
CLK_PCKENR2 = 0x02; // clock for timer1
PC_DDR = 0x80; // direction output for led
PC_CR1 = 0x80; // fast push pull mode
PE_DDR = 0x80; // direction output for led
PE_CR1 = 0x80; // fast push pull mode
TIM1_PSCRH = 0x3e; //to create a frequency for 1000 hz
TIM1_PSCRL = 0x80; // so prescalar is 16000
TIM1_CR1 = 0x01;
TIM1_IER = 0x01;
_asm("rim\n");
while(1)
{
if (count == 1000)
{
PE_ODR ^= 0x80;
count = 0;
}
}
}
中断仅进入一次,但之后不进入。因此变量“ count”保持为值1
最佳答案
您将魔术数字用作位掩码,而不是定义的常量,因此对于您我来说,代码都很难读。更改它,以使代码最终像例如TIM1_SR1 &= ~TIM1_SR1_UIF;
由于这是一个8位MCU,因此您必须u
为所有整数后缀加上后缀,否则它们将成为带符号的int
,这是不必要的。
例如,此代码TIM1_SR1 &= ~(0x01);
等效于TIM1_SR1 &= -2
。这样很容易编写意外的细微错误。我建议学习Implicit type promotion rules。
强烈建议拆解您编写的每个ISR,以查看最终使用的机器代码,并在调试器中一步步观察调试器,同时查看寄存器。这个特定的寄存器似乎忽略了向其写入1的情况,因此您可能只需执行TIM1_SR = TIM1_SR1_UIF;
即可。 ISR内部未正确清除的计时器标志是嵌入式系统中最常见的错误之一。
引用手册:
UIF:更新中断标志
–如果TIM1_CR1寄存器中的UDIS = 0,则发生上溢或下溢
–如果使用TIM1_EGR寄存器中的UG位由软件重新初始化CNT,并且TIM1_CR1寄存器中的URS = 0和UDIS = 0。
–通过触发事件重新初始化CNT(请参考TIM1_SMCR寄存器说明)时,如果TIM1_CR1寄存器中的URS = 0和UDIS = 0
您的代码似乎没有执行任何此操作,因此可以很安全地假定计时器计数器未重置。
另一个问题是必须将count
声明为volatile
,否则编译器可能会完全优化此代码:
if (count == 1000)
{
PE_ODR ^= 0x80;
count = 0;
}
关于c - 我需要知道为什么我的打扰在这里不起作用,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58087436/