Timer PIC18F47K42上的定时器0计数寄存器的增量快于预期

Timer PIC18F47K42上的定时器0计数寄存器的增量快于预期,timer,embedded,cpu-registers,Timer,Embedded,Cpu Registers,我是嵌入式的新手,有点小问题。 我想问题在于我的代码。但是我已经检查了几十次了,我找不到故障 我有一个计时器0,我可以编程为16位(最多可以计数65536)。有一个寄存器位TMR0L和TMR0H,在每个时钟边缘或时钟信号的倍数处递增。我希望它以每0.00001秒的速度递增 根据我的数据表,我设置了以下设置: OSCFRQ = 0x02; //--- HFFRQ 4_MHz T0CON0 = 10010000; //--- Module Enabled; Timer is 16bits; 1:1

我是嵌入式的新手,有点小问题。 我想问题在于我的代码。但是我已经检查了几十次了,我找不到故障

我有一个计时器0,我可以编程为16位(最多可以计数65536)。有一个寄存器位TMR0L和TMR0H,在每个时钟边缘或时钟信号的倍数处递增。我希望它以每0.00001秒的速度递增

根据我的数据表,我设置了以下设置:

OSCFRQ = 0x02; //--- HFFRQ 4_MHz
T0CON0 = 10010000; //--- Module Enabled; Timer is 16bits; 1:1 postscaler
T0CON1 = 01010101; //--- Fosc/4; 1:32 prescaler
我不擅长数学,但我肯定能做基本的算术。 我的时钟是4Mhz。我使用时钟/4作为计时器0的输入。所以这给出了1MHz的频率。1000000/32=31250Hz,每次计数为0.000032秒。一毫秒(0.001/0.000032=31.25计数),所以为了获得一毫秒,我必须用这些参数计算大约31次。对吧?

//Delay function that can delay from 1 milisecond to 2000 miliseconds.
//Uses timer0.

void countDelay(int ms_delay)
{
    //unsigned int oscFreq = ((1<<(00001111&OSCFRQ))*1000000)/4;
    //unsigned int Prescaler = (1<<(00001111&T0CON1));

    unsigned int oscFreq = 4000000;
    unsigned int Prescaler = 32;
    float countTime = (Prescaler/(oscFreq/4)); 

    int countsNum = (int)(((ms_delay/1000)/countTime));

    char endCountDelay = 0;
    TMR0L = 0x00;
    TMR0H = 0x00;
    unsigned int Time16 = 0x0000;

    while(endCountDelay == 0)//PORBLEM
    {
        Time16 = 0;
        Time16 |= TMR0L;
        Time16 |= (TMR0H<<8);
        if (Time16 >= countsNum)
        {
            endCountDelay = 1;
        }
    }

}
有了这个代码,我可以看到LED一直亮着。 我用示波器检查信号:141.76Hz 我们应该看到0.5Hz,周期为2秒,也就是0.5Hz

因此,简言之,我们是283倍太高了。接近2^8中的256。所以我相信这是我代码中的一个错误。也许我的延迟函数中有什么东西?。有人有主意吗

编辑#1:我做了其他测试。我更改了变量的值。不会改变结果。信号保持141Hz,+/-10Hz。即使x16的时钟速度

更改预分频值的操作几乎相同。这次信号保持在141.76Hz

编辑#2:我在pickit中使用了调试器。当我这样做的时候

int countsNum = (((ms_delay/1000)/(Prescaler/(oscFreq/4))));
结果是0。知道为什么吗?不应该

编辑#3:当我使用长字体时,它给了我2.51亿美元

编辑#4:已验证的时钟速度。没关系。 然而,即使所有的整数都不起作用,这种计算也会失败。countsNum的答案是74,但应该是15

unsigned int ms_delay = 500;
unsigned long oscFreq = 4000000;
unsigned long Prescaler = 32768;
unsigned int countsNum = ((ms_delay)/((Prescaler)/(oscFreq/4000)));

这里很难指出确切的问题。我们首先需要验证一些硬件假设:

您的主时钟实际运行频率为4 MHz

你的计时器实际上是以1MHz的频率计数的。再次检查预分频器设置

现在,假设硬件时钟正常,我发现您的时间->计数计算有问题

int countsNum = (((ms_delay/1000)/(Prescaler/(oscFreq/4))));
让我们来评估这条线

ms_delay是传递给特定时间延迟的参数。看起来这是以毫秒为单位的。但是,别忘了我们在做整数数学! 因此,对于任何低于1000的值,ms_delay/1000将计算为零

您可能需要研究浮点计算。或者您需要更改countsNum的计算方式,以防止除法返回零

@编辑4:

unsigned int ms_delay = 500;
unsigned long oscFreq = 4000000;
unsigned long Prescaler = 32768;
unsigned int countsNum = ((ms_delay)/((Prescaler)/(oscFreq/4000)));
让我们用整数来计算

countsNum = (500)/((32768/(4000000/4000))
countsNum = (500)/((32768)/(1000))
countsNum = (500)/(32)
countsNum = 15
即使所有这些数字都使用浮点,结果也是15.259。 而你却得到了74分

PIC18F47K42是一个8位部件,您使用的是“长”值,这使它们具有16位宽。所以这些变量的范围是[065535]表示无符号,或者[-3276832767]表示有符号。如果此算法的任何结果超过此范围,则值将环绕。对于此计算,可能会使可变宽度溢出或下溢。尝试包括并使用类型int32\u t或uint32\u t。如果这解决了您的问题,则表明存在溢出/下溢问题。如果这证明了问题的存在,您可以尝试使用一些编译时表达式

@评论2: 我重读了这个问题。我想我们可能把事情弄得太复杂了。 如上所述,您的16位计时器有一个4MHz时钟,预分频为4,留给我们一个有效的1MHz时钟。其周期为1微秒。对于16位计数器,这意味着我们在以下位置溢出:

 65536 * 1uS = .065535 seconds = 65.536 millisecond
现在,如果我们想找到运行1毫秒的合适计数量,那么我们需要等待多少1微秒的计数,直到有1毫秒?直观地说,我们需要1000微秒才能得到1毫秒

那么,在1微秒时,我们还剩下多少个滴答声才能得到1毫秒?让我们倒过来看看,然后把它放在给定的变量中:

.001 = ntics * (1 / 1000000)
.001 = ntics * (1 / (4000000/4))
.001 = ntics * (1 / (timer_clk / timer_psc))
-so-
.001 * 1000000 = ntics
1000 = ntics
这是否解决了您的问题?

延迟例程中的第三行是一个潜在问题(但不确定它是否解释了所有问题)

    Time16 = 0;
    Time16 |= TMR0L;
    Time16 |= (TMR0H<<8);
    if (Time16 >= countsNum)
    {
        endCountDelay = 1;
    }
Time16=0;
时间16 |=TMR0L;

Time16 |=(TMR0H我找到了答案!原来,有一个寄存器是我的MCC插件自己写的。 在PIC18F47k42中,寄存器

// NOSC HFINTOSC; NDIV 1; 
    OSCCON1 = 0x60;
控制系统时钟。结果是它被设置为0x61,这增加了一个由另一个寄存器设置的除法器。它的值是4


故事的寓意是,逐个检查您的配置寄存器,不要总是信任插件!

谢谢您的时间。是的,我已经验证了时钟信号,它实际上是4MHz。请编辑。我在visual studio上使用无符号长变量编写了相同的代码,它给了我15,就像整数预期的那样。但整数是16位的宽。我可以用整数达到65k,我在寄存器中看到正确的值。长是32位编码。它们以0x00000000的形式出现在我的调试器上。这是32位。执行时的数学似乎大致正确。这意味着基本方程是不正确的。再次感谢您对此进行研究。是的,但我使用,用于我的timer,clockspeed/4+32的预分频器。原因是我想数到65毫秒以上。我需要一个从1ms到1秒的多价延迟函数,这意味着我必须使用这些参数。4000000/4=1000000.1000000/32=31250Hz。这意味着我的计时器应该以每秒31250次的速率递增秒。由于我可以数到65k,我应该可以数到2秒(大约是31250的两倍).这意味着每次计数之间的时间大约是0.000032秒。假设我想数到500毫秒。然后,知道每次计数持续0.000032秒,0.5/0.000032应该给我需要达到500毫秒的计数数。它是15625次计数,这很有意义,是半秒,所以h
// NOSC HFINTOSC; NDIV 1; 
    OSCCON1 = 0x60;